abi-compliance-checker.pl revision 35c44fd1428ba96f71ba80f1d45c175a9ab4a197
1d30bf2eb6d6bbebd41236bf205d3a6dfc51a3659Douglas Gregor#!/usr/bin/perl
2d30bf2eb6d6bbebd41236bf205d3a6dfc51a3659Douglas Gregor###########################################################################
3d30bf2eb6d6bbebd41236bf205d3a6dfc51a3659Douglas Gregor# ABI Compliance Checker (ACC) 1.98.1
4d30bf2eb6d6bbebd41236bf205d3a6dfc51a3659Douglas Gregor# A tool for checking backward compatibility of a C/C++ library API
5d30bf2eb6d6bbebd41236bf205d3a6dfc51a3659Douglas Gregor#
6d30bf2eb6d6bbebd41236bf205d3a6dfc51a3659Douglas Gregor# Copyright (C) 2009-2010 The Linux Foundation
7d30bf2eb6d6bbebd41236bf205d3a6dfc51a3659Douglas Gregor# Copyright (C) 2009-2011 Institute for System Programming, RAS
8d30bf2eb6d6bbebd41236bf205d3a6dfc51a3659Douglas Gregor# Copyright (C) 2011-2012 Nokia Corporation and/or its subsidiary(-ies)
9d30bf2eb6d6bbebd41236bf205d3a6dfc51a3659Douglas Gregor# Copyright (C) 2011-2012 ROSA Laboratory
10d30bf2eb6d6bbebd41236bf205d3a6dfc51a3659Douglas Gregor#
11d30bf2eb6d6bbebd41236bf205d3a6dfc51a3659Douglas Gregor# Written by Andrey Ponomarenko
12d30bf2eb6d6bbebd41236bf205d3a6dfc51a3659Douglas Gregor#
13d30bf2eb6d6bbebd41236bf205d3a6dfc51a3659Douglas Gregor# PLATFORMS
14d30bf2eb6d6bbebd41236bf205d3a6dfc51a3659Douglas Gregor# =========
15d30bf2eb6d6bbebd41236bf205d3a6dfc51a3659Douglas Gregor#  Linux, FreeBSD, Mac OS X, Haiku, MS Windows, Symbian
16d30bf2eb6d6bbebd41236bf205d3a6dfc51a3659Douglas Gregor#
1787d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar# REQUIREMENTS
1887d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar# ============
19651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines#  Linux
20d30bf2eb6d6bbebd41236bf205d3a6dfc51a3659Douglas Gregor#    - G++ (3.0-4.7, recommended 4.5 or newer)
21d30bf2eb6d6bbebd41236bf205d3a6dfc51a3659Douglas Gregor#    - GNU Binutils (readelf, c++filt, objdump)
22d30bf2eb6d6bbebd41236bf205d3a6dfc51a3659Douglas Gregor#    - Perl 5 (5.8 or newer)
23d30bf2eb6d6bbebd41236bf205d3a6dfc51a3659Douglas Gregor#
24c640058aa7f224a71ce3b1d2601d84e1b57f82d3Alexey Bataev#  Mac OS X
25d30bf2eb6d6bbebd41236bf205d3a6dfc51a3659Douglas Gregor#    - Xcode (gcc, otool, c++filt)
26d30bf2eb6d6bbebd41236bf205d3a6dfc51a3659Douglas Gregor#
27d30bf2eb6d6bbebd41236bf205d3a6dfc51a3659Douglas Gregor#  MS Windows
28d30bf2eb6d6bbebd41236bf205d3a6dfc51a3659Douglas Gregor#    - MinGW (3.0-4.7, recommended 4.5 or newer)
2987d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar#    - MS Visual C++ (dumpbin, undname, cl)
30d30bf2eb6d6bbebd41236bf205d3a6dfc51a3659Douglas Gregor#    - Active Perl 5 (5.8 or newer)
31d30bf2eb6d6bbebd41236bf205d3a6dfc51a3659Douglas Gregor#    - Sigcheck v1.71 or newer
32d30bf2eb6d6bbebd41236bf205d3a6dfc51a3659Douglas Gregor#    - Info-ZIP 3.0 (zip, unzip)
33d30bf2eb6d6bbebd41236bf205d3a6dfc51a3659Douglas Gregor#    - Add gcc.exe path (C:\MinGW\bin\) to your system PATH variable
344fa7eab771ab8212e1058bd1a91061ff120c8fbbAlexey Bataev#    - Run vsvars32.bat (C:\Microsoft Visual Studio 9.0\Common7\Tools\)
35d30bf2eb6d6bbebd41236bf205d3a6dfc51a3659Douglas Gregor#
36d30bf2eb6d6bbebd41236bf205d3a6dfc51a3659Douglas Gregor# This program is free software: you can redistribute it and/or modify
37d30bf2eb6d6bbebd41236bf205d3a6dfc51a3659Douglas Gregor# it under the terms of the GNU General Public License or the GNU Lesser
384d2229c7a9514ee2b960aa9e59f7259cebbaa421Nick Lewycky# General Public License as published by the Free Software Foundation.
39d30bf2eb6d6bbebd41236bf205d3a6dfc51a3659Douglas Gregor#
407d66f8cafd807e551efb4739cdb37fc272cf5345Chandler Carruth# This program is distributed in the hope that it will be useful,
417d66f8cafd807e551efb4739cdb37fc272cf5345Chandler Carruth# but WITHOUT ANY WARRANTY; without even the implied warranty of
427d66f8cafd807e551efb4739cdb37fc272cf5345Chandler Carruth# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
437d66f8cafd807e551efb4739cdb37fc272cf5345Chandler Carruth# GNU General Public License for more details.
446bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines#
456bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines# You should have received a copy of the GNU General Public License
466bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines# and the GNU Lesser General Public License along with this program.
476bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines# If not, see <http://www.gnu.org/licenses/>.
4887d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar###########################################################################
497d66f8cafd807e551efb4739cdb37fc272cf5345Chandler Carruthuse Getopt::Long;
507d66f8cafd807e551efb4739cdb37fc272cf5345Chandler CarruthGetopt::Long::Configure ("posix_default", "no_ignore_case");
516bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hinesuse File::Path qw(mkpath rmtree);
526bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hinesuse File::Temp qw(tempdir);
536bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hinesuse File::Copy qw(copy move);
546bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hinesuse Cwd qw(abs_path cwd);
556bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hinesuse Data::Dumper;
566bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hinesuse Config;
577d66f8cafd807e551efb4739cdb37fc272cf5345Chandler Carruth
587d66f8cafd807e551efb4739cdb37fc272cf5345Chandler Carruthmy $TOOL_VERSION = "1.98.1";
596bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hinesmy $ABI_DUMP_VERSION = "2.17";
606bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hinesmy $OLDEST_SUPPORTED_VERSION = "1.18";
616bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hinesmy $XML_REPORT_VERSION = "1.0";
627d66f8cafd807e551efb4739cdb37fc272cf5345Chandler Carruthmy $XML_ABI_DUMP_VERSION = "1.1";
63d30bf2eb6d6bbebd41236bf205d3a6dfc51a3659Douglas Gregormy $OSgroup = get_OSgroup();
64facfc77487a890bfb7b5eee7e21cd2b395a9faafChandler Carruthmy $ORIG_DIR = cwd();
65dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruthmy $TMP_DIR = tempdir(CLEANUP=>1);
66dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth
67dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth# Internal modules
68dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruthmy $MODULES_DIR = get_Modules();
696bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hinespush(@INC, get_dirname($MODULES_DIR));
706bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines# Rules DB
716bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hinesmy %RULES_PATH = (
726bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    "Binary" => $MODULES_DIR."/RulesBin.xml",
736bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    "Source" => $MODULES_DIR."/RulesSrc.xml");
74dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth
754967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainarmy ($Help, $ShowVersion, %Descriptor, $TargetLibraryName, $GenerateTemplate,
764967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar$TestTool, $DumpAPI, $SymbolsListPath, $CheckHeadersOnly_Opt, $UseDumps,
77dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth$CheckObjectsOnly_Opt, $AppPath, $StrictCompat, $DumpVersion, $ParamNamesPath,
78dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth%RelativeDirectory, $TargetLibraryFName, $TestDump, $CheckImpl, $LoggingPath,
79dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth%TargetVersion, $InfoMsg, $UseOldDumps, %UsedDump, $CrossGcc, %OutputLogPath,
80dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth$OutputReportPath, $OutputDumpPath, $ShowRetVal, $SystemRoot_Opt, $DumpSystem,
81dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth$CmpSystems, $TargetLibsPath, $Debug, $CrossPrefix, $UseStaticLibs, $NoStdInc,
82dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth$TargetComponent_Opt, $TargetSysInfo, $TargetHeader, $ExtendedCheck, $Quiet,
83dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth$SkipHeadersPath, $Cpp2003, $LogMode, $StdOut, $ListAffected, $ReportFormat,
84dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth$UserLang, $TargetHeadersPath, $BinaryOnly, $SourceOnly, $BinaryReportPath,
85dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth$SourceReportPath, $UseXML, $Browse, $OpenReport, $SortDump, $DumpFormat);
86dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth
87dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruthmy $CmdName = get_filename($0);
88ea245e0ba48caf7e7acf870880c030d7ddc76667Craig Silversteinmy %OS_LibExt = (
89dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth    "dynamic" => {
90ea245e0ba48caf7e7acf870880c030d7ddc76667Craig Silverstein        "default"=>"so",
91dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth        "macos"=>"dylib",
92dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth        "windows"=>"dll",
93ea245e0ba48caf7e7acf870880c030d7ddc76667Craig Silverstein        "symbian"=>"dso"
94dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth    },
95ea245e0ba48caf7e7acf870880c030d7ddc76667Craig Silverstein    "static" => {
96dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth        "default"=>"a",
97dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth        "windows"=>"lib",
98dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth        "symbian"=>"lib"
99ea245e0ba48caf7e7acf870880c030d7ddc76667Craig Silverstein    }
100dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth);
101dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth
102dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruthmy %OS_Archive = (
103e3e210c3aa3c1b289eee669a1d235fc16df384a0Chandler Carruth    "windows"=>"zip",
104dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth    "default"=>"tar.gz"
105dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth);
106b5c202f9e4f6d0f230d5cb8848779259ebf95b7fChandler Carruth
107b5c202f9e4f6d0f230d5cb8848779259ebf95b7fChandler Carruthmy %ERROR_CODE = (
108b5c202f9e4f6d0f230d5cb8848779259ebf95b7fChandler Carruth    # Compatible verdict
10980434a334c92d2f24f38fbbd14acd6c3f6c72306Michael Han    "Compatible"=>0,
110b5c202f9e4f6d0f230d5cb8848779259ebf95b7fChandler Carruth    "Success"=>0,
111b5c202f9e4f6d0f230d5cb8848779259ebf95b7fChandler Carruth    # Incompatible verdict
112dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth    "Incompatible"=>1,
113dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth    # Undifferentiated error code
114dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth    "Error"=>2,
115dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth    # System command is not found
116dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth    "Not_Found"=>3,
117dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth    # Cannot access input files
118dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth    "Access_Error"=>4,
119dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth    # Cannot compile header files
120dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth    "Cannot_Compile"=>5,
121dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth    # Header compiled with errors
122dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth    "Compile_Error"=>6,
123e3e210c3aa3c1b289eee669a1d235fc16df384a0Chandler Carruth    # Invalid input ABI dump
124dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth    "Invalid_Dump"=>7,
125760c8af273d9871d063250ae626fb6df94c121f2John McCall    # Incompatible version of ABI dump
126760c8af273d9871d063250ae626fb6df94c121f2John McCall    "Dump_Version"=>8,
127760c8af273d9871d063250ae626fb6df94c121f2John McCall    # Cannot find a module
128760c8af273d9871d063250ae626fb6df94c121f2John McCall    "Module_Error"=>9,
129760c8af273d9871d063250ae626fb6df94c121f2John McCall    # Empty intersection between
130760c8af273d9871d063250ae626fb6df94c121f2John McCall    # headers and shared objects
131760c8af273d9871d063250ae626fb6df94c121f2John McCall    "Empty_Intersection"=>10,
132760c8af273d9871d063250ae626fb6df94c121f2John McCall    # Empty set of symbols in headers
133760c8af273d9871d063250ae626fb6df94c121f2John McCall    "Empty_Set"=>11
134760c8af273d9871d063250ae626fb6df94c121f2John McCall);
135760c8af273d9871d063250ae626fb6df94c121f2John McCall
1364967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainarmy %HomePage = (
1374967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    "Wiki"=>"http://ispras.linuxbase.org/index.php/ABI_compliance_checker",
1384967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    "Dev1"=>"https://github.com/lvc/abi-compliance-checker",
1394967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    "Dev2"=>"http://forge.ispras.ru/projects/abi-compliance-checker"
1406bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines);
141db3f847cb883fdb19d79c7223fa032e7266c0ee5Nick Lewycky
14287d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainarmy $ShortUsage = "ABI Compliance Checker (ACC) $TOOL_VERSION
14387d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga NainarA tool for checking backward compatibility of a C/C++ library API
14487d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga NainarCopyright (C) 2012 ROSA Laboratory
14587d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga NainarLicense: GNU LGPL or GNU GPL
1464967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar
1474967a710c84587c654b56c828382219c3937dacbPirama Arumuga NainarUsage: $CmdName [options]
1484967a710c84587c654b56c828382219c3937dacbPirama Arumuga NainarExample: $CmdName -lib NAME -old OLD.xml -new NEW.xml
14987d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar
150db3f847cb883fdb19d79c7223fa032e7266c0ee5Nick LewyckyOLD.xml and NEW.xml are XML-descriptors:
1516bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines
152db3f847cb883fdb19d79c7223fa032e7266c0ee5Nick Lewycky    <version>
153760c8af273d9871d063250ae626fb6df94c121f2John McCall        1.0
154760c8af273d9871d063250ae626fb6df94c121f2John McCall    </version>
155760c8af273d9871d063250ae626fb6df94c121f2John McCall
156536bab452fa38692834233187ed3d49b83722cb3Craig Silverstein    <headers>
157a40bc724849f9cdc6a7706bc5d230685c3bdf63cDouglas Gregor        /path/to/headers/
158a40bc724849f9cdc6a7706bc5d230685c3bdf63cDouglas Gregor    </headers>
159a40bc724849f9cdc6a7706bc5d230685c3bdf63cDouglas Gregor
160ba243b59a1074e0962f6abfa3bb9aa984eac1245David Blaikie    <libs>
161c28a335184207a47f34eb9d1707dc8d7c6c7b8b6Richard Smith        /path/to/libraries/
16252ec0c0357ce970ca52a27c1086626450f0967e7Daniel Jasper    </libs>
16352ec0c0357ce970ca52a27c1086626450f0967e7Daniel Jasper
164c28a335184207a47f34eb9d1707dc8d7c6c7b8b6Richard SmithMore info: $CmdName --help\n";
1654967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar
1664967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainarif($#ARGV==-1) {
1674967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    printMsg("INFO", $ShortUsage);
168db3f847cb883fdb19d79c7223fa032e7266c0ee5Nick Lewycky    exit(0);
169717cc00c16eabf0eefd3cc69394e97f7229af0c8Zhanyong Wan}
170db3f847cb883fdb19d79c7223fa032e7266c0ee5Nick Lewycky
171e3e210c3aa3c1b289eee669a1d235fc16df384a0Chandler Carruthforeach (2 .. $#ARGV)
17287d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar{ # correct comma separated options
17387d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar    if($ARGV[$_-1] eq ",") {
174db3f847cb883fdb19d79c7223fa032e7266c0ee5Nick Lewycky        $ARGV[$_-2].=",".$ARGV[$_];
1754967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar        splice(@ARGV, $_-1, 2);
1764967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    }
1774967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    elsif($ARGV[$_-1]=~/,\Z/) {
1784967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar        $ARGV[$_-1].=$ARGV[$_];
1794967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar        splice(@ARGV, $_, 1);
1804967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    }
1814967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    elsif($ARGV[$_]=~/\A,/
1824967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    and $ARGV[$_] ne ",") {
1834967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar        $ARGV[$_-1].=$ARGV[$_];
1844967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar        splice(@ARGV, $_, 1);
1854967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    }
1864967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar}
187db3f847cb883fdb19d79c7223fa032e7266c0ee5Nick Lewycky
188717cc00c16eabf0eefd3cc69394e97f7229af0c8Zhanyong WanGetOptions("h|help!" => \$Help,
189db3f847cb883fdb19d79c7223fa032e7266c0ee5Nick Lewycky  "i|info!" => \$InfoMsg,
190e3e210c3aa3c1b289eee669a1d235fc16df384a0Chandler Carruth  "v|version!" => \$ShowVersion,
191db3f847cb883fdb19d79c7223fa032e7266c0ee5Nick Lewycky  "dumpversion!" => \$DumpVersion,
192dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth# general options
193db3f847cb883fdb19d79c7223fa032e7266c0ee5Nick Lewycky  "l|lib|library=s" => \$TargetLibraryName,
1944d2229c7a9514ee2b960aa9e59f7259cebbaa421Nick Lewycky  "d1|old|o=s" => \$Descriptor{1}{"Path"},
195717cc00c16eabf0eefd3cc69394e97f7229af0c8Zhanyong Wan  "d2|new|n=s" => \$Descriptor{2}{"Path"},
1964d2229c7a9514ee2b960aa9e59f7259cebbaa421Nick Lewycky  "dump|dump-abi|dump_abi=s" => \$DumpAPI,
1974d2229c7a9514ee2b960aa9e59f7259cebbaa421Nick Lewycky  "old-dumps!" => \$UseOldDumps,
1984d2229c7a9514ee2b960aa9e59f7259cebbaa421Nick Lewycky# extra options
1994d2229c7a9514ee2b960aa9e59f7259cebbaa421Nick Lewycky  "d|descriptor-template!" => \$GenerateTemplate,
2004d2229c7a9514ee2b960aa9e59f7259cebbaa421Nick Lewycky  "app|application=s" => \$AppPath,
201651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  "static-libs!" => \$UseStaticLibs,
202651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  "cross-gcc|gcc-path=s" => \$CrossGcc,
203651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  "cross-prefix|gcc-prefix=s" => \$CrossPrefix,
204651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  "sysroot=s" => \$SystemRoot_Opt,
205651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  "v1|version1|vnum=s" => \$TargetVersion{1},
206651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  "v2|version2=s" => \$TargetVersion{2},
207651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  "s|strict!" => \$StrictCompat,
208db3f847cb883fdb19d79c7223fa032e7266c0ee5Nick Lewycky  "symbols-list=s" => \$SymbolsListPath,
209717cc00c16eabf0eefd3cc69394e97f7229af0c8Zhanyong Wan  "skip-headers=s" => \$SkipHeadersPath,
210db3f847cb883fdb19d79c7223fa032e7266c0ee5Nick Lewycky  "headers-only|headers_only!" => \$CheckHeadersOnly_Opt,
211e3e210c3aa3c1b289eee669a1d235fc16df384a0Chandler Carruth  "objects-only!" => \$CheckObjectsOnly_Opt,
212db3f847cb883fdb19d79c7223fa032e7266c0ee5Nick Lewycky  "check-impl|check-implementation!" => \$CheckImpl,
213dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth  "show-retval!" => \$ShowRetVal,
214db3f847cb883fdb19d79c7223fa032e7266c0ee5Nick Lewycky  "use-dumps!" => \$UseDumps,
215db3f847cb883fdb19d79c7223fa032e7266c0ee5Nick Lewycky  "nostdinc!" => \$NoStdInc,
216db3f847cb883fdb19d79c7223fa032e7266c0ee5Nick Lewycky  "dump-system=s" => \$DumpSystem,
217e3e210c3aa3c1b289eee669a1d235fc16df384a0Chandler Carruth  "sysinfo=s" => \$TargetSysInfo,
218dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth  "cmp-systems!" => \$CmpSystems,
219db3f847cb883fdb19d79c7223fa032e7266c0ee5Nick Lewycky  "libs-list=s" => \$TargetLibsPath,
220ba243b59a1074e0962f6abfa3bb9aa984eac1245David Blaikie  "headers-list=s" => \$TargetHeadersPath,
221dc355713be51fcb4ee52d9fd6b4548ceff47fadfDouglas Gregor  "header=s" => \$TargetHeader,
222dc355713be51fcb4ee52d9fd6b4548ceff47fadfDouglas Gregor  "ext|extended!" => \$ExtendedCheck,
223dc355713be51fcb4ee52d9fd6b4548ceff47fadfDouglas Gregor  "q|quiet!" => \$Quiet,
224dc355713be51fcb4ee52d9fd6b4548ceff47fadfDouglas Gregor  "stdout!" => \$StdOut,
225dc355713be51fcb4ee52d9fd6b4548ceff47fadfDouglas Gregor  "report-format=s" => \$ReportFormat,
22665019acfc46ffb191fac4e781ac0c4b8d0c8434eDouglas Gregor  "dump-format=s" => \$DumpFormat,
22765019acfc46ffb191fac4e781ac0c4b8d0c8434eDouglas Gregor  "xml!" => \$UseXML,
22865019acfc46ffb191fac4e781ac0c4b8d0c8434eDouglas Gregor  "lang=s" => \$UserLang,
22965019acfc46ffb191fac4e781ac0c4b8d0c8434eDouglas Gregor  "binary|bin|abi!" => \$BinaryOnly,
230ba243b59a1074e0962f6abfa3bb9aa984eac1245David Blaikie  "source|src|api!" => \$SourceOnly,
231dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth# other options
232dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth  "test!" => \$TestTool,
233db3f847cb883fdb19d79c7223fa032e7266c0ee5Nick Lewycky  "test-dump!" => \$TestDump,
234e3e210c3aa3c1b289eee669a1d235fc16df384a0Chandler Carruth  "debug!" => \$Debug,
235dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth  "cpp-compatible!" => \$Cpp2003,
236db3f847cb883fdb19d79c7223fa032e7266c0ee5Nick Lewycky  "p|params=s" => \$ParamNamesPath,
237dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth  "relpath1|relpath=s" => \$RelativeDirectory{1},
238dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth  "relpath2=s" => \$RelativeDirectory{2},
239db3f847cb883fdb19d79c7223fa032e7266c0ee5Nick Lewycky  "dump-path=s" => \$OutputDumpPath,
240e3e210c3aa3c1b289eee669a1d235fc16df384a0Chandler Carruth  "sort!" => \$SortDump,
2414d2229c7a9514ee2b960aa9e59f7259cebbaa421Nick Lewycky  "report-path=s" => \$OutputReportPath,
242dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth  "bin-report-path=s" => \$BinaryReportPath,
243db3f847cb883fdb19d79c7223fa032e7266c0ee5Nick Lewycky  "src-report-path=s" => \$SourceReportPath,
2444d2229c7a9514ee2b960aa9e59f7259cebbaa421Nick Lewycky  "log-path=s" => \$LoggingPath,
2454d2229c7a9514ee2b960aa9e59f7259cebbaa421Nick Lewycky  "log1-path=s" => \$OutputLogPath{1},
2464d2229c7a9514ee2b960aa9e59f7259cebbaa421Nick Lewycky  "log2-path=s" => \$OutputLogPath{2},
2474d2229c7a9514ee2b960aa9e59f7259cebbaa421Nick Lewycky  "logging-mode=s" => \$LogMode,
2484d2229c7a9514ee2b960aa9e59f7259cebbaa421Nick Lewycky  "list-affected!" => \$ListAffected,
2494d2229c7a9514ee2b960aa9e59f7259cebbaa421Nick Lewycky  "l-full|lib-full=s" => \$TargetLibraryFName,
250db3f847cb883fdb19d79c7223fa032e7266c0ee5Nick Lewycky  "component=s" => \$TargetComponent_Opt,
251dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth  "b|browse=s" => \$Browse,
252dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth  "open!" => \$OpenReport
253db3f847cb883fdb19d79c7223fa032e7266c0ee5Nick Lewycky) or ERR_MESSAGE();
254e3e210c3aa3c1b289eee669a1d235fc16df384a0Chandler Carruth
255dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruthsub ERR_MESSAGE()
256dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth{
257dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth    printMsg("INFO", "\n".$ShortUsage);
258db3f847cb883fdb19d79c7223fa032e7266c0ee5Nick Lewycky    exit($ERROR_CODE{"Error"});
2590f8c08843fc6c8abe03654f609e1e03fcc557855Craig Silverstein}
2600f8c08843fc6c8abe03654f609e1e03fcc557855Craig Silverstein
2610f8c08843fc6c8abe03654f609e1e03fcc557855Craig Silversteinmy $LIB_TYPE = $UseStaticLibs?"static":"dynamic";
2624d072932287eb074a4168804cac1acb18a51d5e8Craig Silversteinmy $SLIB_TYPE = $LIB_TYPE;
2630f8c08843fc6c8abe03654f609e1e03fcc557855Craig Silversteinif($OSgroup!~/macos|windows/ and $SLIB_TYPE eq "dynamic")
2640f8c08843fc6c8abe03654f609e1e03fcc557855Craig Silverstein{ # show as "shared" library
265cbb67480094b3bcb5b715acd827cbad55e2a204cSean Hunt    $SLIB_TYPE = "shared";
2660f8c08843fc6c8abe03654f609e1e03fcc557855Craig Silverstein}
267011d8b93b7cfa8492b8a9c909a850d6577e08dcaDouglas Gregormy $LIB_EXT = getLIB_EXT($OSgroup);
268011d8b93b7cfa8492b8a9c909a850d6577e08dcaDouglas Gregormy $AR_EXT = getAR_EXT($OSgroup);
269011d8b93b7cfa8492b8a9c909a850d6577e08dcaDouglas Gregormy $BYTE_SIZE = 8;
2706bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hinesmy $COMMON_LOG_PATH = "logs/run.log";
27149007d7561212c0ae168702c1af1404c01ef43ffJames Dennett
27249007d7561212c0ae168702c1af1404c01ef43ffJames Dennettmy $HelpMessage="
27349007d7561212c0ae168702c1af1404c01ef43ffJames DennettNAME:
27449007d7561212c0ae168702c1af1404c01ef43ffJames Dennett  ABI Compliance Checker ($CmdName)
27549007d7561212c0ae168702c1af1404c01ef43ffJames Dennett  Check backward compatibility of a C/C++ library API
27649007d7561212c0ae168702c1af1404c01ef43ffJames Dennett
27749007d7561212c0ae168702c1af1404c01ef43ffJames DennettDESCRIPTION:
27887d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar  ABI Compliance Checker (ACC) is a tool for checking backward binary and
27987d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar  source-level compatibility of a $SLIB_TYPE C/C++ library. The tool checks
28087d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar  header files and $SLIB_TYPE libraries (*.$LIB_EXT) of old and new versions and
28187d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar  analyzes changes in API and ABI (ABI=API+compiler ABI) that may break binary
28287d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar  and/or source-level compatibility: changes in calling stack, v-table changes,
28387d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar  removed symbols, renamed fields, etc. Binary incompatibility may result in
28487d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar  crashing or incorrect behavior of applications built with an old version of
28587d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar  a library if they run on a new one. Source incompatibility may result in
28649007d7561212c0ae168702c1af1404c01ef43ffJames Dennett  recompilation errors with a new library version.
287651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
288651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  The tool is intended for developers of software libraries and maintainers
289651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  of operating systems who are interested in ensuring backward compatibility,
290651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  i.e. allow old applications to run or to be recompiled with newer library
291651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  versions.
2926bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines
293651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  Also the tool can be used by ISVs for checking applications portability to
294651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  new library versions. Found issues can be taken into account when adapting
295651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  the application to a new library version.
296651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
2976bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  This tool is free software: you can redistribute it and/or modify it
298dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth  under the terms of the GNU LGPL or GNU GPL.
29987d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar
30087d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga NainarUSAGE:
30187d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar  $CmdName [options]
30287d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar
30387d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga NainarEXAMPLE:
30487d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar  $CmdName -lib NAME -old OLD.xml -new NEW.xml
30587d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar
30687d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar  OLD.xml and NEW.xml are XML-descriptors:
30787d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar
30887d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar    <version>
30987d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar        1.0
31087d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar    </version>
31187d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar
31287d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar    <headers>
31387d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar        /path1/to/header(s)/
31487d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar        /path2/to/header(s)/
31587d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar         ...
31687d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar    </headers>
31787d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar
31887d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar    <libs>
31987d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar        /path1/to/library(ies)/
32087d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar        /path2/to/library(ies)/
32187d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar         ...
32287d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar    </libs>
32387d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar
32487d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga NainarINFORMATION OPTIONS:
32587d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar  -h|-help
32687d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar      Print this help.
32787d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar
32887d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar  -i|-info
32987d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar      Print complete info.
33087d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar
33187d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar  -v|-version
33287d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar      Print version information.
3336bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines
334dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth  -dumpversion
33587d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar      Print the tool version ($TOOL_VERSION) and don't do anything else.
33687d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar
337dfc35e33177a433b56454f1d2b5e53734f65b288Chandler CarruthGENERAL OPTIONS:
338dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth  -l|-lib|-library <name>
339dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth      Library name (without version).
340dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth      It affects only on the path and the title of the report.
341dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth
342e3e210c3aa3c1b289eee669a1d235fc16df384a0Chandler Carruth  -d1|-old|-o <path>
3436bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines      Descriptor of 1st (old) library version.
3446bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines      It may be one of the following:
3456bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines
3466bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines         1. XML-descriptor (VERSION.xml file):
3476bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines
3486bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines              <version>
349e3e210c3aa3c1b289eee669a1d235fc16df384a0Chandler Carruth                  1.0
350d30bf2eb6d6bbebd41236bf205d3a6dfc51a3659Douglas Gregor              </version>
351db3f847cb883fdb19d79c7223fa032e7266c0ee5Nick Lewycky
3526bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines              <headers>
3536bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines                  /path1/to/header(s)/
3546bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines                  /path2/to/header(s)/
3556bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines                   ...
35687d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar              </headers>
35787d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar
3586bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines              <libs>
3594967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar                  /path1/to/library(ies)/
3606bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines                  /path2/to/library(ies)/
3616bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines                   ...
3626bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines              </libs>
3636bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines
3646bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines                 ... (XML-descriptor template
3656bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines                         can be generated by -d option)
3666bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines
367e3e210c3aa3c1b289eee669a1d235fc16df384a0Chandler Carruth         2. ABI dump generated by -dump option
368dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth         3. Directory with headers and/or $SLIB_TYPE libraries
3697d66f8cafd807e551efb4739cdb37fc272cf5345Chandler Carruth         4. Single header file
3707d66f8cafd807e551efb4739cdb37fc272cf5345Chandler Carruth         5. Single $SLIB_TYPE library
371dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth         6. Comma separated list of headers and/or libraries
3726bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines
3736bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines      If you are using an 2-6 descriptor types then you should
3746bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines      specify version numbers with -v1 <num> and -v2 <num> options too.
3756bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines
37687d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar      For more information, please see:
3774967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar        http://ispras.linuxbase.org/index.php/Library_Descriptor
3784967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar
3794967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar  -d2|-new|-n <path>
3804967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar      Descriptor of 2nd (new) library version.
3816bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines
3826bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  -dump|-dump-abi <descriptor path(s)>
3836bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines      Dump library ABI to gzipped TXT format file. You can transfer it
3846bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines      anywhere and pass instead of the descriptor. Also it can be used
3856bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines      for debugging the tool. Compatible dump versions: ".majorVersion($ABI_DUMP_VERSION).".0<=V<=$ABI_DUMP_VERSION
3866bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines
3876bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  -old-dumps
388e3e210c3aa3c1b289eee669a1d235fc16df384a0Chandler Carruth      Enable support for old-version ABI dumps ($OLDEST_SUPPORTED_VERSION<=V<".majorVersion($ABI_DUMP_VERSION).".0).\n";
389dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth
3907d66f8cafd807e551efb4739cdb37fc272cf5345Chandler Carruthsub HELP_MESSAGE() {
3917d66f8cafd807e551efb4739cdb37fc272cf5345Chandler Carruth    printMsg("INFO", $HelpMessage."
3927d66f8cafd807e551efb4739cdb37fc272cf5345Chandler CarruthMORE INFO:
393db3f847cb883fdb19d79c7223fa032e7266c0ee5Nick Lewycky     $CmdName --info\n");
3946bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines}
3956bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines
3966bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hinessub INFO_MESSAGE()
3976bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines{
3986bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    printMsg("INFO", "$HelpMessage
3997d66f8cafd807e551efb4739cdb37fc272cf5345Chandler CarruthEXTRA OPTIONS:
400dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth  -d|-descriptor-template
4017d66f8cafd807e551efb4739cdb37fc272cf5345Chandler Carruth      Create XML-descriptor template ./VERSION.xml
4027d66f8cafd807e551efb4739cdb37fc272cf5345Chandler Carruth
403dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth  -app|-application <path>
404facfc77487a890bfb7b5eee7e21cd2b395a9faafChandler Carruth      This option allows to specify the application that should be checked
4056bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines      for portability to the new library version.
4066bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines
407facfc77487a890bfb7b5eee7e21cd2b395a9faafChandler Carruth  -static-libs
4086bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines      Check static libraries instead of the shared ones. The <libs> section
409dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth      of the XML-descriptor should point to static libraries location.
4106bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines
411dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth  -cross-gcc|-gcc-path <path>
412dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth      Path to the cross GCC compiler to use instead of the usual (host) GCC.
413dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth
414dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth  -cross-prefix|-gcc-prefix <prefix>
415dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth      GCC toolchain prefix.
416e3e210c3aa3c1b289eee669a1d235fc16df384a0Chandler Carruth
4176bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  -sysroot <dirpath>
4186bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines      Specify the alternative root directory. The tool will search for include
4196bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines      paths in the <dirpath>/usr/include and <dirpath>/usr/lib directories.
4206bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines
4216bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  -v1|-version1 <num>
4226bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines      Specify 1st library version outside the descriptor. This option is needed
423e3e210c3aa3c1b289eee669a1d235fc16df384a0Chandler Carruth      if you have prefered an alternative descriptor type (see -d1 option).
424d30bf2eb6d6bbebd41236bf205d3a6dfc51a3659Douglas Gregor
425facfc77487a890bfb7b5eee7e21cd2b395a9faafChandler Carruth      In general case you should specify it in the XML-descriptor:
4266bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines          <version>
4276bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines              VERSION
4284d2229c7a9514ee2b960aa9e59f7259cebbaa421Nick Lewycky          </version>
4296bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines
4304d2229c7a9514ee2b960aa9e59f7259cebbaa421Nick Lewycky  -v2|-version2 <num>
4316bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines      Specify 2nd library version outside the descriptor.
4324d2229c7a9514ee2b960aa9e59f7259cebbaa421Nick Lewycky
4334d2229c7a9514ee2b960aa9e59f7259cebbaa421Nick Lewycky  -s|-strict
4344d2229c7a9514ee2b960aa9e59f7259cebbaa421Nick Lewycky      Treat all compatibility warnings as problems. Add a number of \"Low\"
435717cc00c16eabf0eefd3cc69394e97f7229af0c8Zhanyong Wan      severity problems to the return value of the tool.
4364d2229c7a9514ee2b960aa9e59f7259cebbaa421Nick Lewycky
437717cc00c16eabf0eefd3cc69394e97f7229af0c8Zhanyong Wan  -headers-only
438717cc00c16eabf0eefd3cc69394e97f7229af0c8Zhanyong Wan      Check header files without $SLIB_TYPE libraries. It is easy to run, but may
439717cc00c16eabf0eefd3cc69394e97f7229af0c8Zhanyong Wan      provide a low quality compatibility report with false positives and
440717cc00c16eabf0eefd3cc69394e97f7229af0c8Zhanyong Wan      without detecting of added/removed symbols.
4414d2229c7a9514ee2b960aa9e59f7259cebbaa421Nick Lewycky
4424d2229c7a9514ee2b960aa9e59f7259cebbaa421Nick Lewycky      Alternatively you can write \"none\" word to the <libs> section
4434d2229c7a9514ee2b960aa9e59f7259cebbaa421Nick Lewycky      in the XML-descriptor:
444717cc00c16eabf0eefd3cc69394e97f7229af0c8Zhanyong Wan          <libs>
4454d2229c7a9514ee2b960aa9e59f7259cebbaa421Nick Lewycky              none
4464d2229c7a9514ee2b960aa9e59f7259cebbaa421Nick Lewycky          </libs>
4474d2229c7a9514ee2b960aa9e59f7259cebbaa421Nick Lewycky
448717cc00c16eabf0eefd3cc69394e97f7229af0c8Zhanyong Wan  -objects-only
449717cc00c16eabf0eefd3cc69394e97f7229af0c8Zhanyong Wan      Check $SLIB_TYPE libraries without header files. It is easy to run, but may
4506bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines      provide a low quality compatibility report with false positives and
4516bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines      without analysis of changes in parameters and data types.
4526bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines
4536bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines      Alternatively you can write \"none\" word to the <headers> section
4546bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines      in the XML-descriptor:
4556bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines          <headers>
4566bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines              none
457717cc00c16eabf0eefd3cc69394e97f7229af0c8Zhanyong Wan          </headers>
4584d2229c7a9514ee2b960aa9e59f7259cebbaa421Nick Lewycky
4594d2229c7a9514ee2b960aa9e59f7259cebbaa421Nick Lewycky  -check-impl|-check-implementation
4606bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines      Compare canonified disassembled binary code of $SLIB_TYPE libraries to
461dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth      detect changes in the implementation. Add \'Problems with Implementation\'
4626bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines      section to the report.
463dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth
4646bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  -show-retval
465dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth      Show the symbol's return type in the report.
466dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth
467dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth  -symbols-list <path>
468dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth      This option allows to specify a file with a list of symbols (mangled
469dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth      names in C++) that should be checked, other symbols will not be checked.
470e3e210c3aa3c1b289eee669a1d235fc16df384a0Chandler Carruth
4716bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  -skip-headers <path>
4726bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines      The file with the list of header files, that should not be checked.
4736bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines
4746bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  -use-dumps
4756bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines      Make dumps for two versions of a library and compare dumps. This should
4766bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines      increase the performance of the tool and decrease the system memory usage.
477e3e210c3aa3c1b289eee669a1d235fc16df384a0Chandler Carruth
4789a55591af3e5506b95a9718e15380129fbfc5ebcSean Hunt  -nostdinc
4799a55591af3e5506b95a9718e15380129fbfc5ebcSean Hunt      Do not search the GCC standard system directories for header files.
480dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth
481dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth  -dump-system <name> -sysroot <dirpath>
482dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth      Find all the shared libraries and header files in <dirpath> directory,
4838d2a5ea694ed0002b45deb2bd35db451b16a07d6Larisse Voufo      create XML descriptors and make ABI dumps for each library. The result
4848d2a5ea694ed0002b45deb2bd35db451b16a07d6Larisse Voufo      set of ABI dumps can be compared (--cmp-systems) with the other one
4858d2a5ea694ed0002b45deb2bd35db451b16a07d6Larisse Voufo      created for other version of operating system in order to check them for
4868d2a5ea694ed0002b45deb2bd35db451b16a07d6Larisse Voufo      compatibility. Do not forget to specify -cross-gcc option if your target
4878d2a5ea694ed0002b45deb2bd35db451b16a07d6Larisse Voufo      system requires some specific version of GCC compiler (different from
4888d2a5ea694ed0002b45deb2bd35db451b16a07d6Larisse Voufo      the host GCC). The system ABI dump will be generated to:
489536bab452fa38692834233187ed3d49b83722cb3Craig Silverstein          sys_dumps/<name>/<arch>
490dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth
491cf4679e60a5c5fa13e4bfe69f8186658c828af49Craig Silverstein  -dump-system <descriptor.xml>
492dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth      The same as the previous option but takes an XML descriptor of the target
493dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth      system as input, where you should describe it:
494dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth
4954d072932287eb074a4168804cac1acb18a51d5e8Craig Silverstein          /* Primary sections */
496dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth
497dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth          <name>
498651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines              /* Name of the system */
499176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines          </name>
500c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines
5016bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines          <headers>
5024fa7eab771ab8212e1058bd1a91061ff120c8fbbAlexey Bataev              /* The list of paths to header files and/or
503543c4ae954f2bce5ac58ed22080f23cbd94794d2Alexey Bataev                 directories with header files, one per line */
504c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines          </headers>
5054967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar
5064967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar          <libs>
5074967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar              /* The list of paths to shared libraries and/or
50890226acd0b9be2964343cd63ae604bf0a656d33bArgyrios Kyrtzidis                 directories with shared libraries, one per line */
50987d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar          </libs>
5104967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar
51186b32fd702d794bb655c59a1238bf7422869f506Ted Kremenek          /* Optional sections */
51286b32fd702d794bb655c59a1238bf7422869f506Ted Kremenek
5136bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines          <search_headers>
51486b32fd702d794bb655c59a1238bf7422869f506Ted Kremenek              /* List of directories to be searched
51587d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar                 for header files to automatically
51687d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar                 generate include paths, one per line */
51787d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar          </search_headers>
51886b32fd702d794bb655c59a1238bf7422869f506Ted Kremenek
51987d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar          <search_libs>
52087d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar              /* List of directories to be searched
52187d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar                 for shared libraries to resolve
52286b32fd702d794bb655c59a1238bf7422869f506Ted Kremenek                 dependencies, one per line */
52386b32fd702d794bb655c59a1238bf7422869f506Ted Kremenek          </search_libs>
5246bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines
5256bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines          <tools>
52687d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar              /* List of directories with tools used
52786b32fd702d794bb655c59a1238bf7422869f506Ted Kremenek                 for analysis (GCC toolchain), one per line */
5286bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines          </tools>
52986b32fd702d794bb655c59a1238bf7422869f506Ted Kremenek
53087d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar          <cross_prefix>
53186b32fd702d794bb655c59a1238bf7422869f506Ted Kremenek              /* GCC toolchain prefix.
5326bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines                 Examples:
5336bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines                     arm-linux-gnueabi
53487d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar                     arm-none-symbianelf */
53586b32fd702d794bb655c59a1238bf7422869f506Ted Kremenek          </cross_prefix>
5366bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines
53786b32fd702d794bb655c59a1238bf7422869f506Ted Kremenek          <gcc_options>
53887d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar              /* Additional GCC options, one per line */
53990226acd0b9be2964343cd63ae604bf0a656d33bArgyrios Kyrtzidis          </gcc_options>
54086b32fd702d794bb655c59a1238bf7422869f506Ted Kremenek
54186b32fd702d794bb655c59a1238bf7422869f506Ted Kremenek  -sysinfo <dir>
5426bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines      This option may be used with -dump-system to dump ABI of operating
5436bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines      systems and configure the dumping process.
54487d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar      Default:
54590226acd0b9be2964343cd63ae604bf0a656d33bArgyrios Kyrtzidis          modules/Targets/{unix, symbian, windows}
5466bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines
54786b32fd702d794bb655c59a1238bf7422869f506Ted Kremenek  -cmp-systems -d1 sys_dumps/<name1>/<arch> -d2 sys_dumps/<name2>/<arch>
54887d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar      Compare two system ABI dumps. Create compatibility reports for each
54990226acd0b9be2964343cd63ae604bf0a656d33bArgyrios Kyrtzidis      library and the common HTML report including the summary of test
55086b32fd702d794bb655c59a1238bf7422869f506Ted Kremenek      results for all checked libraries. Report will be generated to:
55186b32fd702d794bb655c59a1238bf7422869f506Ted Kremenek          sys_compat_reports/<name1>_to_<name2>/<arch>
55286b32fd702d794bb655c59a1238bf7422869f506Ted Kremenek
55386b32fd702d794bb655c59a1238bf7422869f506Ted Kremenek  -libs-list <path>
5546bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines      The file with a list of libraries, that should be dumped by
5556bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines      the -dump-system option or should be checked by the -cmp-systems option.
55686b32fd702d794bb655c59a1238bf7422869f506Ted Kremenek
5576bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  -header <name>
5586bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines      Check/Dump ABI of this header only.
55987d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar
56086b32fd702d794bb655c59a1238bf7422869f506Ted Kremenek  -headers-list <path>
56186b32fd702d794bb655c59a1238bf7422869f506Ted Kremenek      The file with a list of headers, that should be checked/dumped.
56286b32fd702d794bb655c59a1238bf7422869f506Ted Kremenek
56386b32fd702d794bb655c59a1238bf7422869f506Ted Kremenek  -ext|-extended
56486b32fd702d794bb655c59a1238bf7422869f506Ted Kremenek      If your library A is supposed to be used by other library B and you
56590226acd0b9be2964343cd63ae604bf0a656d33bArgyrios Kyrtzidis      want to control the ABI of B, then you should enable this option. The
56687d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar      tool will check for changes in all data types, even if they are not
567dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth      used by any function in the library A. Such data types are not part
5684967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar      of the A library ABI, but may be a part of the ABI of the B library.
5694967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar
5704967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar      The short scheme is:
5714967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar        app C (broken) -> lib B (broken ABI) -> lib A (stable ABI)
5724967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar
5734967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar  -q|-quiet
5744967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar      Print all messages to the file instead of stdout and stderr.
5754967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar      Default path (can be changed by -log-path option):
5764967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar          $COMMON_LOG_PATH
5774967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar
5784967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar  -stdout
5794967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar      Print analysis results (compatibility reports and ABI dumps) to stdout
5804967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar      instead of creating a file. This would allow piping data to other programs.
5814967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar
5824967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar  -report-format <fmt>
5834967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar      Change format of compatibility report.
5844967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar      Formats:
5854967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar        htm - HTML format (default)
5866bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines        xml - XML format
58787d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar
58887d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar  -dump-format <fmt>
589db3f847cb883fdb19d79c7223fa032e7266c0ee5Nick Lewycky      Change format of ABI dump.
590e3e210c3aa3c1b289eee669a1d235fc16df384a0Chandler Carruth      Formats:
591db3f847cb883fdb19d79c7223fa032e7266c0ee5Nick Lewycky        perl - Data::Dumper format (default)
59287d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar        xml - XML format
5934967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar
59487d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar  -xml
59587d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar      Alias for: --report-format=xml or --dump-format=xml
59686b32fd702d794bb655c59a1238bf7422869f506Ted Kremenek
5974967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar  -lang <lang>
5984967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar      Set library language (C or C++). You can use this option if the tool
59986b32fd702d794bb655c59a1238bf7422869f506Ted Kremenek      cannot auto-detect a language. This option may be useful for checking
60087d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar      C-library headers (--lang=C) in --headers-only or --extended modes.
6014967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar
6024967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar  -binary|-bin|-abi
6034967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar      Show \"Binary\" compatibility problems only.
6044967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar      Generate report to:
6054967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar        compat_reports/<library name>/<v1>_to_<v2>/abi_compat_report.html
6064967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar
6074967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar  -source|-src|-api
6084967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar      Show \"Source\" compatibility problems only.
6094967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar      Generate report to:
6104967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar        compat_reports/<library name>/<v1>_to_<v2>/src_compat_report.html
6114967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar
61286b32fd702d794bb655c59a1238bf7422869f506Ted KremenekOTHER OPTIONS:
6134967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar  -test
6144967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar      Run internal tests. Create two binary incompatible versions of a sample
6154967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar      library and run the tool to check them for compatibility. This option
6164967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar      allows to check if the tool works correctly in the current environment.
6174967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar
6184967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar  -test-dump
6194967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar      Test ability to create, read and compare ABI dumps.
6204967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar
6214967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar  -debug
622d30bf2eb6d6bbebd41236bf205d3a6dfc51a3659Douglas Gregor      Debugging mode. Print debug info on the screen. Save intermediate
623db3f847cb883fdb19d79c7223fa032e7266c0ee5Nick Lewycky      analysis stages in the debug directory:
624e3e210c3aa3c1b289eee669a1d235fc16df384a0Chandler Carruth          debug/<library>/<version>/
625db3f847cb883fdb19d79c7223fa032e7266c0ee5Nick Lewycky
626db3f847cb883fdb19d79c7223fa032e7266c0ee5Nick Lewycky      Also consider using --dump option for debugging the tool.
62787d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar
62887d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar  -cpp-compatible
6296bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines      If your header file is written in C language and can be compiled by
6306bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines      the C++ compiler (i.e. doesn't contain C++-keywords and other bad
631dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth      things), then you can tell ACC about this and speedup the analysis.
632db3f847cb883fdb19d79c7223fa032e7266c0ee5Nick Lewycky
633e3e210c3aa3c1b289eee669a1d235fc16df384a0Chandler Carruth  -p|-params <path>
634db3f847cb883fdb19d79c7223fa032e7266c0ee5Nick Lewycky      Path to file with the function parameter names. It can be used
635db3f847cb883fdb19d79c7223fa032e7266c0ee5Nick Lewycky      for improving report view if the library header files have no
636dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth      parameter names. File format:
6376bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines
6386bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines            func1;param1;param2;param3 ...
6396bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines            func2;param1;param2;param3 ...
640d30bf2eb6d6bbebd41236bf205d3a6dfc51a3659Douglas Gregor             ...
641d30bf2eb6d6bbebd41236bf205d3a6dfc51a3659Douglas Gregor
642db3f847cb883fdb19d79c7223fa032e7266c0ee5Nick Lewycky  -relpath <path>
643e3e210c3aa3c1b289eee669a1d235fc16df384a0Chandler Carruth      Replace {RELPATH} macros to <path> in the XML-descriptor used
644db3f847cb883fdb19d79c7223fa032e7266c0ee5Nick Lewycky      for dumping the library ABI (see -dump option).
645db3f847cb883fdb19d79c7223fa032e7266c0ee5Nick Lewycky
6466bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  -relpath1 <path>
6474d2229c7a9514ee2b960aa9e59f7259cebbaa421Nick Lewycky      Replace {RELPATH} macros to <path> in the 1st XML-descriptor (-d1).
6484d2229c7a9514ee2b960aa9e59f7259cebbaa421Nick Lewycky
6494d2229c7a9514ee2b960aa9e59f7259cebbaa421Nick Lewycky  -relpath2 <path>
6504d2229c7a9514ee2b960aa9e59f7259cebbaa421Nick Lewycky      Replace {RELPATH} macros to <path> in the 2nd XML-descriptor (-d2).
6514d2229c7a9514ee2b960aa9e59f7259cebbaa421Nick Lewycky
6524d2229c7a9514ee2b960aa9e59f7259cebbaa421Nick Lewycky  -dump-path <path>
6536bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines      Specify a *.abi.$AR_EXT or *.abi file path where to generate an ABI dump.
6546bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines      Default:
65539e6ab4be93d9c5e729a578ddd9d415cd2d49872David Blaikie          abi_dumps/<library>/<library>_<version>.abi.$AR_EXT
6564d2229c7a9514ee2b960aa9e59f7259cebbaa421Nick Lewycky
6574d2229c7a9514ee2b960aa9e59f7259cebbaa421Nick Lewycky  -sort
6584d2229c7a9514ee2b960aa9e59f7259cebbaa421Nick Lewycky      Enable sorting of data in ABI dumps.
6594d2229c7a9514ee2b960aa9e59f7259cebbaa421Nick Lewycky
6604d2229c7a9514ee2b960aa9e59f7259cebbaa421Nick Lewycky  -report-path <path>
6614d2229c7a9514ee2b960aa9e59f7259cebbaa421Nick Lewycky      Path to compatibility report.
662651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      Default:
663651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines          compat_reports/<library name>/<v1>_to_<v2>/compat_report.html
664651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
665651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  -bin-report-path <path>
666651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      Path to \"Binary\" compatibility report.
6676bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines      Default:
668dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth          compat_reports/<library name>/<v1>_to_<v2>/abi_compat_report.html
669db3f847cb883fdb19d79c7223fa032e7266c0ee5Nick Lewycky
670e3e210c3aa3c1b289eee669a1d235fc16df384a0Chandler Carruth  -src-report-path <path>
671db3f847cb883fdb19d79c7223fa032e7266c0ee5Nick Lewycky      Path to \"Source\" compatibility report.
672c28a335184207a47f34eb9d1707dc8d7c6c7b8b6Richard Smith      Default:
673c28a335184207a47f34eb9d1707dc8d7c6c7b8b6Richard Smith          compat_reports/<library name>/<v1>_to_<v2>/src_compat_report.html
67452ec0c0357ce970ca52a27c1086626450f0967e7Daniel Jasper
675d0b982ca5cf685af08d5015e8c2dfae3ecab1a0bCraig Silverstein  -log-path <path>
676d0b982ca5cf685af08d5015e8c2dfae3ecab1a0bCraig Silverstein      Log path for all messages.
677db3f847cb883fdb19d79c7223fa032e7266c0ee5Nick Lewycky      Default:
6789a55591af3e5506b95a9718e15380129fbfc5ebcSean Hunt          logs/<library>/<version>/log.txt
6796bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines
6806bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  -log1-path <path>
6816bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines      Log path for 1st version of a library.
6826bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines      Default:
683651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines          logs/<library name>/<v1>/log.txt
6849a55591af3e5506b95a9718e15380129fbfc5ebcSean Hunt
685651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  -log2-path <path>
686d30bf2eb6d6bbebd41236bf205d3a6dfc51a3659Douglas Gregor      Log path for 2nd version of a library.
687651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      Default:
688651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines          logs/<library name>/<v2>/log.txt
689651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
690651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  -logging-mode <mode>
691651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      Change logging mode.
692e3e210c3aa3c1b289eee669a1d235fc16df384a0Chandler Carruth      Modes:
693db3f847cb883fdb19d79c7223fa032e7266c0ee5Nick Lewycky        w - overwrite old logs (default)
694db3f847cb883fdb19d79c7223fa032e7266c0ee5Nick Lewycky        a - append old logs
695dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth        n - do not write any logs
696dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth
6976bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  -list-affected
698dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth      Generate file with the list of incompatible
6996bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines      symbols beside the HTML compatibility report.
700dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth      Use 'c++filt \@file' command from GNU binutils
701e3e210c3aa3c1b289eee669a1d235fc16df384a0Chandler Carruth      to unmangle C++ symbols in the generated file.
702dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth      Default names:
7036c321e35008f2c99eeb1409b43859a04c48e5ce5Chandler Carruth          abi_affected.txt
7046c321e35008f2c99eeb1409b43859a04c48e5ce5Chandler Carruth          src_affected.txt
705db3f847cb883fdb19d79c7223fa032e7266c0ee5Nick Lewycky
706db3f847cb883fdb19d79c7223fa032e7266c0ee5Nick Lewycky  -component <name>
707db3f847cb883fdb19d79c7223fa032e7266c0ee5Nick Lewycky      The component name in the title and summary of the HTML report.
708db3f847cb883fdb19d79c7223fa032e7266c0ee5Nick Lewycky      Default:
70914aba76042e041b2c5e439bf4ae353a0a3c7fd73Douglas Gregor          library
710db3f847cb883fdb19d79c7223fa032e7266c0ee5Nick Lewycky
711176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines  -l-full|-lib-full <name>
712e3e210c3aa3c1b289eee669a1d235fc16df384a0Chandler Carruth      Change library name in the report title to <name>. By default
713db3f847cb883fdb19d79c7223fa032e7266c0ee5Nick Lewycky      will be displayed a name specified by -l option.
714db3f847cb883fdb19d79c7223fa032e7266c0ee5Nick Lewycky
715db3f847cb883fdb19d79c7223fa032e7266c0ee5Nick Lewycky  -b|-browse <program>
7166c321e35008f2c99eeb1409b43859a04c48e5ce5Chandler Carruth      Open report(s) in the browser (firefox, opera, etc.).
717d30bf2eb6d6bbebd41236bf205d3a6dfc51a3659Douglas Gregor
718d30bf2eb6d6bbebd41236bf205d3a6dfc51a3659Douglas Gregor  -open
719e3e210c3aa3c1b289eee669a1d235fc16df384a0Chandler Carruth      Open report(s) in the default browser.
720db3f847cb883fdb19d79c7223fa032e7266c0ee5Nick Lewycky
721d30bf2eb6d6bbebd41236bf205d3a6dfc51a3659Douglas GregorREPORT:
7226bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    Compatibility report will be generated to:
723dc355713be51fcb4ee52d9fd6b4548ceff47fadfDouglas Gregor        compat_reports/<library name>/<v1>_to_<v2>/compat_report.html
7246bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines
725dc355713be51fcb4ee52d9fd6b4548ceff47fadfDouglas Gregor    Log will be generated to:
726dc355713be51fcb4ee52d9fd6b4548ceff47fadfDouglas Gregor        logs/<library name>/<v1>/log.txt
727ba243b59a1074e0962f6abfa3bb9aa984eac1245David Blaikie        logs/<library name>/<v2>/log.txt
7286bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines
7296bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen HinesEXIT CODES:
730ba243b59a1074e0962f6abfa3bb9aa984eac1245David Blaikie    0 - Compatible. The tool has run without any errors.
731dc355713be51fcb4ee52d9fd6b4548ceff47fadfDouglas Gregor    non-zero - Incompatible or the tool has run with errors.
732dc355713be51fcb4ee52d9fd6b4548ceff47fadfDouglas Gregor
733dc355713be51fcb4ee52d9fd6b4548ceff47fadfDouglas GregorREPORT BUGS TO:
734dc355713be51fcb4ee52d9fd6b4548ceff47fadfDouglas Gregor    Andrey Ponomarenko <aponomarenko\@rosalab.ru>
735dc355713be51fcb4ee52d9fd6b4548ceff47fadfDouglas Gregor
736176edba5311f6eff0cad2631449885ddf4fbc9eaStephen HinesMORE INFORMATION:
737dc355713be51fcb4ee52d9fd6b4548ceff47fadfDouglas Gregor    ".$HomePage{"Wiki"}."
738ba243b59a1074e0962f6abfa3bb9aa984eac1245David Blaikie    ".$HomePage{"Dev1"}."\n");
739dc355713be51fcb4ee52d9fd6b4548ceff47fadfDouglas Gregor}
740dc355713be51fcb4ee52d9fd6b4548ceff47fadfDouglas Gregor
741dc355713be51fcb4ee52d9fd6b4548ceff47fadfDouglas Gregormy $DescriptorTemplate = "
742dc355713be51fcb4ee52d9fd6b4548ceff47fadfDouglas Gregor<?xml version=\"1.0\" encoding=\"utf-8\"?>
743dc355713be51fcb4ee52d9fd6b4548ceff47fadfDouglas Gregor<descriptor>
744ba243b59a1074e0962f6abfa3bb9aa984eac1245David Blaikie
745dc355713be51fcb4ee52d9fd6b4548ceff47fadfDouglas Gregor/* Primary sections */
746dc355713be51fcb4ee52d9fd6b4548ceff47fadfDouglas Gregor
747dc355713be51fcb4ee52d9fd6b4548ceff47fadfDouglas Gregor<version>
7486bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    /* Version of the library */
74965019acfc46ffb191fac4e781ac0c4b8d0c8434eDouglas Gregor</version>
7506bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines
75165019acfc46ffb191fac4e781ac0c4b8d0c8434eDouglas Gregor<headers>
75265019acfc46ffb191fac4e781ac0c4b8d0c8434eDouglas Gregor    /* The list of paths to header files and/or
75365019acfc46ffb191fac4e781ac0c4b8d0c8434eDouglas Gregor       directories with header files, one per line */
75465019acfc46ffb191fac4e781ac0c4b8d0c8434eDouglas Gregor</headers>
75565019acfc46ffb191fac4e781ac0c4b8d0c8434eDouglas Gregor
75665019acfc46ffb191fac4e781ac0c4b8d0c8434eDouglas Gregor<libs>
757ba243b59a1074e0962f6abfa3bb9aa984eac1245David Blaikie    /* The list of paths to shared libraries (*.$LIB_EXT) and/or
75865019acfc46ffb191fac4e781ac0c4b8d0c8434eDouglas Gregor       directories with shared libraries, one per line */
759ba243b59a1074e0962f6abfa3bb9aa984eac1245David Blaikie</libs>
76065019acfc46ffb191fac4e781ac0c4b8d0c8434eDouglas Gregor
76165019acfc46ffb191fac4e781ac0c4b8d0c8434eDouglas Gregor/* Optional sections */
76265019acfc46ffb191fac4e781ac0c4b8d0c8434eDouglas Gregor
76365019acfc46ffb191fac4e781ac0c4b8d0c8434eDouglas Gregor<include_paths>
76465019acfc46ffb191fac4e781ac0c4b8d0c8434eDouglas Gregor    /* The list of include paths that will be provided
76565019acfc46ffb191fac4e781ac0c4b8d0c8434eDouglas Gregor       to GCC to compile library headers, one per line.
76665019acfc46ffb191fac4e781ac0c4b8d0c8434eDouglas Gregor       NOTE: If you define this section then the tool
76765019acfc46ffb191fac4e781ac0c4b8d0c8434eDouglas Gregor       will not automatically generate include paths */
76865019acfc46ffb191fac4e781ac0c4b8d0c8434eDouglas Gregor</include_paths>
769ba243b59a1074e0962f6abfa3bb9aa984eac1245David Blaikie
77065019acfc46ffb191fac4e781ac0c4b8d0c8434eDouglas Gregor<add_include_paths>
77165019acfc46ffb191fac4e781ac0c4b8d0c8434eDouglas Gregor    /* The list of include paths that will be added
77265019acfc46ffb191fac4e781ac0c4b8d0c8434eDouglas Gregor       to the automatically generated include paths, one per line */
7736bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines</add_include_paths>
774dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth
775db3f847cb883fdb19d79c7223fa032e7266c0ee5Nick Lewycky<skip_include_paths>
7766c321e35008f2c99eeb1409b43859a04c48e5ce5Chandler Carruth    /* The list of include paths that will be removed from the
7776c321e35008f2c99eeb1409b43859a04c48e5ce5Chandler Carruth       list of automatically generated include paths, one per line */
7786c321e35008f2c99eeb1409b43859a04c48e5ce5Chandler Carruth</skip_include_paths>
779db3f847cb883fdb19d79c7223fa032e7266c0ee5Nick Lewycky
780e3e210c3aa3c1b289eee669a1d235fc16df384a0Chandler Carruth<gcc_options>
781db3f847cb883fdb19d79c7223fa032e7266c0ee5Nick Lewycky    /* Additional GCC options, one per line */
782db3f847cb883fdb19d79c7223fa032e7266c0ee5Nick Lewycky</gcc_options>
7836bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines
784dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth<include_preamble>
7856bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    /* The list of header files that will be
786db3f847cb883fdb19d79c7223fa032e7266c0ee5Nick Lewycky       included before other headers, one per line.
787db3f847cb883fdb19d79c7223fa032e7266c0ee5Nick Lewycky       Examples:
788db3f847cb883fdb19d79c7223fa032e7266c0ee5Nick Lewycky           1) tree.h for libxml2
789db3f847cb883fdb19d79c7223fa032e7266c0ee5Nick Lewycky           2) ft2build.h for freetype2 */
790d7a6b1640e565487d163023a6a2e83f55476ae96Eli Friedman</include_preamble>
791e3e210c3aa3c1b289eee669a1d235fc16df384a0Chandler Carruth
792d30bf2eb6d6bbebd41236bf205d3a6dfc51a3659Douglas Gregor<defines>
793db3f847cb883fdb19d79c7223fa032e7266c0ee5Nick Lewycky    /* The list of defines that will be added at the
794dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth       headers compiling stage, one per line:
795d30bf2eb6d6bbebd41236bf205d3a6dfc51a3659Douglas Gregor          #define A B
796db3f847cb883fdb19d79c7223fa032e7266c0ee5Nick Lewycky          #define C D */
797a7fc901a2e39bfe55bfcff5934b2d9fdf9656491Douglas Gregor</defines>
798a7fc901a2e39bfe55bfcff5934b2d9fdf9656491Douglas Gregor
7996bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines<add_namespaces>
800db3f847cb883fdb19d79c7223fa032e7266c0ee5Nick Lewycky    /* The list of namespaces that should be added to the alanysis
801db3f847cb883fdb19d79c7223fa032e7266c0ee5Nick Lewycky       if the tool cannot find them automatically, one per line */
802dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth</add_namespaces>
803db3f847cb883fdb19d79c7223fa032e7266c0ee5Nick Lewycky
804db3f847cb883fdb19d79c7223fa032e7266c0ee5Nick Lewycky<skip_types>
805dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth    /* The list of data types, that
806dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth       should not be checked, one per line */
807d30bf2eb6d6bbebd41236bf205d3a6dfc51a3659Douglas Gregor</skip_types>
808d30bf2eb6d6bbebd41236bf205d3a6dfc51a3659Douglas Gregor
809e3e210c3aa3c1b289eee669a1d235fc16df384a0Chandler Carruth<skip_symbols>
810db3f847cb883fdb19d79c7223fa032e7266c0ee5Nick Lewycky    /* The list of functions (mangled/symbol names in C++),
811db3f847cb883fdb19d79c7223fa032e7266c0ee5Nick Lewycky       that should not be checked, one per line */
8124d2229c7a9514ee2b960aa9e59f7259cebbaa421Nick Lewycky</skip_symbols>
8134d2229c7a9514ee2b960aa9e59f7259cebbaa421Nick Lewycky
8146bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines<skip_namespaces>
8154d2229c7a9514ee2b960aa9e59f7259cebbaa421Nick Lewycky    /* The list of C++ namespaces, that
8166bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines       should not be checked, one per line */
8174d2229c7a9514ee2b960aa9e59f7259cebbaa421Nick Lewycky</skip_namespaces>
8184d2229c7a9514ee2b960aa9e59f7259cebbaa421Nick Lewycky
8194d2229c7a9514ee2b960aa9e59f7259cebbaa421Nick Lewycky<skip_constants>
8204d2229c7a9514ee2b960aa9e59f7259cebbaa421Nick Lewycky    /* The list of constants that should
8214d2229c7a9514ee2b960aa9e59f7259cebbaa421Nick Lewycky       not be checked, one name per line */
8224d2229c7a9514ee2b960aa9e59f7259cebbaa421Nick Lewycky</skip_constants>
823d7a6b1640e565487d163023a6a2e83f55476ae96Eli Friedman
8244d2229c7a9514ee2b960aa9e59f7259cebbaa421Nick Lewycky<skip_headers>
8254d2229c7a9514ee2b960aa9e59f7259cebbaa421Nick Lewycky    /* The list of header files and/or directories
8264d2229c7a9514ee2b960aa9e59f7259cebbaa421Nick Lewycky       with header files that should not be checked, one per line */
827fcf431609769a9600c24618d1a33135caec4fef2Zhanyong Wan</skip_headers>
828fcf431609769a9600c24618d1a33135caec4fef2Zhanyong Wan
829fcf431609769a9600c24618d1a33135caec4fef2Zhanyong Wan<skip_libs>
830ba243b59a1074e0962f6abfa3bb9aa984eac1245David Blaikie    /* The list of shared libraries and/or directories
831f1fe3759e6e8b1756c514f1181c86bd4b9d1666cDouglas Gregor       with shared libraries that should not be checked, one per line */
8324d2229c7a9514ee2b960aa9e59f7259cebbaa421Nick Lewycky</skip_libs>
8334d2229c7a9514ee2b960aa9e59f7259cebbaa421Nick Lewycky
8344d2229c7a9514ee2b960aa9e59f7259cebbaa421Nick Lewycky<skip_including>
835a7fc901a2e39bfe55bfcff5934b2d9fdf9656491Douglas Gregor    /* The list of header files, that cannot be included
836b6744efecba58792cce20d2d7b9ee39927c5422eDouglas Gregor       directly (or non-self compiled ones), one per line */
837b6744efecba58792cce20d2d7b9ee39927c5422eDouglas Gregor</skip_including>
8386bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines
839a7fc901a2e39bfe55bfcff5934b2d9fdf9656491Douglas Gregor<search_headers>
8406bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    /* List of directories to be searched
8414d2229c7a9514ee2b960aa9e59f7259cebbaa421Nick Lewycky       for header files to automatically
8424d2229c7a9514ee2b960aa9e59f7259cebbaa421Nick Lewycky       generate include paths, one per line. */
8434d2229c7a9514ee2b960aa9e59f7259cebbaa421Nick Lewycky</search_headers>
8444d2229c7a9514ee2b960aa9e59f7259cebbaa421Nick Lewycky
8454d2229c7a9514ee2b960aa9e59f7259cebbaa421Nick Lewycky<search_libs>
8464d2229c7a9514ee2b960aa9e59f7259cebbaa421Nick Lewycky    /* List of directories to be searched
8474d2229c7a9514ee2b960aa9e59f7259cebbaa421Nick Lewycky       for shared librariess to resolve
8484d2229c7a9514ee2b960aa9e59f7259cebbaa421Nick Lewycky       dependencies, one per line */
8494d2229c7a9514ee2b960aa9e59f7259cebbaa421Nick Lewycky</search_libs>
8504d2229c7a9514ee2b960aa9e59f7259cebbaa421Nick Lewycky
8514d2229c7a9514ee2b960aa9e59f7259cebbaa421Nick Lewycky<tools>
8524d2229c7a9514ee2b960aa9e59f7259cebbaa421Nick Lewycky    /* List of directories with tools used
8536bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines       for analysis (GCC toolchain), one per line */
854dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth</tools>
8556bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines
856dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth<cross_prefix>
857dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth    /* GCC toolchain prefix.
858dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth       Examples:
859d30bf2eb6d6bbebd41236bf205d3a6dfc51a3659Douglas Gregor           arm-linux-gnueabi
860e3e210c3aa3c1b289eee669a1d235fc16df384a0Chandler Carruth           arm-none-symbianelf */
861db3f847cb883fdb19d79c7223fa032e7266c0ee5Nick Lewycky</cross_prefix>
862db3f847cb883fdb19d79c7223fa032e7266c0ee5Nick Lewycky
8636bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines</descriptor>";
8644d072932287eb074a4168804cac1acb18a51d5e8Craig Silverstein
8656bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hinesmy %Operator_Indication = (
86676852c218a207ef43583515cb835b6e855353a0fDouglas Gregor    "not" => "~",
86776852c218a207ef43583515cb835b6e855353a0fDouglas Gregor    "assign" => "=",
868ba243b59a1074e0962f6abfa3bb9aa984eac1245David Blaikie    "andassign" => "&=",
8698268fe7c4bdfa341975a687a8a5e236c2c5b88a4James Dennett    "orassign" => "|=",
8700f8c08843fc6c8abe03654f609e1e03fcc557855Craig Silverstein    "xorassign" => "^=",
8714967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    "or" => "|",
8724967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    "xor" => "^",
8734967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    "addr" => "&",
8744967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    "and" => "&",
8754967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    "lnot" => "!",
8764967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    "eq" => "==",
8774967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    "ne" => "!=",
8784967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    "lt" => "<",
8794967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    "lshift" => "<<",
8804967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    "lshiftassign" => "<<=",
8814967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    "rshiftassign" => ">>=",
8820f8c08843fc6c8abe03654f609e1e03fcc557855Craig Silverstein    "call" => "()",
8830f8c08843fc6c8abe03654f609e1e03fcc557855Craig Silverstein    "mod" => "%",
8840f8c08843fc6c8abe03654f609e1e03fcc557855Craig Silverstein    "modassign" => "%=",
8856bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    "subs" => "[]",
8866bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    "land" => "&&",
8876bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    "lor" => "||",
8886bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    "rshift" => ">>",
889b6d6993e6e6d3daf4d9876794254d20a134e37c2Pirama Arumuga Nainar    "ref" => "->",
89004fa7a33279808dc3e5117c41b5f84c40eeb7362Richard Smith    "le" => "<=",
891011d8b93b7cfa8492b8a9c909a850d6577e08dcaDouglas Gregor    "deref" => "*",
892011d8b93b7cfa8492b8a9c909a850d6577e08dcaDouglas Gregor    "mult" => "*",
8930f8c08843fc6c8abe03654f609e1e03fcc557855Craig Silverstein    "preinc" => "++",
8946bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    "delete" => " delete",
89587d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar    "vecnew" => " new[]",
89687d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar    "vecdelete" => " delete[]",
89787d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar    "predec" => "--",
89849007d7561212c0ae168702c1af1404c01ef43ffJames Dennett    "postinc" => "++",
89949007d7561212c0ae168702c1af1404c01ef43ffJames Dennett    "postdec" => "--",
90049007d7561212c0ae168702c1af1404c01ef43ffJames Dennett    "plusassign" => "+=",
901dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth    "plus" => "+",
902dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth    "minus" => "-",
903dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth    "minusassign" => "-=",
9046bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    "gt" => ">",
9056bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    "ge" => ">=",
9066bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    "new" => " new",
9074967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    "multassign" => "*=",
9084967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    "divassign" => "/=",
9096bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    "div" => "/",
9104967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    "neg" => "-",
9114967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    "pos" => "+",
9126bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    "memref" => "->*",
913d30bf2eb6d6bbebd41236bf205d3a6dfc51a3659Douglas Gregor    "compound" => "," );
914d30bf2eb6d6bbebd41236bf205d3a6dfc51a3659Douglas Gregor
9156bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hinesmy %UnknownOperator;
916db3f847cb883fdb19d79c7223fa032e7266c0ee5Nick Lewycky
9176bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hinesmy %NodeType= (
918db3f847cb883fdb19d79c7223fa032e7266c0ee5Nick Lewycky  "array_type" => "Array",
9196bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  "binfo" => "Other",
920db3f847cb883fdb19d79c7223fa032e7266c0ee5Nick Lewycky  "boolean_type" => "Intrinsic",
9216bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  "complex_type" => "Intrinsic",
9226bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  "const_decl" => "Other",
923db3f847cb883fdb19d79c7223fa032e7266c0ee5Nick Lewycky  "enumeral_type" => "Enum",
9246bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  "field_decl" => "Other",
9256bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  "function_decl" => "Other",
926db3f847cb883fdb19d79c7223fa032e7266c0ee5Nick Lewycky  "function_type" => "FunctionType",
9276bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  "identifier_node" => "Other",
9286bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  "integer_cst" => "Other",
929db3f847cb883fdb19d79c7223fa032e7266c0ee5Nick Lewycky  "integer_type" => "Intrinsic",
930dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth  "method_type" => "MethodType",
9316bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  "namespace_decl" => "Other",
9326bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  "parm_decl" => "Other",
9336bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  "pointer_type" => "Pointer",
934db3f847cb883fdb19d79c7223fa032e7266c0ee5Nick Lewycky  "real_cst" => "Other",
9356bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  "real_type" => "Intrinsic",
936651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  "record_type" => "Struct",
9376bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  "reference_type" => "Ref",
93812df246d6dea2ee1f92c186f922f1afcf499647aReid Kleckner  "string_cst" => "Other",
9396bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  "template_decl" => "Other",
9406bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  "template_type_parm" => "Other",
941d30bf2eb6d6bbebd41236bf205d3a6dfc51a3659Douglas Gregor  "tree_list" => "Other",
9426bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  "tree_vec" => "Other",
9436bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  "type_decl" => "Other",
944db3f847cb883fdb19d79c7223fa032e7266c0ee5Nick Lewycky  "union_type" => "Union",
945dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth  "var_decl" => "Other",
9466bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  "void_type" => "Intrinsic",
9476bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  # "nop_expr" => "Other",
9486bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  # "addr_expr" => "Other",
949db3f847cb883fdb19d79c7223fa032e7266c0ee5Nick Lewycky  "offset_type" => "Other" );
950dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth
9516bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hinesmy %CppKeywords_C = map {$_=>1} (
9526bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    # C++ 2003 keywords
9536bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    "public",
9546bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    "protected",
955d30bf2eb6d6bbebd41236bf205d3a6dfc51a3659Douglas Gregor    "private",
956dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth    "default",
9576bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    "template",
9586bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    "new",
9596bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    #"asm",
9606bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    "dynamic_cast",
961d30bf2eb6d6bbebd41236bf205d3a6dfc51a3659Douglas Gregor    "auto",
9626bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    "try",
963d30bf2eb6d6bbebd41236bf205d3a6dfc51a3659Douglas Gregor    "namespace",
9646bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    "typename",
965d30bf2eb6d6bbebd41236bf205d3a6dfc51a3659Douglas Gregor    "using",
966651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    "reinterpret_cast",
967651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    "friend",
968db3f847cb883fdb19d79c7223fa032e7266c0ee5Nick Lewycky    "class",
969dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth    "virtual",
970651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    "const_cast",
971db3f847cb883fdb19d79c7223fa032e7266c0ee5Nick Lewycky    "mutable",
972651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    "static_cast",
973651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    "export",
974651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    # C++0x keywords
975d30bf2eb6d6bbebd41236bf205d3a6dfc51a3659Douglas Gregor    "noexcept",
976651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    "nullptr",
977651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    "constexpr",
978651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    "static_assert",
979176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines    "explicit",
980176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines    # cannot be used as a macro name
981176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines    # as it is an operator in C++
982651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    "and",
983d30bf2eb6d6bbebd41236bf205d3a6dfc51a3659Douglas Gregor    #"and_eq",
9846bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    "not",
9856bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    #"not_eq",
986d30bf2eb6d6bbebd41236bf205d3a6dfc51a3659Douglas Gregor    "or"
9876bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    #"or_eq",
9886bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    #"bitand",
989d30bf2eb6d6bbebd41236bf205d3a6dfc51a3659Douglas Gregor    #"bitor",
9906bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    #"xor",
991db3f847cb883fdb19d79c7223fa032e7266c0ee5Nick Lewycky    #"xor_eq",
9926bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    #"compl"
9936bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines);
994d30bf2eb6d6bbebd41236bf205d3a6dfc51a3659Douglas Gregor
995ca63c200346c0ca9e00194ec6e34a5a7b0ed9321Sean Huntmy %CppKeywords_F = map {$_=>1} (
9966bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    "delete",
9976bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    "catch",
9986bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    "alignof",
999ca63c200346c0ca9e00194ec6e34a5a7b0ed9321Sean Hunt    "thread_local",
10006bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    "decltype",
100134b41d939a1328f484511c6002ba2456db879a29Richard Smith    "typeid"
10026bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines);
10036bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines
10046bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hinesmy %CppKeywords_O = map {$_=>1} (
10056bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    "bool",
10066bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    "register",
1007db3f847cb883fdb19d79c7223fa032e7266c0ee5Nick Lewycky    "inline",
1008dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth    "operator"
10096bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines);
10106bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines
10116bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hinesmy %CppKeywords_A = map {$_=>1} (
1012d30bf2eb6d6bbebd41236bf205d3a6dfc51a3659Douglas Gregor    "this",
10136bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    "throw"
1014d30bf2eb6d6bbebd41236bf205d3a6dfc51a3659Douglas Gregor);
10156bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines
10166bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hinesforeach (keys(%CppKeywords_C),
10179d156a7b1b2771e191f2f5a45a7b7a694129463bJohn McCallkeys(%CppKeywords_F),
10186bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hineskeys(%CppKeywords_O)) {
1019075f8f1b6bed4d1b224c74f87508534cc6392ce6Abramo Bagnara    $CppKeywords_A{$_}=1;
1020dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth}
10216bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines
102233500955d731c73717af52088b7fc0e7a85681e7John McCall# Header file extensions as described by gcc
10236bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hinesmy $HEADER_EXT = "h|hh|hp|hxx|hpp|h\\+\\+";
10246bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines
10256bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hinesmy %IntrinsicMangling = (
10266bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    "void" => "v",
10276bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    "bool" => "b",
10286bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    "wchar_t" => "w",
1029d30bf2eb6d6bbebd41236bf205d3a6dfc51a3659Douglas Gregor    "char" => "c",
103033500955d731c73717af52088b7fc0e7a85681e7John McCall    "signed char" => "a",
10316bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    "unsigned char" => "h",
10326bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    "short" => "s",
10336bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    "unsigned short" => "t",
1034d30bf2eb6d6bbebd41236bf205d3a6dfc51a3659Douglas Gregor    "int" => "i",
10356bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    "unsigned int" => "j",
10367536dd5e6c99584481b7dab68b7e7d8df9c54054Douglas Gregor    "long" => "l",
10376bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    "unsigned long" => "m",
1038d30bf2eb6d6bbebd41236bf205d3a6dfc51a3659Douglas Gregor    "long long" => "x",
1039dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth    "__int64" => "x",
10406bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    "unsigned long long" => "y",
10416bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    "__int128" => "n",
10426bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    "unsigned __int128" => "o",
10436bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    "float" => "f",
104487d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar    "double" => "d",
104587d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar    "long double" => "e",
104687d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar    "__float80" => "e",
10476bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    "__float128" => "g",
1048d30bf2eb6d6bbebd41236bf205d3a6dfc51a3659Douglas Gregor    "..." => "z"
10496bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines);
10506bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines
1051dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruthmy %StdcxxMangling = (
10526bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    "3std"=>"St",
1053b001de7458d17c17e6d8b8034c7cfcefd3b70c00Eli Friedman    "3std9allocator"=>"Sa",
10544967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    "3std12basic_string"=>"Sb",
10554967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    "3std12basic_stringIcE"=>"Ss",
1056dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth    "3std13basic_istreamIcE"=>"Si",
1057dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth    "3std13basic_ostreamIcE"=>"So",
10584d2229c7a9514ee2b960aa9e59f7259cebbaa421Nick Lewycky    "3std14basic_iostreamIcE"=>"Sd"
10594d2229c7a9514ee2b960aa9e59f7259cebbaa421Nick Lewycky);
10604d2229c7a9514ee2b960aa9e59f7259cebbaa421Nick Lewycky
1061ba243b59a1074e0962f6abfa3bb9aa984eac1245David Blaikiemy %ConstantSuffix = (
1062ba243b59a1074e0962f6abfa3bb9aa984eac1245David Blaikie    "unsigned int"=>"u",
1063a40bc724849f9cdc6a7706bc5d230685c3bdf63cDouglas Gregor    "long"=>"l",
1064717cc00c16eabf0eefd3cc69394e97f7229af0c8Zhanyong Wan    "unsigned long"=>"ul",
10656bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    "long long"=>"ll",
10666bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    "unsigned long long"=>"ull"
10676bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines);
10686bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines
10696bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hinesmy %ConstantSuffixR =
10706bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hinesreverse(%ConstantSuffix);
10716bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines
10726bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hinesmy %OperatorMangling = (
10734d2229c7a9514ee2b960aa9e59f7259cebbaa421Nick Lewycky    "~" => "co",
10744d2229c7a9514ee2b960aa9e59f7259cebbaa421Nick Lewycky    "=" => "aS",
10756bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    "|" => "or",
10766bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    "^" => "eo",
10776bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    "&" => "an",#ad (addr)
10786b3f1ebce775499aff03845193de78128671262fCraig Silverstein    "==" => "eq",
10796b3f1ebce775499aff03845193de78128671262fCraig Silverstein    "!" => "nt",
10806b3f1ebce775499aff03845193de78128671262fCraig Silverstein    "!=" => "ne",
10816b3f1ebce775499aff03845193de78128671262fCraig Silverstein    "<" => "lt",
10826b3f1ebce775499aff03845193de78128671262fCraig Silverstein    "<=" => "le",
10836b3f1ebce775499aff03845193de78128671262fCraig Silverstein    "<<" => "ls",
10846b3f1ebce775499aff03845193de78128671262fCraig Silverstein    "<<=" => "lS",
10856b3f1ebce775499aff03845193de78128671262fCraig Silverstein    ">" => "gt",
10866b3f1ebce775499aff03845193de78128671262fCraig Silverstein    ">=" => "ge",
10876b3f1ebce775499aff03845193de78128671262fCraig Silverstein    ">>" => "rs",
10886b3f1ebce775499aff03845193de78128671262fCraig Silverstein    ">>=" => "rS",
10896b3f1ebce775499aff03845193de78128671262fCraig Silverstein    "()" => "cl",
10906b3f1ebce775499aff03845193de78128671262fCraig Silverstein    "%" => "rm",
10916b3f1ebce775499aff03845193de78128671262fCraig Silverstein    "[]" => "ix",
10926b3f1ebce775499aff03845193de78128671262fCraig Silverstein    "&&" => "aa",
10936b3f1ebce775499aff03845193de78128671262fCraig Silverstein    "||" => "oo",
1094c34c2116346a29869b47b190f6dea589823d6947Craig Silverstein    "*" => "ml",#de (deref)
10954d2229c7a9514ee2b960aa9e59f7259cebbaa421Nick Lewycky    "++" => "pp",#
10966bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    "--" => "mm",#
10974d2229c7a9514ee2b960aa9e59f7259cebbaa421Nick Lewycky    "new" => "nw",
10984d2229c7a9514ee2b960aa9e59f7259cebbaa421Nick Lewycky    "delete" => "dl",
1099717cc00c16eabf0eefd3cc69394e97f7229af0c8Zhanyong Wan    "new[]" => "na",
11006bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    "delete[]" => "da",
11016bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    "+=" => "pL",
11024d2229c7a9514ee2b960aa9e59f7259cebbaa421Nick Lewycky    "+" => "pl",#ps (pos)
11036bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    "-" => "mi",#ng (neg)
11046bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    "-=" => "mI",
11054d2229c7a9514ee2b960aa9e59f7259cebbaa421Nick Lewycky    "*=" => "mL",
11066bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    "/=" => "dV",
11076bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    "&=" => "aN",
11084d2229c7a9514ee2b960aa9e59f7259cebbaa421Nick Lewycky    "|=" => "oR",
11096bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    "%=" => "rM",
11106bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    "^=" => "eO",
11114d2229c7a9514ee2b960aa9e59f7259cebbaa421Nick Lewycky    "/" => "dv",
11126bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    "->*" => "pm",
11136bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    "->" => "pt",#rf (ref)
11144d2229c7a9514ee2b960aa9e59f7259cebbaa421Nick Lewycky    "," => "cm",
11154d2229c7a9514ee2b960aa9e59f7259cebbaa421Nick Lewycky    "?" => "qu",
11164d2229c7a9514ee2b960aa9e59f7259cebbaa421Nick Lewycky    "." => "dt",
11174d2229c7a9514ee2b960aa9e59f7259cebbaa421Nick Lewycky    "sizeof"=> "sz"#st
1118717cc00c16eabf0eefd3cc69394e97f7229af0c8Zhanyong Wan);
11196bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines
11206bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hinesmy %Intrinsic_Keywords = map {$_=>1} (
11216bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    "true",
11224d2229c7a9514ee2b960aa9e59f7259cebbaa421Nick Lewycky    "false",
11236bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    "_Bool",
11246bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    "_Complex",
1125651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    "const",
11266bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    "int",
11276bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    "long",
112812df246d6dea2ee1f92c186f922f1afcf499647aReid Kleckner    "void",
11296bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    "short",
1130cf4679e60a5c5fa13e4bfe69f8186658c828af49Craig Silverstein    "float",
1131cf4679e60a5c5fa13e4bfe69f8186658c828af49Craig Silverstein    "volatile",
1132cf4679e60a5c5fa13e4bfe69f8186658c828af49Craig Silverstein    "restrict",
1133cf4679e60a5c5fa13e4bfe69f8186658c828af49Craig Silverstein    "unsigned",
1134cf4679e60a5c5fa13e4bfe69f8186658c828af49Craig Silverstein    "signed",
1135cf4679e60a5c5fa13e4bfe69f8186658c828af49Craig Silverstein    "char",
1136717cc00c16eabf0eefd3cc69394e97f7229af0c8Zhanyong Wan    "double",
11376bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    "class",
11386bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    "struct",
11396bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    "union",
11404d2229c7a9514ee2b960aa9e59f7259cebbaa421Nick Lewycky    "enum"
1141717cc00c16eabf0eefd3cc69394e97f7229af0c8Zhanyong Wan);
11426bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines
11436bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hinesmy %GlibcHeader = map {$_=>1} (
11446bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    "aliases.h",
11454d2229c7a9514ee2b960aa9e59f7259cebbaa421Nick Lewycky    "argp.h",
1146717cc00c16eabf0eefd3cc69394e97f7229af0c8Zhanyong Wan    "argz.h",
11476bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    "assert.h",
11486bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    "cpio.h",
11496bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    "ctype.h",
11504d2229c7a9514ee2b960aa9e59f7259cebbaa421Nick Lewycky    "dirent.h",
1151717cc00c16eabf0eefd3cc69394e97f7229af0c8Zhanyong Wan    "envz.h",
11526bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    "errno.h",
11536bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    "error.h",
11546bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    "execinfo.h",
11554d2229c7a9514ee2b960aa9e59f7259cebbaa421Nick Lewycky    "fcntl.h",
11564d2229c7a9514ee2b960aa9e59f7259cebbaa421Nick Lewycky    "fstab.h",
11574d2229c7a9514ee2b960aa9e59f7259cebbaa421Nick Lewycky    "ftw.h",
1158717cc00c16eabf0eefd3cc69394e97f7229af0c8Zhanyong Wan    "glob.h",
11596bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    "grp.h",
11606bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    "iconv.h",
11616bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    "ifaddrs.h",
11626bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    "inttypes.h",
11634d2229c7a9514ee2b960aa9e59f7259cebbaa421Nick Lewycky    "langinfo.h",
11644d2229c7a9514ee2b960aa9e59f7259cebbaa421Nick Lewycky    "limits.h",
1165717cc00c16eabf0eefd3cc69394e97f7229af0c8Zhanyong Wan    "link.h",
11666bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    "locale.h",
11676bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    "malloc.h",
11684d2229c7a9514ee2b960aa9e59f7259cebbaa421Nick Lewycky    "math.h",
11694d2229c7a9514ee2b960aa9e59f7259cebbaa421Nick Lewycky    "mntent.h",
11704d2229c7a9514ee2b960aa9e59f7259cebbaa421Nick Lewycky    "monetary.h",
1171717cc00c16eabf0eefd3cc69394e97f7229af0c8Zhanyong Wan    "nl_types.h",
11726bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    "obstack.h",
11736bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    "printf.h",
11744d2229c7a9514ee2b960aa9e59f7259cebbaa421Nick Lewycky    "pwd.h",
11756bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    "regex.h",
11766bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    "sched.h",
11774d2229c7a9514ee2b960aa9e59f7259cebbaa421Nick Lewycky    "search.h",
1178536bab452fa38692834233187ed3d49b83722cb3Craig Silverstein    "setjmp.h",
1179717cc00c16eabf0eefd3cc69394e97f7229af0c8Zhanyong Wan    "shadow.h",
11806bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    "signal.h",
11814d2229c7a9514ee2b960aa9e59f7259cebbaa421Nick Lewycky    "spawn.h",
11826bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    "stdarg.h",
1183536bab452fa38692834233187ed3d49b83722cb3Craig Silverstein    "stdint.h",
11846bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    "stdio.h",
11856bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    "stdlib.h",
11866bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    "string.h",
11876bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    "tar.h",
11886bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    "termios.h",
11894d2229c7a9514ee2b960aa9e59f7259cebbaa421Nick Lewycky    "time.h",
11906bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    "ulimit.h",
1191536bab452fa38692834233187ed3d49b83722cb3Craig Silverstein    "unistd.h",
11926bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    "utime.h",
11936bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    "wchar.h",
11946bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    "wctype.h",
1195176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines    "wordexp.h" );
1196176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines
1197176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hinesmy %GlibcDir = map {$_=>1} (
11986bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    "arpa",
11994d2229c7a9514ee2b960aa9e59f7259cebbaa421Nick Lewycky    "bits",
12006bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    "gnu",
12016bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    "netinet",
12024d2229c7a9514ee2b960aa9e59f7259cebbaa421Nick Lewycky    "net",
12036bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    "nfs",
12046bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    "rpc",
12054d2229c7a9514ee2b960aa9e59f7259cebbaa421Nick Lewycky    "sys",
1206717cc00c16eabf0eefd3cc69394e97f7229af0c8Zhanyong Wan    "linux" );
12076bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines
12086bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hinesmy %LocalIncludes = map {$_=>1} (
12094d2229c7a9514ee2b960aa9e59f7259cebbaa421Nick Lewycky    "/usr/local/include",
12104d2229c7a9514ee2b960aa9e59f7259cebbaa421Nick Lewycky    "/usr/local" );
1211717cc00c16eabf0eefd3cc69394e97f7229af0c8Zhanyong Wan
12126bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hinesmy %OS_AddPath=(
12136bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines# These paths are needed if the tool cannot detect them automatically
12144d2229c7a9514ee2b960aa9e59f7259cebbaa421Nick Lewycky    "macos"=>{
1215ca63c200346c0ca9e00194ec6e34a5a7b0ed9321Sean Hunt        "include"=>{
12166bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines            "/Library"=>1,
12176bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines            "/Developer/usr/include"=>1
1218ca63c200346c0ca9e00194ec6e34a5a7b0ed9321Sean Hunt        },
121934b41d939a1328f484511c6002ba2456db879a29Richard Smith        "lib"=>{
12206bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines            "/Library"=>1,
12216bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines            "/Developer/usr/lib"=>1
122234b41d939a1328f484511c6002ba2456db879a29Richard Smith        },
12236bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines        "bin"=>{
12246bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines            "/Developer/usr/bin"=>1
12256bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines        }
12266bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    },
12276bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    "beos"=>{
12284d2229c7a9514ee2b960aa9e59f7259cebbaa421Nick Lewycky    # Haiku has GCC 2.95.3 by default
12294d2229c7a9514ee2b960aa9e59f7259cebbaa421Nick Lewycky    # try to find GCC>=3.0 in /boot/develop/abi
1230717cc00c16eabf0eefd3cc69394e97f7229af0c8Zhanyong Wan        "include"=>{
12316bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines            "/boot/common"=>1,
12326bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines            "/boot/develop"=>1},
12336bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines        "lib"=>{
12346bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines            "/boot/common/lib"=>1,
12356bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines            "/boot/system/lib"=>1,
12364d2229c7a9514ee2b960aa9e59f7259cebbaa421Nick Lewycky            "/boot/apps"=>1},
12376bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines        "bin"=>{
12384d2229c7a9514ee2b960aa9e59f7259cebbaa421Nick Lewycky            "/boot/common/bin"=>1,
12396bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines            "/boot/system/bin"=>1,
1240075f8f1b6bed4d1b224c74f87508534cc6392ce6Abramo Bagnara            "/boot/develop/abi"=>1
12416bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    }
12426bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines}
12439d156a7b1b2771e191f2f5a45a7b7a694129463bJohn McCall);
1244717cc00c16eabf0eefd3cc69394e97f7229af0c8Zhanyong Wan
12456bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hinesmy %Slash_Type=(
12466bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    "default"=>"/",
12476bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    "windows"=>"\\"
12486bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines);
12496bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines
12504d2229c7a9514ee2b960aa9e59f7259cebbaa421Nick Lewyckymy $SLASH = $Slash_Type{$OSgroup}?$Slash_Type{$OSgroup}:$Slash_Type{"default"};
1251717cc00c16eabf0eefd3cc69394e97f7229af0c8Zhanyong Wan
12526bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines# Global Variables
12536bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hinesmy %COMMON_LANGUAGE=(
12544d2229c7a9514ee2b960aa9e59f7259cebbaa421Nick Lewycky  1 => "C",
1255717cc00c16eabf0eefd3cc69394e97f7229af0c8Zhanyong Wan  2 => "C" );
12566bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines
12576bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hinesmy $MAX_COMMAND_LINE_ARGUMENTS = 4096;
12586bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hinesmy (%WORD_SIZE, %CPU_ARCH, %GCC_VERSION);
1259ba243b59a1074e0962f6abfa3bb9aa984eac1245David Blaikie
12606bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hinesmy $STDCXX_TESTING = 0;
12616bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hinesmy $GLIBC_TESTING = 0;
12626bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines
12636bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hinesmy $CheckHeadersOnly = $CheckHeadersOnly_Opt;
12644d2229c7a9514ee2b960aa9e59f7259cebbaa421Nick Lewyckymy $CheckObjectsOnly = $CheckObjectsOnly_Opt;
12656bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hinesmy $TargetComponent;
12666bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines
12677536dd5e6c99584481b7dab68b7e7d8df9c54054Douglas Gregor# Set Target Component Name
12686bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hinesif($TargetComponent_Opt) {
12694d2229c7a9514ee2b960aa9e59f7259cebbaa421Nick Lewycky    $TargetComponent = lc($TargetComponent_Opt);
1270717cc00c16eabf0eefd3cc69394e97f7229af0c8Zhanyong Wan}
12716bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hineselse
12726bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines{ # default: library
12736bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  # other components: header, system, ...
12746bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    $TargetComponent = "library";
127587d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar}
127687d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar
12776bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hinesmy $TOP_REF = "<a style='font-size:11px;' href='#Top'>to the top</a>";
12784d2229c7a9514ee2b960aa9e59f7259cebbaa421Nick Lewycky
12796bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hinesmy $SystemRoot;
12806bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines
12814d2229c7a9514ee2b960aa9e59f7259cebbaa421Nick Lewyckymy $MAIN_CPP_DIR;
12826bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hinesmy %RESULT;
1283b001de7458d17c17e6d8b8034c7cfcefd3b70c00Eli Friedmanmy %LOG_PATH;
12844967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainarmy %DEBUG_PATH;
12854967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainarmy %Cache;
12864d2229c7a9514ee2b960aa9e59f7259cebbaa421Nick Lewyckymy %LibInfo;
12874d2229c7a9514ee2b960aa9e59f7259cebbaa421Nick Lewyckymy $COMPILE_ERRORS = 0;
1288dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruthmy %CompilerOptions;
1289dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruthmy %CheckedDyLib;
1290dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruthmy $TargetLibraryShortName = parse_libname($TargetLibraryName, "shortest", $OSgroup);
1291dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth
1292dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth# Constants (#defines)
1293dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruthmy %Constants;
1294dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruthmy %SkipConstants;
12956bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines
12964d072932287eb074a4168804cac1acb18a51d5e8Craig Silverstein# Types
12970c05a1bae9e8a57f56663991d0442a69df34a003Zhanyong Wanmy %TypeInfo;
12980c05a1bae9e8a57f56663991d0442a69df34a003Zhanyong Wanmy %TemplateInstance;
12990c05a1bae9e8a57f56663991d0442a69df34a003Zhanyong Wanmy %TemplateDecl;
1300651f13cea278ec967336033dd032faef0e9fc2ecStephen Hinesmy %SkipTypes = (
13016afcf8875d4e447645cd7bf3733dd8e2eb8455dcTareq A. Siraj  "1"=>{},
13026afcf8875d4e447645cd7bf3733dd8e2eb8455dcTareq A. Siraj  "2"=>{} );
1303651f13cea278ec967336033dd032faef0e9fc2ecStephen Hinesmy %CheckedTypes;
1304651f13cea278ec967336033dd032faef0e9fc2ecStephen Hinesmy %TName_Tid;
13050c05a1bae9e8a57f56663991d0442a69df34a003Zhanyong Wanmy %EnumMembName_Id;
13060c05a1bae9e8a57f56663991d0442a69df34a003Zhanyong Wanmy %NestedNameSpaces = (
13070c05a1bae9e8a57f56663991d0442a69df34a003Zhanyong Wan  "1"=>{},
13080c05a1bae9e8a57f56663991d0442a69df34a003Zhanyong Wan  "2"=>{} );
13090c05a1bae9e8a57f56663991d0442a69df34a003Zhanyong Wanmy %UsedType;
1310dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruthmy %VirtualTable;
13116bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hinesmy %VirtualTable_Model;
13126bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hinesmy %ClassVTable;
13136bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hinesmy %ClassVTable_Content;
13144967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainarmy %VTableClass;
13154967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainarmy %AllocableClass;
13164967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainarmy %ClassMethods;
13174967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainarmy %ClassNames;
13186bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hinesmy %Class_SubClasses;
13194967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainarmy %OverriddenMethods;
13204967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainarmy $MAX_ID = 0;
13214967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar
13224967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar# Typedefs
13234967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainarmy %Typedef_BaseName;
13246bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hinesmy %Typedef_Tr;
1325d30bf2eb6d6bbebd41236bf205d3a6dfc51a3659Douglas Gregormy %Typedef_Eq;
13266bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hinesmy %StdCxxTypedef;
1327d30bf2eb6d6bbebd41236bf205d3a6dfc51a3659Douglas Gregormy %MissedTypedef;
1328dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruthmy %MissedBase;
13296bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hinesmy %MissedBase_R;
13306bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines
13316bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines# Symbols
1332c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hinesmy %SymbolInfo;
1333c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hinesmy %tr_name;
1334c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hinesmy %mangled_name_gcc;
1335c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hinesmy %mangled_name;
1336c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hinesmy %SkipSymbols = (
13374967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar  "1"=>{},
13386bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  "2"=>{} );
1339d30bf2eb6d6bbebd41236bf205d3a6dfc51a3659Douglas Gregormy %SkipNameSpaces = (
13406afcf8875d4e447645cd7bf3733dd8e2eb8455dcTareq A. Siraj  "1"=>{},
13416bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  "2"=>{} );
13424967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainarmy %AddNameSpaces = (
13436bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  "1"=>{},
13446afcf8875d4e447645cd7bf3733dd8e2eb8455dcTareq A. Siraj  "2"=>{} );
13456bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hinesmy %SymbolsList;
1346684aa73192d92850a926870be62a1787eb5b7ed9Michael Hanmy %SymbolsList_App;
13476bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hinesmy %CheckedSymbols;
13486bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hinesmy %Symbol_Library = (
1349d30bf2eb6d6bbebd41236bf205d3a6dfc51a3659Douglas Gregor  "1"=>{},
13506bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  "2"=>{} );
135115de72cf580840c61e5704c2f8a2b56f9d0638e1Douglas Gregormy %Library_Symbol = (
1352dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth  "1"=>{},
13536bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  "2"=>{} );
13546bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hinesmy %DepSymbol_Library = (
13556bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  "1"=>{},
13566bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  "2"=>{} );
13576bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hinesmy %DepLibrary_Symbol = (
13586bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  "1"=>{},
1359d30bf2eb6d6bbebd41236bf205d3a6dfc51a3659Douglas Gregor  "2"=>{} );
1360dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruthmy %MangledNames;
13616bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hinesmy %AddIntParams;
13626bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hinesmy %Interface_Impl;
13636bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hinesmy %GlobalDataObject;
13646bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines
13656bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines# Headers
13666bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hinesmy %Include_Preamble;
13676bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hinesmy %Registered_Headers;
13686bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hinesmy %HeaderName_Paths;
13696bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hinesmy %Header_Dependency;
1370dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruthmy %Include_Neighbors;
13716bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hinesmy %Include_Paths;
13726bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hinesmy %INC_PATH_AUTODETECT = (
1373d30bf2eb6d6bbebd41236bf205d3a6dfc51a3659Douglas Gregor  "1"=>1,
1374af0f4d0b2e38c810effc8b024ad2fb6604eec5d3Francois Pichet  "2"=>1 );
13756bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hinesmy %Add_Include_Paths;
13766b02009359a462ffe633696a4441313b462e6566Nico Webermy %Skip_Include_Paths;
13776bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hinesmy %RegisteredDirs;
13786bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hinesmy %Header_ErrorRedirect;
13796bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hinesmy %Header_Includes;
13806bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hinesmy %Header_ShouldNotBeUsed;
13816bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hinesmy %RecursiveIncludes;
13826bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hinesmy %Header_Include_Prefix;
1383af0f4d0b2e38c810effc8b024ad2fb6604eec5d3Francois Pichetmy %SkipHeaders;
13846bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hinesmy %SkipHeadersList=(
1385db3f847cb883fdb19d79c7223fa032e7266c0ee5Nick Lewycky  "1"=>{},
13866bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  "2"=>{} );
13876bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hinesmy %SkipLibs;
1388db3f847cb883fdb19d79c7223fa032e7266c0ee5Nick Lewyckymy %Include_Order;
1389dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruthmy %TUnit_NameSpaces;
13906bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines
13916bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hinesmy %C99Mode = (
13926bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  "1"=>0,
1393db3f847cb883fdb19d79c7223fa032e7266c0ee5Nick Lewycky  "2"=>0 );
13946bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hinesmy %AutoPreambleMode = (
13956bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  "1"=>0,
13966bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  "2"=>0 );
13976bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hinesmy %MinGWMode = (
13986bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  "1"=>0,
13996bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  "2"=>0 );
1400db3f847cb883fdb19d79c7223fa032e7266c0ee5Nick Lewycky
14014967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar# Shared Objects
14024967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainarmy %DyLib_DefaultPath;
14034967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainarmy %InputObject_Paths;
14044967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainarmy %RegisteredObjDirs;
14053ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar
14063ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar# System Objects
1407dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruthmy %SystemObjects;
140887d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainarmy %DefaultLibPaths;
140987d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar
14106bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines# System Headers
14116bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hinesmy %SystemHeaders;
14124967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainarmy %DefaultCppPaths;
1413ad8dcf4a9df0e24051dc31bf9e6f3cd138a34298Chris Lattnermy %DefaultGccPaths;
1414ba243b59a1074e0962f6abfa3bb9aa984eac1245David Blaikiemy %DefaultIncPaths;
14156bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hinesmy %DefaultCppHeader;
14166bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hinesmy %DefaultGccHeader;
1417ba243b59a1074e0962f6abfa3bb9aa984eac1245David Blaikiemy %UserIncPath;
14186bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines
14196bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines# Merging
14206bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hinesmy %CompleteSignature;
14216bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hinesmy $Version;
14226bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hinesmy %AddedInt;
14236bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hinesmy %RemovedInt;
1424d30bf2eb6d6bbebd41236bf205d3a6dfc51a3659Douglas Gregormy %AddedInt_Virt;
14256bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hinesmy %RemovedInt_Virt;
14266bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hinesmy %VirtualReplacement;
1427db3f847cb883fdb19d79c7223fa032e7266c0ee5Nick Lewyckymy %ChangedTypedef;
14286bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hinesmy %CompatRules;
142987d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainarmy %IncompleteRules;
143087d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainarmy %UnknownRules;
143187d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainarmy %VTableChanged_M;
143287d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainarmy %ExtendedSymbols;
143387d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainarmy %ReturnedClass;
143487d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainarmy %ParamClass;
1435dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruthmy %SourceAlternative;
14366bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hinesmy %SourceAlternative_B;
14376bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hinesmy %SourceReplacement;
1438dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth
14396bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines# OS Compliance
14406bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hinesmy %TargetLibs;
1441dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruthmy %TargetHeaders;
14426bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines
144387d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar# OS Specifics
144487d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainarmy $OStarget = $OSgroup;
144587d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainarmy %TargetTools;
144687d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar
144787d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar# Compliance Report
144887d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainarmy %Type_MaxSeverity;
144987d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar
145087d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar# Recursion locks
145187d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainarmy @RecurLib;
145287d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainarmy @RecurSymlink;
1453dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruthmy @RecurTypes;
14546bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hinesmy @RecurInclude;
14556bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hinesmy @RecurConstant;
1456dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth
1457dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth# System
1458651f13cea278ec967336033dd032faef0e9fc2ecStephen Hinesmy %SystemPaths;
1459651f13cea278ec967336033dd032faef0e9fc2ecStephen Hinesmy %DefaultBinPaths;
1460651f13cea278ec967336033dd032faef0e9fc2ecStephen Hinesmy $GCC_PATH;
14614967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar
14624967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar# Symbols versioning
1463651f13cea278ec967336033dd032faef0e9fc2ecStephen Hinesmy %SymVer = (
1464651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  "1"=>{},
1465651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  "2"=>{} );
1466651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
14674967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar# Problem descriptions
1468651f13cea278ec967336033dd032faef0e9fc2ecStephen Hinesmy %CompatProblems;
1469dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruthmy %ProblemsWithConstants;
147087d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainarmy %ImplProblems;
147187d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainarmy %TotalAffected;
147287d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar
147387d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar# Reports
147487d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainarmy $ContentID = 1;
147587d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainarmy $ContentSpanStart = "<span class=\"section\" onclick=\"javascript:showContent(this, 'CONTENT_ID')\">\n";
147687d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainarmy $ContentSpanStart_Affected = "<span class=\"section_affected\" onclick=\"javascript:showContent(this, 'CONTENT_ID')\">\n";
147787d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainarmy $ContentSpanStart_Info = "<span class=\"section_info\" onclick=\"javascript:showContent(this, 'CONTENT_ID')\">\n";
147887d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainarmy $ContentSpanEnd = "</span>\n";
1479c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hinesmy $ContentDivStart = "<div id=\"CONTENT_ID\" style=\"display:none;\">\n";
1480c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hinesmy $ContentDivEnd = "</div>\n";
1481c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hinesmy $Content_Counter = 0;
1482c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines
1483c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines# XML Dump
14844967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainarmy $TAG_ID = 0;
1485c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hinesmy $INDENT = "    ";
1486dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth
1487dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth# Modes
14886bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hinesmy $JoinReport = 1;
14896bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hinesmy $DoubleReport = 0;
14906bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines
1491dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruthsub get_Modules()
1492dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth{
14936bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    my $TOOL_DIR = get_dirname($0);
14946bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    if(not $TOOL_DIR)
1495dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth    { # patch for MS Windows
14966bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines        $TOOL_DIR = ".";
1497d30bf2eb6d6bbebd41236bf205d3a6dfc51a3659Douglas Gregor    }
14984967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    my @SEARCH_DIRS = (
14994967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar        # tool's directory
1500c640058aa7f224a71ce3b1d2601d84e1b57f82d3Alexey Bataev        abs_path($TOOL_DIR),
15016bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines        # relative path to modules
15026bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines        abs_path($TOOL_DIR)."/../share/abi-compliance-checker",
15036bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines        # system directory
15046bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines        "ACC_MODULES_INSTALL_PATH"
1505c640058aa7f224a71ce3b1d2601d84e1b57f82d3Alexey Bataev    );
15064967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    foreach my $DIR (@SEARCH_DIRS)
15074967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    {
15084967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar        if(not is_abs($DIR))
15094967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar        { # relative path
15104967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar            $DIR = abs_path($TOOL_DIR)."/".$DIR;
15114967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar        }
15124967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar        if(-d $DIR."/modules") {
15134967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar            return $DIR."/modules";
15144967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar        }
15154967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    }
1516dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth    exitStatus("Module_Error", "can't find modules");
15176bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines}
1518dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth
1519dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruthsub loadModule($)
1520dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth{
1521dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth    my $Name = $_[0];
1522dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth    my $Path = $MODULES_DIR."/Internals/$Name.pm";
1523dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth    if(not -f $Path) {
1524dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth        exitStatus("Module_Error", "can't access \'$Path\'");
1525dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth    }
1526e3e210c3aa3c1b289eee669a1d235fc16df384a0Chandler Carruth    require $Path;
1527db3f847cb883fdb19d79c7223fa032e7266c0ee5Nick Lewycky}
1528d30bf2eb6d6bbebd41236bf205d3a6dfc51a3659Douglas Gregor
15296bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hinessub showPos($)
1530651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines{
1531651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    my $Number = $_[0];
1532651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    if(not $Number) {
1533651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines        $Number = 1;
1534651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    }
1535651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    else {
1536651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines        $Number = int($Number)+1;
1537651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    }
15386bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    if($Number>3) {
15396bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines        return $Number."th";
1540651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    }
1541651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    elsif($Number==1) {
1542651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines        return "1st";
1543651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    }
1544651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    elsif($Number==2) {
1545651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines        return "2nd";
1546651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    }
1547651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    elsif($Number==3) {
1548651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines        return "3rd";
1549651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    }
1550651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    else {
1551651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines        return $Number;
1552651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    }
1553651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines}
1554651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
1555651f13cea278ec967336033dd032faef0e9fc2ecStephen Hinessub search_Tools($)
1556651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines{
1557651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    my $Name = $_[0];
1558651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    return "" if(not $Name);
1559651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    if(my @Paths = keys(%TargetTools))
15606bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    {
1561651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines        foreach my $Path (@Paths)
1562651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines        {
1563651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines            if(-f joinPath($Path, $Name)) {
1564651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines                return joinPath($Path, $Name);
15656bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines            }
15666bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines            if($CrossPrefix)
1567651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines            { # user-defined prefix (arm-none-symbianelf, ...)
1568651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines                my $Candidate = joinPath($Path, $CrossPrefix."-".$Name);
1569651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines                if(-f $Candidate) {
1570651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines                    return $Candidate;
1571651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines                }
1572651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines            }
1573651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines        }
1574651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    }
1575651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    else {
1576651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines        return "";
1577651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    }
1578651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines}
1579651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
1580651f13cea278ec967336033dd032faef0e9fc2ecStephen Hinessub synch_Cmd($)
1581ef4579cda09b73e3d4d98af48201da25adc29326Larisse Voufo{
1582ef4579cda09b73e3d4d98af48201da25adc29326Larisse Voufo    my $Name = $_[0];
1583760c8af273d9871d063250ae626fb6df94c121f2John McCall    if(not $GCC_PATH)
1584760c8af273d9871d063250ae626fb6df94c121f2John McCall    { # GCC was not found yet
15856bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines        return "";
15868d2a5ea694ed0002b45deb2bd35db451b16a07d6Larisse Voufo    }
1587a313b2fbba86c901e58dc58df036e731f24fdaeeRichard Smith    my $Candidate = $GCC_PATH;
1588651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    if($Candidate=~s/\bgcc(|\.\w+)\Z/$Name$1/) {
1589651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines        return $Candidate;
1590651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    }
1591651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    return "";
1592651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines}
1593651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
1594651f13cea278ec967336033dd032faef0e9fc2ecStephen Hinessub get_CmdPath($)
1595651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines{
1596651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    my $Name = $_[0];
1597651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    return "" if(not $Name);
1598651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    if(defined $Cache{"get_CmdPath"}{$Name}) {
1599651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines        return $Cache{"get_CmdPath"}{$Name};
1600651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    }
1601651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    my %BinUtils = map {$_=>1} (
1602651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines        "c++filt",
1603651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines        "objdump",
1604651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines        "readelf"
1605651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    );
1606651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    if($BinUtils{$Name} and $GCC_PATH)
1607760c8af273d9871d063250ae626fb6df94c121f2John McCall    {
1608760c8af273d9871d063250ae626fb6df94c121f2John McCall        if(my $Dir = get_dirname($GCC_PATH)) {
1609536bab452fa38692834233187ed3d49b83722cb3Craig Silverstein            $TargetTools{$Dir}=1;
1610760c8af273d9871d063250ae626fb6df94c121f2John McCall        }
1611760c8af273d9871d063250ae626fb6df94c121f2John McCall    }
1612536bab452fa38692834233187ed3d49b83722cb3Craig Silverstein    my $Path = search_Tools($Name);
16138d2a5ea694ed0002b45deb2bd35db451b16a07d6Larisse Voufo    if(not $Path and $OSgroup eq "windows") {
16148d2a5ea694ed0002b45deb2bd35db451b16a07d6Larisse Voufo        $Path = search_Tools($Name.".exe");
16156bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    }
16166bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    if(not $Path and $BinUtils{$Name})
1617c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines    {
1618c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines        if($CrossPrefix)
1619c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines        { # user-defined prefix
1620c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines            $Path = search_Cmd($CrossPrefix."-".$Name);
1621c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines        }
1622c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines    }
1623c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines    if(not $Path and $BinUtils{$Name})
1624c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines    {
1625c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines        if(my $Candidate = synch_Cmd($Name))
1626c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines        { # synch with GCC
1627c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines            if($Candidate=~/[\/\\]/)
1628c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines            { # command path
1629c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines                if(-f $Candidate) {
1630c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines                    $Path = $Candidate;
1631c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines                }
1632c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines            }
16338d2a5ea694ed0002b45deb2bd35db451b16a07d6Larisse Voufo            elsif($Candidate = search_Cmd($Candidate))
16348d2a5ea694ed0002b45deb2bd35db451b16a07d6Larisse Voufo            { # command name
16358d2a5ea694ed0002b45deb2bd35db451b16a07d6Larisse Voufo                $Path = $Candidate;
16368d2a5ea694ed0002b45deb2bd35db451b16a07d6Larisse Voufo            }
16378d2a5ea694ed0002b45deb2bd35db451b16a07d6Larisse Voufo        }
1638dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth    }
1639dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth    if(not $Path) {
16406bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines        $Path = search_Cmd($Name);
16416bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    }
16426bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    if(not $Path and $OSgroup eq "windows")
16436bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    { # search for *.exe file
16446bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines        $Path=search_Cmd($Name.".exe");
16456bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    }
16466bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    if($Path=~/\s/) {
16476bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines        $Path = "\"".$Path."\"";
1648dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth    }
164987d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar    return ($Cache{"get_CmdPath"}{$Name}=$Path);
165087d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar}
165187d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar
165287d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainarsub search_Cmd($)
1653dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth{
16546bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    my $Name = $_[0];
16556bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    return "" if(not $Name);
16566bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    if(defined $Cache{"search_Cmd"}{$Name}) {
16576bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines        return $Cache{"search_Cmd"}{$Name};
16586bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    }
16596bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    if(my $DefaultPath = get_CmdPath_Default($Name)) {
1660dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth        return ($Cache{"search_Cmd"}{$Name} = $DefaultPath);
1661dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth    }
16626bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    foreach my $Path (sort {length($a)<=>length($b)} keys(%{$SystemPaths{"bin"}}))
16636bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    {
16646bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines        my $CmdPath = joinPath($Path,$Name);
16656bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines        if(-f $CmdPath)
16666bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines        {
1667dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth            if($Name=~/gcc/) {
1668162e1c1b487352434552147967c3dd296ebee2f7Richard Smith                next if(not check_gcc($CmdPath, "3"));
16696bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines            }
16706bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines            return ($Cache{"search_Cmd"}{$Name} = $CmdPath);
16716bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines        }
16726bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    }
16736bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    return ($Cache{"search_Cmd"}{$Name} = "");
1674162e1c1b487352434552147967c3dd296ebee2f7Richard Smith}
16753e4c6c4c79a03f5cb0c4671d7c282d623c6dc35eRichard Smith
16766bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hinessub get_CmdPath_Default($)
16776bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines{ # search in PATH
16786bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    return "" if(not $_[0]);
16793e4c6c4c79a03f5cb0c4671d7c282d623c6dc35eRichard Smith    if(defined $Cache{"get_CmdPath_Default"}{$_[0]}) {
1680dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth        return $Cache{"get_CmdPath_Default"}{$_[0]};
16816bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    }
16826bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    return ($Cache{"get_CmdPath_Default"}{$_[0]} = get_CmdPath_Default_I($_[0]));
16836bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines}
16846bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines
16856bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hinessub get_CmdPath_Default_I($)
16866bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines{ # search in PATH
16876bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    my $Name = $_[0];
1688d30bf2eb6d6bbebd41236bf205d3a6dfc51a3659Douglas Gregor    if($Name=~/find/)
1689dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth    { # special case: search for "find" utility
16906bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines        if(`find \"$TMP_DIR\" -maxdepth 0 2>\"$TMP_DIR/null\"`) {
16916bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines            return "find";
1692dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth        }
16936bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    }
16946bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    elsif($Name=~/gcc/) {
16956bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines        return check_gcc($Name, "3");
16966bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    }
1697dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth    if(check_command($Name)) {
1698dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth        return $Name;
16996bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    }
17006bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    if($OSgroup eq "windows")
1701dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth    {
1702dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth        if(`$Name /? 2>\"$TMP_DIR/null\"`) {
1703a0e27f00158c9306d53b0003b94182e415380ea9Francois Pichet            return $Name;
17043812999df1a50e0804985c8845fcfa3fd7ffe14cCraig Silverstein        }
1705e3e210c3aa3c1b289eee669a1d235fc16df384a0Chandler Carruth    }
1706db3f847cb883fdb19d79c7223fa032e7266c0ee5Nick Lewycky    if($Name!~/which/)
1707d30bf2eb6d6bbebd41236bf205d3a6dfc51a3659Douglas Gregor    {
17086bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines        if(my $WhichCmd = get_CmdPath("which"))
17096bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines        {
1710e3e210c3aa3c1b289eee669a1d235fc16df384a0Chandler Carruth            if(`$WhichCmd $Name 2>\"$TMP_DIR/null\"`) {
1711e3e210c3aa3c1b289eee669a1d235fc16df384a0Chandler Carruth                return $Name;
17129f99d06e0d22380b9d1f0609a083dbfbd8b37c10Manuel Klimek            }
1713651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines        }
1714651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    }
1715dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth    foreach my $Path (sort {length($a)<=>length($b)} keys(%DefaultBinPaths))
1716dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth    {
1717dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth        if(-f $Path."/".$Name) {
1718dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth            return joinPath($Path,$Name);
1719e3e210c3aa3c1b289eee669a1d235fc16df384a0Chandler Carruth        }
1720db3f847cb883fdb19d79c7223fa032e7266c0ee5Nick Lewycky    }
1721d30bf2eb6d6bbebd41236bf205d3a6dfc51a3659Douglas Gregor    return "";
17226bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines}
17236bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines
17246bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hinessub clean_path($)
17256bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines{
17266bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    my $Path = $_[0];
17276bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    $Path=~s/[\/\\]+\Z//g;
17286bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    return $Path;
17296bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines}
17306bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines
17316bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hinessub classifyPath($)
17326bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines{
17336bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    my $Path = $_[0];
17346bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    if($Path=~/[\*\[]/)
17356bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    { # wildcard
17366bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines        $Path=~s/\*/.*/g;
17376bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines        $Path=~s/\\/\\\\/g;
17386bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines        return ($Path, "Pattern");
17396bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    }
17406bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    elsif($Path=~/[\/\\]/)
17416bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    { # directory or relative path
17426bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines        $Path=~s/[\/\\]+\Z//g;
17436bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines        return (path_format($Path, $OSgroup), "Path");
17446bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    }
17456bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    else {
17468d2a5ea694ed0002b45deb2bd35db451b16a07d6Larisse Voufo        return ($Path, "Name");
17478d2a5ea694ed0002b45deb2bd35db451b16a07d6Larisse Voufo    }
17488d2a5ea694ed0002b45deb2bd35db451b16a07d6Larisse Voufo}
17498d2a5ea694ed0002b45deb2bd35db451b16a07d6Larisse Voufo
1750d30bf2eb6d6bbebd41236bf205d3a6dfc51a3659Douglas Gregorsub readDescriptor($$)
1751dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth{
1752dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth    my ($LibVersion, $Content) = @_;
1753dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth    return if(not $LibVersion);
1754dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth    my $DName = $DumpAPI?"descriptor":"descriptor \"d$LibVersion\"";
17554d2229c7a9514ee2b960aa9e59f7259cebbaa421Nick Lewycky    if(not $Content) {
1756dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth        exitStatus("Error", "$DName is empty");
1757e3e210c3aa3c1b289eee669a1d235fc16df384a0Chandler Carruth    }
1758db3f847cb883fdb19d79c7223fa032e7266c0ee5Nick Lewycky    if($Content!~/\</) {
1759db3f847cb883fdb19d79c7223fa032e7266c0ee5Nick Lewycky        exitStatus("Error", "incorrect descriptor (see -d1 option)");
17606bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    }
17616bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    $Content=~s/\/\*(.|\n)+?\*\///g;
1762c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines    $Content=~s/<\!--(.|\n)+?-->//g;
1763c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines    $Descriptor{$LibVersion}{"Version"} = parseTag(\$Content, "version");
1764c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines    if($TargetVersion{$LibVersion}) {
1765c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines        $Descriptor{$LibVersion}{"Version"} = $TargetVersion{$LibVersion};
1766c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines    }
1767c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines    if(not $Descriptor{$LibVersion}{"Version"}) {
1768c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines        exitStatus("Error", "version in the $DName is not specified (<version> section)");
1769c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines    }
1770c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines    if($Content=~/{RELPATH}/)
1771c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines    {
1772c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines        if(my $RelDir = $RelativeDirectory{$LibVersion}) {
1773c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines            $Content =~ s/{RELPATH}/$RelDir/g;
1774c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines        }
1775c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines        else
1776c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines        {
1777c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines            my $NeedRelpath = $DumpAPI?"-relpath":"-relpath$LibVersion";
1778c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines            exitStatus("Error", "you have not specified $NeedRelpath option, but the $DName contains {RELPATH} macro");
1779c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines        }
17808d2a5ea694ed0002b45deb2bd35db451b16a07d6Larisse Voufo    }
17818d2a5ea694ed0002b45deb2bd35db451b16a07d6Larisse Voufo
17828d2a5ea694ed0002b45deb2bd35db451b16a07d6Larisse Voufo    if(not $CheckObjectsOnly_Opt)
17838d2a5ea694ed0002b45deb2bd35db451b16a07d6Larisse Voufo    {
1784dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth        my $DHeaders = parseTag(\$Content, "headers");
17856bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines        if(not $DHeaders) {
1786dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth            exitStatus("Error", "header files in the $DName are not specified (<headers> section)");
1787dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth        }
17886bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines        elsif(lc($DHeaders) ne "none")
17896bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines        { # append the descriptor headers list
17906bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines            if($Descriptor{$LibVersion}{"Headers"})
17916bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines            { # multiple descriptors
17926bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines                $Descriptor{$LibVersion}{"Headers"} .= "\n".$DHeaders;
1793dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth            }
179487c2e121cf0522fc266efe2922b58091cd2e0182Francois Pichet            else {
179587c2e121cf0522fc266efe2922b58091cd2e0182Francois Pichet                $Descriptor{$LibVersion}{"Headers"} = $DHeaders;
17966bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines            }
1797dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth            foreach my $Path (split(/\s*\n\s*/, $DHeaders))
17983812999df1a50e0804985c8845fcfa3fd7ffe14cCraig Silverstein            {
1799dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth                if(not -e $Path) {
18004d2229c7a9514ee2b960aa9e59f7259cebbaa421Nick Lewycky                    exitStatus("Access_Error", "can't access \'$Path\'");
1801406f98f6a5a7bde5707085af8d66204e7e76af45Douglas Gregor                }
1802406f98f6a5a7bde5707085af8d66204e7e76af45Douglas Gregor            }
1803e3e210c3aa3c1b289eee669a1d235fc16df384a0Chandler Carruth        }
1804db3f847cb883fdb19d79c7223fa032e7266c0ee5Nick Lewycky    }
1805c12c5bba6ceb6acd4e51e7a0fc03257da9cfd44eJohn McCall    if(not $CheckHeadersOnly_Opt)
18066bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    {
180776da55d3a49e1805f51b1ced7c5da5bcd7f759d8John McCall        my $DObjects = parseTag(\$Content, "libs");
1808dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth        if(not $DObjects) {
18096bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines            exitStatus("Error", "$SLIB_TYPE libraries in the $DName are not specified (<libs> section)");
18106bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines        }
18116bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines        elsif(lc($DObjects) ne "none")
18126bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines        { # append the descriptor libraries list
18136bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines            if($Descriptor{$LibVersion}{"Libs"})
18146bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines            { # multiple descriptors
1815dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth                $Descriptor{$LibVersion}{"Libs"} .= "\n".$DObjects;
1816dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth            }
18176bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines            else {
18186bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines                $Descriptor{$LibVersion}{"Libs"} .= $DObjects;
18196bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines            }
18206bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines            foreach my $Path (split(/\s*\n\s*/, $DObjects))
18216bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines            {
1822dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth                if(not -e $Path) {
1823dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth                    exitStatus("Access_Error", "can't access \'$Path\'");
18246bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines                }
18256bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines            }
18266bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines        }
18276bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    }
18286bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "search_headers")))
1829dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth    {
18306bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines        $Path = clean_path($Path);
1831dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth        if(not -d $Path) {
18323812999df1a50e0804985c8845fcfa3fd7ffe14cCraig Silverstein            exitStatus("Access_Error", "can't access directory \'$Path\'");
183365019acfc46ffb191fac4e781ac0c4b8d0c8434eDouglas Gregor        }
18340c05a1bae9e8a57f56663991d0442a69df34a003Zhanyong Wan        $Path = path_format($Path, $OSgroup);
1835cf4679e60a5c5fa13e4bfe69f8186658c828af49Craig Silverstein        $SystemPaths{"include"}{$Path}=1;
1836536bab452fa38692834233187ed3d49b83722cb3Craig Silverstein    }
1837536bab452fa38692834233187ed3d49b83722cb3Craig Silverstein    foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "search_libs")))
1838536bab452fa38692834233187ed3d49b83722cb3Craig Silverstein    {
1839536bab452fa38692834233187ed3d49b83722cb3Craig Silverstein        $Path = clean_path($Path);
1840cf4679e60a5c5fa13e4bfe69f8186658c828af49Craig Silverstein        if(not -d $Path) {
18416bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines            exitStatus("Access_Error", "can't access directory \'$Path\'");
1842cf4679e60a5c5fa13e4bfe69f8186658c828af49Craig Silverstein        }
1843cf4679e60a5c5fa13e4bfe69f8186658c828af49Craig Silverstein        $Path = path_format($Path, $OSgroup);
184444db3251aec7c0e6edaf1c70d7d53a272686791aNick Lewycky        $SystemPaths{"lib"}{$Path}=1;
184544db3251aec7c0e6edaf1c70d7d53a272686791aNick Lewycky    }
184671a7605977113c795edd44fcbd2302ad49506653Argyrios Kyrtzidis    foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "tools")))
18476bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    {
184871a7605977113c795edd44fcbd2302ad49506653Argyrios Kyrtzidis        $Path=clean_path($Path);
184971a7605977113c795edd44fcbd2302ad49506653Argyrios Kyrtzidis        if(not -d $Path) {
185044db3251aec7c0e6edaf1c70d7d53a272686791aNick Lewycky            exitStatus("Access_Error", "can't access directory \'$Path\'");
1851cf4679e60a5c5fa13e4bfe69f8186658c828af49Craig Silverstein        }
1852cf4679e60a5c5fa13e4bfe69f8186658c828af49Craig Silverstein        $Path = path_format($Path, $OSgroup);
1853cf4679e60a5c5fa13e4bfe69f8186658c828af49Craig Silverstein        $SystemPaths{"bin"}{$Path}=1;
1854536bab452fa38692834233187ed3d49b83722cb3Craig Silverstein        $TargetTools{$Path}=1;
1855536bab452fa38692834233187ed3d49b83722cb3Craig Silverstein    }
1856536bab452fa38692834233187ed3d49b83722cb3Craig Silverstein    if(my $Prefix = parseTag(\$Content, "cross_prefix")) {
1857536bab452fa38692834233187ed3d49b83722cb3Craig Silverstein        $CrossPrefix = $Prefix;
18588ddfb0b72d0e439d01759c1bc7a79ba73dd2830cManuel Klimek    }
1859c28a335184207a47f34eb9d1707dc8d7c6c7b8b6Richard Smith    foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "include_paths")))
18604b6730d40e7c603bd0e223d3fa8b56a0c88a324aMichael Han    {
18614b6730d40e7c603bd0e223d3fa8b56a0c88a324aMichael Han        $Path=clean_path($Path);
18624b6730d40e7c603bd0e223d3fa8b56a0c88a324aMichael Han        if(not -d $Path) {
18634b6730d40e7c603bd0e223d3fa8b56a0c88a324aMichael Han            exitStatus("Access_Error", "can't access directory \'$Path\'");
18644b6730d40e7c603bd0e223d3fa8b56a0c88a324aMichael Han        }
18654967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar        $Path = path_format($Path, $OSgroup);
18664967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar        $Descriptor{$LibVersion}{"IncludePaths"}{$Path} = 1;
18674967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    }
1868c28a335184207a47f34eb9d1707dc8d7c6c7b8b6Richard Smith    foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "add_include_paths")))
1869cf4679e60a5c5fa13e4bfe69f8186658c828af49Craig Silverstein    {
18706beaf938c0a2587ac4b2b60a51fbb9a80f72b766Zhanyong Wan        $Path=clean_path($Path);
18716beaf938c0a2587ac4b2b60a51fbb9a80f72b766Zhanyong Wan        if(not -d $Path) {
1872651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines            exitStatus("Access_Error", "can't access directory \'$Path\'");
1873651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines        }
18746beaf938c0a2587ac4b2b60a51fbb9a80f72b766Zhanyong Wan        $Path = path_format($Path, $OSgroup);
18756beaf938c0a2587ac4b2b60a51fbb9a80f72b766Zhanyong Wan        $Descriptor{$LibVersion}{"AddIncludePaths"}{$Path} = 1;
18766beaf938c0a2587ac4b2b60a51fbb9a80f72b766Zhanyong Wan    }
1877dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth    foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "skip_include_paths")))
18786bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    {
1879dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth        # skip some auto-generated include paths
1880e3e210c3aa3c1b289eee669a1d235fc16df384a0Chandler Carruth        $Skip_Include_Paths{$LibVersion}{path_format($Path)}=1;
1881db3f847cb883fdb19d79c7223fa032e7266c0ee5Nick Lewycky    }
1882d30bf2eb6d6bbebd41236bf205d3a6dfc51a3659Douglas Gregor    foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "skip_including")))
1883dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth    {
18846bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines        # skip direct including of some headers
18856bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines        $SkipHeadersList{$LibVersion}{$Path} = 2;
18864967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar        my ($CPath, $Type) = classifyPath($Path);
18874967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar        $SkipHeaders{$LibVersion}{$Type}{$CPath} = 2;
18886bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    }
1889facfc77487a890bfb7b5eee7e21cd2b395a9faafChandler Carruth    $Descriptor{$LibVersion}{"GccOptions"} = parseTag(\$Content, "gcc_options");
1890dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth    foreach my $Option (split(/\s*\n\s*/, $Descriptor{$LibVersion}{"GccOptions"})) {
18916bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines        $CompilerOptions{$LibVersion} .= " ".$Option;
18926bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    }
18934967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    $Descriptor{$LibVersion}{"SkipHeaders"} = parseTag(\$Content, "skip_headers");
18944967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    foreach my $Path (split(/\s*\n\s*/, $Descriptor{$LibVersion}{"SkipHeaders"}))
18956bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    {
1896facfc77487a890bfb7b5eee7e21cd2b395a9faafChandler Carruth        $SkipHeadersList{$LibVersion}{$Path} = 1;
1897dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth        my ($CPath, $Type) = classifyPath($Path);
18986bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines        $SkipHeaders{$LibVersion}{$Type}{$CPath} = 1;
18996bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    }
19004967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    $Descriptor{$LibVersion}{"SkipLibs"} = parseTag(\$Content, "skip_libs");
19014967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    foreach my $Path (split(/\s*\n\s*/, $Descriptor{$LibVersion}{"SkipLibs"}))
19026bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    {
1903facfc77487a890bfb7b5eee7e21cd2b395a9faafChandler Carruth        my ($CPath, $Type) = classifyPath($Path);
19040c05a1bae9e8a57f56663991d0442a69df34a003Zhanyong Wan        $SkipLibs{$LibVersion}{$Type}{$CPath} = 1;
19050c05a1bae9e8a57f56663991d0442a69df34a003Zhanyong Wan    }
1906dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth    if(my $DDefines = parseTag(\$Content, "defines"))
19076bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    {
19086bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines        if($Descriptor{$LibVersion}{"Defines"})
19094967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar        { # multiple descriptors
19104967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar            $Descriptor{$LibVersion}{"Defines"} .= "\n".$DDefines;
19116bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines        }
1912d30bf2eb6d6bbebd41236bf205d3a6dfc51a3659Douglas Gregor        else {
1913dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth            $Descriptor{$LibVersion}{"Defines"} = $DDefines;
19146bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines        }
19156bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    }
19164967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    foreach my $Order (split(/\s*\n\s*/, parseTag(\$Content, "include_order")))
19174967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    {
19186bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines        if($Order=~/\A(.+):(.+)\Z/) {
1919dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth            $Include_Order{$LibVersion}{$1} = $2;
19206bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines        }
1921dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth    }
19226c321e35008f2c99eeb1409b43859a04c48e5ce5Chandler Carruth    foreach my $Type_Name (split(/\s*\n\s*/, parseTag(\$Content, "opaque_types")),
1923c874ca1c7378d62aff008d74cf744636730f2db4Argyrios Kyrtzidis    split(/\s*\n\s*/, parseTag(\$Content, "skip_types")))
192452ec0c0357ce970ca52a27c1086626450f0967e7Daniel Jasper    { # opaque_types renamed to skip_types (1.23.4)
19257349cce2b303c8cc1e00c3aa7192513d6ca5004fDaniel Jasper        $SkipTypes{$LibVersion}{$Type_Name} = 1;
1926c874ca1c7378d62aff008d74cf744636730f2db4Argyrios Kyrtzidis    }
1927e3e210c3aa3c1b289eee669a1d235fc16df384a0Chandler Carruth    foreach my $Symbol (split(/\s*\n\s*/, parseTag(\$Content, "skip_interfaces")),
1928db3f847cb883fdb19d79c7223fa032e7266c0ee5Nick Lewycky    split(/\s*\n\s*/, parseTag(\$Content, "skip_symbols")))
1929db3f847cb883fdb19d79c7223fa032e7266c0ee5Nick Lewycky    { # skip_interfaces renamed to skip_symbols (1.22.1)
19306bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines        $SkipSymbols{$LibVersion}{$Symbol} = 1;
1931db3f847cb883fdb19d79c7223fa032e7266c0ee5Nick Lewycky    }
19326bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    foreach my $NameSpace (split(/\s*\n\s*/, parseTag(\$Content, "skip_namespaces"))) {
1933facfc77487a890bfb7b5eee7e21cd2b395a9faafChandler Carruth        $SkipNameSpaces{$LibVersion}{$NameSpace} = 1;
1934dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth    }
19356bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    foreach my $NameSpace (split(/\s*\n\s*/, parseTag(\$Content, "add_namespaces"))) {
19366bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines        $AddNameSpaces{$LibVersion}{$NameSpace} = 1;
19376bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    }
19386bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    foreach my $Constant (split(/\s*\n\s*/, parseTag(\$Content, "skip_constants"))) {
19396bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines        $SkipConstants{$LibVersion}{$Constant} = 1;
1940facfc77487a890bfb7b5eee7e21cd2b395a9faafChandler Carruth    }
1941dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth    if(my $DIncPreamble = parseTag(\$Content, "include_preamble"))
19426bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    {
1943be9aa9614f0f15f2182c9ac5c571a868263131adCraig Silverstein        if($Descriptor{$LibVersion}{"IncludePreamble"})
19446bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines        { # multiple descriptors
19456bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines            $Descriptor{$LibVersion}{"IncludePreamble"} .= "\n".$DIncPreamble;
19466bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines        }
1947dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth        else {
19486bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines            $Descriptor{$LibVersion}{"IncludePreamble"} = $DIncPreamble;
19496bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines        }
19506bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    }
19516bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines}
1952facfc77487a890bfb7b5eee7e21cd2b395a9faafChandler Carruth
1953dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruthsub parseTag($$)
1954facfc77487a890bfb7b5eee7e21cd2b395a9faafChandler Carruth{
1955dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth    my ($CodeRef, $Tag) = @_;
1956dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth    return "" if(not $CodeRef or not ${$CodeRef} or not $Tag);
1957dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth    if(${$CodeRef}=~s/\<\Q$Tag\E\>((.|\n)+?)\<\/\Q$Tag\E\>//)
19587502c1d3ce8bb97bcc4f7bebef507040bd93b26fJohn McCall    {
19597502c1d3ce8bb97bcc4f7bebef507040bd93b26fJohn McCall        my $Content = $1;
19607502c1d3ce8bb97bcc4f7bebef507040bd93b26fJohn McCall        $Content=~s/(\A\s+|\s+\Z)//g;
19617502c1d3ce8bb97bcc4f7bebef507040bd93b26fJohn McCall        return $Content;
19627502c1d3ce8bb97bcc4f7bebef507040bd93b26fJohn McCall    }
1963dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth    else {
1964dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth        return "";
19656bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    }
19666bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines}
196787d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar
196887d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainarsub addTag(@)
19694967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar{
19704967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    my $Tag = shift(@_);
19714967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    my $Val = shift(@_);
19724967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    my @Ext = @_;
19736bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    my $Content = openTag($Tag, @Ext);
19744967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    chomp($Content);
19754967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    $Content .= xmlSpecChars($Val);
19764967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    $Content .= "</$Tag>\n";
19774967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    $TAG_ID-=1;
19786bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines
19794967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    return $Content;
19804967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar}
19814967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar
19826bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hinessub openTag(@)
1983facfc77487a890bfb7b5eee7e21cd2b395a9faafChandler Carruth{
1984df5faf5e7ae6823d0af0b801c4ac26d47f2cee97Chad Rosier    my $Tag = shift(@_);
198587d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar    my @Ext = @_;
19866bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    my $Content = "";
198787d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar    foreach (1 .. $TAG_ID) {
19886bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines        $Content .= $INDENT;
19896bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    }
199087d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar    $TAG_ID+=1;
19916bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    if(@Ext)
19926bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    {
199387d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar        $Content .= "<".$Tag;
19946bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines        my $P = 0;
19956bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines        while($P<=$#Ext-1)
19966bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines        {
1997facfc77487a890bfb7b5eee7e21cd2b395a9faafChandler Carruth            $Content .= " ".$Ext[$P];
19986bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines            $Content .= "=\"".xmlSpecChars($Ext[$P+1])."\"";
19996bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines            $P+=2;
20006bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines        }
20016bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines        $Content .= ">\n";
20026bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    }
20038cd64b4c5553fa6284d248336cb7c82dc960a394Chad Rosier    else {
2004dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth        $Content .= "<".$Tag.">\n";
20056bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    }
20066bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    return $Content;
20076bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines}
2008dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth
2009be9aa9614f0f15f2182c9ac5c571a868263131adCraig Silversteinsub closeTag($)
20106bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines{
20116bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    my $Tag = $_[0];
20126bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    my $Content = "";
20136bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    $TAG_ID-=1;
20146bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    foreach (1 .. $TAG_ID) {
20156bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines        $Content .= $INDENT;
20166bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    }
20176bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    $Content .= "</".$Tag.">\n";
20184967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    return $Content;
20196bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines}
2020dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth
2021dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruthsub checkTags()
2022dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth{
20236bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    if($TAG_ID!=0) {
20246bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines        printMsg("WARNING", "the number of opened tags is not equal to number of closed tags");
20256bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    }
20266bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines}
20276bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines
20286bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hinessub getInfo($)
20296bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines{
20306bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    my $DumpPath = $_[0];
20316bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    return if(not $DumpPath or not -f $DumpPath);
20326bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines
20336bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    readTUDump($DumpPath);
20346bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines
20356bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    # processing info
20366bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    setTemplateParams_All();
20376bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    getTypeInfo_All();
20386bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    simplifyNames();
20396bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    getSymbolInfo_All();
20406bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    getVarInfo_All();
20416bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines
20426bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    # clean memory
20436bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    %LibInfo = ();
204452ec0c0357ce970ca52a27c1086626450f0967e7Daniel Jasper    %TemplateInstance = ();
20457349cce2b303c8cc1e00c3aa7192513d6ca5004fDaniel Jasper    %MangledNames = ();
204687d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar    %TemplateDecl = ();
204787d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar    %StdCxxTypedef = ();
204887d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar    %MissedTypedef = ();
204952ec0c0357ce970ca52a27c1086626450f0967e7Daniel Jasper    %Typedef_Tr = ();
20504967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    %Typedef_Eq = ();
205152ec0c0357ce970ca52a27c1086626450f0967e7Daniel Jasper
205252ec0c0357ce970ca52a27c1086626450f0967e7Daniel Jasper    # clean cache
2053ba243b59a1074e0962f6abfa3bb9aa984eac1245David Blaikie    delete($Cache{"getTypeAttr"});
20546bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    delete($Cache{"getTypeDeclId"});
20556bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines
2056ba0513de93d2fab6db5ab30b6927209fcc883078Douglas Gregor    # remove unused types
20576bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    if($BinaryOnly and not $ExtendedCheck)
20586bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    { # --binary
20596bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines        removeUnused($Version, "All");
2060dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth    }
2061dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth    else {
20626bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines        removeUnused($Version, "Derived");
20636bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    }
20646bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines
20656bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    if($Debug) {
20666bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines        # debugMangling($Version);
20676bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    }
20686bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines}
2069dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth
2070dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruthsub readTUDump($)
20716bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines{
20726bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    my $DumpPath = $_[0];
20736bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines
20746bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    open(TU_DUMP, $DumpPath);
20756bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    local $/ = undef;
2076dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth    my $Content = <TU_DUMP>;
2077dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth    close(TU_DUMP);
20786bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines
20796bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    unlink($DumpPath);
20806bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines
20814967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    $Content=~s/\n[ ]+/ /g;
20824967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    my @Lines = split("\n", $Content);
20836bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines
20846bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    # clean memory
2085dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth    undef $Content;
2086dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth
20876bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    $MAX_ID = $#Lines+1;
20886bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines
20896bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    foreach (0 .. $#Lines)
20906bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    {
20916bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines        if($Lines[$_]=~/\A\@(\d+)[ ]+([a-z_]+)[ ]+(.+)\Z/i)
2092facfc77487a890bfb7b5eee7e21cd2b395a9faafChandler Carruth        { # get a number and attributes of a node
20936bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines            next if(not $NodeType{$2});
20946bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines            $LibInfo{$Version}{"info_type"}{$1}=$2;
20956bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines            $LibInfo{$Version}{"info"}{$1}=$3;
20966bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines        }
20976bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines
2098facfc77487a890bfb7b5eee7e21cd2b395a9faafChandler Carruth        # clean memory
2099dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth        delete($Lines[$_]);
21006bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    }
21016bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines
2102dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth    # clean memory
2103dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth    undef @Lines;
21046bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines}
21056bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines
2106dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruthsub simplifyNames()
2107dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth{
21086bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    foreach my $Base (keys(%{$Typedef_Tr{$Version}}))
21096bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    {
2110dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth        my @Translations = keys(%{$Typedef_Tr{$Version}{$Base}});
2111dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth        if($#Translations==0 and length($Translations[0])<=length($Base)) {
21126bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines            $Typedef_Eq{$Version}{$Base} = $Translations[0];
21136bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines        }
2114dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth    }
2115dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth    foreach my $TypeId (keys(%{$TypeInfo{$Version}}))
21166bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    {
21176bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines        my $TypeName = $TypeInfo{$Version}{$TypeId}{"Name"};
2118dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth        if(not $TypeName) {
2119dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth            next;
21206bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines        }
21216bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines        next if(index($TypeName,"<")==-1);# template instances only
2122dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth        if($TypeName=~/>(::\w+)+\Z/)
21236bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines        { # skip unused types
212487d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar            next;
212587d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar        };
212687d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar        foreach my $Base (sort {length($b)<=>length($a)}
21274967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar        sort {$b cmp $a} keys(%{$Typedef_Eq{$Version}}))
21284967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar        {
21294967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar            next if(not $Base);
21304967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar            next if(index($TypeName,$Base)==-1);
21314967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar            next if(length($TypeName) - length($Base) <= 3);
21320e2c34f92f00628d48968dfea096d36381f494cbStephen Hines            my $Typedef = $Typedef_Eq{$Version}{$Base};
213387d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar            $TypeName=~s/(\<|\,)\Q$Base\E(\W|\Z)/$1$Typedef$2/g;
213487d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar            $TypeName=~s/(\<|\,)\Q$Base\E(\w|\Z)/$1$Typedef $2/g;
21350e2c34f92f00628d48968dfea096d36381f494cbStephen Hines            if(defined $TypeInfo{$Version}{$TypeId}{"TParam"})
2136ea245e0ba48caf7e7acf870880c030d7ddc76667Craig Silverstein            {
2137ea245e0ba48caf7e7acf870880c030d7ddc76667Craig Silverstein                foreach my $TPos (keys(%{$TypeInfo{$Version}{$TypeId}{"TParam"}}))
2138ea245e0ba48caf7e7acf870880c030d7ddc76667Craig Silverstein                {
2139ea245e0ba48caf7e7acf870880c030d7ddc76667Craig Silverstein                    my $TPName = $TypeInfo{$Version}{$TypeId}{"TParam"}{$TPos}{"name"};
214087d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar                    $TPName=~s/\A\Q$Base\E(\W|\Z)/$Typedef$1/g;
214187d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar                    $TypeInfo{$Version}{$TypeId}{"TParam"}{$TPos}{"name"} = formatName($TPName);
214287d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar                }
214387d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar            }
214487d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar        }
214587d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar        $TypeName = formatName($TypeName);
214687d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar        $TypeInfo{$Version}{$TypeId}{"Name"} = $TypeName;
214787d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar        $TName_Tid{$Version}{$TypeName} = $TypeId;
214887d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar    }
214987d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar}
215087d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar
21514967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainarsub setTemplateParams_All()
215287d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar{
215387d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar    foreach (keys(%{$LibInfo{$Version}{"info"}}))
2154f111d935722ed488144600cea5ed03a6b5069e8fPeter Collingbourne    {
2155f111d935722ed488144600cea5ed03a6b5069e8fPeter Collingbourne        if($LibInfo{$Version}{"info_type"}{$_} eq "template_decl") {
2156f111d935722ed488144600cea5ed03a6b5069e8fPeter Collingbourne            setTemplateParams($_);
215787d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar        }
215886b32fd702d794bb655c59a1238bf7422869f506Ted Kremenek    }
2159f111d935722ed488144600cea5ed03a6b5069e8fPeter Collingbourne}
2160f111d935722ed488144600cea5ed03a6b5069e8fPeter Collingbourne
2161f111d935722ed488144600cea5ed03a6b5069e8fPeter Collingbournesub setTemplateParams($)
216287d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar{
2163f111d935722ed488144600cea5ed03a6b5069e8fPeter Collingbourne    if(my $Info = $LibInfo{$Version}{"info"}{$_[0]})
21644967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    {
216587d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar        if($Info=~/(inst|spcs)[ ]*:[ ]*@(\d+) /)
2166f111d935722ed488144600cea5ed03a6b5069e8fPeter Collingbourne        {
216787d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar            my $TmplInst_Id = $2;
21684b9c2d235fb9449e249d74f48ecfec601650de93John McCall            setTemplateInstParams($TmplInst_Id);
216987d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar            while($TmplInst_Id = getNextElem($TmplInst_Id)) {
217087d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar                setTemplateInstParams($TmplInst_Id);
21716bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines            }
21726bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines        }
21736bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    }
21744b9c2d235fb9449e249d74f48ecfec601650de93John McCall    if(my $TypeId = getTreeAttr_Type($_[0]))
21754b9c2d235fb9449e249d74f48ecfec601650de93John McCall    {
21764b9c2d235fb9449e249d74f48ecfec601650de93John McCall        if(my $IType = $LibInfo{$Version}{"info_type"}{$TypeId})
217787d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar        {
21784b9c2d235fb9449e249d74f48ecfec601650de93John McCall            if($IType eq "record_type") {
21794967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar                $TemplateDecl{$Version}{$TypeId}=1;
218087d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar            }
21814b9c2d235fb9449e249d74f48ecfec601650de93John McCall        }
2182ed8abf18329df67b0abcbb3a10458bd8c1d2a595Douglas Gregor    }
21836bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines}
21846bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines
21856bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hinessub setTemplateInstParams($)
21866bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines{
2187ea245e0ba48caf7e7acf870880c030d7ddc76667Craig Silverstein    if(my $Info = $LibInfo{$Version}{"info"}{$_[0]})
2188ea245e0ba48caf7e7acf870880c030d7ddc76667Craig Silverstein    {
21891bb2a93ab7b1499dda6f6b58865bd0dce1864228Douglas Gregor        my ($Params_InfoId, $ElemId) = ();
21901bb2a93ab7b1499dda6f6b58865bd0dce1864228Douglas Gregor        if($Info=~/purp[ ]*:[ ]*@(\d+) /) {
21916bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines            $Params_InfoId = $1;
2192ea245e0ba48caf7e7acf870880c030d7ddc76667Craig Silverstein        }
2193cf4679e60a5c5fa13e4bfe69f8186658c828af49Craig Silverstein        if($Info=~/valu[ ]*:[ ]*@(\d+) /) {
21946bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines            $ElemId = $1;
21956bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines        }
21966bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines        if($Params_InfoId and $ElemId)
21976bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines        {
21986bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines            my $Params_Info = $LibInfo{$Version}{"info"}{$Params_InfoId};
21996bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines            while($Params_Info=~s/ (\d+)[ ]*:[ ]*\@(\d+) / /)
2200cf4679e60a5c5fa13e4bfe69f8186658c828af49Craig Silverstein            {
2201f4e3cfbe8abd124be6341ef5d714819b4fbd9082Peter Collingbourne                my ($PPos, $PTypeId) = ($1, $2);
22026bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines                if(my $PType = $LibInfo{$Version}{"info_type"}{$PTypeId})
22036bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines                {
22046bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines                    if($PType eq "template_type_parm")
22056bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines                    {
22066bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines                        $TemplateDecl{$Version}{$ElemId}=1;
2207cf4679e60a5c5fa13e4bfe69f8186658c828af49Craig Silverstein                        return;
220827de0f2cb3e8c26c37f31e61929b0e442c809ca5Craig Silverstein                    }
22096bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines                }
22106bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines                if($LibInfo{$Version}{"info_type"}{$ElemId} eq "function_decl")
22116bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines                { # functions
22126bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines                    $TemplateInstance{$Version}{"Func"}{$ElemId}{$PPos} = $PTypeId;
22136bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines                }
221401b7c3028da5bbcb9f8e52ba67e4613070de0e60Francois Pichet                else
221576da55d3a49e1805f51b1ced7c5da5bcd7f759d8John McCall                { # types
221676da55d3a49e1805f51b1ced7c5da5bcd7f759d8John McCall                    $TemplateInstance{$Version}{"Type"}{$ElemId}{$PPos} = $PTypeId;
221776da55d3a49e1805f51b1ced7c5da5bcd7f759d8John McCall                }
221876da55d3a49e1805f51b1ced7c5da5bcd7f759d8John McCall            }
221987d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar        }
222087d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar    }
222101b7c3028da5bbcb9f8e52ba67e4613070de0e60Francois Pichet}
22226bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines
22236bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hinessub getTypeDeclId($)
22246bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines{
22256bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    if($_[0])
22266bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    {
222727de0f2cb3e8c26c37f31e61929b0e442c809ca5Craig Silverstein        if(defined $Cache{"getTypeDeclId"}{$Version}{$_[0]}) {
22284ca8ac2e61c37ddadf37024af86f3e1019af8532Douglas Gregor            return $Cache{"getTypeDeclId"}{$Version}{$_[0]};
22294ca8ac2e61c37ddadf37024af86f3e1019af8532Douglas Gregor        }
22304ca8ac2e61c37ddadf37024af86f3e1019af8532Douglas Gregor        if(my $Info = $LibInfo{$Version}{"info"}{$_[0]})
22314ca8ac2e61c37ddadf37024af86f3e1019af8532Douglas Gregor        {
22324ca8ac2e61c37ddadf37024af86f3e1019af8532Douglas Gregor            if($Info=~/name[ ]*:[ ]*@(\d+)/) {
223321ff2e516b0e0bc8c1dbf965cb3d44bac3c64330John Wiegley                return ($Cache{"getTypeDeclId"}{$Version}{$_[0]} = $1);
22346bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines            }
22356bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines        }
223621ff2e516b0e0bc8c1dbf965cb3d44bac3c64330John Wiegley    }
22376bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    return ($Cache{"getTypeDeclId"}{$Version}{$_[0]} = 0);
223887d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar}
2239552622067dc45013d240f73952fece703f5e63bdJohn Wiegley
2240ac45ad57f0641b0d556ca27d19a59930925d6addCraig Silversteinsub getTypeInfo_All()
22416bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines{
22426bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    if(not check_gcc($GCC_PATH, "4.5"))
22436bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    { # support for GCC < 4.5
2244ac45ad57f0641b0d556ca27d19a59930925d6addCraig Silverstein      # missed typedefs: QStyle::State is typedef to QFlags<QStyle::StateFlag>
2245ac45ad57f0641b0d556ca27d19a59930925d6addCraig Silverstein      # but QStyleOption.state is of type QFlags<QStyle::StateFlag> in the TU dump
22466bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines      # FIXME: check GCC versions
22476bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines        addMissedTypes_Pre();
22486bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    }
2249ac45ad57f0641b0d556ca27d19a59930925d6addCraig Silverstein
22506bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    foreach (sort {int($a)<=>int($b)} keys(%{$LibInfo{$Version}{"info"}}))
225187d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar    { # forward order only
2252011d8b93b7cfa8492b8a9c909a850d6577e08dcaDouglas Gregor        my $IType = $LibInfo{$Version}{"info_type"}{$_};
22536bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines        if($IType=~/_type\Z/ and $IType ne "function_type"
2254011d8b93b7cfa8492b8a9c909a850d6577e08dcaDouglas Gregor        and $IType ne "method_type") {
22550d8e9646bc000bab521ce52ed294209a92298cefRichard Smith            getTypeInfo("$_");
2256011d8b93b7cfa8492b8a9c909a850d6577e08dcaDouglas Gregor        }
2257011d8b93b7cfa8492b8a9c909a850d6577e08dcaDouglas Gregor    }
2258176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines
2259176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines    # add "..." type
2260176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines    $TypeInfo{$Version}{-1} = {
2261176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines        "Name" => "...",
2262176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines        "Type" => "Intrinsic",
2263176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines        "Tid" => -1
2264176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines    };
2265176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines    $TName_Tid{$Version}{"..."} = -1;
2266176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines
2267176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines    if(not check_gcc($GCC_PATH, "4.5"))
2268176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines    { # support for GCC < 4.5
22696bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines        addMissedTypes_Post();
2270176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines    }
2271176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines}
2272011d8b93b7cfa8492b8a9c909a850d6577e08dcaDouglas Gregor
2273176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hinessub addMissedTypes_Pre()
2274176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines{
2275176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines    my %MissedTypes = ();
2276176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines    foreach my $MissedTDid (sort {int($a)<=>int($b)} keys(%{$LibInfo{$Version}{"info"}}))
2277176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines    { # detecting missed typedefs
2278176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines        if($LibInfo{$Version}{"info_type"}{$MissedTDid} eq "type_decl")
2279176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines        {
228087d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar            my $TypeId = getTreeAttr_Type($MissedTDid);
2281011d8b93b7cfa8492b8a9c909a850d6577e08dcaDouglas Gregor            next if(not $TypeId);
2282011d8b93b7cfa8492b8a9c909a850d6577e08dcaDouglas Gregor            my $TypeType = getTypeType($TypeId);
22834967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar            if($TypeType eq "Unknown")
22844967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar            { # template_type_parm
228587d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar                next;
228601d08018b7cf5ce1601707cfd7a84d22015fc04eDouglas Gregor            }
2287ac45ad57f0641b0d556ca27d19a59930925d6addCraig Silverstein            my $TypeDeclId = getTypeDeclId($TypeId);
22886bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines            next if($TypeDeclId eq $MissedTDid);#or not $TypeDeclId
22896bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines            my $TypedefName = getNameByInfo($MissedTDid);
22906bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines            next if(not $TypedefName);
2291ac45ad57f0641b0d556ca27d19a59930925d6addCraig Silverstein            next if($TypedefName eq "__float80");
2292ac45ad57f0641b0d556ca27d19a59930925d6addCraig Silverstein            next if(isAnon($TypedefName));
2293ac45ad57f0641b0d556ca27d19a59930925d6addCraig Silverstein            if(not $TypeDeclId
22946bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines            or getNameByInfo($TypeDeclId) ne $TypedefName) {
22956bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines                $MissedTypes{$Version}{$TypeId}{$MissedTDid} = 1;
22966bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines            }
2297ac45ad57f0641b0d556ca27d19a59930925d6addCraig Silverstein        }
2298dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth    }
2299dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth    my %AddTypes = ();
23006bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    foreach my $Tid (keys(%{$MissedTypes{$Version}}))
23016bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    { # add missed typedefs
230287d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar        my @Missed = keys(%{$MissedTypes{$Version}{$Tid}});
2303336f51e463340dc7b159bc38517ac4a68081302dArgyrios Kyrtzidis        if(not @Missed or $#Missed>=1) {
2304336f51e463340dc7b159bc38517ac4a68081302dArgyrios Kyrtzidis            next;
2305336f51e463340dc7b159bc38517ac4a68081302dArgyrios Kyrtzidis        }
2306336f51e463340dc7b159bc38517ac4a68081302dArgyrios Kyrtzidis        my $MissedTDid = $Missed[0];
23076bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines        my ($TypedefName, $TypedefNS) = getTrivialName($MissedTDid, $Tid);
230882b4550fb25ad578b6c8143b87a003fae7106caeRichard Smith        if(not $TypedefName) {
230982b4550fb25ad578b6c8143b87a003fae7106caeRichard Smith            next;
231082b4550fb25ad578b6c8143b87a003fae7106caeRichard Smith        }
23116bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines        $MAX_ID++;
23126bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines        my %MissedInfo = ( # typedef info
23136bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines            "Name" => $TypedefName,
23146bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines            "NameSpace" => $TypedefNS,
23156bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines            "BaseType" => {
23166bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines                            "Tid" => $Tid
23174967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar                          },
23186bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines            "Type" => "Typedef",
23196bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines            "Tid" => "$MAX_ID" );
2320ba243b59a1074e0962f6abfa3bb9aa984eac1245David Blaikie        my ($H, $L) = getLocation($MissedTDid);
2321f3db29fff6a583ecda823cf909ab7737d8d30129Douglas Gregor        $MissedInfo{"Header"} = $H;
232210ffc00e2177f042808f507c8dd50b744ed6f738Douglas Gregor        $MissedInfo{"Line"} = $L;
232310ffc00e2177f042808f507c8dd50b744ed6f738Douglas Gregor        if($TypedefName=~/\*|\&|\s/)
232410ffc00e2177f042808f507c8dd50b744ed6f738Douglas Gregor        { # other types
232510ffc00e2177f042808f507c8dd50b744ed6f738Douglas Gregor            next;
232610ffc00e2177f042808f507c8dd50b744ed6f738Douglas Gregor        }
23276bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines        if($TypedefName=~/>(::\w+)+\Z/)
23286bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines        { # QFlags<Qt::DropAction>::enum_type
23296bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines            next;
23306bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines        }
2331b6d6993e6e6d3daf4d9876794254d20a134e37c2Pirama Arumuga Nainar        if(getTypeType($Tid)=~/\A(Intrinsic|Union|Struct|Enum|Class)\Z/)
23326bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines        { # double-check for the name of typedef
23336bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines            my ($TName, $TNS) = getTrivialName(getTypeDeclId($Tid), $Tid); # base type info
23346bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines            next if(not $TName);
2335b6d6993e6e6d3daf4d9876794254d20a134e37c2Pirama Arumuga Nainar            if(length($TypedefName)>=length($TName))
23366bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines            { # too long typedef
233787014f33f123461a012995b2f7eb5e6ecf6dc461Argyrios Kyrtzidis                next;
233887014f33f123461a012995b2f7eb5e6ecf6dc461Argyrios Kyrtzidis            }
233987014f33f123461a012995b2f7eb5e6ecf6dc461Argyrios Kyrtzidis            if($TName=~/\A\Q$TypedefName\E</) {
234087014f33f123461a012995b2f7eb5e6ecf6dc461Argyrios Kyrtzidis                next;
23416bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines            }
23426bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines            if($TypedefName=~/\A\Q$TName\E/)
23431270673bf5208a140b397419c8c34e7bdcce2339Argyrios Kyrtzidis            { # QDateTimeEdit::Section and QDateTimeEdit::Sections::enum_type
23441270673bf5208a140b397419c8c34e7bdcce2339Argyrios Kyrtzidis                next;
23451270673bf5208a140b397419c8c34e7bdcce2339Argyrios Kyrtzidis            }
23461270673bf5208a140b397419c8c34e7bdcce2339Argyrios Kyrtzidis            if(get_depth($TypedefName)==0 and get_depth($TName)!=0)
23476bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines            { # std::_Vector_base and std::vector::_Base
23486bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines                next;
23496bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines            }
23506bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines        }
23516bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines
2352f85e193739c953358c865005855253af4f68a497John McCall        $AddTypes{$MissedInfo{"Tid"}} = \%MissedInfo;
2353f85e193739c953358c865005855253af4f68a497John McCall
2354f85e193739c953358c865005855253af4f68a497John McCall        # register typedef
23556bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines        $MissedTypedef{$Version}{$Tid}{"Tid"} = $MissedInfo{"Tid"};
23566bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines        $MissedTypedef{$Version}{$Tid}{"TDid"} = $MissedTDid;
23576bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines        $TName_Tid{$Version}{$TypedefName} = $MissedInfo{"Tid"};
23586bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    }
23596bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines
23606bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    # add missed & remove other
2361d3731198193eee92796ddeb493973b7a598b003eDouglas Gregor    $TypeInfo{$Version} = \%AddTypes;
23624c9be89bb615ec07eb3ed507c8fa9d0baa8a5ad7Douglas Gregor    delete($Cache{"getTypeAttr"}{$Version});
236366cf92a9670d57da61842adb69f9b038ce29dca5Matt Beaumont-Gay}
2364ba243b59a1074e0962f6abfa3bb9aa984eac1245David Blaikie
236566cf92a9670d57da61842adb69f9b038ce29dca5Matt Beaumont-Gaysub addMissedTypes_Post()
236666cf92a9670d57da61842adb69f9b038ce29dca5Matt Beaumont-Gay{
2367d3731198193eee92796ddeb493973b7a598b003eDouglas Gregor    foreach my $BaseId (keys(%{$MissedTypedef{$Version}}))
2368ba243b59a1074e0962f6abfa3bb9aa984eac1245David Blaikie    {
2369d3731198193eee92796ddeb493973b7a598b003eDouglas Gregor        if(my $Tid = $MissedTypedef{$Version}{$BaseId}{"Tid"})
23704c9be89bb615ec07eb3ed507c8fa9d0baa8a5ad7Douglas Gregor        {
237166cf92a9670d57da61842adb69f9b038ce29dca5Matt Beaumont-Gay            $TypeInfo{$Version}{$Tid}{"Size"} = $TypeInfo{$Version}{$BaseId}{"Size"};
2372ba243b59a1074e0962f6abfa3bb9aa984eac1245David Blaikie            if(my $TName = $TypeInfo{$Version}{$Tid}{"Name"}) {
237366cf92a9670d57da61842adb69f9b038ce29dca5Matt Beaumont-Gay                $Typedef_BaseName{$Version}{$TName} = $TypeInfo{$Version}{$BaseId}{"Name"};
237466cf92a9670d57da61842adb69f9b038ce29dca5Matt Beaumont-Gay            }
2375d3731198193eee92796ddeb493973b7a598b003eDouglas Gregor        }
2376d3731198193eee92796ddeb493973b7a598b003eDouglas Gregor    }
237728bbe4b8acc338476fe0825769b41fb32b423c72John Wiegley}
237828bbe4b8acc338476fe0825769b41fb32b423c72John Wiegley
23796bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hinessub getTypeInfo($)
2380c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines{
23816bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    my $TypeId = $_[0];
238228bbe4b8acc338476fe0825769b41fb32b423c72John Wiegley    %{$TypeInfo{$Version}{$TypeId}} = getTypeAttr($TypeId);
23836bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    my $TName = $TypeInfo{$Version}{$TypeId}{"Name"};
23846bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    if(not $TName) {
2385176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines        delete($TypeInfo{$Version}{$TypeId});
23866bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    }
2387dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth}
2388dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth
2389dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruthsub getArraySize($$)
23906bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines{
23916bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    my ($TypeId, $BaseName) = @_;
23926bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    if(my $Size = getSize($TypeId))
23936bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    {
23946bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines        my $Elems = $Size/$BYTE_SIZE;
23956bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines        while($BaseName=~s/\s*\[(\d+)\]//) {
23966bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines            $Elems/=$1;
23976bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines        }
23986bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines        if(my $BasicId = $TName_Tid{$Version}{$BaseName})
23996bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines        {
24006bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines            if(my $BasicSize = $TypeInfo{$Version}{$BasicId}{"Size"}) {
24016bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines                $Elems/=$BasicSize;
2402176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines            }
24036bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines        }
2404dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth        return $Elems;
240587d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar    }
240687d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar    return 0;
240787d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar}
240887d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar
240987d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainarsub getTParams($$)
241087d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar{
24114967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    my ($TypeId, $Kind) = @_;
241287d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar    my @TmplParams = ();
241387d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar    my @Positions = sort {int($a)<=>int($b)} keys(%{$TemplateInstance{$Version}{$Kind}{$TypeId}});
241487d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar    foreach my $Pos (@Positions)
241587d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar    {
241687d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar        my $Param_TypeId = $TemplateInstance{$Version}{$Kind}{$TypeId}{$Pos};
24174967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar        my $NodeType = $LibInfo{$Version}{"info_type"}{$Param_TypeId};
241887d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar        if(not $NodeType)
241987d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar        { # typename_type
242087d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar            return ();
242187d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar        }
242287d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar        if($NodeType eq "tree_vec")
24234967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar        {
242487d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar            if($Pos!=$#Positions)
242587d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar            { # select last vector of parameters ( ns<P1>::type<P2> )
242687d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar                next;
242787d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar            }
242887d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar        }
24294967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar        my @Params = get_TemplateParam($Pos, $Param_TypeId);
243087d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar        foreach my $P (@Params)
243187d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar        {
243287d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar            if($P eq "") {
2433dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth                return ();
24346bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines            }
24356bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines            elsif($P ne "\@skip\@") {
24366bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines                @TmplParams = (@TmplParams, $P);
24376bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines            }
24386bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines        }
24396bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    }
24406bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    return @TmplParams;
24416bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines}
24426bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines
24436bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hinessub getTypeAttr($)
244461eee0ca33b29e102f11bab77c8b74cc00e2392bTanya Lattner{
24456bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    my $TypeId = $_[0];
2446dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth    my %TypeAttr = ();
24474fa7eab771ab8212e1058bd1a91061ff120c8fbbAlexey Bataev    if(defined $TypeInfo{$Version}{$TypeId}
24486bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    and $TypeInfo{$Version}{$TypeId}{"Name"})
2449651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    { # already created
24506bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines        return %{$TypeInfo{$Version}{$TypeId}};
2451c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines    }
2452c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines    elsif($Cache{"getTypeAttr"}{$Version}{$TypeId})
2453c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines    { # incomplete type
2454651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines        return ();
2455651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    }
2456651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    $Cache{"getTypeAttr"}{$Version}{$TypeId} = 1;
2457176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines
2458176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines    my $TypeDeclId = getTypeDeclId($TypeId);
2459176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines    $TypeAttr{"Tid"} = $TypeId;
2460176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines
2461176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines    if(not $MissedBase{$Version}{$TypeId} and isTypedef($TypeId))
2462176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines    {
2463c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines        if(my $Info = $LibInfo{$Version}{"info"}{$TypeId})
2464c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines        {
2465651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines            if($Info=~/qual[ ]*:/)
2466c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines            {
2467c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines                if(my $NID = ++$MAX_ID)
2468c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines                {
2469c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines                    $MissedBase{$Version}{$TypeId}="$NID";
2470c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines                    $MissedBase_R{$Version}{$NID}=$TypeId;
2471c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines                    $LibInfo{$Version}{"info"}{$NID} = $LibInfo{$Version}{"info"}{$TypeId};
2472176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines                    $LibInfo{$Version}{"info_type"}{$NID} = $LibInfo{$Version}{"info_type"}{$TypeId};
2473176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines                }
2474176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines            }
2475c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines        }
2476c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines        $TypeAttr{"Type"} = "Typedef";
2477c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines    }
2478c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines    else {
2479c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines        $TypeAttr{"Type"} = getTypeType($TypeId);
2480c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines    }
2481c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines
2482c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines    if($TypeAttr{"Type"} eq "Unknown") {
2483c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines        return ();
2484176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines    }
2485176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines    elsif($TypeAttr{"Type"}=~/(Func|Method|Field)Ptr/)
2486176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines    {
2487176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines        %TypeAttr = getMemPtrAttr(pointTo($TypeId), $TypeId, $TypeAttr{"Type"});
2488176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines        if(my $TName = $TypeAttr{"Name"})
2489176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines        {
2490176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines            %{$TypeInfo{$Version}{$TypeId}} = %TypeAttr;
2491176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines            $TName_Tid{$Version}{$TName} = $TypeId;
2492c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines            return %TypeAttr;
2493c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines        }
2494c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines        else {
2495176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines            return ();
2496176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines        }
2497176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines    }
2498c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines    elsif($TypeAttr{"Type"} eq "Array")
2499c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines    {
25004fa7eab771ab8212e1058bd1a91061ff120c8fbbAlexey Bataev        my ($BTid, $BTSpec) = selectBaseType($TypeId);
2501176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines        if(not $BTid) {
2502176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines            return ();
2503176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines        }
2504176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines        $TypeAttr{"BaseType"}{"Tid"} = $BTid;
2505176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines        if(my %BTAttr = getTypeAttr($BTid))
2506176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines        {
2507176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines            if(not $BTAttr{"Name"}) {
2508176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines                return ();
2509176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines            }
2510176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines            if(my $NElems = getArraySize($TypeId, $BTAttr{"Name"}))
2511176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines            {
2512176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines                if(my $Size = getSize($TypeId)) {
251387d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar                    $TypeAttr{"Size"} = $Size/$BYTE_SIZE;
251487d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar                }
251587d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar                if($BTAttr{"Name"}=~/\A([^\[\]]+)(\[(\d+|)\].*)\Z/) {
251687d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar                    $TypeAttr{"Name"} = $1."[$NElems]".$2;
251787d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar                }
251887d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar                else {
251987d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar                    $TypeAttr{"Name"} = $BTAttr{"Name"}."[$NElems]";
252087d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar                }
252187d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar            }
2522176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines            else
2523176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines            {
2524176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines                $TypeAttr{"Size"} = $WORD_SIZE{$Version}; # pointer
2525176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines                if($BTAttr{"Name"}=~/\A([^\[\]]+)(\[(\d+|)\].*)\Z/) {
2526176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines                    $TypeAttr{"Name"} = $1."[]".$2;
2527176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines                }
2528176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines                else {
2529176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines                    $TypeAttr{"Name"} = $BTAttr{"Name"}."[]";
2530176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines                }
2531176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines            }
2532176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines            $TypeAttr{"Name"} = formatName($TypeAttr{"Name"});
2533176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines            if($BTAttr{"Header"})  {
253487d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar                $TypeAttr{"Header"} = $BTAttr{"Header"};
253587d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar            }
253687d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar            %{$TypeInfo{$Version}{$TypeId}} = %TypeAttr;
25374967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar            $TName_Tid{$Version}{$TypeAttr{"Name"}} = $TypeId;
25384967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar            return %TypeAttr;
25394967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar        }
25404967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar        return ();
25414967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    }
25424967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    elsif($TypeAttr{"Type"}=~/\A(Intrinsic|Union|Struct|Enum|Class)\Z/)
25434967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    {
25444967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar        %TypeAttr = getTrivialTypeAttr($TypeId);
25454967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar        if($TypeAttr{"Name"})
25464967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar        {
25474967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar            %{$TypeInfo{$Version}{$TypeId}} = %TypeAttr;
25484967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar            if($TypeAttr{"Name"} ne "int" or getTypeDeclId($TypeAttr{"Tid"}))
2549176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines            { # NOTE: register only one int: with built-in decl
2550176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines                if(not $TName_Tid{$Version}{$TypeAttr{"Name"}}) {
2551176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines                    $TName_Tid{$Version}{$TypeAttr{"Name"}} = $TypeId;
25524967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar                }
25534967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar            }
25544967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar            return %TypeAttr;
255587d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar        }
255687d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar        else {
255787d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar            return ();
255887d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar        }
255987d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar    }
256087d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar    else
256187d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar    { # derived types
256287d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar        my ($BTid, $BTSpec) = selectBaseType($TypeId);
256387d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar        if(not $BTid) {
25644967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar            return ();
25654967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar        }
25664967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar        $TypeAttr{"BaseType"}{"Tid"} = $BTid;
25674967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar        if(defined $MissedTypedef{$Version}{$BTid})
25684967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar        {
25694967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar            if(my $MissedTDid = $MissedTypedef{$Version}{$BTid}{"TDid"})
25704967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar            {
25714967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar                if($MissedTDid ne $TypeDeclId) {
25724967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar                    $TypeAttr{"BaseType"}{"Tid"} = $MissedTypedef{$Version}{$BTid}{"Tid"};
25734967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar                }
25744967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar            }
25754967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar        }
25764fa7eab771ab8212e1058bd1a91061ff120c8fbbAlexey Bataev        my %BTAttr = getTypeAttr($TypeAttr{"BaseType"}{"Tid"});
25776bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines        if(not $BTAttr{"Name"})
25784fa7eab771ab8212e1058bd1a91061ff120c8fbbAlexey Bataev        { # templates
25796bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines            return ();
25806bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines        }
25814fa7eab771ab8212e1058bd1a91061ff120c8fbbAlexey Bataev        if($BTAttr{"Type"} eq "Typedef")
25826bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines        { # relinking typedefs
25836bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines            my %BaseBase = get_Type($BTAttr{"BaseType"}{"Tid"}, $Version);
2584c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines            if($BTAttr{"Name"} eq $BaseBase{"Name"}) {
2585c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines                $TypeAttr{"BaseType"}{"Tid"} = $BaseBase{"Tid"};
25864fa7eab771ab8212e1058bd1a91061ff120c8fbbAlexey Bataev            }
2587c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines        }
25884967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar        if($BTSpec)
2589c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines        {
25906bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines            if($TypeAttr{"Type"} eq "Pointer"
25914fa7eab771ab8212e1058bd1a91061ff120c8fbbAlexey Bataev            and $BTAttr{"Name"}=~/\([\*]+\)/)
25924fa7eab771ab8212e1058bd1a91061ff120c8fbbAlexey Bataev            {
25934fa7eab771ab8212e1058bd1a91061ff120c8fbbAlexey Bataev                $TypeAttr{"Name"} = $BTAttr{"Name"};
25944fa7eab771ab8212e1058bd1a91061ff120c8fbbAlexey Bataev                $TypeAttr{"Name"}=~s/\(([*]+)\)/($1*)/g;
25956bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines            }
25964967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar            else {
25974967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar                $TypeAttr{"Name"} = $BTAttr{"Name"}." ".$BTSpec;
25984967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar            }
25994967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar        }
26004967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar        else {
26014967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar            $TypeAttr{"Name"} = $BTAttr{"Name"};
26024967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar        }
26034967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar        if($TypeAttr{"Type"} eq "Typedef")
26044967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar        {
26054967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar            $TypeAttr{"Name"} = getNameByInfo($TypeDeclId);
26064967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar            if(isAnon($TypeAttr{"Name"}))
26074967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar            { # anon typedef to anon type: ._N
26084967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar                return ();
26094967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar            }
26104967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar            if(my $NS = getNameSpace($TypeDeclId))
2611651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines            {
2612c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines                my $TypeName = $TypeAttr{"Name"};
2613651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines                if($NS=~/\A(struct |union |class |)((.+)::|)\Q$TypeName\E\Z/)
2614651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines                { # "some_type" is the typedef to "struct some_type" in C++
2615651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines                    if($3) {
26166bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines                        $TypeAttr{"Name"} = $3."::".$TypeName;
2617176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines                    }
2618176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines                }
2619176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines                else
2620176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines                {
2621176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines                    $TypeAttr{"NameSpace"} = $NS;
2622176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines                    $TypeAttr{"Name"} = $TypeAttr{"NameSpace"}."::".$TypeAttr{"Name"};
26236bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines
26246bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines                    if($TypeAttr{"NameSpace"}=~/\Astd(::|\Z)/
2625c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines                    and $TypeAttr{"Name"}!~/>(::\w+)+\Z/)
2626651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines                    {
2627651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines                        if($BTAttr{"NameSpace"}
2628651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines                        and $BTAttr{"NameSpace"}=~/\Astd(::|\Z)/ and $BTAttr{"Name"}=~/</)
2629c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines                        { # types like "std::fpos<__mbstate_t>" are
2630651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines                          # not covered by typedefs in the TU dump
2631c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines                          # so trying to add such typedefs manually
2632c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines                            $StdCxxTypedef{$Version}{$BTAttr{"Name"}}{$TypeAttr{"Name"}} = 1;
2633c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines                            if(length($TypeAttr{"Name"})<=length($BTAttr{"Name"}))
2634c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines                            {
2635c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines                                if(($BTAttr{"Name"}!~/\A(std|boost)::/ or $TypeAttr{"Name"}!~/\A[a-z]+\Z/))
263687d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar                                { # skip "other" in "std" and "type" in "boost"
263787d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar                                    $Typedef_Eq{$Version}{$BTAttr{"Name"}} = $TypeAttr{"Name"};
263887d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar                                }
263987d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar                            }
264087d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar                        }
264187d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar                    }
2642c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines                }
2643c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines            }
2644c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines            if($TypeAttr{"Name"} ne $BTAttr{"Name"}
2645651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines            and $TypeAttr{"Name"}!~/>(::\w+)+\Z/ and $BTAttr{"Name"}!~/>(::\w+)+\Z/)
2646651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines            {
2647651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines                if(not defined $Typedef_BaseName{$Version}{$TypeAttr{"Name"}})
26486bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines                { # typedef int*const TYPEDEF; // first
2649c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines                  # int foo(TYPEDEF p); // const is optimized out
26506bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines                    $Typedef_BaseName{$Version}{$TypeAttr{"Name"}} = $BTAttr{"Name"};
26516bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines                    if($BTAttr{"Name"}=~/</)
26526bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines                    {
2653c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines                        if(($BTAttr{"Name"}!~/\A(std|boost)::/ or $TypeAttr{"Name"}!~/\A[a-z]+\Z/)) {
2654c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines                            $Typedef_Tr{$Version}{$BTAttr{"Name"}}{$TypeAttr{"Name"}} = 1;
26554fa7eab771ab8212e1058bd1a91061ff120c8fbbAlexey Bataev                        }
26564fa7eab771ab8212e1058bd1a91061ff120c8fbbAlexey Bataev                    }
26574fa7eab771ab8212e1058bd1a91061ff120c8fbbAlexey Bataev                }
26586bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines            }
26596bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines            ($TypeAttr{"Header"}, $TypeAttr{"Line"}) = getLocation($TypeDeclId);
2660c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines        }
26614967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar        if(not $TypeAttr{"Size"})
2662c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines        {
2663c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines            if($TypeAttr{"Type"} eq "Pointer") {
2664c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines                $TypeAttr{"Size"} = $WORD_SIZE{$Version};
2665c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines            }
2666c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines            elsif($BTAttr{"Size"}) {
266787d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar                $TypeAttr{"Size"} = $BTAttr{"Size"};
266887d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar            }
2669c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines        }
2670c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines        $TypeAttr{"Name"} = formatName($TypeAttr{"Name"});
2671c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines        if(not $TypeAttr{"Header"} and $BTAttr{"Header"})  {
2672c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines            $TypeAttr{"Header"} = $BTAttr{"Header"};
2673c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines        }
26746bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines        %{$TypeInfo{$Version}{$TypeId}} = %TypeAttr;
26756bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines        if($TypeAttr{"Name"} ne $BTAttr{"Name"})
26766bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines        { # typedef to "class Class"
26776bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines          # should not be registered in TName_Tid
2678176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines            if(not $TName_Tid{$Version}{$TypeAttr{"Name"}}) {
2679176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines                $TName_Tid{$Version}{$TypeAttr{"Name"}} = $TypeId;
2680176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines            }
2681176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines        }
2682176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines        return %TypeAttr;
2683176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines    }
2684176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines}
2685176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines
2686176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hinessub getTreeVec($)
2687176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines{
2688176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines    my %Vector = ();
2689176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines    if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
2690176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines    {
2691176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines        while($Info=~s/ (\d+)[ ]*:[ ]*\@(\d+) / /)
2692176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines        { # string length is N-1 because of the null terminator
2693176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines            $Vector{$1} = $2;
2694176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines        }
2695176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines    }
2696176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines    return \%Vector;
2697176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines}
2698176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines
2699176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hinessub get_TemplateParam($$)
2700176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines{
2701176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines    my ($Pos, $Type_Id) = @_;
2702176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines    return () if(not $Type_Id);
2703176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines    my $NodeType = $LibInfo{$Version}{"info_type"}{$Type_Id};
2704176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines    return () if(not $NodeType);
2705176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines    if($NodeType eq "integer_cst")
2706176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines    { # int (1), unsigned (2u), char ('c' as 99), ...
2707176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines        my $CstTid = getTreeAttr_Type($Type_Id);
2708176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines        my %CstType = getTypeAttr($CstTid); # without recursion
2709176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines        my $Num = getNodeIntCst($Type_Id);
2710176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines        if(my $CstSuffix = $ConstantSuffix{$CstType{"Name"}}) {
2711176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines            return ($Num.$CstSuffix);
2712176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines        }
2713176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines        else {
271487d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar            return ("(".$CstType{"Name"}.")".$Num);
271587d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar        }
271687d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar    }
271787d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar    elsif($NodeType eq "string_cst") {
271887d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar        return (getNodeStrCst($Type_Id));
271987d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar    }
272087d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar    elsif($NodeType eq "tree_vec")
272187d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar    {
272287d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar        my $Vector = getTreeVec($Type_Id);
272387d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar        my @Params = ();
272487d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar        foreach my $P1 (sort {int($a)<=>int($b)} keys(%{$Vector}))
272587d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar        {
272687d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar            foreach my $P2 (get_TemplateParam($Pos, $Vector->{$P1})) {
272787d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar                push(@Params, $P2);
272887d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar            }
27296bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines        }
2730c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines        return @Params;
2731c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines    }
2732c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines    else
2733c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines    {
2734c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines        my %ParamAttr = getTypeAttr($Type_Id);
2735543c4ae954f2bce5ac58ed22080f23cbd94794d2Alexey Bataev        my $PName = $ParamAttr{"Name"};
27364fa7eab771ab8212e1058bd1a91061ff120c8fbbAlexey Bataev        if(not $PName) {
27376bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines            return ();
27380c018357b8bbb1f96bbf622a5807421e626b4228Alexey Bataev        }
2739c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines        if($PName=~/\>/)
2740176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines        {
2741176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines            if(my $Cover = cover_stdcxx_typedef($PName)) {
2742176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines                $PName = $Cover;
27434fa7eab771ab8212e1058bd1a91061ff120c8fbbAlexey Bataev            }
27444fa7eab771ab8212e1058bd1a91061ff120c8fbbAlexey Bataev        }
27454fa7eab771ab8212e1058bd1a91061ff120c8fbbAlexey Bataev        if($Pos>=1 and
27466bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines        $PName=~/\Astd::(allocator|less|((char|regex)_traits)|((i|o)streambuf_iterator))\</)
2747d195bc38fd424b0c928e3c354038a8ca6e2ccac3Alexey Bataev        { # template<typename _Tp, typename _Alloc = std::allocator<_Tp> >
27486bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines          # template<typename _Key, typename _Compare = std::less<_Key>
2749c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines          # template<typename _CharT, typename _Traits = std::char_traits<_CharT> >
27504967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar          # template<typename _Ch_type, typename _Rx_traits = regex_traits<_Ch_type> >
2751176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines          # template<typename _CharT, typename _InIter = istreambuf_iterator<_CharT> >
2752176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines          # template<typename _CharT, typename _OutIter = ostreambuf_iterator<_CharT> >
2753176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines            return ("\@skip\@");
2754176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines        }
2755176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines        return ($PName);
2756176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines    }
2757c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines}
2758c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines
2759c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hinessub cover_stdcxx_typedef($)
2760c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines{
2761c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines    my $TypeName = $_[0];
2762c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines    if(my @Covers = sort {length($a)<=>length($b)}
2763c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines    sort keys(%{$StdCxxTypedef{$Version}{$TypeName}}))
27644967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    { # take the shortest typedef
276558878f85ab89b13e9eea4af3ccf055e42c557bc8Pirama Arumuga Nainar      # FIXME: there may be more than
276658878f85ab89b13e9eea4af3ccf055e42c557bc8Pirama Arumuga Nainar      # one typedefs to the same type
276758878f85ab89b13e9eea4af3ccf055e42c557bc8Pirama Arumuga Nainar        return $Covers[0];
276858878f85ab89b13e9eea4af3ccf055e42c557bc8Pirama Arumuga Nainar    }
276958878f85ab89b13e9eea4af3ccf055e42c557bc8Pirama Arumuga Nainar    my $TypeName_Covered = $TypeName;
277058878f85ab89b13e9eea4af3ccf055e42c557bc8Pirama Arumuga Nainar    while($TypeName=~s/(>)[ ]*(const|volatile|restrict| |\*|\&)\Z/$1/g){};
277158878f85ab89b13e9eea4af3ccf055e42c557bc8Pirama Arumuga Nainar    if(my @Covers = sort {length($a)<=>length($b)} sort keys(%{$StdCxxTypedef{$Version}{$TypeName}}))
277258878f85ab89b13e9eea4af3ccf055e42c557bc8Pirama Arumuga Nainar    {
277358878f85ab89b13e9eea4af3ccf055e42c557bc8Pirama Arumuga Nainar        my $Cover = $Covers[0];
277458878f85ab89b13e9eea4af3ccf055e42c557bc8Pirama Arumuga Nainar        $TypeName_Covered=~s/\b\Q$TypeName\E(\W|\Z)/$Cover$1/g;
277558878f85ab89b13e9eea4af3ccf055e42c557bc8Pirama Arumuga Nainar        $TypeName_Covered=~s/\b\Q$TypeName\E(\w|\Z)/$Cover $1/g;
277658878f85ab89b13e9eea4af3ccf055e42c557bc8Pirama Arumuga Nainar    }
2777d195bc38fd424b0c928e3c354038a8ca6e2ccac3Alexey Bataev    return formatName($TypeName_Covered);
2778d195bc38fd424b0c928e3c354038a8ca6e2ccac3Alexey Bataev}
2779d195bc38fd424b0c928e3c354038a8ca6e2ccac3Alexey Bataev
27806bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hinessub getNodeIntCst($)
27810c018357b8bbb1f96bbf622a5807421e626b4228Alexey Bataev{
2782c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines    my $CstId = $_[0];
27830c018357b8bbb1f96bbf622a5807421e626b4228Alexey Bataev    my $CstTypeId = getTreeAttr_Type($CstId);
27840c018357b8bbb1f96bbf622a5807421e626b4228Alexey Bataev    if($EnumMembName_Id{$Version}{$CstId}) {
27850c018357b8bbb1f96bbf622a5807421e626b4228Alexey Bataev        return $EnumMembName_Id{$Version}{$CstId};
27866bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    }
27876bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    elsif((my $Value = getTreeValue($CstId)) ne "")
2788c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines    {
27893ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar        if($Value eq "0")
2790c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines        {
27914967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar            if($LibInfo{$Version}{"info_type"}{$CstTypeId} eq "boolean_type") {
279287d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar                return "false";
279387d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar            }
279487d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar            else {
27953ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar                return "0";
27963ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar            }
27973ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar        }
27983ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar        elsif($Value eq "1")
27993ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar        {
28003ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar            if($LibInfo{$Version}{"info_type"}{$CstTypeId} eq "boolean_type") {
28013ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar                return "true";
28023ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar            }
28033ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar            else {
2804c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines                return "1";
2805c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines            }
2806c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines        }
2807c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines        else {
2808c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines            return $Value;
2809c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines        }
2810c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines    }
28116bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    return "";
28126bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines}
28136bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines
28146bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hinessub getNodeStrCst($)
2815651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines{
2816c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines    if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
281758878f85ab89b13e9eea4af3ccf055e42c557bc8Pirama Arumuga Nainar    {
281858878f85ab89b13e9eea4af3ccf055e42c557bc8Pirama Arumuga Nainar        if($Info=~/strg[ ]*: (.+) lngt:[ ]*(\d+)/)
281958878f85ab89b13e9eea4af3ccf055e42c557bc8Pirama Arumuga Nainar        { # string length is N-1 because of the null terminator
282058878f85ab89b13e9eea4af3ccf055e42c557bc8Pirama Arumuga Nainar            return substr($1, 0, $2-1);
282158878f85ab89b13e9eea4af3ccf055e42c557bc8Pirama Arumuga Nainar        }
282258878f85ab89b13e9eea4af3ccf055e42c557bc8Pirama Arumuga Nainar    }
282358878f85ab89b13e9eea4af3ccf055e42c557bc8Pirama Arumuga Nainar    return "";
282458878f85ab89b13e9eea4af3ccf055e42c557bc8Pirama Arumuga Nainar}
282558878f85ab89b13e9eea4af3ccf055e42c557bc8Pirama Arumuga Nainar
2826c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hinessub getMemPtrAttr($$$)
2827c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines{ # function, method and field pointers
2828c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines    my ($PtrId, $TypeId, $Type) = @_;
2829c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines    my $MemInfo = $LibInfo{$Version}{"info"}{$PtrId};
2830c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines    if($Type eq "FieldPtr") {
2831c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines        $MemInfo = $LibInfo{$Version}{"info"}{$TypeId};
2832c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines    }
28333ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar    my $MemInfo_Type = $LibInfo{$Version}{"info_type"}{$PtrId};
28343ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar    my $MemPtrName = "";
28353ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar    my %TypeAttr = ("Size"=>$WORD_SIZE{$Version}, "Type"=>$Type, "Tid"=>$TypeId);
28363ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar    if($Type eq "MethodPtr")
28373ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar    { # size of "method pointer" may be greater than WORD size
28383ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar        if(my $Size = getSize($TypeId)) {
28393ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar            $TypeAttr{"Size"} = $Size/$BYTE_SIZE;
28403ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar        }
28413ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar    }
2842c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines    # Return
2843c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines    if($Type eq "FieldPtr")
2844c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines    {
2845c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines        my %ReturnAttr = getTypeAttr($PtrId);
2846c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines        if($ReturnAttr{"Name"}) {
2847c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines            $MemPtrName .= $ReturnAttr{"Name"};
2848c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines        }
2849c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines        $TypeAttr{"Return"} = $PtrId;
2850c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines    }
28514967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    else
285287d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar    {
285387d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar        if($MemInfo=~/retn[ ]*:[ ]*\@(\d+) /)
285487d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar        {
285558878f85ab89b13e9eea4af3ccf055e42c557bc8Pirama Arumuga Nainar            my $ReturnTypeId = $1;
285658878f85ab89b13e9eea4af3ccf055e42c557bc8Pirama Arumuga Nainar            my %ReturnAttr = getTypeAttr($ReturnTypeId);
285758878f85ab89b13e9eea4af3ccf055e42c557bc8Pirama Arumuga Nainar            if(not $ReturnAttr{"Name"})
285858878f85ab89b13e9eea4af3ccf055e42c557bc8Pirama Arumuga Nainar            { # templates
285958878f85ab89b13e9eea4af3ccf055e42c557bc8Pirama Arumuga Nainar                return ();
286058878f85ab89b13e9eea4af3ccf055e42c557bc8Pirama Arumuga Nainar            }
286158878f85ab89b13e9eea4af3ccf055e42c557bc8Pirama Arumuga Nainar            $MemPtrName .= $ReturnAttr{"Name"};
286258878f85ab89b13e9eea4af3ccf055e42c557bc8Pirama Arumuga Nainar            $TypeAttr{"Return"} = $ReturnTypeId;
286358878f85ab89b13e9eea4af3ccf055e42c557bc8Pirama Arumuga Nainar        }
2864651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    }
2865651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    # Class
2866651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    if($MemInfo=~/(clas|cls)[ ]*:[ ]*@(\d+) /)
2867176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines    {
2868176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines        $TypeAttr{"Class"} = $2;
2869176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines        my %Class = getTypeAttr($TypeAttr{"Class"});
2870176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines        if($Class{"Name"}) {
2871176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines            $MemPtrName .= " (".$Class{"Name"}."\:\:*)";
2872176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines        }
287387d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar        else {
287487d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar            $MemPtrName .= " (*)";
287587d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar        }
287687d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar    }
287787d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar    else {
287887d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar        $MemPtrName .= " (*)";
287987d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar    }
288087d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar    # Parameters
288187d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar    if($Type eq "FuncPtr"
288287d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar    or $Type eq "MethodPtr")
288387d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar    {
288487d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar        my @ParamTypeName = ();
288587d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar        if($MemInfo=~/prms[ ]*:[ ]*@(\d+) /)
288687d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar        {
288787d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar            my $PTypeInfoId = $1;
288887d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar            my $Pos = 0;
288987d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar            while($PTypeInfoId)
289087d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar            {
289187d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar                my $PTypeInfo = $LibInfo{$Version}{"info"}{$PTypeInfoId};
289287d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar                if($PTypeInfo=~/valu[ ]*:[ ]*@(\d+) /)
289387d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar                {
289487d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar                    my $PTypeId = $1;
289587d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar                    my %ParamAttr = getTypeAttr($PTypeId);
289687d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar                    if(not $ParamAttr{"Name"})
289787d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar                    { # templates (template_type_parm), etc.
289887d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar                        return ();
289987d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar                    }
290087d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar                    if($ParamAttr{"Name"} eq "void") {
290187d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar                        last;
290287d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar                    }
290387d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar                    if($Pos!=0 or $Type ne "MethodPtr")
290487d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar                    {
290587d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar                        $TypeAttr{"Param"}{$Pos}{"type"} = $PTypeId;
290687d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar                        push(@ParamTypeName, $ParamAttr{"Name"});
290787d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar                    }
290887d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar                    if($PTypeInfoId = getNextElem($PTypeInfoId)) {
290987d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar                        $Pos+=1;
291087d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar                    }
291187d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar                    else {
291287d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar                        last;
291387d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar                    }
291487d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar                }
291587d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar                else {
291687d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar                    last;
291787d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar                }
291887d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar            }
291987d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar        }
292087d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar        $MemPtrName .= " (".join(", ", @ParamTypeName).")";
292187d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar    }
292287d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar    $TypeAttr{"Name"} = formatName($MemPtrName);
292387d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar    return %TypeAttr;
292487d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar}
292587d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar
292687d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainarsub getTreeTypeName($)
292787d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar{
292887d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar    my $TypeId = $_[0];
292987d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar    if(my $Info = $LibInfo{$Version}{"info"}{$TypeId})
293087d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar    {
293187d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar        if($LibInfo{$Version}{"info_type"}{$_[0]} eq "integer_type")
29324967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar        {
29334967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar            if(my $Name = getNameByInfo($TypeId))
29344967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar            { # bit_size_type
29354967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar                return $Name;
29364967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar            }
29374967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar            elsif($Info=~/unsigned/) {
29384967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar                return "unsigned int";
29394967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar            }
29404967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar            else {
29414967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar                return "int";
29424967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar            }
29434967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar        }
29444967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar        elsif($Info=~/name[ ]*:[ ]*@(\d+) /)
29454967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar        {
29464967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar            return getNameByInfo($1);
29474967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar        }
29484967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    }
29494967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    return "";
29504967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar}
29514967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar
29524967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainarsub isFuncPtr($)
29534967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar{
29544967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    my $Ptd = pointTo($_[0]);
29554967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    return 0 if(not $Ptd);
29564967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    if(my $Info = $LibInfo{$Version}{"info"}{$_[0]})
29574967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    {
29584967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar        if($Info=~/unql[ ]*:/ and $Info!~/qual[ ]*:/) {
29594967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar            return 0;
29604967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar        }
29614967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    }
29624967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    if(my $InfoT1 = $LibInfo{$Version}{"info_type"}{$_[0]}
29634967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    and my $InfoT2 = $LibInfo{$Version}{"info_type"}{$Ptd})
29644967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    {
29654967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar        if($InfoT1 eq "pointer_type"
29664967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar        and $InfoT2 eq "function_type") {
29674967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar            return 1;
29684967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar        }
29694967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    }
29704967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    return 0;
29714967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar}
2972dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth
2973dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruthsub isMethodPtr($)
2974dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth{
2975dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth    my $Ptd = pointTo($_[0]);
2976dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth    return 0 if(not $Ptd);
2977dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth    if(my $Info = $LibInfo{$Version}{"info"}{$_[0]})
2978dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth    {
2979dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth        if($LibInfo{$Version}{"info_type"}{$_[0]} eq "record_type"
2980dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth        and $LibInfo{$Version}{"info_type"}{$Ptd} eq "method_type"
2981dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth        and $Info=~/ ptrmem /) {
2982dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth            return 1;
29832ac54ec0a8ad305fdd76847c2fd6631cfb7baa82Zhanyong Wan        }
2984dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth    }
2985f4e3cfbe8abd124be6341ef5d714819b4fbd9082Peter Collingbourne    return 0;
2986dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth}
2987dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth
2988dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruthsub isFieldPtr($)
2989dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth{
299087d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar    if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
299187d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar    {
2992dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth        if($LibInfo{$Version}{"info_type"}{$_[0]} eq "offset_type"
2993dfc35e33177a433b56454f1d2b5e53734f65b288Chandler Carruth        and $Info=~/ ptrmem /) {
2994facfc77487a890bfb7b5eee7e21cd2b395a9faafChandler Carruth            return 1;
2995d30bf2eb6d6bbebd41236bf205d3a6dfc51a3659Douglas Gregor        }
2996d30bf2eb6d6bbebd41236bf205d3a6dfc51a3659Douglas Gregor    }
2997d30bf2eb6d6bbebd41236bf205d3a6dfc51a3659Douglas Gregor    return 0;
2998}
2999
3000sub pointTo($)
3001{
3002    if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
3003    {
3004        if($Info=~/ptd[ ]*:[ ]*@(\d+)/) {
3005            return $1;
3006        }
3007    }
3008    return "";
3009}
3010
3011sub getTypeTypeByTypeId($)
3012{
3013    my $TypeId = $_[0];
3014    if(my $TType = $LibInfo{$Version}{"info_type"}{$TypeId})
3015    {
3016        my $NType = $NodeType{$TType};
3017        if($NType eq "Intrinsic") {
3018            return $NType;
3019        }
3020        elsif(isFuncPtr($TypeId)) {
3021            return "FuncPtr";
3022        }
3023        elsif(isMethodPtr($TypeId)) {
3024            return "MethodPtr";
3025        }
3026        elsif(isFieldPtr($TypeId)) {
3027            return "FieldPtr";
3028        }
3029        elsif($NType ne "Other") {
3030            return $NType;
3031        }
3032    }
3033    return "Unknown";
3034}
3035
3036sub getQual($)
3037{
3038    my $TypeId = $_[0];
3039    my %UnQual = (
3040        "r"=>"restrict",
3041        "v"=>"volatile",
3042        "c"=>"const",
3043        "cv"=>"const volatile"
3044    );
3045    if(my $Info = $LibInfo{$Version}{"info"}{$TypeId})
3046    {
3047        my ($Qual, $To) = ();
3048        if($Info=~/qual[ ]*:[ ]*(r|c|v|cv) /) {
3049            $Qual = $UnQual{$1};
3050        }
3051        if($Info=~/unql[ ]*:[ ]*\@(\d+)/) {
3052            $To = $1;
3053        }
3054        if($Qual and $To) {
3055            return ($Qual, $To);
3056        }
3057    }
3058    return ();
3059}
3060
3061sub getQualType($)
3062{
3063    if($_[0] eq "const volatile") {
3064        return "ConstVolatile";
3065    }
3066    return ucfirst($_[0]);
3067}
3068
3069sub getTypeType($)
3070{
3071    my $TypeId = $_[0];
3072    my $TypeDeclId = getTypeDeclId($TypeId);
3073    if(defined $MissedTypedef{$Version}{$TypeId})
3074    { # support for old GCC versions
3075        if($MissedTypedef{$Version}{$TypeId}{"TDid"} eq $TypeDeclId) {
3076            return "Typedef";
3077        }
3078    }
3079    my $Info = $LibInfo{$Version}{"info"}{$TypeId};
3080    my ($Qual, $To) = getQual($TypeId);
3081    if(($Qual or $To) and $Info=~/name[ ]*:[ ]*\@(\d+) /
3082    and (getTypeId($1) ne $TypeId))
3083    { # qualified types (special)
3084        return getQualType($Qual);
3085    }
3086    elsif(not $MissedBase_R{$Version}{$TypeId}
3087    and isTypedef($TypeId)) {
3088        return "Typedef";
3089    }
3090    elsif($Qual)
3091    { # qualified types
3092        return getQualType($Qual);
3093    }
3094    my $TypeType = getTypeTypeByTypeId($TypeId);
3095    if($TypeType eq "Struct")
3096    {
3097        if($TypeDeclId
3098        and $LibInfo{$Version}{"info_type"}{$TypeDeclId} eq "template_decl") {
3099            return "Template";
3100        }
3101    }
3102    return $TypeType;
3103}
3104
3105sub isTypedef($)
3106{
3107    if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
3108    {
3109        my $TDid = getTypeDeclId($_[0]);
3110        if(getNameByInfo($TDid)
3111        and $Info=~/unql[ ]*:[ ]*\@(\d+) /
3112        and getTypeId($TDid) eq $_[0]) {
3113            return $1;
3114        }
3115    }
3116    return 0;
3117}
3118
3119sub selectBaseType($)
3120{
3121    my $TypeId = $_[0];
3122    if(defined $MissedTypedef{$Version}{$TypeId})
3123    { # add missed typedefs
3124        if($MissedTypedef{$Version}{$TypeId}{"TDid"} eq getTypeDeclId($TypeId)) {
3125            return ($TypeId, "");
3126        }
3127    }
3128    my $Info = $LibInfo{$Version}{"info"}{$TypeId};
3129    my $InfoType = $LibInfo{$Version}{"info_type"}{$TypeId};
3130
3131    my $MB_R = $MissedBase_R{$Version}{$TypeId};
3132    my $MB = $MissedBase{$Version}{$TypeId};
3133
3134    my ($Qual, $To) = getQual($TypeId);
3135    if(($Qual or $To) and $Info=~/name[ ]*:[ ]*\@(\d+) /
3136    and (getTypeId($1) ne $TypeId)
3137    and (not $MB_R or getTypeId($1) ne $MB_R))
3138    { # qualified types (special)
3139        return (getTypeId($1), $Qual);
3140    }
3141    elsif($MB)
3142    { # add base
3143        return ($MB, "");
3144    }
3145    elsif(not $MB_R and my $Bid = isTypedef($TypeId))
3146    { # typedefs
3147        return ($Bid, "");
3148    }
3149    elsif($Qual or $To)
3150    { # qualified types
3151        return ($To, $Qual);
3152    }
3153    elsif($InfoType eq "reference_type")
3154    {
3155        if($Info=~/refd[ ]*:[ ]*@(\d+) /) {
3156            return ($1, "&");
3157        }
3158        else {
3159            return (0, "");
3160        }
3161    }
3162    elsif($InfoType eq "array_type")
3163    {
3164        if($Info=~/elts[ ]*:[ ]*@(\d+) /) {
3165            return ($1, "");
3166        }
3167        else {
3168            return (0, "");
3169        }
3170    }
3171    elsif($InfoType eq "pointer_type")
3172    {
3173        if($Info=~/ptd[ ]*:[ ]*@(\d+) /) {
3174            return ($1, "*");
3175        }
3176        else {
3177            return (0, "");
3178        }
3179    }
3180    else {
3181        return (0, "");
3182    }
3183}
3184
3185sub getSymbolInfo_All()
3186{
3187    foreach (sort {int($b)<=>int($a)} keys(%{$LibInfo{$Version}{"info"}}))
3188    { # reverse order
3189        if($LibInfo{$Version}{"info_type"}{$_} eq "function_decl") {
3190            getSymbolInfo($_);
3191        }
3192    }
3193}
3194
3195sub getVarInfo_All()
3196{
3197    foreach (sort {int($b)<=>int($a)} keys(%{$LibInfo{$Version}{"info"}}))
3198    { # reverse order
3199        if($LibInfo{$Version}{"info_type"}{$_} eq "var_decl") {
3200            getVarInfo($_);
3201        }
3202    }
3203}
3204
3205sub isBuiltIn($) {
3206    return ($_[0] and $_[0]=~/\<built\-in\>|\<internal\>|\A\./);
3207}
3208
3209sub getVarInfo($)
3210{
3211    my $InfoId = $_[0];
3212    if(my $NSid = getNameSpaceId($InfoId))
3213    {
3214        my $NSInfoType = $LibInfo{$Version}{"info_type"}{$NSid};
3215        if($NSInfoType and $NSInfoType eq "function_decl") {
3216            return;
3217        }
3218    }
3219    ($SymbolInfo{$Version}{$InfoId}{"Header"}, $SymbolInfo{$Version}{$InfoId}{"Line"}) = getLocation($InfoId);
3220    if(not $SymbolInfo{$Version}{$InfoId}{"Header"}
3221    or isBuiltIn($SymbolInfo{$Version}{$InfoId}{"Header"})) {
3222        delete($SymbolInfo{$Version}{$InfoId});
3223        return;
3224    }
3225    my $ShortName = getTreeStr(getTreeAttr_Name($InfoId));
3226    if(not $ShortName) {
3227        delete($SymbolInfo{$Version}{$InfoId});
3228        return;
3229    }
3230    if($ShortName=~/\Atmp_add_class_\d+\Z/) {
3231        delete($SymbolInfo{$Version}{$InfoId});
3232        return;
3233    }
3234    $SymbolInfo{$Version}{$InfoId}{"ShortName"} = $ShortName;
3235    $SymbolInfo{$Version}{$InfoId}{"MnglName"} = getTreeStr(getTreeAttr_Mngl($InfoId));
3236    if($SymbolInfo{$Version}{$InfoId}{"MnglName"}
3237    and $SymbolInfo{$Version}{$InfoId}{"MnglName"}!~/\A_Z/)
3238    { # validate mangled name
3239        delete($SymbolInfo{$Version}{$InfoId});
3240        return;
3241    }
3242    if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"}
3243    and $ShortName=~/\A_Z/)
3244    { # _ZTS, etc.
3245        $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $ShortName;
3246    }
3247    if(isPrivateData($SymbolInfo{$Version}{$InfoId}{"MnglName"}))
3248    { # non-public global data
3249        delete($SymbolInfo{$Version}{$InfoId});
3250        return;
3251    }
3252    $SymbolInfo{$Version}{$InfoId}{"Data"} = 1;
3253    if(my $Rid = getTypeId($InfoId))
3254    {
3255        if(not $TypeInfo{$Version}{$Rid}{"Name"})
3256        { # typename_type
3257            delete($SymbolInfo{$Version}{$InfoId});
3258            return;
3259        }
3260        $SymbolInfo{$Version}{$InfoId}{"Return"} = $Rid;
3261        my $Val = getDataVal($InfoId, $Rid);
3262        if(defined $Val) {
3263            $SymbolInfo{$Version}{$InfoId}{"Value"} = $Val;
3264        }
3265    }
3266    set_Class_And_Namespace($InfoId);
3267    if(my $ClassId = $SymbolInfo{$Version}{$InfoId}{"Class"})
3268    {
3269        if(not $TypeInfo{$Version}{$ClassId}{"Name"})
3270        { # templates
3271            delete($SymbolInfo{$Version}{$InfoId});
3272            return;
3273        }
3274    }
3275    if($LibInfo{$Version}{"info"}{$InfoId}=~/ lang:[ ]*C /i)
3276    { # extern "C"
3277        $SymbolInfo{$Version}{$InfoId}{"Lang"} = "C";
3278        $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $ShortName;
3279    }
3280    if($UserLang and $UserLang eq "C")
3281    { # --lang=C option
3282        $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $ShortName;
3283    }
3284    if(not $CheckHeadersOnly)
3285    {
3286        if(not $SymbolInfo{$Version}{$InfoId}{"Class"})
3287        {
3288            if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"}
3289            or not link_symbol($SymbolInfo{$Version}{$InfoId}{"MnglName"}, $Version, "-Deps"))
3290            {
3291                if(link_symbol($ShortName, $Version, "-Deps"))
3292                { # "const" global data is mangled as _ZL... in the TU dump
3293                  # but not mangled when compiling a C shared library
3294                    $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $ShortName;
3295                }
3296            }
3297        }
3298    }
3299    if($COMMON_LANGUAGE{$Version} eq "C++")
3300    {
3301        if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"})
3302        { # for some symbols (_ZTI) the short name is the mangled name
3303            if($ShortName=~/\A_Z/) {
3304                $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $ShortName;
3305            }
3306        }
3307        if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"})
3308        { # try to mangle symbol (link with libraries)
3309            $SymbolInfo{$Version}{$InfoId}{"MnglName"} = linkSymbol($InfoId);
3310        }
3311        if($OStarget eq "windows")
3312        {
3313            if(my $Mangled = $mangled_name{$Version}{modelUnmangled($InfoId, "MSVC")})
3314            { # link MS C++ symbols from library with GCC symbols from headers
3315                $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $Mangled;
3316            }
3317        }
3318    }
3319    if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"}) {
3320        $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $ShortName;
3321    }
3322    if(my $Symbol = $SymbolInfo{$Version}{$InfoId}{"MnglName"})
3323    {
3324        if(not selectSymbol($Symbol, $SymbolInfo{$Version}{$InfoId}, "Dump", $Version))
3325        { # non-target symbols
3326            delete($SymbolInfo{$Version}{$InfoId});
3327            return;
3328        }
3329    }
3330    if(my $Rid = $SymbolInfo{$Version}{$InfoId}{"Return"})
3331    {
3332        if(defined $MissedTypedef{$Version}{$Rid})
3333        {
3334            if(my $AddedTid = $MissedTypedef{$Version}{$Rid}{"Tid"}) {
3335                $SymbolInfo{$Version}{$InfoId}{"Return"} = $AddedTid;
3336            }
3337        }
3338    }
3339    setFuncAccess($InfoId);
3340    if($SymbolInfo{$Version}{$InfoId}{"MnglName"}=~/\A_ZTV/) {
3341        delete($SymbolInfo{$Version}{$InfoId}{"Return"});
3342    }
3343    if($ShortName=~/\A(_Z|\?)/) {
3344        delete($SymbolInfo{$Version}{$InfoId}{"ShortName"});
3345    }
3346}
3347
3348sub isConstType($$)
3349{
3350    my ($TypeId, $LibVersion) = @_;
3351    my %Base = get_Type($TypeId, $LibVersion);
3352    while(defined $Base{"Type"} and $Base{"Type"} eq "Typedef") {
3353        %Base = get_OneStep_BaseType($Base{"Tid"}, $LibVersion);
3354    }
3355    return ($Base{"Type"} eq "Const");
3356}
3357
3358sub getTrivialName($$)
3359{
3360    my ($TypeInfoId, $TypeId) = @_;
3361    my %TypeAttr = ();
3362    $TypeAttr{"Name"} = getNameByInfo($TypeInfoId);
3363    if(not $TypeAttr{"Name"}) {
3364        $TypeAttr{"Name"} = getTreeTypeName($TypeId);
3365    }
3366    ($TypeAttr{"Header"}, $TypeAttr{"Line"}) = getLocation($TypeInfoId);
3367    $TypeAttr{"Type"} = getTypeType($TypeId);
3368    $TypeAttr{"Name"}=~s/<(.+)\Z//g; # GCC 3.4.4 add template params to the name
3369    if(isAnon($TypeAttr{"Name"}))
3370    {
3371        my $NameSpaceId = $TypeId;
3372        while(my $NSId = getNameSpaceId(getTypeDeclId($NameSpaceId)))
3373        { # searching for a first not anon scope
3374            if($NSId eq $NameSpaceId) {
3375                last;
3376            }
3377            else
3378            {
3379                $TypeAttr{"NameSpace"} = getNameSpace(getTypeDeclId($TypeId));
3380                if(not $TypeAttr{"NameSpace"}
3381                or isNotAnon($TypeAttr{"NameSpace"})) {
3382                    last;
3383                }
3384            }
3385            $NameSpaceId=$NSId;
3386        }
3387    }
3388    else
3389    {
3390        if(my $NameSpaceId = getNameSpaceId($TypeInfoId))
3391        {
3392            if($NameSpaceId ne $TypeId) {
3393                $TypeAttr{"NameSpace"} = getNameSpace($TypeInfoId);
3394            }
3395        }
3396    }
3397    if($TypeAttr{"NameSpace"} and isNotAnon($TypeAttr{"Name"})) {
3398        $TypeAttr{"Name"} = $TypeAttr{"NameSpace"}."::".$TypeAttr{"Name"};
3399    }
3400    $TypeAttr{"Name"} = formatName($TypeAttr{"Name"});
3401    if(isAnon($TypeAttr{"Name"}))
3402    { # anon-struct-header.h-line
3403        $TypeAttr{"Name"} = "anon-".lc($TypeAttr{"Type"})."-";
3404        $TypeAttr{"Name"} .= $TypeAttr{"Header"}."-".$TypeAttr{"Line"};
3405        if($TypeAttr{"NameSpace"}) {
3406            $TypeAttr{"Name"} = $TypeAttr{"NameSpace"}."::".$TypeAttr{"Name"};
3407        }
3408    }
3409    if(defined $TemplateInstance{$Version}{"Type"}{$TypeId}
3410    and getTypeDeclId($TypeId) eq $TypeInfoId)
3411    {
3412        my @TParams = getTParams($TypeId, "Type");
3413        if(not @TParams)
3414        { # template declarations with abstract params
3415            return ("", "");
3416        }
3417        $TypeAttr{"Name"} = formatName($TypeAttr{"Name"}."< ".join(", ", @TParams)." >");
3418    }
3419    return ($TypeAttr{"Name"}, $TypeAttr{"NameSpace"});
3420}
3421
3422sub getTrivialTypeAttr($)
3423{
3424    my $TypeId = $_[0];
3425    my $TypeInfoId = getTypeDeclId($_[0]);
3426
3427    if($TemplateDecl{$Version}{$TypeId})
3428    { # template_decl
3429        return ();
3430    }
3431    if(my $ScopeId = getTreeAttr_Scpe($TypeInfoId))
3432    {
3433        if($TemplateDecl{$Version}{$ScopeId})
3434        { # template_decl
3435            return ();
3436        }
3437    }
3438
3439    my %TypeAttr = ();
3440    if(getTypeTypeByTypeId($TypeId)!~/\A(Intrinsic|Union|Struct|Enum|Class)\Z/) {
3441        return ();
3442    }
3443    setTypeAccess($TypeId, \%TypeAttr);
3444    ($TypeAttr{"Header"}, $TypeAttr{"Line"}) = getLocation($TypeInfoId);
3445    if(isBuiltIn($TypeAttr{"Header"}))
3446    {
3447        delete($TypeAttr{"Header"});
3448        delete($TypeAttr{"Line"});
3449    }
3450    $TypeAttr{"Type"} = getTypeType($TypeId);
3451    ($TypeAttr{"Name"}, $TypeAttr{"NameSpace"}) = getTrivialName($TypeInfoId, $TypeId);
3452    if(not $TypeAttr{"Name"}) {
3453        return ();
3454    }
3455    if(not $TypeAttr{"NameSpace"}) {
3456        delete($TypeAttr{"NameSpace"});
3457    }
3458    if(defined $TemplateInstance{$Version}{"Type"}{$TypeId})
3459    {
3460        if(my @TParams = getTParams($TypeId, "Type"))
3461        {
3462            foreach my $Pos (0 .. $#TParams) {
3463                $TypeAttr{"TParam"}{$Pos}{"name"}=$TParams[$Pos];
3464            }
3465        }
3466    }
3467    if(my $Size = getSize($TypeId)) {
3468        $TypeAttr{"Size"} = $Size/$BYTE_SIZE;
3469    }
3470    if($TypeAttr{"Type"} eq "Struct"
3471    and detect_lang($TypeId))
3472    {
3473        $TypeAttr{"Type"} = "Class";
3474        $TypeAttr{"Copied"} = 1; # default, will be changed in getSymbolInfo()
3475    }
3476    if($TypeAttr{"Type"} eq "Struct"
3477    or $TypeAttr{"Type"} eq "Class")
3478    {
3479        my $Skip = setBaseClasses($TypeId, \%TypeAttr);
3480        if($Skip) {
3481            return ();
3482        }
3483    }
3484    setSpec($TypeId, \%TypeAttr);
3485    setTypeMemb($TypeId, \%TypeAttr);
3486    $TypeAttr{"Tid"} = $TypeId;
3487    if(my $VTable = $ClassVTable_Content{$Version}{$TypeAttr{"Name"}})
3488    {
3489        my @Entries = split(/\n/, $VTable);
3490        foreach (1 .. $#Entries)
3491        {
3492            my $Entry = $Entries[$_];
3493            if($Entry=~/\A(\d+)\s+(.+)\Z/) {
3494                $TypeAttr{"VTable"}{$1} = $2;
3495            }
3496        }
3497    }
3498    return %TypeAttr;
3499}
3500
3501sub detect_lang($)
3502{
3503    my $TypeId = $_[0];
3504    my $Info = $LibInfo{$Version}{"info"}{$TypeId};
3505    if(check_gcc($GCC_PATH, "4"))
3506    { # GCC 4 fncs-node points to only non-artificial methods
3507        return ($Info=~/(fncs)[ ]*:[ ]*@(\d+) /);
3508    }
3509    else
3510    { # GCC 3
3511        my $Fncs = getTreeAttr_Fncs($TypeId);
3512        while($Fncs)
3513        {
3514            if($LibInfo{$Version}{"info"}{$Fncs}!~/artificial/) {
3515                return 1;
3516            }
3517            $Fncs = getTreeAttr_Chan($Fncs);
3518        }
3519    }
3520    return 0;
3521}
3522
3523sub setSpec($$)
3524{
3525    my ($TypeId, $TypeAttr) = @_;
3526    my $Info = $LibInfo{$Version}{"info"}{$TypeId};
3527    if($Info=~/\s+spec\s+/) {
3528        $TypeAttr->{"Spec"} = 1;
3529    }
3530}
3531
3532sub setBaseClasses($$)
3533{
3534    my ($TypeId, $TypeAttr) = @_;
3535    my $Info = $LibInfo{$Version}{"info"}{$TypeId};
3536    if($Info=~/binf[ ]*:[ ]*@(\d+) /)
3537    {
3538        $Info = $LibInfo{$Version}{"info"}{$1};
3539        my $Pos = 0;
3540        while($Info=~s/(pub|public|prot|protected|priv|private|)[ ]+binf[ ]*:[ ]*@(\d+) //)
3541        {
3542            my ($Access, $BInfoId) = ($1, $2);
3543            my $ClassId = getBinfClassId($BInfoId);
3544            my $CType = $LibInfo{$Version}{"info_type"}{$ClassId};
3545            if(not $CType or $CType eq "template_type_parm"
3546            or $CType eq "typename_type")
3547            { # skip
3548                return 1;
3549            }
3550            my $BaseInfo = $LibInfo{$Version}{"info"}{$BInfoId};
3551            if($Access=~/prot/)
3552            {
3553                $TypeAttr->{"Base"}{$ClassId}{"access"} = "protected";
3554            }
3555            elsif($Access=~/priv/)
3556            {
3557                $TypeAttr->{"Base"}{$ClassId}{"access"} = "private";
3558            }
3559            $TypeAttr->{"Base"}{$ClassId}{"pos"} = $Pos++;
3560            if($BaseInfo=~/virt/)
3561            { # virtual base
3562                $TypeAttr->{"Base"}{$ClassId}{"virtual"} = 1;
3563            }
3564            $Class_SubClasses{$Version}{$ClassId}{$TypeId}=1;
3565        }
3566    }
3567    return 0;
3568}
3569
3570sub getBinfClassId($)
3571{
3572    my $Info = $LibInfo{$Version}{"info"}{$_[0]};
3573    $Info=~/type[ ]*:[ ]*@(\d+) /;
3574    return $1;
3575}
3576
3577sub unmangledFormat($$)
3578{
3579    my ($Name, $LibVersion) = @_;
3580    $Name = uncover_typedefs($Name, $LibVersion);
3581    while($Name=~s/([^\w>*])(const|volatile)(,|>|\Z)/$1$3/g){};
3582    $Name=~s/\(\w+\)(\d)/$1/;
3583    return $Name;
3584}
3585
3586sub modelUnmangled($$)
3587{
3588    my ($InfoId, $Compiler) = @_;
3589    if($Cache{"modelUnmangled"}{$Version}{$Compiler}{$InfoId}) {
3590        return $Cache{"modelUnmangled"}{$Version}{$Compiler}{$InfoId};
3591    }
3592    my $PureSignature = $SymbolInfo{$Version}{$InfoId}{"ShortName"};
3593    if($SymbolInfo{$Version}{$InfoId}{"Destructor"}) {
3594        $PureSignature = "~".$PureSignature;
3595    }
3596    if(not $SymbolInfo{$Version}{$InfoId}{"Data"})
3597    {
3598        my (@Params, @ParamTypes) = ();
3599        if(defined $SymbolInfo{$Version}{$InfoId}{"Param"}
3600        and not $SymbolInfo{$Version}{$InfoId}{"Destructor"}) {
3601            @Params = keys(%{$SymbolInfo{$Version}{$InfoId}{"Param"}});
3602        }
3603        foreach my $ParamPos (sort {int($a) <=> int($b)} @Params)
3604        { # checking parameters
3605            my $PId = $SymbolInfo{$Version}{$InfoId}{"Param"}{$ParamPos}{"type"};
3606            my %PType = get_PureType($PId, $Version);
3607            my $PTName = unmangledFormat($PType{"Name"}, $Version);
3608            $PTName=~s/\b(restrict|register)\b//g;
3609            if($Compiler eq "MSVC") {
3610                $PTName=~s/\blong long\b/__int64/;
3611            }
3612            @ParamTypes = (@ParamTypes, $PTName);
3613        }
3614        if(@ParamTypes) {
3615            $PureSignature .= "(".join(", ", @ParamTypes).")";
3616        }
3617        else
3618        {
3619            if($Compiler eq "MSVC")
3620            {
3621                $PureSignature .= "(void)";
3622            }
3623            else
3624            { # GCC
3625                $PureSignature .= "()";
3626            }
3627        }
3628        $PureSignature = delete_keywords($PureSignature);
3629    }
3630    if(my $ClassId = $SymbolInfo{$Version}{$InfoId}{"Class"})
3631    {
3632        my $ClassName = unmangledFormat($TypeInfo{$Version}{$ClassId}{"Name"}, $Version);
3633        $PureSignature = $ClassName."::".$PureSignature;
3634    }
3635    elsif(my $NS = $SymbolInfo{$Version}{$InfoId}{"NameSpace"}) {
3636        $PureSignature = $NS."::".$PureSignature;
3637    }
3638    if($SymbolInfo{$Version}{$InfoId}{"Const"}) {
3639        $PureSignature .= " const";
3640    }
3641    if($SymbolInfo{$Version}{$InfoId}{"Volatile"}) {
3642        $PureSignature .= " volatile";
3643    }
3644    my $ShowReturn = 0;
3645    if($Compiler eq "MSVC"
3646    and $SymbolInfo{$Version}{$InfoId}{"Data"})
3647    {
3648        $ShowReturn=1;
3649    }
3650    elsif(defined $TemplateInstance{$Version}{"Func"}{$InfoId}
3651    and keys(%{$TemplateInstance{$Version}{"Func"}{$InfoId}}))
3652    {
3653        $ShowReturn=1;
3654    }
3655    if($ShowReturn)
3656    { # mangled names for template function specializations include return value
3657        if(my $ReturnId = $SymbolInfo{$Version}{$InfoId}{"Return"})
3658        {
3659            my %RType = get_PureType($ReturnId, $Version);
3660            my $ReturnName = unmangledFormat($RType{"Name"}, $Version);
3661            $PureSignature = $ReturnName." ".$PureSignature;
3662        }
3663    }
3664    return ($Cache{"modelUnmangled"}{$Version}{$Compiler}{$InfoId} = formatName($PureSignature));
3665}
3666
3667sub mangle_symbol($$$)
3668{ # mangling for simple methods
3669  # see gcc-4.6.0/gcc/cp/mangle.c
3670    my ($InfoId, $LibVersion, $Compiler) = @_;
3671    if($Cache{"mangle_symbol"}{$LibVersion}{$InfoId}{$Compiler}) {
3672        return $Cache{"mangle_symbol"}{$LibVersion}{$InfoId}{$Compiler};
3673    }
3674    my $Mangled = "";
3675    if($Compiler eq "GCC") {
3676        $Mangled = mangle_symbol_GCC($InfoId, $LibVersion);
3677    }
3678    elsif($Compiler eq "MSVC") {
3679        $Mangled = mangle_symbol_MSVC($InfoId, $LibVersion);
3680    }
3681    return ($Cache{"mangle_symbol"}{$LibVersion}{$InfoId}{$Compiler} = $Mangled);
3682}
3683
3684sub mangle_symbol_MSVC($$)
3685{
3686    my ($InfoId, $LibVersion) = @_;
3687    return "";
3688}
3689
3690sub mangle_symbol_GCC($$)
3691{ # see gcc-4.6.0/gcc/cp/mangle.c
3692    my ($InfoId, $LibVersion) = @_;
3693    my ($Mangled, $ClassId, $NameSpace) = ("_Z", 0, "");
3694    my $Return = $SymbolInfo{$LibVersion}{$InfoId}{"Return"};
3695    my %Repl = ();# SN_ replacements
3696    if($ClassId = $SymbolInfo{$LibVersion}{$InfoId}{"Class"})
3697    {
3698        my $MangledClass = mangle_param($ClassId, $LibVersion, \%Repl);
3699        if($MangledClass!~/\AN/) {
3700            $MangledClass = "N".$MangledClass;
3701        }
3702        else {
3703            $MangledClass=~s/E\Z//;
3704        }
3705        if($SymbolInfo{$LibVersion}{$InfoId}{"Volatile"}) {
3706            $MangledClass=~s/\AN/NV/;
3707        }
3708        if($SymbolInfo{$LibVersion}{$InfoId}{"Const"}) {
3709            $MangledClass=~s/\AN/NK/;
3710        }
3711        $Mangled .= $MangledClass;
3712    }
3713    elsif($NameSpace = $SymbolInfo{$LibVersion}{$InfoId}{"NameSpace"})
3714    { # mangled by name due to the absence of structured info
3715        my $MangledNS = mangle_ns($NameSpace, $LibVersion, \%Repl);
3716        if($MangledNS!~/\AN/) {
3717            $MangledNS = "N".$MangledNS;
3718        }
3719        else {
3720            $MangledNS=~s/E\Z//;
3721        }
3722        $Mangled .= $MangledNS;
3723    }
3724    my ($ShortName, $TmplParams) = template_base($SymbolInfo{$LibVersion}{$InfoId}{"ShortName"});
3725    my @TParams = ();
3726    if(my @TPos = keys(%{$SymbolInfo{$LibVersion}{$InfoId}{"TParam"}}))
3727    { # parsing mode
3728        foreach (@TPos) {
3729            push(@TParams, $SymbolInfo{$LibVersion}{$InfoId}{"TParam"}{$_}{"name"});
3730        }
3731    }
3732    elsif($TmplParams)
3733    { # remangling mode
3734      # support for old ABI dumps
3735        @TParams = separate_params($TmplParams, 0);
3736    }
3737    if($SymbolInfo{$LibVersion}{$InfoId}{"Constructor"}) {
3738        $Mangled .= "C1";
3739    }
3740    elsif($SymbolInfo{$LibVersion}{$InfoId}{"Destructor"}) {
3741        $Mangled .= "D0";
3742    }
3743    elsif($ShortName)
3744    {
3745        if($SymbolInfo{$LibVersion}{$InfoId}{"Data"})
3746        {
3747            if(not $SymbolInfo{$LibVersion}{$InfoId}{"Class"}
3748            and isConstType($Return, $LibVersion))
3749            { # "const" global data is mangled as _ZL...
3750                $Mangled .= "L";
3751            }
3752        }
3753        if($ShortName=~/\Aoperator(\W.*)\Z/)
3754        {
3755            my $Op = $1;
3756            $Op=~s/\A[ ]+//g;
3757            if(my $OpMngl = $OperatorMangling{$Op}) {
3758                $Mangled .= $OpMngl;
3759            }
3760            else { # conversion operator
3761                $Mangled .= "cv".mangle_param(getTypeIdByName($Op, $LibVersion), $LibVersion, \%Repl);
3762            }
3763        }
3764        else {
3765            $Mangled .= length($ShortName).$ShortName;
3766        }
3767        if(@TParams)
3768        { # templates
3769            $Mangled .= "I";
3770            foreach my $TParam (@TParams) {
3771                $Mangled .= mangle_template_param($TParam, $LibVersion, \%Repl);
3772            }
3773            $Mangled .= "E";
3774        }
3775        if(not $ClassId and @TParams) {
3776            add_substitution($ShortName, \%Repl, 0);
3777        }
3778    }
3779    if($ClassId or $NameSpace) {
3780        $Mangled .= "E";
3781    }
3782    if(@TParams)
3783    {
3784        if($Return) {
3785            $Mangled .= mangle_param($Return, $LibVersion, \%Repl);
3786        }
3787    }
3788    if(not $SymbolInfo{$LibVersion}{$InfoId}{"Data"})
3789    {
3790        my @Params = ();
3791        if(defined $SymbolInfo{$LibVersion}{$InfoId}{"Param"}
3792        and not $SymbolInfo{$LibVersion}{$InfoId}{"Destructor"}) {
3793            @Params = keys(%{$SymbolInfo{$LibVersion}{$InfoId}{"Param"}});
3794        }
3795        foreach my $ParamPos (sort {int($a) <=> int($b)} @Params)
3796        { # checking parameters
3797            my $ParamType_Id = $SymbolInfo{$LibVersion}{$InfoId}{"Param"}{$ParamPos}{"type"};
3798            $Mangled .= mangle_param($ParamType_Id, $LibVersion, \%Repl);
3799        }
3800        if(not @Params) {
3801            $Mangled .= "v";
3802        }
3803    }
3804    $Mangled = correct_incharge($InfoId, $LibVersion, $Mangled);
3805    $Mangled = write_stdcxx_substitution($Mangled);
3806    if($Mangled eq "_Z") {
3807        return "";
3808    }
3809    return $Mangled;
3810}
3811
3812sub correct_incharge($$$)
3813{
3814    my ($InfoId, $LibVersion, $Mangled) = @_;
3815    if($SymbolInfo{$LibVersion}{$InfoId}{"Constructor"})
3816    {
3817        if($MangledNames{$LibVersion}{$Mangled}) {
3818            $Mangled=~s/C1E/C2E/;
3819        }
3820    }
3821    elsif($SymbolInfo{$LibVersion}{$InfoId}{"Destructor"})
3822    {
3823        if($MangledNames{$LibVersion}{$Mangled}) {
3824            $Mangled=~s/D0E/D1E/;
3825        }
3826        if($MangledNames{$LibVersion}{$Mangled}) {
3827            $Mangled=~s/D1E/D2E/;
3828        }
3829    }
3830    return $Mangled;
3831}
3832
3833sub template_base($)
3834{ # NOTE: std::_Vector_base<mysqlpp::mysql_type_info>::_Vector_impl
3835  # NOTE: operators: >>, <<
3836    my $Name = $_[0];
3837    if($Name!~/>\Z/ or $Name!~/</) {
3838        return $Name;
3839    }
3840    my $TParams = $Name;
3841    while(my $CPos = find_center($TParams, "<"))
3842    { # search for the last <T>
3843        $TParams = substr($TParams, $CPos);
3844    }
3845    if($TParams=~s/\A<(.+)>\Z/$1/) {
3846        $Name=~s/<\Q$TParams\E>\Z//;
3847    }
3848    else
3849    { # error
3850        $TParams = "";
3851    }
3852    return ($Name, $TParams);
3853}
3854
3855sub get_sub_ns($)
3856{
3857    my $Name = $_[0];
3858    my @NS = ();
3859    while(my $CPos = find_center($Name, ":"))
3860    {
3861        push(@NS, substr($Name, 0, $CPos));
3862        $Name = substr($Name, $CPos);
3863        $Name=~s/\A:://;
3864    }
3865    return (join("::", @NS), $Name);
3866}
3867
3868sub mangle_ns($$$)
3869{
3870    my ($Name, $LibVersion, $Repl) = @_;
3871    if(my $Tid = $TName_Tid{$LibVersion}{$Name})
3872    {
3873        my $Mangled = mangle_param($Tid, $LibVersion, $Repl);
3874        $Mangled=~s/\AN(.+)E\Z/$1/;
3875        return $Mangled;
3876
3877    }
3878    else
3879    {
3880        my ($MangledNS, $SubNS) = ("", "");
3881        ($SubNS, $Name) = get_sub_ns($Name);
3882        if($SubNS) {
3883            $MangledNS .= mangle_ns($SubNS, $LibVersion, $Repl);
3884        }
3885        $MangledNS .= length($Name).$Name;
3886        add_substitution($MangledNS, $Repl, 0);
3887        return $MangledNS;
3888    }
3889}
3890
3891sub mangle_param($$$)
3892{
3893    my ($PTid, $LibVersion, $Repl) = @_;
3894    my ($MPrefix, $Mangled) = ("", "");
3895    my %ReplCopy = %{$Repl};
3896    my %BaseType = get_BaseType($PTid, $LibVersion);
3897    my $BaseType_Name = $BaseType{"Name"};
3898    if(not $BaseType_Name) {
3899        return "";
3900    }
3901    my ($ShortName, $TmplParams) = template_base($BaseType_Name);
3902    my $Suffix = get_BaseTypeQual($PTid, $LibVersion);
3903    while($Suffix=~s/\s*(const|volatile|restrict)\Z//g){};
3904    while($Suffix=~/(&|\*|const)\Z/)
3905    {
3906        if($Suffix=~s/[ ]*&\Z//) {
3907            $MPrefix .= "R";
3908        }
3909        if($Suffix=~s/[ ]*\*\Z//) {
3910            $MPrefix .= "P";
3911        }
3912        if($Suffix=~s/[ ]*const\Z//)
3913        {
3914            if($MPrefix=~/R|P/
3915            or $Suffix=~/&|\*/) {
3916                $MPrefix .= "K";
3917            }
3918        }
3919        if($Suffix=~s/[ ]*volatile\Z//) {
3920            $MPrefix .= "V";
3921        }
3922        #if($Suffix=~s/[ ]*restrict\Z//) {
3923            #$MPrefix .= "r";
3924        #}
3925    }
3926    if(my $Token = $IntrinsicMangling{$BaseType_Name}) {
3927        $Mangled .= $Token;
3928    }
3929    elsif($BaseType{"Type"}=~/(Class|Struct|Union|Enum)/)
3930    {
3931        my @TParams = ();
3932        if(my @TPos = keys(%{$BaseType{"TParam"}}))
3933        { # parsing mode
3934            foreach (@TPos) {
3935                push(@TParams, $BaseType{"TParam"}{$_}{"name"});
3936            }
3937        }
3938        elsif($TmplParams)
3939        { # remangling mode
3940          # support for old ABI dumps
3941            @TParams = separate_params($TmplParams, 0);
3942        }
3943        my $MangledNS = "";
3944        my ($SubNS, $SName) = get_sub_ns($ShortName);
3945        if($SubNS) {
3946            $MangledNS .= mangle_ns($SubNS, $LibVersion, $Repl);
3947        }
3948        $MangledNS .= length($SName).$SName;
3949        if(@TParams) {
3950            add_substitution($MangledNS, $Repl, 0);
3951        }
3952        $Mangled .= "N".$MangledNS;
3953        if(@TParams)
3954        { # templates
3955            $Mangled .= "I";
3956            foreach my $TParam (@TParams) {
3957                $Mangled .= mangle_template_param($TParam, $LibVersion, $Repl);
3958            }
3959            $Mangled .= "E";
3960        }
3961        $Mangled .= "E";
3962    }
3963    elsif($BaseType{"Type"}=~/(FuncPtr|MethodPtr)/)
3964    {
3965        if($BaseType{"Type"} eq "MethodPtr") {
3966            $Mangled .= "M".mangle_param($BaseType{"Class"}, $LibVersion, $Repl)."F";
3967        }
3968        else {
3969            $Mangled .= "PF";
3970        }
3971        $Mangled .= mangle_param($BaseType{"Return"}, $LibVersion, $Repl);
3972        my @Params = keys(%{$BaseType{"Param"}});
3973        foreach my $Num (sort {int($a)<=>int($b)} @Params) {
3974            $Mangled .= mangle_param($BaseType{"Param"}{$Num}{"type"}, $LibVersion, $Repl);
3975        }
3976        if(not @Params) {
3977            $Mangled .= "v";
3978        }
3979        $Mangled .= "E";
3980    }
3981    elsif($BaseType{"Type"} eq "FieldPtr")
3982    {
3983        $Mangled .= "M".mangle_param($BaseType{"Class"}, $LibVersion, $Repl);
3984        $Mangled .= mangle_param($BaseType{"Return"}, $LibVersion, $Repl);
3985    }
3986    $Mangled = $MPrefix.$Mangled;# add prefix (RPK)
3987    if(my $Optimized = write_substitution($Mangled, \%ReplCopy))
3988    {
3989        if($Mangled eq $Optimized)
3990        {
3991            if($ShortName!~/::/)
3992            { # remove "N ... E"
3993                if($MPrefix) {
3994                    $Mangled=~s/\A($MPrefix)N(.+)E\Z/$1$2/g;
3995                }
3996                else {
3997                    $Mangled=~s/\AN(.+)E\Z/$1/g;
3998                }
3999            }
4000        }
4001        else {
4002            $Mangled = $Optimized;
4003        }
4004    }
4005    add_substitution($Mangled, $Repl, 1);
4006    return $Mangled;
4007}
4008
4009sub mangle_template_param($$$)
4010{ # types + literals
4011    my ($TParam, $LibVersion, $Repl) = @_;
4012    if(my $TPTid = $TName_Tid{$LibVersion}{$TParam}) {
4013        return mangle_param($TPTid, $LibVersion, $Repl);
4014    }
4015    elsif($TParam=~/\A(\d+)(\w+)\Z/)
4016    { # class_name<1u>::method(...)
4017        return "L".$IntrinsicMangling{$ConstantSuffixR{$2}}.$1."E";
4018    }
4019    elsif($TParam=~/\A\(([\w ]+)\)(\d+)\Z/)
4020    { # class_name<(signed char)1>::method(...)
4021        return "L".$IntrinsicMangling{$1}.$2."E";
4022    }
4023    elsif($TParam eq "true")
4024    { # class_name<true>::method(...)
4025        return "Lb1E";
4026    }
4027    elsif($TParam eq "false")
4028    { # class_name<true>::method(...)
4029        return "Lb0E";
4030    }
4031    else { # internal error
4032        return length($TParam).$TParam;
4033    }
4034}
4035
4036sub add_substitution($$$)
4037{
4038    my ($Value, $Repl, $Rec) = @_;
4039    if($Rec)
4040    { # subtypes
4041        my @Subs = ($Value);
4042        while($Value=~s/\A(R|P|K)//) {
4043            push(@Subs, $Value);
4044        }
4045        foreach (reverse(@Subs)) {
4046            add_substitution($_, $Repl, 0);
4047        }
4048        return;
4049    }
4050    return if($Value=~/\AS(\d*)_\Z/);
4051    $Value=~s/\AN(.+)E\Z/$1/g;
4052    return if(defined $Repl->{$Value});
4053    return if(length($Value)<=1);
4054    return if($StdcxxMangling{$Value});
4055    # check for duplicates
4056    my $Base = $Value;
4057    foreach my $Type (sort {$Repl->{$a}<=>$Repl->{$b}} sort keys(%{$Repl}))
4058    {
4059        my $Num = $Repl->{$Type};
4060        my $Replace = macro_mangle($Num);
4061        $Base=~s/\Q$Replace\E/$Type/;
4062    }
4063    if(my $OldNum = $Repl->{$Base})
4064    {
4065        $Repl->{$Value} = $OldNum;
4066        return;
4067    }
4068    my @Repls = sort {$b<=>$a} values(%{$Repl});
4069    if(@Repls) {
4070        $Repl->{$Value} = $Repls[0]+1;
4071    }
4072    else {
4073        $Repl->{$Value} = -1;
4074    }
4075    # register duplicates
4076    # upward
4077    $Base = $Value;
4078    foreach my $Type (sort {$Repl->{$a}<=>$Repl->{$b}} sort keys(%{$Repl}))
4079    {
4080        next if($Base eq $Type);
4081        my $Num = $Repl->{$Type};
4082        my $Replace = macro_mangle($Num);
4083        $Base=~s/\Q$Type\E/$Replace/;
4084        $Repl->{$Base} = $Repl->{$Value};
4085    }
4086}
4087
4088sub macro_mangle($)
4089{
4090    my $Num = $_[0];
4091    if($Num==-1) {
4092        return "S_";
4093    }
4094    else
4095    {
4096        my $Code = "";
4097        if($Num<10)
4098        { # S0_, S1_, S2_, ...
4099            $Code = $Num;
4100        }
4101        elsif($Num>=10 and $Num<=35)
4102        { # SA_, SB_, SC_, ...
4103            $Code = chr(55+$Num);
4104        }
4105        else
4106        { # S10_, S11_, S12_
4107            $Code = $Num-26; # 26 is length of english alphabet
4108        }
4109        return "S".$Code."_";
4110    }
4111}
4112
4113sub write_stdcxx_substitution($)
4114{
4115    my $Mangled = $_[0];
4116    if($StdcxxMangling{$Mangled}) {
4117        return $StdcxxMangling{$Mangled};
4118    }
4119    else
4120    {
4121        my @Repls = keys(%StdcxxMangling);
4122        @Repls = sort {length($b)<=>length($a)} sort {$b cmp $a} @Repls;
4123        foreach my $MangledType (@Repls)
4124        {
4125            my $Replace = $StdcxxMangling{$MangledType};
4126            #if($Mangled!~/$Replace/) {
4127                $Mangled=~s/N\Q$MangledType\EE/$Replace/g;
4128                $Mangled=~s/\Q$MangledType\E/$Replace/g;
4129            #}
4130        }
4131    }
4132    return $Mangled;
4133}
4134
4135sub write_substitution($$)
4136{
4137    my ($Mangled, $Repl) = @_;
4138    if(defined $Repl->{$Mangled}
4139    and my $MnglNum = $Repl->{$Mangled}) {
4140        $Mangled = macro_mangle($MnglNum);
4141    }
4142    else
4143    {
4144        my @Repls = keys(%{$Repl});
4145        #@Repls = sort {$Repl->{$a}<=>$Repl->{$b}} @Repls;
4146        # FIXME: how to apply replacements? by num or by pos
4147        @Repls = sort {length($b)<=>length($a)} sort {$b cmp $a} @Repls;
4148        foreach my $MangledType (@Repls)
4149        {
4150            my $Replace = macro_mangle($Repl->{$MangledType});
4151            if($Mangled!~/$Replace/) {
4152                $Mangled=~s/N\Q$MangledType\EE/$Replace/g;
4153                $Mangled=~s/\Q$MangledType\E/$Replace/g;
4154            }
4155        }
4156    }
4157    return $Mangled;
4158}
4159
4160sub delete_keywords($)
4161{
4162    my $TypeName = $_[0];
4163    $TypeName=~s/\b(enum|struct|union|class) //g;
4164    return $TypeName;
4165}
4166
4167sub uncover_typedefs($$)
4168{
4169    my ($TypeName, $LibVersion) = @_;
4170    return "" if(not $TypeName);
4171    if(defined $Cache{"uncover_typedefs"}{$LibVersion}{$TypeName}) {
4172        return $Cache{"uncover_typedefs"}{$LibVersion}{$TypeName};
4173    }
4174    my ($TypeName_New, $TypeName_Pre) = (formatName($TypeName), "");
4175    while($TypeName_New ne $TypeName_Pre)
4176    {
4177        $TypeName_Pre = $TypeName_New;
4178        my $TypeName_Copy = $TypeName_New;
4179        my %Words = ();
4180        while($TypeName_Copy=~s/\b([a-z_]([\w:]*\w|))\b//io)
4181        {
4182            if(not $Intrinsic_Keywords{$1}) {
4183                $Words{$1} = 1;
4184            }
4185        }
4186        foreach my $Word (keys(%Words))
4187        {
4188            my $BaseType_Name = $Typedef_BaseName{$LibVersion}{$Word};
4189            next if(not $BaseType_Name);
4190            next if($TypeName_New=~/\b(struct|union|enum)\s\Q$Word\E\b/);
4191            if($BaseType_Name=~/\([\*]+\)/)
4192            { # FuncPtr
4193                if($TypeName_New=~/\Q$Word\E(.*)\Z/)
4194                {
4195                    my $Type_Suffix = $1;
4196                    $TypeName_New = $BaseType_Name;
4197                    if($TypeName_New=~s/\(([\*]+)\)/($1 $Type_Suffix)/) {
4198                        $TypeName_New = formatName($TypeName_New);
4199                    }
4200                }
4201            }
4202            else
4203            {
4204                if($TypeName_New=~s/\b\Q$Word\E\b/$BaseType_Name/g) {
4205                    $TypeName_New = formatName($TypeName_New);
4206                }
4207            }
4208        }
4209    }
4210    return ($Cache{"uncover_typedefs"}{$LibVersion}{$TypeName} = $TypeName_New);
4211}
4212
4213sub isInternal($)
4214{
4215    if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
4216    {
4217        if($Info=~/mngl[ ]*:[ ]*@(\d+) /)
4218        {
4219            if($LibInfo{$Version}{"info"}{$1}=~/\*[ ]*INTERNAL[ ]*\*/)
4220            { # _ZN7mysqlpp8DateTimeC1ERKS0_ *INTERNAL*
4221                return 1;
4222            }
4223        }
4224    }
4225    return 0;
4226}
4227
4228sub getDataVal($$)
4229{
4230    my ($InfoId, $TypeId) = @_;
4231    if(my $Info = $LibInfo{$Version}{"info"}{$InfoId})
4232    {
4233        if($Info=~/init[ ]*:[ ]*@(\d+) /)
4234        {
4235            if(defined $LibInfo{$Version}{"info_type"}{$1}
4236            and $LibInfo{$Version}{"info_type"}{$1} eq "nop_expr")
4237            { # char const* data = "str"
4238              # NOTE: disabled
4239                if(my $NopExpr = $LibInfo{$Version}{"info"}{$1})
4240                {
4241                    if($NopExpr=~/op 0[ ]*:[ ]*@(\d+) /)
4242                    {
4243                        if(defined $LibInfo{$Version}{"info_type"}{$1}
4244                        and $LibInfo{$Version}{"info_type"}{$1} eq "addr_expr")
4245                        {
4246                            if(my $AddrExpr = $LibInfo{$Version}{"info"}{$1})
4247                            {
4248                                if($AddrExpr=~/op 0[ ]*:[ ]*@(\d+) /)
4249                                {
4250                                    return getInitVal($1, $TypeId);
4251                                }
4252                            }
4253                        }
4254                    }
4255                }
4256            }
4257            else {
4258                return getInitVal($1, $TypeId);
4259            }
4260        }
4261    }
4262    return undef;
4263}
4264
4265sub getInitVal($$)
4266{
4267    my ($InfoId, $TypeId) = @_;
4268    if(my $Info = $LibInfo{$Version}{"info"}{$InfoId})
4269    {
4270        if(my $InfoType = $LibInfo{$Version}{"info_type"}{$InfoId})
4271        {
4272            if($InfoType eq "integer_cst")
4273            {
4274                my $Val = getNodeIntCst($InfoId);
4275                if($TypeId and $TypeInfo{$Version}{$TypeId}{"Name"}=~/\Achar(| const)\Z/)
4276                { # characters
4277                    $Val = chr($Val);
4278                }
4279                return $Val;
4280            }
4281            elsif($InfoType eq "string_cst") {
4282                return getNodeStrCst($InfoId);
4283            }
4284        }
4285    }
4286    return undef;
4287}
4288
4289sub set_Class_And_Namespace($)
4290{
4291    my $InfoId = $_[0];
4292    if(my $Info = $LibInfo{$Version}{"info"}{$InfoId})
4293    {
4294        if($Info=~/scpe[ ]*:[ ]*@(\d+) /)
4295        {
4296            my $NSInfoId = $1;
4297            if(my $InfoType = $LibInfo{$Version}{"info_type"}{$NSInfoId})
4298            {
4299                if($InfoType eq "namespace_decl") {
4300                    $SymbolInfo{$Version}{$InfoId}{"NameSpace"} = getNameSpace($InfoId);
4301                }
4302                elsif($InfoType eq "record_type") {
4303                    $SymbolInfo{$Version}{$InfoId}{"Class"} = $NSInfoId;
4304                }
4305            }
4306        }
4307    }
4308    if($SymbolInfo{$Version}{$InfoId}{"Class"}
4309    or $SymbolInfo{$Version}{$InfoId}{"NameSpace"})
4310    { # identify language
4311        setLanguage($Version, "C++");
4312    }
4313}
4314
4315sub debugType($$)
4316{
4317    my ($Tid, $LibVersion) = @_;
4318    my %Type = get_Type($Tid, $LibVersion);
4319    printMsg("INFO", Dumper(\%Type));
4320}
4321
4322sub debugMangling($)
4323{
4324    my $LibVersion = $_[0];
4325    my %Mangled = ();
4326    foreach my $InfoId (keys(%{$SymbolInfo{$LibVersion}}))
4327    {
4328        if(my $Mngl = $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"})
4329        {
4330            if($Mngl=~/\A(_Z|\?)/) {
4331                $Mangled{$Mngl}=$InfoId;
4332            }
4333        }
4334    }
4335    translateSymbols(keys(%Mangled), $LibVersion);
4336    foreach my $Mngl (keys(%Mangled))
4337    {
4338        my $U1 = modelUnmangled($Mangled{$Mngl}, "GCC");
4339        my $U2 = $tr_name{$Mngl};
4340        if($U1 ne $U2) {
4341            printMsg("INFO", "INCORRECT MANGLING:\n  $Mngl\n  $U1\n  $U2\n");
4342        }
4343    }
4344}
4345
4346sub linkSymbol($)
4347{ # link symbols from shared libraries
4348  # with the symbols from header files
4349    my $InfoId = $_[0];
4350    # try to mangle symbol
4351    if((not check_gcc($GCC_PATH, "4") and $SymbolInfo{$Version}{$InfoId}{"Class"})
4352    or (check_gcc($GCC_PATH, "4") and not $SymbolInfo{$Version}{$InfoId}{"Class"}))
4353    { # 1. GCC 3.x doesn't mangle class methods names in the TU dump (only functions and global data)
4354      # 2. GCC 4.x doesn't mangle C++ functions in the TU dump (only class methods) except extern "C" functions
4355        if(not $CheckHeadersOnly)
4356        {
4357            if(my $Mangled = $mangled_name_gcc{modelUnmangled($InfoId, "GCC")}) {
4358                return correct_incharge($InfoId, $Version, $Mangled);
4359            }
4360        }
4361        if($CheckHeadersOnly
4362        or not $BinaryOnly)
4363        { # 1. --headers-only mode
4364          # 2. not mangled src-only symbols
4365            if(my $Mangled = mangle_symbol($InfoId, $Version, "GCC")) {
4366                return $Mangled;
4367            }
4368        }
4369    }
4370    return "";
4371}
4372
4373sub setLanguage($$)
4374{
4375    my ($LibVersion, $Lang) = @_;
4376    if(not $UserLang) {
4377        $COMMON_LANGUAGE{$LibVersion} = $Lang;
4378    }
4379}
4380
4381sub getSymbolInfo($)
4382{
4383    my $InfoId = $_[0];
4384    if(isInternal($InfoId)) {
4385        return;
4386    }
4387    ($SymbolInfo{$Version}{$InfoId}{"Header"}, $SymbolInfo{$Version}{$InfoId}{"Line"}) = getLocation($InfoId);
4388    if(not $SymbolInfo{$Version}{$InfoId}{"Header"}
4389    or isBuiltIn($SymbolInfo{$Version}{$InfoId}{"Header"}))
4390    {
4391        delete($SymbolInfo{$Version}{$InfoId});
4392        return;
4393    }
4394    setFuncAccess($InfoId);
4395    setFuncKind($InfoId);
4396    if($SymbolInfo{$Version}{$InfoId}{"PseudoTemplate"})
4397    {
4398        delete($SymbolInfo{$Version}{$InfoId});
4399        return;
4400    }
4401    $SymbolInfo{$Version}{$InfoId}{"Type"} = getFuncType($InfoId);
4402    if($SymbolInfo{$Version}{$InfoId}{"Return"} = getFuncReturn($InfoId))
4403    {
4404        if(not $TypeInfo{$Version}{$SymbolInfo{$Version}{$InfoId}{"Return"}}{"Name"})
4405        { # templates
4406            delete($SymbolInfo{$Version}{$InfoId});
4407            return;
4408        }
4409    }
4410    if(my $Rid = $SymbolInfo{$Version}{$InfoId}{"Return"})
4411    {
4412        if(defined $MissedTypedef{$Version}{$Rid})
4413        {
4414            if(my $AddedTid = $MissedTypedef{$Version}{$Rid}{"Tid"}) {
4415                $SymbolInfo{$Version}{$InfoId}{"Return"} = $AddedTid;
4416            }
4417        }
4418    }
4419    if(not $SymbolInfo{$Version}{$InfoId}{"Return"}) {
4420        delete($SymbolInfo{$Version}{$InfoId}{"Return"});
4421    }
4422    my $Orig = getFuncOrig($InfoId);
4423    $SymbolInfo{$Version}{$InfoId}{"ShortName"} = getFuncShortName($Orig);
4424    if($SymbolInfo{$Version}{$InfoId}{"ShortName"}=~/\._/)
4425    {
4426        delete($SymbolInfo{$Version}{$InfoId});
4427        return;
4428    }
4429
4430    if(defined $TemplateInstance{$Version}{"Func"}{$Orig})
4431    {
4432        my @TParams = getTParams($Orig, "Func");
4433        if(not @TParams)
4434        {
4435            delete($SymbolInfo{$Version}{$InfoId});
4436            return;
4437        }
4438        foreach my $Pos (0 .. $#TParams) {
4439            $SymbolInfo{$Version}{$InfoId}{"TParam"}{$Pos}{"name"}=$TParams[$Pos];
4440        }
4441        my $PrmsInLine = join(", ", @TParams);
4442        if($SymbolInfo{$Version}{$InfoId}{"ShortName"}=~/\Aoperator\W+\Z/)
4443        { # operator<< <T>, operator>> <T>
4444            $SymbolInfo{$Version}{$InfoId}{"ShortName"} .= " ";
4445        }
4446        $SymbolInfo{$Version}{$InfoId}{"ShortName"} .= "<".$PrmsInLine.">";
4447        $SymbolInfo{$Version}{$InfoId}{"ShortName"} = formatName($SymbolInfo{$Version}{$InfoId}{"ShortName"});
4448    }
4449    else
4450    { # support for GCC 3.4
4451        $SymbolInfo{$Version}{$InfoId}{"ShortName"}=~s/<.+>\Z//;
4452    }
4453    $SymbolInfo{$Version}{$InfoId}{"MnglName"} = getTreeStr(getTreeAttr_Mngl($InfoId));
4454    # NOTE: mangling of some symbols may change depending on GCC version
4455    # GCC 4.6: _ZN28QExplicitlySharedDataPointerI11QPixmapDataEC2IT_EERKS_IT_E
4456    # GCC 4.7: _ZN28QExplicitlySharedDataPointerI11QPixmapDataEC2ERKS1_
4457
4458    if($SymbolInfo{$Version}{$InfoId}{"MnglName"}
4459    and $SymbolInfo{$Version}{$InfoId}{"MnglName"}!~/\A_Z/)
4460    {
4461        delete($SymbolInfo{$Version}{$InfoId});
4462        return;
4463    }
4464    if(not $SymbolInfo{$Version}{$InfoId}{"Destructor"})
4465    { # destructors have an empty parameter list
4466        my $Skip = setFuncParams($InfoId);
4467        if($Skip) {
4468            delete($SymbolInfo{$Version}{$InfoId});
4469            return;
4470        }
4471    }
4472    set_Class_And_Namespace($InfoId);
4473    if(my $ClassId = $SymbolInfo{$Version}{$InfoId}{"Class"})
4474    {
4475        if(not $TypeInfo{$Version}{$ClassId}{"Name"})
4476        { # templates
4477            delete($SymbolInfo{$Version}{$InfoId});
4478            return;
4479        }
4480    }
4481    if(not $CheckHeadersOnly)
4482    {
4483        if($SymbolInfo{$Version}{$InfoId}{"Type"} eq "Function"
4484        and not $SymbolInfo{$Version}{$InfoId}{"Class"}
4485        and link_symbol($SymbolInfo{$Version}{$InfoId}{"ShortName"}, $Version, "-Deps"))
4486        { # functions (C++): not mangled in library, but are mangled in TU dump
4487            if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"}
4488            or not link_symbol($SymbolInfo{$Version}{$InfoId}{"MnglName"}, $Version, "-Deps")) {
4489                $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $SymbolInfo{$Version}{$InfoId}{"ShortName"};
4490            }
4491        }
4492    }
4493    if($LibInfo{$Version}{"info"}{$InfoId}=~/ lang:[ ]*C /i)
4494    { # extern "C"
4495        $SymbolInfo{$Version}{$InfoId}{"Lang"} = "C";
4496        $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $SymbolInfo{$Version}{$InfoId}{"ShortName"};
4497    }
4498    if($UserLang and $UserLang eq "C")
4499    { # --lang=C option
4500        $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $SymbolInfo{$Version}{$InfoId}{"ShortName"};
4501    }
4502    if($COMMON_LANGUAGE{$Version} eq "C++")
4503    { # correct mangled & short names
4504      # C++ or --headers-only mode
4505        if($SymbolInfo{$Version}{$InfoId}{"ShortName"}=~/\A__(comp|base|deleting)_(c|d)tor\Z/)
4506        { # support for old GCC versions: reconstruct real names for constructors and destructors
4507            $SymbolInfo{$Version}{$InfoId}{"ShortName"} = getNameByInfo(getTypeDeclId($SymbolInfo{$Version}{$InfoId}{"Class"}));
4508            $SymbolInfo{$Version}{$InfoId}{"ShortName"}=~s/<.+>\Z//;
4509        }
4510        if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"})
4511        { # try to mangle symbol (link with libraries)
4512            if(my $Mangled = linkSymbol($InfoId)) {
4513                $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $Mangled;
4514            }
4515        }
4516        if($OStarget eq "windows")
4517        { # link MS C++ symbols from library with GCC symbols from headers
4518            if(my $Mangled1 = $mangled_name{$Version}{modelUnmangled($InfoId, "MSVC")})
4519            { # exported symbols
4520                $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $Mangled1;
4521            }
4522            elsif(my $Mangled2 = mangle_symbol($InfoId, $Version, "MSVC"))
4523            { # pure virtual symbols
4524                $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $Mangled2;
4525            }
4526        }
4527    }
4528    if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"})
4529    { # can't detect symbol name
4530        delete($SymbolInfo{$Version}{$InfoId});
4531        return;
4532    }
4533    if(not $SymbolInfo{$Version}{$InfoId}{"Constructor"}
4534    and my $Spec = getVirtSpec($Orig))
4535    { # identify virtual and pure virtual functions
4536      # NOTE: constructors cannot be virtual
4537      # NOTE: in GCC 4.7 D1 destructors have no virtual spec
4538      # in the TU dump, so taking it from the original symbol
4539        if(not ($SymbolInfo{$Version}{$InfoId}{"Destructor"}
4540        and $SymbolInfo{$Version}{$InfoId}{"MnglName"}=~/D2E/))
4541        { # NOTE: D2 destructors are not present in a v-table
4542            $SymbolInfo{$Version}{$InfoId}{$Spec} = 1;
4543        }
4544    }
4545    if(isInline($InfoId)) {
4546        $SymbolInfo{$Version}{$InfoId}{"InLine"} = 1;
4547    }
4548    if($LibInfo{$Version}{"info"}{$InfoId}=~/ artificial /i) {
4549        $SymbolInfo{$Version}{$InfoId}{"Artificial"} = 1;
4550    }
4551    if($SymbolInfo{$Version}{$InfoId}{"Constructor"}
4552    and my $ClassId = $SymbolInfo{$Version}{$InfoId}{"Class"})
4553    {
4554        if(not $SymbolInfo{$Version}{$InfoId}{"InLine"}
4555        and not $SymbolInfo{$Version}{$InfoId}{"Artificial"})
4556        { # inline or auto-generated constructor
4557            delete($TypeInfo{$Version}{$ClassId}{"Copied"});
4558        }
4559    }
4560    if(my $Symbol = $SymbolInfo{$Version}{$InfoId}{"MnglName"})
4561    {
4562        if(not selectSymbol($Symbol, $SymbolInfo{$Version}{$InfoId}, "Dump", $Version))
4563        { # non-target symbols
4564            delete($SymbolInfo{$Version}{$InfoId});
4565            return;
4566        }
4567    }
4568    if($SymbolInfo{$Version}{$InfoId}{"Type"} eq "Method"
4569    or $SymbolInfo{$Version}{$InfoId}{"Constructor"}
4570    or $SymbolInfo{$Version}{$InfoId}{"Destructor"}
4571    or $SymbolInfo{$Version}{$InfoId}{"Class"})
4572    {
4573        if($SymbolInfo{$Version}{$InfoId}{"MnglName"}!~/\A(_Z|\?)/) {
4574            delete($SymbolInfo{$Version}{$InfoId});
4575            return;
4576        }
4577    }
4578    if($SymbolInfo{$Version}{$InfoId}{"MnglName"})
4579    {
4580        if($MangledNames{$Version}{$SymbolInfo{$Version}{$InfoId}{"MnglName"}})
4581        { # one instance for one mangled name only
4582            delete($SymbolInfo{$Version}{$InfoId});
4583            return;
4584        }
4585        else {
4586            $MangledNames{$Version}{$SymbolInfo{$Version}{$InfoId}{"MnglName"}} = 1;
4587        }
4588    }
4589    if($SymbolInfo{$Version}{$InfoId}{"Constructor"}
4590    or $SymbolInfo{$Version}{$InfoId}{"Destructor"}) {
4591        delete($SymbolInfo{$Version}{$InfoId}{"Return"});
4592    }
4593    if($SymbolInfo{$Version}{$InfoId}{"MnglName"}=~/\A(_Z|\?)/
4594    and $SymbolInfo{$Version}{$InfoId}{"Class"})
4595    {
4596        if($SymbolInfo{$Version}{$InfoId}{"Type"} eq "Function")
4597        { # static methods
4598            $SymbolInfo{$Version}{$InfoId}{"Static"} = 1;
4599        }
4600    }
4601    if(getFuncLink($InfoId) eq "Static") {
4602        $SymbolInfo{$Version}{$InfoId}{"Static"} = 1;
4603    }
4604    if($SymbolInfo{$Version}{$InfoId}{"MnglName"}=~/\A(_Z|\?)/)
4605    {
4606        if(my $Unmangled = $tr_name{$SymbolInfo{$Version}{$InfoId}{"MnglName"}})
4607        {
4608            if($Unmangled=~/\.\_\d/) {
4609                delete($SymbolInfo{$Version}{$InfoId});
4610                return;
4611            }
4612        }
4613    }
4614    delete($SymbolInfo{$Version}{$InfoId}{"Type"});
4615    if($SymbolInfo{$Version}{$InfoId}{"MnglName"}=~/\A_ZN(V|)K/) {
4616        $SymbolInfo{$Version}{$InfoId}{"Const"} = 1;
4617    }
4618    if($SymbolInfo{$Version}{$InfoId}{"MnglName"}=~/\A_ZN(K|)V/) {
4619        $SymbolInfo{$Version}{$InfoId}{"Volatile"} = 1;
4620    }
4621}
4622
4623sub isInline($)
4624{ # "body: undefined" in the tree
4625  # -fkeep-inline-functions GCC option should be specified
4626    if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
4627    {
4628        if($Info=~/ undefined /i) {
4629            return 0;
4630        }
4631    }
4632    return 1;
4633}
4634
4635sub getTypeId($)
4636{
4637    if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
4638    {
4639        if($Info=~/type[ ]*:[ ]*@(\d+) /) {
4640            return $1;
4641        }
4642    }
4643    return "";
4644}
4645
4646sub setTypeMemb($$)
4647{
4648    my ($TypeId, $TypeAttr) = @_;
4649    my $TypeType = $TypeAttr->{"Type"};
4650    my ($Pos, $UnnamedPos) = (0, 0);
4651    if($TypeType eq "Enum")
4652    {
4653        my $TypeMembInfoId = getTreeAttr_Csts($TypeId);
4654        while($TypeMembInfoId)
4655        {
4656            $TypeAttr->{"Memb"}{$Pos}{"value"} = getEnumMembVal($TypeMembInfoId);
4657            my $MembName = getTreeStr(getTreeAttr_Purp($TypeMembInfoId));
4658            $TypeAttr->{"Memb"}{$Pos}{"name"} = $MembName;
4659            $EnumMembName_Id{$Version}{getTreeAttr_Valu($TypeMembInfoId)} = ($TypeAttr->{"NameSpace"})?$TypeAttr->{"NameSpace"}."::".$MembName:$MembName;
4660            $TypeMembInfoId = getNextElem($TypeMembInfoId);
4661            $Pos += 1;
4662        }
4663    }
4664    elsif($TypeType=~/\A(Struct|Class|Union)\Z/)
4665    {
4666        my $TypeMembInfoId = getTreeAttr_Flds($TypeId);
4667        while($TypeMembInfoId)
4668        {
4669            my $IType = $LibInfo{$Version}{"info_type"}{$TypeMembInfoId};
4670            my $MInfo = $LibInfo{$Version}{"info"}{$TypeMembInfoId};
4671            if(not $IType or $IType ne "field_decl")
4672            { # search for fields, skip other stuff in the declaration
4673                $TypeMembInfoId = getNextElem($TypeMembInfoId);
4674                next;
4675            }
4676            my $StructMembName = getStructMembName($TypeMembInfoId);
4677            if($StructMembName=~/_vptr\./)
4678            { # virtual tables
4679                $TypeMembInfoId = getNextElem($TypeMembInfoId);
4680                next;
4681            }
4682            if(not $StructMembName)
4683            { # unnamed fields
4684                if($TypeAttr->{"Name"}!~/_type_info_pseudo/)
4685                {
4686                    my $UnnamedTid = getTreeAttr_Type($TypeMembInfoId);
4687                    my $UnnamedTName = getNameByInfo(getTypeDeclId($UnnamedTid));
4688                    if(isAnon($UnnamedTName))
4689                    { # rename unnamed fields to unnamed0, unnamed1, ...
4690                        $StructMembName = "unnamed".($UnnamedPos++);
4691                    }
4692                }
4693            }
4694            if(not $StructMembName)
4695            { # unnamed fields and base classes
4696                $TypeMembInfoId = getNextElem($TypeMembInfoId);
4697                next;
4698            }
4699            my $MembTypeId = getTreeAttr_Type($TypeMembInfoId);
4700            if(defined $MissedTypedef{$Version}{$MembTypeId})
4701            {
4702                if(my $AddedTid = $MissedTypedef{$Version}{$MembTypeId}{"Tid"}) {
4703                    $MembTypeId = $AddedTid;
4704                }
4705            }
4706            $TypeAttr->{"Memb"}{$Pos}{"type"} = $MembTypeId;
4707            $TypeAttr->{"Memb"}{$Pos}{"name"} = $StructMembName;
4708            if((my $Access = getTreeAccess($TypeMembInfoId)) ne "public")
4709            { # marked only protected and private, public by default
4710                $TypeAttr->{"Memb"}{$Pos}{"access"} = $Access;
4711            }
4712            if($MInfo=~/spec:\s*mutable /)
4713            { # mutable fields
4714                $TypeAttr->{"Memb"}{$Pos}{"mutable"} = 1;
4715            }
4716            if(my $BFSize = getStructMembBitFieldSize($TypeMembInfoId)) {
4717                $TypeAttr->{"Memb"}{$Pos}{"bitfield"} = $BFSize;
4718            }
4719            else
4720            { # set alignment for non-bit fields
4721              # alignment for bitfields is always equal to 1 bit
4722                if(my $Algn = getAlgn($TypeMembInfoId)) {
4723                    $TypeAttr->{"Memb"}{$Pos}{"algn"} = $Algn/$BYTE_SIZE;
4724                }
4725            }
4726            $TypeMembInfoId = getNextElem($TypeMembInfoId);
4727            $Pos += 1;
4728        }
4729    }
4730}
4731
4732sub setFuncParams($)
4733{
4734    my $InfoId = $_[0];
4735    my $ParamInfoId = getTreeAttr_Args($InfoId);
4736    if(getFuncType($InfoId) eq "Method")
4737    { # check type of "this" pointer
4738        my $ObjectTypeId = getTreeAttr_Type($ParamInfoId);
4739        if(my $ObjectName = $TypeInfo{$Version}{$ObjectTypeId}{"Name"})
4740        {
4741            if($ObjectName=~/\bconst(| volatile)\*const\b/) {
4742                $SymbolInfo{$Version}{$InfoId}{"Const"} = 1;
4743            }
4744            if($ObjectName=~/\bvolatile\b/) {
4745                $SymbolInfo{$Version}{$InfoId}{"Volatile"} = 1;
4746            }
4747        }
4748        else
4749        { # skip
4750            return 1;
4751        }
4752        $ParamInfoId = getNextElem($ParamInfoId);
4753    }
4754    my ($Pos, $Vtt_Pos) = (0, -1);
4755    while($ParamInfoId)
4756    { # formal args
4757        my $ParamTypeId = getTreeAttr_Type($ParamInfoId);
4758        my $ParamName = getTreeStr(getTreeAttr_Name($ParamInfoId));
4759        if(not $ParamName)
4760        { # unnamed
4761            $ParamName = "p".($Pos+1);
4762        }
4763        if(defined $MissedTypedef{$Version}{$ParamTypeId})
4764        {
4765            if(my $AddedTid = $MissedTypedef{$Version}{$ParamTypeId}{"Tid"}) {
4766                $ParamTypeId = $AddedTid;
4767            }
4768        }
4769        my $PType = $TypeInfo{$Version}{$ParamTypeId}{"Type"};
4770        if(not $PType or $PType eq "Unknown") {
4771            return 1;
4772        }
4773        my $PTName = $TypeInfo{$Version}{$ParamTypeId}{"Name"};
4774        if(not $PTName) {
4775            return 1;
4776        }
4777        if($PTName eq "void") {
4778            last;
4779        }
4780        if($ParamName eq "__vtt_parm"
4781        and $TypeInfo{$Version}{$ParamTypeId}{"Name"} eq "void const**")
4782        {
4783            $Vtt_Pos = $Pos;
4784            $ParamInfoId = getNextElem($ParamInfoId);
4785            next;
4786        }
4787        $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"type"} = $ParamTypeId;
4788        $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"name"} = $ParamName;
4789        if(my $Algn = getAlgn($ParamInfoId)) {
4790            $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"algn"} = $Algn/$BYTE_SIZE;
4791        }
4792        if(not $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"name"}) {
4793            $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"name"} = "p".($Pos+1);
4794        }
4795        if($LibInfo{$Version}{"info"}{$ParamInfoId}=~/spec:\s*register /)
4796        { # foo(register type arg)
4797            $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"reg"} = 1;
4798        }
4799        $ParamInfoId = getNextElem($ParamInfoId);
4800        $Pos += 1;
4801    }
4802    if(setFuncArgs($InfoId, $Vtt_Pos)) {
4803        $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"type"} = -1;
4804    }
4805    return 0;
4806}
4807
4808sub setFuncArgs($$)
4809{
4810    my ($InfoId, $Vtt_Pos) = @_;
4811    my $FuncTypeId = getFuncTypeId($InfoId);
4812    my $ParamListElemId = getTreeAttr_Prms($FuncTypeId);
4813    if(getFuncType($InfoId) eq "Method") {
4814        $ParamListElemId = getNextElem($ParamListElemId);
4815    }
4816    if(not $ParamListElemId)
4817    { # foo(...)
4818        return 1;
4819    }
4820    my $HaveVoid = 0;
4821    my $Pos = 0;
4822    while($ParamListElemId)
4823    { # actual params: may differ from formal args
4824      # formal int*const
4825      # actual: int*
4826        if($Vtt_Pos!=-1 and $Pos==$Vtt_Pos)
4827        {
4828            $Vtt_Pos=-1;
4829            $ParamListElemId = getNextElem($ParamListElemId);
4830            next;
4831        }
4832        my $ParamTypeId = getTreeAttr_Valu($ParamListElemId);
4833        if($TypeInfo{$Version}{$ParamTypeId}{"Name"} eq "void")
4834        {
4835            $HaveVoid = 1;
4836            last;
4837        }
4838        elsif(not defined $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"type"})
4839        {
4840            $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"type"} = $ParamTypeId;
4841            if(not $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"name"})
4842            { # unnamed
4843                $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"name"} = "p".($Pos+1);
4844            }
4845        }
4846        if(my $PurpId = getTreeAttr_Purp($ParamListElemId))
4847        { # default arguments
4848            if(my $PurpType = $LibInfo{$Version}{"info_type"}{$PurpId}) {
4849                $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"default"} = getInitVal($PurpId, $ParamTypeId);
4850            }
4851        }
4852        $ParamListElemId = getNextElem($ParamListElemId);
4853        $Pos += 1;
4854    }
4855    return ($Pos>=1 and not $HaveVoid);
4856}
4857
4858sub getTreeAttr_Chan($)
4859{
4860    if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
4861    {
4862        if($Info=~/chan[ ]*:[ ]*@(\d+) /) {
4863            return $1;
4864        }
4865    }
4866    return "";
4867}
4868
4869sub getTreeAttr_Chain($)
4870{
4871    if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
4872    {
4873        if($Info=~/chain[ ]*:[ ]*@(\d+) /) {
4874            return $1;
4875        }
4876    }
4877    return "";
4878}
4879
4880sub getTreeAttr_Scpe($)
4881{
4882    if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
4883    {
4884        if($Info=~/scpe[ ]*:[ ]*@(\d+) /) {
4885            return $1;
4886        }
4887    }
4888    return "";
4889}
4890
4891sub getTreeAttr_Type($)
4892{
4893    if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
4894    {
4895        if($Info=~/type[ ]*:[ ]*@(\d+) /) {
4896            return $1;
4897        }
4898    }
4899    return "";
4900}
4901
4902sub getTreeAttr_Name($)
4903{
4904    if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
4905    {
4906        if($Info=~/name[ ]*:[ ]*@(\d+) /) {
4907            return $1;
4908        }
4909    }
4910    return "";
4911}
4912
4913sub getTreeAttr_Mngl($)
4914{
4915    if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
4916    {
4917        if($Info=~/mngl[ ]*:[ ]*@(\d+) /) {
4918            return $1;
4919        }
4920    }
4921    return "";
4922}
4923
4924sub getTreeAttr_Prms($)
4925{
4926    if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
4927    {
4928        if($Info=~/prms[ ]*:[ ]*@(\d+) /) {
4929            return $1;
4930        }
4931    }
4932    return "";
4933}
4934
4935sub getTreeAttr_Fncs($)
4936{
4937    if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
4938    {
4939        if($Info=~/fncs[ ]*:[ ]*@(\d+) /) {
4940            return $1;
4941        }
4942    }
4943    return "";
4944}
4945
4946sub getTreeAttr_Csts($)
4947{
4948    if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
4949    {
4950        if($Info=~/csts[ ]*:[ ]*@(\d+) /) {
4951            return $1;
4952        }
4953    }
4954    return "";
4955}
4956
4957sub getTreeAttr_Purp($)
4958{
4959    if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
4960    {
4961        if($Info=~/purp[ ]*:[ ]*@(\d+) /) {
4962            return $1;
4963        }
4964    }
4965    return "";
4966}
4967
4968sub getTreeAttr_Valu($)
4969{
4970    if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
4971    {
4972        if($Info=~/valu[ ]*:[ ]*@(\d+) /) {
4973            return $1;
4974        }
4975    }
4976    return "";
4977}
4978
4979sub getTreeAttr_Flds($)
4980{
4981    if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
4982    {
4983        if($Info=~/flds[ ]*:[ ]*@(\d+) /) {
4984            return $1;
4985        }
4986    }
4987    return "";
4988}
4989
4990sub getTreeAttr_Args($)
4991{
4992    if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
4993    {
4994        if($Info=~/args[ ]*:[ ]*@(\d+) /) {
4995            return $1;
4996        }
4997    }
4998    return "";
4999}
5000
5001sub getTreeValue($)
5002{
5003    if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5004    {
5005        if($Info=~/low[ ]*:[ ]*([^ ]+) /) {
5006            return $1;
5007        }
5008    }
5009    return "";
5010}
5011
5012sub getTreeAccess($)
5013{
5014    if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5015    {
5016        if($Info=~/accs[ ]*:[ ]*([a-zA-Z]+) /)
5017        {
5018            my $Access = $1;
5019            if($Access eq "prot") {
5020                return "protected";
5021            }
5022            elsif($Access eq "priv") {
5023                return "private";
5024            }
5025        }
5026        elsif($Info=~/ protected /)
5027        { # support for old GCC versions
5028            return "protected";
5029        }
5030        elsif($Info=~/ private /)
5031        { # support for old GCC versions
5032            return "private";
5033        }
5034    }
5035    return "public";
5036}
5037
5038sub setFuncAccess($)
5039{
5040    my $Access = getTreeAccess($_[0]);
5041    if($Access eq "protected") {
5042        $SymbolInfo{$Version}{$_[0]}{"Protected"} = 1;
5043    }
5044    elsif($Access eq "private") {
5045        $SymbolInfo{$Version}{$_[0]}{"Private"} = 1;
5046    }
5047}
5048
5049sub setTypeAccess($$)
5050{
5051    my ($TypeId, $TypeAttr) = @_;
5052    my $Access = getTreeAccess($TypeId);
5053    if($Access eq "protected") {
5054        $TypeAttr->{"Protected"} = 1;
5055    }
5056    elsif($Access eq "private") {
5057        $TypeAttr->{"Private"} = 1;
5058    }
5059}
5060
5061sub setFuncKind($)
5062{
5063    if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5064    {
5065        if($Info=~/pseudo tmpl/) {
5066            $SymbolInfo{$Version}{$_[0]}{"PseudoTemplate"} = 1;
5067        }
5068        elsif($Info=~/ constructor /) {
5069            $SymbolInfo{$Version}{$_[0]}{"Constructor"} = 1;
5070        }
5071        elsif($Info=~/ destructor /) {
5072            $SymbolInfo{$Version}{$_[0]}{"Destructor"} = 1;
5073        }
5074    }
5075}
5076
5077sub getVirtSpec($)
5078{
5079    if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5080    {
5081        if($Info=~/spec[ ]*:[ ]*pure /) {
5082            return "PureVirt";
5083        }
5084        elsif($Info=~/spec[ ]*:[ ]*virt /) {
5085            return "Virt";
5086        }
5087        elsif($Info=~/ pure\s+virtual /)
5088        { # support for old GCC versions
5089            return "PureVirt";
5090        }
5091        elsif($Info=~/ virtual /)
5092        { # support for old GCC versions
5093            return "Virt";
5094        }
5095    }
5096    return "";
5097}
5098
5099sub getFuncLink($)
5100{
5101    if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5102    {
5103        if($Info=~/link[ ]*:[ ]*static /) {
5104            return "Static";
5105        }
5106        elsif($Info=~/link[ ]*:[ ]*([a-zA-Z]+) /) {
5107            return $1;
5108        }
5109    }
5110    return "";
5111}
5112
5113sub get_IntNameSpace($$)
5114{
5115    my ($Interface, $LibVersion) = @_;
5116    return "" if(not $Interface or not $LibVersion);
5117    if(defined $Cache{"get_IntNameSpace"}{$Interface}{$LibVersion}) {
5118        return $Cache{"get_IntNameSpace"}{$Interface}{$LibVersion};
5119    }
5120    my $Signature = get_Signature($Interface, $LibVersion);
5121    if($Signature=~/\:\:/)
5122    {
5123        my $FounNameSpace = 0;
5124        foreach my $NameSpace (sort {get_depth($b)<=>get_depth($a)} keys(%{$NestedNameSpaces{$LibVersion}}))
5125        {
5126            if($Signature=~/(\A|\s+for\s+)\Q$NameSpace\E\:\:/) {
5127                return ($Cache{"get_IntNameSpace"}{$Interface}{$LibVersion} = $NameSpace);
5128            }
5129        }
5130    }
5131    else {
5132        return ($Cache{"get_IntNameSpace"}{$Interface}{$LibVersion} = "");
5133    }
5134}
5135
5136sub parse_TypeNameSpace($$)
5137{
5138    my ($TypeName, $LibVersion) = @_;
5139    return "" if(not $TypeName or not $LibVersion);
5140    if(defined $Cache{"parse_TypeNameSpace"}{$TypeName}{$LibVersion}) {
5141        return $Cache{"parse_TypeNameSpace"}{$TypeName}{$LibVersion};
5142    }
5143    if($TypeName=~/\:\:/)
5144    {
5145        my $FounNameSpace = 0;
5146        foreach my $NameSpace (sort {get_depth($b)<=>get_depth($a)} keys(%{$NestedNameSpaces{$LibVersion}}))
5147        {
5148            if($TypeName=~/\A\Q$NameSpace\E\:\:/) {
5149                return ($Cache{"parse_TypeNameSpace"}{$TypeName}{$LibVersion} = $NameSpace);
5150            }
5151        }
5152    }
5153    else {
5154        return ($Cache{"parse_TypeNameSpace"}{$TypeName}{$LibVersion} = "");
5155    }
5156}
5157
5158sub getNameSpace($)
5159{
5160    my $TypeInfoId = $_[0];
5161    if(my $NSInfoId = getTreeAttr_Scpe($TypeInfoId))
5162    {
5163        if(my $InfoType = $LibInfo{$Version}{"info_type"}{$NSInfoId})
5164        {
5165            if($InfoType eq "namespace_decl")
5166            {
5167                if($LibInfo{$Version}{"info"}{$NSInfoId}=~/name[ ]*:[ ]*@(\d+) /)
5168                {
5169                    my $NameSpace = getTreeStr($1);
5170                    if($NameSpace eq "::")
5171                    { # global namespace
5172                        return "";
5173                    }
5174                    if(my $BaseNameSpace = getNameSpace($NSInfoId)) {
5175                        $NameSpace = $BaseNameSpace."::".$NameSpace;
5176                    }
5177                    $NestedNameSpaces{$Version}{$NameSpace} = 1;
5178                    return $NameSpace;
5179                }
5180                else {
5181                    return "";
5182                }
5183            }
5184            elsif($InfoType eq "record_type")
5185            { # inside data type
5186                my ($Name, $NameNS) = getTrivialName(getTypeDeclId($NSInfoId), $NSInfoId);
5187                return $Name;
5188            }
5189        }
5190    }
5191    return "";
5192}
5193
5194sub getNameSpaceId($)
5195{
5196    if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5197    {
5198        if($Info=~/scpe[ ]*:[ ]*\@(\d+)/) {
5199            return $1;
5200        }
5201    }
5202    return "";
5203}
5204
5205sub getStructMembName($)
5206{
5207    if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5208    {
5209        if($Info=~/name[ ]*:[ ]*\@(\d+)/) {
5210            return getTreeStr($1);
5211        }
5212    }
5213    return "";
5214}
5215
5216sub getEnumMembVal($)
5217{
5218    if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5219    {
5220        if($Info=~/valu[ ]*:[ ]*\@(\d+)/)
5221        {
5222            if(my $VInfo = $LibInfo{$Version}{"info"}{$1})
5223            {
5224                if($VInfo=~/cnst[ ]*:[ ]*\@(\d+)/)
5225                { # in newer versions of GCC the value is in the "const_decl->cnst" node
5226                    return getTreeValue($1);
5227                }
5228                else
5229                { # some old versions of GCC (3.3) have the value in the "integer_cst" node
5230                    return getTreeValue($1);
5231                }
5232            }
5233        }
5234    }
5235    return "";
5236}
5237
5238sub getSize($)
5239{
5240    if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5241    {
5242        if($Info=~/size[ ]*:[ ]*\@(\d+)/) {
5243            return getTreeValue($1);
5244        }
5245    }
5246    return 0;
5247}
5248
5249sub getAlgn($)
5250{
5251    if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5252    {
5253        if($Info=~/algn[ ]*:[ ]*(\d+) /) {
5254            return $1;
5255        }
5256    }
5257    return "";
5258}
5259
5260sub getStructMembBitFieldSize($)
5261{
5262    if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5263    {
5264        if($Info=~/ bitfield /) {
5265            return getSize($_[0]);
5266        }
5267    }
5268    return 0;
5269}
5270
5271sub getNextElem($)
5272{
5273    if(my $Chan = getTreeAttr_Chan($_[0])) {
5274        return $Chan;
5275    }
5276    elsif(my $Chain = getTreeAttr_Chain($_[0])) {
5277        return $Chain;
5278    }
5279    return "";
5280}
5281
5282sub registerHeader($$)
5283{ # input: absolute path of header, relative path or name
5284    my ($Header, $LibVersion) = @_;
5285    if(not $Header) {
5286        return "";
5287    }
5288    if(is_abs($Header) and not -f $Header)
5289    { # incorrect absolute path
5290        exitStatus("Access_Error", "can't access \'$Header\'");
5291    }
5292    if(skipHeader($Header, $LibVersion))
5293    { # skip
5294        return "";
5295    }
5296    if(my $Header_Path = identifyHeader($Header, $LibVersion))
5297    {
5298        detect_header_includes($Header_Path, $LibVersion);
5299
5300        if(my $RHeader_Path = $Header_ErrorRedirect{$LibVersion}{$Header_Path})
5301        { # redirect
5302            if($Registered_Headers{$LibVersion}{$RHeader_Path}{"Identity"}
5303            or skipHeader($RHeader_Path, $LibVersion))
5304            { # skip
5305                return "";
5306            }
5307            $Header_Path = $RHeader_Path;
5308        }
5309        elsif($Header_ShouldNotBeUsed{$LibVersion}{$Header_Path})
5310        { # skip
5311            return "";
5312        }
5313
5314        if(my $HName = get_filename($Header_Path))
5315        { # register
5316            $Registered_Headers{$LibVersion}{$Header_Path}{"Identity"} = $HName;
5317            $HeaderName_Paths{$LibVersion}{$HName}{$Header_Path} = 1;
5318        }
5319
5320        if(($Header=~/\.(\w+)\Z/ and $1 ne "h")
5321        or $Header!~/\.(\w+)\Z/)
5322        { # hpp, hh
5323            setLanguage($LibVersion, "C++");
5324        }
5325
5326        if($CheckHeadersOnly
5327        and $Header=~/(\A|\/)c\+\+(\/|\Z)/)
5328        { # /usr/include/c++/4.6.1/...
5329            $STDCXX_TESTING = 1;
5330        }
5331
5332        return $Header_Path;
5333    }
5334    return "";
5335}
5336
5337sub register_directory($$$)
5338{
5339    my ($Dir, $WithDeps, $LibVersion) = @_;
5340    $Dir=~s/[\/\\]+\Z//g;
5341    return if(not $LibVersion or not $Dir or not -d $Dir);
5342    return if(skipHeader($Dir, $LibVersion));
5343    $Dir = get_abs_path($Dir);
5344    my $Mode = "All";
5345    if($WithDeps)
5346    {
5347        if($RegisteredDirs{$LibVersion}{$Dir}{1}) {
5348            return;
5349        }
5350        elsif($RegisteredDirs{$LibVersion}{$Dir}{0}) {
5351            $Mode = "DepsOnly";
5352        }
5353    }
5354    else
5355    {
5356        if($RegisteredDirs{$LibVersion}{$Dir}{1}
5357        or $RegisteredDirs{$LibVersion}{$Dir}{0}) {
5358            return;
5359        }
5360    }
5361    $Header_Dependency{$LibVersion}{$Dir} = 1;
5362    $RegisteredDirs{$LibVersion}{$Dir}{$WithDeps} = 1;
5363    if($Mode eq "DepsOnly")
5364    {
5365        foreach my $Path (cmd_find($Dir,"d","","")) {
5366            $Header_Dependency{$LibVersion}{$Path} = 1;
5367        }
5368        return;
5369    }
5370    foreach my $Path (sort {length($b)<=>length($a)} cmd_find($Dir,"f","",""))
5371    {
5372        if($WithDeps)
5373        {
5374            my $SubDir = $Path;
5375            while(($SubDir = get_dirname($SubDir)) ne $Dir)
5376            { # register all sub directories
5377                $Header_Dependency{$LibVersion}{$SubDir} = 1;
5378            }
5379        }
5380        next if(is_not_header($Path));
5381        next if(ignore_path($Path));
5382        next if(skipHeader($Path, $LibVersion));
5383        # Neighbors
5384        foreach my $Part (get_path_prefixes($Path)) {
5385            $Include_Neighbors{$LibVersion}{$Part} = $Path;
5386        }
5387    }
5388    if(get_filename($Dir) eq "include")
5389    { # search for "lib/include/" directory
5390        my $LibDir = $Dir;
5391        if($LibDir=~s/([\/\\])include\Z/$1lib/g and -d $LibDir) {
5392            register_directory($LibDir, $WithDeps, $LibVersion);
5393        }
5394    }
5395}
5396
5397sub parse_redirect($$$)
5398{
5399    my ($Content, $Path, $LibVersion) = @_;
5400    my @Errors = ();
5401    while($Content=~s/#\s*error\s+([^\n]+?)\s*(\n|\Z)//) {
5402        push(@Errors, $1);
5403    }
5404    my $Redirect = "";
5405    foreach (@Errors)
5406    {
5407        s/\s{2,}/ /g;
5408        if(/(only|must\ include
5409        |update\ to\ include
5410        |replaced\ with
5411        |replaced\ by|renamed\ to
5412        |is\ in|use)\ (<[^<>]+>|[\w\-\/\\]+\.($HEADER_EXT))/ix)
5413        {
5414            $Redirect = $2;
5415            last;
5416        }
5417        elsif(/(include|use|is\ in)\ (<[^<>]+>|[\w\-\/\\]+\.($HEADER_EXT))\ instead/i)
5418        {
5419            $Redirect = $2;
5420            last;
5421        }
5422        elsif(/this\ header\ should\ not\ be\ used
5423         |programs\ should\ not\ directly\ include
5424         |you\ should\ not\ (include|be\ (including|using)\ this\ (file|header))
5425         |is\ not\ supported\ API\ for\ general\ use
5426         |do\ not\ use
5427         |should\ not\ be\ used
5428         |cannot\ be\ included\ directly/ix and not /\ from\ /i) {
5429            $Header_ShouldNotBeUsed{$LibVersion}{$Path} = 1;
5430        }
5431    }
5432    if($Redirect)
5433    {
5434        $Redirect=~s/\A<//g;
5435        $Redirect=~s/>\Z//g;
5436    }
5437    return $Redirect;
5438}
5439
5440sub parse_includes($$)
5441{
5442    my ($Content, $Path) = @_;
5443    my %Includes = ();
5444    while($Content=~s/#([ \t]*)(include|include_next|import)([ \t]*)(<|")([^<>"]+)(>|")//)
5445    { # C/C++: include, Objective C/C++: import directive
5446        my ($Header, $Method) = ($5, $4);
5447        $Header = path_format($Header, $OSgroup);
5448        if($Method eq "\"" or is_abs($Header))
5449        {
5450            if(-e joinPath(get_dirname($Path), $Header))
5451            { # relative path exists
5452                $Includes{$Header} = -1;
5453            }
5454            else
5455            { # include "..." that doesn't exist is equal to include <...>
5456                $Includes{$Header} = 2;
5457            }
5458        }
5459        else {
5460            $Includes{$Header} = 1;
5461        }
5462    }
5463    return \%Includes;
5464}
5465
5466sub ignore_path($)
5467{
5468    my $Path = $_[0];
5469    if($Path=~/\~\Z/)
5470    {# skipping system backup files
5471        return 1;
5472    }
5473    if($Path=~/(\A|[\/\\]+)(\.(svn|git|bzr|hg)|CVS)([\/\\]+|\Z)/)
5474    {# skipping hidden .svn, .git, .bzr, .hg and CVS directories
5475        return 1;
5476    }
5477    return 0;
5478}
5479
5480sub sort_by_word($$)
5481{
5482    my ($ArrRef, $W) = @_;
5483    return if(length($W)<2);
5484    @{$ArrRef} = sort {get_filename($b)=~/\Q$W\E/i<=>get_filename($a)=~/\Q$W\E/i} @{$ArrRef};
5485}
5486
5487sub natural_sorting($$)
5488{
5489    my ($H1, $H2) = @_;
5490    $H1=~s/\.[a-z]+\Z//ig;
5491    $H2=~s/\.[a-z]+\Z//ig;
5492    my ($HDir1, $Hname1) = separate_path($H1);
5493    my ($HDir2, $Hname2) = separate_path($H2);
5494    my $Dirname1 = get_filename($HDir1);
5495    my $Dirname2 = get_filename($HDir2);
5496    if($H1 eq $H2) {
5497        return 0;
5498    }
5499    elsif($H1=~/\A\Q$H2\E/) {
5500        return 1;
5501    }
5502    elsif($H2=~/\A\Q$H1\E/) {
5503        return -1;
5504    }
5505    elsif($HDir1=~/\Q$Hname1\E/i
5506    and $HDir2!~/\Q$Hname2\E/i)
5507    {# include/glib-2.0/glib.h
5508        return -1;
5509    }
5510    elsif($HDir2=~/\Q$Hname2\E/i
5511    and $HDir1!~/\Q$Hname1\E/i)
5512    {# include/glib-2.0/glib.h
5513        return 1;
5514    }
5515    elsif($Hname1=~/\Q$Dirname1\E/i
5516    and $Hname2!~/\Q$Dirname2\E/i)
5517    {# include/hildon-thumbnail/hildon-thumbnail-factory.h
5518        return -1;
5519    }
5520    elsif($Hname2=~/\Q$Dirname2\E/i
5521    and $Hname1!~/\Q$Dirname1\E/i)
5522    {# include/hildon-thumbnail/hildon-thumbnail-factory.h
5523        return 1;
5524    }
5525    elsif($Hname1=~/(config|lib)/i
5526    and $Hname2!~/(config|lib)/i)
5527    {# include/alsa/asoundlib.h
5528        return -1;
5529    }
5530    elsif($Hname2=~/(config|lib)/i
5531    and $Hname1!~/(config|lib)/i)
5532    {# include/alsa/asoundlib.h
5533        return 1;
5534    }
5535    elsif(checkRelevance($H1)
5536    and not checkRelevance($H2))
5537    {# libebook/e-book.h
5538        return -1;
5539    }
5540    elsif(checkRelevance($H2)
5541    and not checkRelevance($H1))
5542    {# libebook/e-book.h
5543        return 1;
5544    }
5545    else {
5546        return (lc($H1) cmp lc($H2));
5547    }
5548}
5549
5550sub searchForHeaders($)
5551{
5552    my $LibVersion = $_[0];
5553    # gcc standard include paths
5554    find_gcc_cxx_headers($LibVersion);
5555    # processing header paths
5556    foreach my $Path (keys(%{$Descriptor{$LibVersion}{"IncludePaths"}}),
5557    keys(%{$Descriptor{$LibVersion}{"AddIncludePaths"}}))
5558    {
5559        my $IPath = $Path;
5560        if($SystemRoot)
5561        {
5562            if(is_abs($Path)) {
5563                $Path = $SystemRoot.$Path;
5564            }
5565        }
5566        if(not -e $Path) {
5567            exitStatus("Access_Error", "can't access \'$Path\'");
5568        }
5569        elsif(-f $Path) {
5570            exitStatus("Access_Error", "\'$Path\' - not a directory");
5571        }
5572        elsif(-d $Path)
5573        {
5574            $Path = get_abs_path($Path);
5575            register_directory($Path, 0, $LibVersion);
5576            if($Descriptor{$LibVersion}{"AddIncludePaths"}{$IPath}) {
5577                $Add_Include_Paths{$LibVersion}{$Path} = 1;
5578            }
5579            else {
5580                $Include_Paths{$LibVersion}{$Path} = 1;
5581            }
5582        }
5583    }
5584    if(keys(%{$Include_Paths{$LibVersion}})) {
5585        $INC_PATH_AUTODETECT{$LibVersion} = 0;
5586    }
5587    # registering directories
5588    foreach my $Path (split(/\s*\n\s*/, $Descriptor{$LibVersion}{"Headers"}))
5589    {
5590        next if(not -e $Path);
5591        $Path = get_abs_path($Path);
5592        $Path = path_format($Path, $OSgroup);
5593        if(-d $Path) {
5594            register_directory($Path, 1, $LibVersion);
5595        }
5596        elsif(-f $Path)
5597        {
5598            my $Dir = get_dirname($Path);
5599            if(not $SystemPaths{"include"}{$Dir}
5600            and not $LocalIncludes{$Dir})
5601            {
5602                register_directory($Dir, 1, $LibVersion);
5603                if(my $OutDir = get_dirname($Dir))
5604                { # registering the outer directory
5605                    if(not $SystemPaths{"include"}{$OutDir}
5606                    and not $LocalIncludes{$OutDir}) {
5607                        register_directory($OutDir, 0, $LibVersion);
5608                    }
5609                }
5610            }
5611        }
5612    }
5613
5614    # clean memory
5615    %RegisteredDirs = ();
5616
5617    # registering headers
5618    my $Position = 0;
5619    foreach my $Dest (split(/\s*\n\s*/, $Descriptor{$LibVersion}{"Headers"}))
5620    {
5621        if(is_abs($Dest) and not -e $Dest) {
5622            exitStatus("Access_Error", "can't access \'$Dest\'");
5623        }
5624        $Dest = path_format($Dest, $OSgroup);
5625        if(is_header($Dest, 1, $LibVersion))
5626        {
5627            if(my $HPath = registerHeader($Dest, $LibVersion)) {
5628                $Registered_Headers{$LibVersion}{$HPath}{"Pos"} = $Position++;
5629            }
5630        }
5631        elsif(-d $Dest)
5632        {
5633            my @Registered = ();
5634            foreach my $Path (cmd_find($Dest,"f","",""))
5635            {
5636                next if(ignore_path($Path));
5637                next if(not is_header($Path, 0, $LibVersion));
5638                if(my $HPath = registerHeader($Path, $LibVersion)) {
5639                    push(@Registered, $HPath);
5640                }
5641            }
5642            @Registered = sort {natural_sorting($a, $b)} @Registered;
5643            sort_by_word(\@Registered, $TargetLibraryShortName);
5644            foreach my $Path (@Registered) {
5645                $Registered_Headers{$LibVersion}{$Path}{"Pos"} = $Position++;
5646            }
5647        }
5648        else {
5649            exitStatus("Access_Error", "can't identify \'$Dest\' as a header file");
5650        }
5651    }
5652    if(my $HList = $Descriptor{$LibVersion}{"IncludePreamble"})
5653    { # preparing preamble headers
5654        my $PPos=0;
5655        foreach my $Header (split(/\s*\n\s*/, $HList))
5656        {
5657            if(is_abs($Header) and not -f $Header) {
5658                exitStatus("Access_Error", "can't access file \'$Header\'");
5659            }
5660            $Header = path_format($Header, $OSgroup);
5661            if(my $Header_Path = is_header($Header, 1, $LibVersion))
5662            {
5663                next if(skipHeader($Header_Path, $LibVersion));
5664                $Include_Preamble{$LibVersion}{$Header_Path}{"Position"} = $PPos++;
5665            }
5666            else {
5667                exitStatus("Access_Error", "can't identify \'$Header\' as a header file");
5668            }
5669        }
5670    }
5671    foreach my $Header_Name (keys(%{$HeaderName_Paths{$LibVersion}}))
5672    { # set relative paths (for duplicates)
5673        if(keys(%{$HeaderName_Paths{$LibVersion}{$Header_Name}})>=2)
5674        { # search for duplicates
5675            my $FirstPath = (keys(%{$HeaderName_Paths{$LibVersion}{$Header_Name}}))[0];
5676            my $Prefix = get_dirname($FirstPath);
5677            while($Prefix=~/\A(.+)[\/\\]+[^\/\\]+\Z/)
5678            { # detect a shortest distinguishing prefix
5679                my $NewPrefix = $1;
5680                my %Identity = ();
5681                foreach my $Path (keys(%{$HeaderName_Paths{$LibVersion}{$Header_Name}}))
5682                {
5683                    if($Path=~/\A\Q$Prefix\E[\/\\]+(.*)\Z/) {
5684                        $Identity{$Path} = $1;
5685                    }
5686                }
5687                if(keys(%Identity)==keys(%{$HeaderName_Paths{$LibVersion}{$Header_Name}}))
5688                { # all names are differend with current prefix
5689                    foreach my $Path (keys(%{$HeaderName_Paths{$LibVersion}{$Header_Name}})) {
5690                        $Registered_Headers{$LibVersion}{$Path}{"Identity"} = $Identity{$Path};
5691                    }
5692                    last;
5693                }
5694                $Prefix = $NewPrefix; # increase prefix
5695            }
5696        }
5697    }
5698
5699    # clean memory
5700    %HeaderName_Paths = ();
5701
5702    foreach my $HeaderName (keys(%{$Include_Order{$LibVersion}}))
5703    { # ordering headers according to descriptor
5704        my $PairName=$Include_Order{$LibVersion}{$HeaderName};
5705        my ($Pos, $PairPos) = (-1, -1);
5706        my ($Path, $PairPath) = ();
5707        my @Paths = keys(%{$Registered_Headers{$LibVersion}});
5708        @Paths = sort {int($Registered_Headers{$LibVersion}{$a}{"Pos"})<=>int($Registered_Headers{$LibVersion}{$b}{"Pos"})} @Paths;
5709        foreach my $Header_Path (@Paths)
5710        {
5711            if(get_filename($Header_Path) eq $PairName)
5712            {
5713                $PairPos = $Registered_Headers{$LibVersion}{$Header_Path}{"Pos"};
5714                $PairPath = $Header_Path;
5715            }
5716            if(get_filename($Header_Path) eq $HeaderName)
5717            {
5718                $Pos = $Registered_Headers{$LibVersion}{$Header_Path}{"Pos"};
5719                $Path = $Header_Path;
5720            }
5721        }
5722        if($PairPos!=-1 and $Pos!=-1
5723        and int($PairPos)<int($Pos))
5724        {
5725            my %Tmp = %{$Registered_Headers{$LibVersion}{$Path}};
5726            %{$Registered_Headers{$LibVersion}{$Path}} = %{$Registered_Headers{$LibVersion}{$PairPath}};
5727            %{$Registered_Headers{$LibVersion}{$PairPath}} = %Tmp;
5728        }
5729    }
5730    if(not keys(%{$Registered_Headers{$LibVersion}})) {
5731        exitStatus("Error", "header files are not found in the ".$Descriptor{$LibVersion}{"Version"});
5732    }
5733}
5734
5735sub detect_real_includes($$)
5736{
5737    my ($AbsPath, $LibVersion) = @_;
5738    return () if(not $LibVersion or not $AbsPath or not -e $AbsPath);
5739    if($Cache{"detect_real_includes"}{$LibVersion}{$AbsPath}
5740    or keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}})) {
5741        return keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}});
5742    }
5743    $Cache{"detect_real_includes"}{$LibVersion}{$AbsPath}=1;
5744
5745    my $Path = callPreprocessor($AbsPath, "", $LibVersion);
5746    return () if(not $Path);
5747    open(PREPROC, $Path);
5748    while(<PREPROC>)
5749    {
5750        if(/#\s+\d+\s+"([^"]+)"[\s\d]*\n/)
5751        {
5752            my $Include = path_format($1, $OSgroup);
5753            if($Include=~/\<(built\-in|internal|command(\-|\s)line)\>|\A\./) {
5754                next;
5755            }
5756            if($Include eq $AbsPath) {
5757                next;
5758            }
5759            $RecursiveIncludes{$LibVersion}{$AbsPath}{$Include} = 1;
5760        }
5761    }
5762    close(PREPROC);
5763    return keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}});
5764}
5765
5766sub detect_header_includes($$)
5767{
5768    my ($Path, $LibVersion) = @_;
5769    return if(not $LibVersion or not $Path);
5770    if(defined $Cache{"detect_header_includes"}{$LibVersion}{$Path}) {
5771        return;
5772    }
5773    $Cache{"detect_header_includes"}{$LibVersion}{$Path}=1;
5774
5775    if(not -e $Path) {
5776        return;
5777    }
5778
5779    my $Content = readFile($Path);
5780    if(my $Redirect = parse_redirect($Content, $Path, $LibVersion))
5781    { # detect error directive in headers
5782        if(my $RedirectPath = identifyHeader($Redirect, $LibVersion))
5783        {
5784            if($RedirectPath=~/\/usr\/include\// and $Path!~/\/usr\/include\//) {
5785                $RedirectPath = identifyHeader(get_filename($Redirect), $LibVersion);
5786            }
5787            if($RedirectPath ne $Path) {
5788                $Header_ErrorRedirect{$LibVersion}{$Path} = $RedirectPath;
5789            }
5790        }
5791    }
5792    if(my $Inc = parse_includes($Content, $Path))
5793    {
5794        foreach my $Include (keys(%{$Inc}))
5795        { # detect includes
5796            $Header_Includes{$LibVersion}{$Path}{$Include} = $Inc->{$Include};
5797        }
5798    }
5799}
5800
5801sub simplify_path($)
5802{
5803    my $Path = $_[0];
5804    while($Path=~s&([\/\\])[^\/\\]+[\/\\]\.\.[\/\\]&$1&){};
5805    return $Path;
5806}
5807
5808sub fromLibc($)
5809{ # GLIBC header
5810    my $Path = $_[0];
5811    my ($Dir, $Name) = separate_path($Path);
5812    if(get_filename($Dir)=~/\A(include|libc)\Z/ and $GlibcHeader{$Name})
5813    { # /usr/include/{stdio, ...}.h
5814      # epoc32/include/libc/{stdio, ...}.h
5815        return 1;
5816    }
5817    if(isLibcDir($Dir)) {
5818        return 1;
5819    }
5820    return 0;
5821}
5822
5823sub isLibcDir($)
5824{ # GLIBC directory
5825    my $Dir = $_[0];
5826    my ($OutDir, $Name) = separate_path($Dir);
5827    if(get_filename($OutDir)=~/\A(include|libc)\Z/
5828    and ($Name=~/\Aasm(|-.+)\Z/ or $GlibcDir{$Name}))
5829    { # /usr/include/{sys,bits,asm,asm-*}/*.h
5830        return 1;
5831    }
5832    return 0;
5833}
5834
5835sub detect_recursive_includes($$)
5836{
5837    my ($AbsPath, $LibVersion) = @_;
5838    return () if(not $AbsPath);
5839    if(isCyclical(\@RecurInclude, $AbsPath)) {
5840        return keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}});
5841    }
5842    my ($AbsDir, $Name) = separate_path($AbsPath);
5843    if(isLibcDir($AbsDir))
5844    { # GLIBC internals
5845        return ();
5846    }
5847    if(keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}})) {
5848        return keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}});
5849    }
5850    return () if($OSgroup ne "windows" and $Name=~/windows|win32|win64/i);
5851    return () if($MAIN_CPP_DIR and $AbsPath=~/\A\Q$MAIN_CPP_DIR\E/ and not $STDCXX_TESTING);
5852    push(@RecurInclude, $AbsPath);
5853    if($DefaultGccPaths{$AbsDir}
5854    or fromLibc($AbsPath))
5855    { # check "real" (non-"model") include paths
5856        my @Paths = detect_real_includes($AbsPath, $LibVersion);
5857        pop(@RecurInclude);
5858        return @Paths;
5859    }
5860    if(not keys(%{$Header_Includes{$LibVersion}{$AbsPath}})) {
5861        detect_header_includes($AbsPath, $LibVersion);
5862    }
5863    foreach my $Include (keys(%{$Header_Includes{$LibVersion}{$AbsPath}}))
5864    {
5865        my $IncType = $Header_Includes{$LibVersion}{$AbsPath}{$Include};
5866        my $HPath = "";
5867        if($IncType<0)
5868        { # for #include "..."
5869            my $Candidate = joinPath($AbsDir, $Include);
5870            if(-f $Candidate) {
5871                $HPath = simplify_path($Candidate);
5872            }
5873        }
5874        elsif($IncType>0
5875        and $Include=~/[\/\\]/) # and not find_in_defaults($Include)
5876        { # search for the nearest header
5877          # QtCore/qabstractanimation.h includes <QtCore/qobject.h>
5878            my $Candidate = joinPath(get_dirname($AbsDir), $Include);
5879            if(-f $Candidate) {
5880                $HPath = $Candidate;
5881            }
5882        }
5883        if(not $HPath) {
5884            $HPath = identifyHeader($Include, $LibVersion);
5885        }
5886        next if(not $HPath);
5887        if($HPath eq $AbsPath) {
5888            next;
5889        }
5890        $RecursiveIncludes{$LibVersion}{$AbsPath}{$HPath} = $IncType;
5891        if($IncType>0)
5892        { # only include <...>, skip include "..." prefixes
5893            $Header_Include_Prefix{$LibVersion}{$AbsPath}{$HPath}{get_dirname($Include)} = 1;
5894        }
5895        foreach my $IncPath (detect_recursive_includes($HPath, $LibVersion))
5896        {
5897            if($IncPath eq $AbsPath) {
5898                next;
5899            }
5900            my $RIncType = $RecursiveIncludes{$LibVersion}{$HPath}{$IncPath};
5901            if($RIncType==-1)
5902            { # include "..."
5903                $RIncType = $IncType;
5904            }
5905            elsif($RIncType==2)
5906            {
5907                if($IncType!=-1) {
5908                    $RIncType = $IncType;
5909                }
5910            }
5911            $RecursiveIncludes{$LibVersion}{$AbsPath}{$IncPath} = $RIncType;
5912            foreach my $Prefix (keys(%{$Header_Include_Prefix{$LibVersion}{$HPath}{$IncPath}})) {
5913                $Header_Include_Prefix{$LibVersion}{$AbsPath}{$IncPath}{$Prefix} = 1;
5914            }
5915        }
5916        foreach my $Dep (keys(%{$Header_Include_Prefix{$LibVersion}{$AbsPath}}))
5917        {
5918            if($GlibcHeader{get_filename($Dep)} and keys(%{$Header_Include_Prefix{$LibVersion}{$AbsPath}{$Dep}})>=2
5919            and defined $Header_Include_Prefix{$LibVersion}{$AbsPath}{$Dep}{""})
5920            { # distinguish math.h from glibc and math.h from the tested library
5921                delete($Header_Include_Prefix{$LibVersion}{$AbsPath}{$Dep}{""});
5922                last;
5923            }
5924        }
5925    }
5926    pop(@RecurInclude);
5927    return keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}});
5928}
5929
5930sub find_in_framework($$$)
5931{
5932    my ($Header, $Framework, $LibVersion) = @_;
5933    return "" if(not $Header or not $Framework or not $LibVersion);
5934    if(defined $Cache{"find_in_framework"}{$LibVersion}{$Framework}{$Header}) {
5935        return $Cache{"find_in_framework"}{$LibVersion}{$Framework}{$Header};
5936    }
5937    foreach my $Dependency (sort {get_depth($a)<=>get_depth($b)} keys(%{$Header_Dependency{$LibVersion}}))
5938    {
5939        if(get_filename($Dependency) eq $Framework
5940        and -f get_dirname($Dependency)."/".$Header) {
5941            return ($Cache{"find_in_framework"}{$LibVersion}{$Framework}{$Header} = get_dirname($Dependency));
5942        }
5943    }
5944    return ($Cache{"find_in_framework"}{$LibVersion}{$Framework}{$Header} = "");
5945}
5946
5947sub find_in_defaults($)
5948{
5949    my $Header = $_[0];
5950    return "" if(not $Header);
5951    if(defined $Cache{"find_in_defaults"}{$Header}) {
5952        return $Cache{"find_in_defaults"}{$Header};
5953    }
5954    foreach my $Dir (sort {get_depth($a)<=>get_depth($b)}
5955    (keys(%DefaultIncPaths), keys(%DefaultGccPaths), keys(%DefaultCppPaths), keys(%UserIncPath)))
5956    {
5957        next if(not $Dir);
5958        if(-f $Dir."/".$Header) {
5959            return ($Cache{"find_in_defaults"}{$Header}=$Dir);
5960        }
5961    }
5962    return ($Cache{"find_in_defaults"}{$Header}="");
5963}
5964
5965sub cmp_paths($$)
5966{
5967    my ($Path1, $Path2) = @_;
5968    my @Parts1 = split(/[\/\\]/, $Path1);
5969    my @Parts2 = split(/[\/\\]/, $Path2);
5970    foreach my $Num (0 .. $#Parts1)
5971    {
5972        my $Part1 = $Parts1[$Num];
5973        my $Part2 = $Parts2[$Num];
5974        if($GlibcDir{$Part1}
5975        and not $GlibcDir{$Part2}) {
5976            return 1;
5977        }
5978        elsif($GlibcDir{$Part2}
5979        and not $GlibcDir{$Part1}) {
5980            return -1;
5981        }
5982        elsif($Part1=~/glib/
5983        and $Part2!~/glib/) {
5984            return 1;
5985        }
5986        elsif($Part1!~/glib/
5987        and $Part2=~/glib/) {
5988            return -1;
5989        }
5990        elsif(my $CmpRes = ($Part1 cmp $Part2)) {
5991            return $CmpRes;
5992        }
5993    }
5994    return 0;
5995}
5996
5997sub checkRelevance($)
5998{
5999    my ($Path) = @_;
6000    return 0 if(not $Path);
6001    if($SystemRoot) {
6002        $Path = cut_path_prefix($Path, $SystemRoot);
6003    }
6004    my ($Dir, $Name) = separate_path($Path);
6005    $Name=~s/\.\w+\Z//g; # remove extension (.h)
6006    my @Tokens = split(/[_\d\W]+/, $Name);
6007    foreach (@Tokens)
6008    {
6009        next if(not $_);
6010        if($Dir=~/(\A|lib|[_\d\W])\Q$_\E([_\d\W]|lib|\Z)/i
6011        or length($_)>=4 and $Dir=~/\Q$_\E/i)
6012        { # include/gupnp-1.0/libgupnp/gupnp-context.h
6013          # include/evolution-data-server-1.4/libebook/e-book.h
6014            return 1;
6015        }
6016    }
6017    return 0;
6018}
6019
6020sub checkFamily(@)
6021{
6022    my @Paths = @_;
6023    return 1 if($#Paths<=0);
6024    my %Prefix = ();
6025    foreach my $Path (@Paths)
6026    {
6027        if($SystemRoot) {
6028            $Path = cut_path_prefix($Path, $SystemRoot);
6029        }
6030        if(my $Dir = get_dirname($Path))
6031        {
6032            $Dir=~s/(\/[^\/]+?)[\d\.\-\_]+\Z/$1/g; # remove version suffix
6033            $Prefix{$Dir} += 1;
6034            $Prefix{get_dirname($Dir)} += 1;
6035        }
6036    }
6037    foreach (sort keys(%Prefix))
6038    {
6039        if(get_depth($_)>=3
6040        and $Prefix{$_}==$#Paths+1) {
6041            return 1;
6042        }
6043    }
6044    return 0;
6045}
6046
6047sub isAcceptable($$$)
6048{
6049    my ($Header, $Candidate, $LibVersion) = @_;
6050    my $HName = get_filename($Header);
6051    if(get_dirname($Header))
6052    { # with prefix
6053        return 1;
6054    }
6055    if($HName=~/config|setup/i and $Candidate=~/[\/\\]lib\d*[\/\\]/)
6056    { # allow to search for glibconfig.h in /usr/lib/glib-2.0/include/
6057        return 1;
6058    }
6059    if(checkRelevance($Candidate))
6060    { # allow to search for atk.h in /usr/include/atk-1.0/atk/
6061        return 1;
6062    }
6063    if(checkFamily(getSystemHeaders($HName, $LibVersion)))
6064    { # /usr/include/qt4/QtNetwork/qsslconfiguration.h
6065      # /usr/include/qt4/Qt/qsslconfiguration.h
6066        return 1;
6067    }
6068    if($OStarget eq "symbian")
6069    {
6070        if($Candidate=~/[\/\\]stdapis[\/\\]/) {
6071            return 1;
6072        }
6073    }
6074    return 0;
6075}
6076
6077sub isRelevant($$$)
6078{ # disallow to search for "abstract" headers in too deep directories
6079    my ($Header, $Candidate, $LibVersion) = @_;
6080    my $HName = get_filename($Header);
6081    if($OStarget eq "symbian")
6082    {
6083        if($Candidate=~/[\/\\](tools|stlportv5)[\/\\]/) {
6084            return 0;
6085        }
6086    }
6087    if($OStarget ne "bsd") {
6088        if($Candidate=~/[\/\\]include[\/\\]bsd[\/\\]/)
6089        { # openssh: skip /usr/lib/bcc/include/bsd/signal.h
6090            return 0;
6091        }
6092    }
6093    if(not get_dirname($Header)
6094    and $Candidate=~/[\/\\]wx[\/\\]/)
6095    { # do NOT search in system /wx/ directory
6096      # for headers without a prefix: sstream.h
6097        return 0;
6098    }
6099    if($Candidate=~/c\+\+[\/\\]\d+/ and $MAIN_CPP_DIR
6100    and $Candidate!~/\A\Q$MAIN_CPP_DIR\E/)
6101    { # skip ../c++/3.3.3/ if using ../c++/4.5/
6102        return 0;
6103    }
6104    if($Candidate=~/[\/\\]asm-/
6105    and (my $Arch = getArch($LibVersion)) ne "unknown")
6106    { # arch-specific header files
6107        if($Candidate!~/[\/\\]asm-\Q$Arch\E/)
6108        {# skip ../asm-arm/ if using x86 architecture
6109            return 0;
6110        }
6111    }
6112    my @Candidates = getSystemHeaders($HName, $LibVersion);
6113    if($#Candidates==1)
6114    { # unique header
6115        return 1;
6116    }
6117    my @SCandidates = getSystemHeaders($Header, $LibVersion);
6118    if($#SCandidates==1)
6119    { # unique name
6120        return 1;
6121    }
6122    my $SystemDepth = $SystemRoot?get_depth($SystemRoot):0;
6123    if(get_depth($Candidate)-$SystemDepth>=5)
6124    { # abstract headers in too deep directories
6125      # sstream.h or typeinfo.h in /usr/include/wx-2.9/wx/
6126        if(not isAcceptable($Header, $Candidate, $LibVersion)) {
6127            return 0;
6128        }
6129    }
6130    if($Header eq "parser.h"
6131    and $Candidate!~/\/libxml2\//)
6132    { # select parser.h from xml2 library
6133        return 0;
6134    }
6135    if(not get_dirname($Header)
6136    and keys(%{$SystemHeaders{$HName}})>=3)
6137    { # many headers with the same name
6138      # like thread.h included without a prefix
6139        if(not checkFamily(@Candidates)) {
6140            return 0;
6141        }
6142    }
6143    return 1;
6144}
6145
6146sub selectSystemHeader($$)
6147{ # cache function
6148    if(defined $Cache{"selectSystemHeader"}{$_[1]}{$_[0]}) {
6149        return $Cache{"selectSystemHeader"}{$_[1]}{$_[0]};
6150    }
6151    return ($Cache{"selectSystemHeader"}{$_[1]}{$_[0]} = selectSystemHeader_I(@_));
6152}
6153
6154sub selectSystemHeader_I($$)
6155{
6156    my ($Header, $LibVersion) = @_;
6157    if(-f $Header) {
6158        return $Header;
6159    }
6160    if(is_abs($Header) and not -f $Header)
6161    { # incorrect absolute path
6162        return "";
6163    }
6164    if($Header=~/\A(atomic|config|configure|build|conf|setup)\.h\Z/i)
6165    { # too abstract configuration headers
6166        return "";
6167    }
6168    if($OSgroup ne "windows")
6169    {
6170        if(get_filename($Header)=~/windows|win32|win64|\A(dos|process|winsock|config-win)\.h\Z/i)
6171        { # windows headers
6172            return "";
6173        }
6174        elsif($Header=~/\A(mem)\.h\Z/)
6175        { # pngconf.h include mem.h for __MSDOS__
6176            return "";
6177        }
6178    }
6179    if($OSgroup ne "solaris")
6180    {
6181        if($Header=~/\A(thread)\.h\Z/)
6182        { # thread.h in Solaris
6183            return "";
6184        }
6185    }
6186
6187    foreach my $Path (keys(%{$SystemPaths{"include"}}))
6188    { # search in default paths
6189        if(-f $Path."/".$Header) {
6190            return joinPath($Path,$Header);
6191        }
6192    }
6193    if(not keys(%SystemHeaders))
6194    { # register all headers in system include dirs
6195        detectSystemHeaders();
6196    }
6197    foreach my $Candidate (sort {get_depth($a)<=>get_depth($b)}
6198    sort {cmp_paths($b, $a)} getSystemHeaders($Header, $LibVersion))
6199    {
6200        if(isRelevant($Header, $Candidate, $LibVersion)) {
6201            return $Candidate;
6202        }
6203    }
6204    # error
6205    return "";
6206}
6207
6208sub getSystemHeaders($$)
6209{
6210    my ($Header, $LibVersion) = @_;
6211    my @Candidates = ();
6212    foreach my $Candidate (sort keys(%{$SystemHeaders{$Header}}))
6213    {
6214        if(skipHeader($Candidate, $LibVersion)) {
6215            next;
6216        }
6217        push(@Candidates, $Candidate);
6218    }
6219    return @Candidates;
6220}
6221
6222sub cut_path_prefix($$)
6223{
6224    my ($Path, $Prefix) = @_;
6225    return $Path if(not $Prefix);
6226    $Prefix=~s/[\/\\]+\Z//;
6227    $Path=~s/\A\Q$Prefix\E([\/\\]+|\Z)//;
6228    return $Path;
6229}
6230
6231sub is_default_include_dir($)
6232{
6233    my $Dir = $_[0];
6234    $Dir=~s/[\/\\]+\Z//;
6235    return ($DefaultGccPaths{$Dir} or $DefaultCppPaths{$Dir} or $DefaultIncPaths{$Dir});
6236}
6237
6238sub identifyHeader($$)
6239{ # cache function
6240    my ($Header, $LibVersion) = @_;
6241    if(not $Header) {
6242        return "";
6243    }
6244    $Header=~s/\A(\.\.[\\\/])+//g;
6245    if(defined $Cache{"identifyHeader"}{$LibVersion}{$Header}) {
6246        return $Cache{"identifyHeader"}{$LibVersion}{$Header};
6247    }
6248    return ($Cache{"identifyHeader"}{$LibVersion}{$Header} = identifyHeader_I($Header, $LibVersion));
6249}
6250
6251sub identifyHeader_I($$)
6252{ # search for header by absolute path, relative path or name
6253    my ($Header, $LibVersion) = @_;
6254    if(-f $Header)
6255    { # it's relative or absolute path
6256        return get_abs_path($Header);
6257    }
6258    elsif($GlibcHeader{$Header} and not $GLIBC_TESTING
6259    and my $HeaderDir = find_in_defaults($Header))
6260    { # search for libc headers in the /usr/include
6261      # for non-libc target library before searching
6262      # in the library paths
6263        return joinPath($HeaderDir,$Header);
6264    }
6265    elsif(my $Path = $Include_Neighbors{$LibVersion}{$Header})
6266    { # search in the target library paths
6267        return $Path;
6268    }
6269    elsif($DefaultGccHeader{$Header})
6270    { # search in the internal GCC include paths
6271        return $DefaultGccHeader{$Header};
6272    }
6273    elsif(my $DefaultDir = find_in_defaults($Header))
6274    { # search in the default GCC include paths
6275        return joinPath($DefaultDir,$Header);
6276    }
6277    elsif($DefaultCppHeader{$Header})
6278    { # search in the default G++ include paths
6279        return $DefaultCppHeader{$Header};
6280    }
6281    elsif(my $AnyPath = selectSystemHeader($Header, $LibVersion))
6282    { # search everywhere in the system
6283        return $AnyPath;
6284    }
6285    elsif($OSgroup eq "macos")
6286    { # search in frameworks: "OpenGL/gl.h" is "OpenGL.framework/Headers/gl.h"
6287        if(my $Dir = get_dirname($Header))
6288        {
6289            my $RelPath = "Headers\/".get_filename($Header);
6290            if(my $HeaderDir = find_in_framework($RelPath, $Dir.".framework", $LibVersion)) {
6291                return joinPath($HeaderDir, $RelPath);
6292            }
6293        }
6294    }
6295    # cannot find anything
6296    return "";
6297}
6298
6299sub getLocation($)
6300{
6301    if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
6302    {
6303        if($Info=~/srcp[ ]*:[ ]*([\w\-\<\>\.\+\/\\]+):(\d+) /) {
6304            return ($1, $2);
6305        }
6306    }
6307    return ();
6308}
6309
6310sub getNameByInfo($)
6311{
6312    if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
6313    {
6314        if($Info=~/name[ ]*:[ ]*@(\d+) /)
6315        {
6316            if(my $NInfo = $LibInfo{$Version}{"info"}{$1})
6317            {
6318                if($NInfo=~/strg[ ]*:[ ]*(.*?)[ ]+lngt/)
6319                { # short unsigned int (may include spaces)
6320                    return $1;
6321                }
6322            }
6323        }
6324    }
6325    return "";
6326}
6327
6328sub getTreeStr($)
6329{
6330    if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
6331    {
6332        if($Info=~/strg[ ]*:[ ]*([^ ]*)/)
6333        {
6334            my $Str = $1;
6335            if($C99Mode{$Version}
6336            and $Str=~/\Ac99_(.+)\Z/) {
6337                if($CppKeywords_A{$1}) {
6338                    $Str=$1;
6339                }
6340            }
6341            return $Str;
6342        }
6343    }
6344    return "";
6345}
6346
6347sub getFuncShortName($)
6348{
6349    if(my $Info = $LibInfo{$Version}{"info"}{$_[0]})
6350    {
6351        if($Info=~/ operator /)
6352        {
6353            if($Info=~/ conversion /)
6354            {
6355                if(my $Rid = $SymbolInfo{$Version}{$_[0]}{"Return"})
6356                {
6357                    if(my $RName = $TypeInfo{$Version}{$Rid}{"Name"}) {
6358                        return "operator ".$RName;
6359                    }
6360                }
6361            }
6362            else
6363            {
6364                if($Info=~/ operator[ ]+([a-zA-Z]+) /)
6365                {
6366                    if(my $Ind = $Operator_Indication{$1}) {
6367                        return "operator".$Ind;
6368                    }
6369                    elsif(not $UnknownOperator{$1})
6370                    {
6371                        printMsg("WARNING", "unknown operator $1");
6372                        $UnknownOperator{$1} = 1;
6373                    }
6374                }
6375            }
6376        }
6377        else
6378        {
6379            if($Info=~/name[ ]*:[ ]*@(\d+) /) {
6380                return getTreeStr($1);
6381            }
6382        }
6383    }
6384    return "";
6385}
6386
6387sub getFuncReturn($)
6388{
6389    if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
6390    {
6391        if($Info=~/type[ ]*:[ ]*@(\d+) /)
6392        {
6393            if($LibInfo{$Version}{"info"}{$1}=~/retn[ ]*:[ ]*@(\d+) /) {
6394                return $1;
6395            }
6396        }
6397    }
6398    return "";
6399}
6400
6401sub getFuncOrig($)
6402{
6403    if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
6404    {
6405        if($Info=~/orig[ ]*:[ ]*@(\d+) /) {
6406            return $1;
6407        }
6408    }
6409    return $_[0];
6410}
6411
6412sub unmangleSymbol($)
6413{
6414    my $Symbol = $_[0];
6415    if(my @Unmngl = unmangleArray($Symbol)) {
6416        return $Unmngl[0];
6417    }
6418    return "";
6419}
6420
6421sub unmangleArray(@)
6422{
6423    if($_[0]=~/\A\?/)
6424    { # MSVC mangling
6425        my $UndNameCmd = get_CmdPath("undname");
6426        if(not $UndNameCmd) {
6427            exitStatus("Not_Found", "can't find \"undname\"");
6428        }
6429        writeFile("$TMP_DIR/unmangle", join("\n", @_));
6430        return split(/\n/, `$UndNameCmd 0x8386 \"$TMP_DIR/unmangle\"`);
6431    }
6432    else
6433    { # GCC mangling
6434        my $CppFiltCmd = get_CmdPath("c++filt");
6435        if(not $CppFiltCmd) {
6436            exitStatus("Not_Found", "can't find c++filt in PATH");
6437        }
6438        my $Info = `$CppFiltCmd -h 2>&1`;
6439        if($Info=~/\@<file>/)
6440        {# new version of c++filt can take a file
6441            my $NoStrip = "";
6442            if($OSgroup eq "macos"
6443            or $OSgroup eq "windows") {
6444                $NoStrip = "-n";
6445            }
6446            writeFile("$TMP_DIR/unmangle", join("\n", @_));
6447            return split(/\n/, `$CppFiltCmd $NoStrip \@\"$TMP_DIR/unmangle\"`);
6448        }
6449        else
6450        { # old-style unmangling
6451            if($#_>$MAX_COMMAND_LINE_ARGUMENTS) {
6452                my @Half = splice(@_, 0, ($#_+1)/2);
6453                return (unmangleArray(@Half), unmangleArray(@_))
6454            }
6455            else
6456            {
6457                my $NoStrip = "";
6458                if($OSgroup eq "macos"
6459                or $OSgroup eq "windows") {
6460                    $NoStrip = "-n";
6461                }
6462                my $Strings = join(" ", @_);
6463                return split(/\n/, `$CppFiltCmd $NoStrip $Strings`);
6464            }
6465        }
6466    }
6467}
6468
6469sub get_SignatureNoInfo($$)
6470{
6471    my ($Symbol, $LibVersion) = @_;
6472    if($Cache{"get_SignatureNoInfo"}{$LibVersion}{$Symbol}) {
6473        return $Cache{"get_SignatureNoInfo"}{$LibVersion}{$Symbol};
6474    }
6475    my ($MnglName, $VersionSpec, $SymbolVersion) = separate_symbol($Symbol);
6476    my $Signature = $tr_name{$MnglName}?$tr_name{$MnglName}:$MnglName;
6477    if($Symbol=~/\A(_Z|\?)/)
6478    { # C++
6479        $Signature=~s/\Qstd::basic_string<char, std::char_traits<char>, std::allocator<char> >\E/std::string/g;
6480        $Signature=~s/\Qstd::map<std::string, std::string, std::less<std::string >, std::allocator<std::pair<std::string const, std::string > > >\E/std::map<std::string, std::string>/g;
6481    }
6482    if(not $CheckObjectsOnly or $OSgroup=~/linux|bsd|beos/)
6483    { # ELF format marks data as OBJECT
6484        if($GlobalDataObject{$LibVersion}{$Symbol}) {
6485            $Signature .= " [data]";
6486        }
6487        elsif($Symbol!~/\A(_Z|\?)/) {
6488            $Signature .= " (...)";
6489        }
6490    }
6491    if(my $ChargeLevel = get_ChargeLevel($Symbol, $LibVersion))
6492    {
6493        my $ShortName = substr($Signature, 0, find_center($Signature, "("));
6494        $Signature=~s/\A\Q$ShortName\E/$ShortName $ChargeLevel/g;
6495    }
6496    if($SymbolVersion) {
6497        $Signature .= $VersionSpec.$SymbolVersion;
6498    }
6499    return ($Cache{"get_SignatureNoInfo"}{$LibVersion}{$Symbol} = $Signature);
6500}
6501
6502sub get_ChargeLevel($$)
6503{
6504    my ($Symbol, $LibVersion) = @_;
6505    return "" if($Symbol!~/\A(_Z|\?)/);
6506    if(defined $CompleteSignature{$LibVersion}{$Symbol}
6507    and $CompleteSignature{$LibVersion}{$Symbol}{"Header"})
6508    {
6509        if($CompleteSignature{$LibVersion}{$Symbol}{"Constructor"})
6510        {
6511            if($Symbol=~/C1E/) {
6512                return "[in-charge]";
6513            }
6514            elsif($Symbol=~/C2E/) {
6515                return "[not-in-charge]";
6516            }
6517        }
6518        elsif($CompleteSignature{$LibVersion}{$Symbol}{"Destructor"})
6519        {
6520            if($Symbol=~/D1E/) {
6521                return "[in-charge]";
6522            }
6523            elsif($Symbol=~/D2E/) {
6524                return "[not-in-charge]";
6525            }
6526            elsif($Symbol=~/D0E/) {
6527                return "[in-charge-deleting]";
6528            }
6529        }
6530    }
6531    else
6532    {
6533        if($Symbol=~/C1E/) {
6534            return "[in-charge]";
6535        }
6536        elsif($Symbol=~/C2E/) {
6537            return "[not-in-charge]";
6538        }
6539        elsif($Symbol=~/D1E/) {
6540            return "[in-charge]";
6541        }
6542        elsif($Symbol=~/D2E/) {
6543            return "[not-in-charge]";
6544        }
6545        elsif($Symbol=~/D0E/) {
6546            return "[in-charge-deleting]";
6547        }
6548    }
6549    return "";
6550}
6551
6552sub get_Signature_M($$)
6553{
6554    my ($Symbol, $LibVersion) = @_;
6555    my $Signature_M = $tr_name{$Symbol};
6556    if(my $RTid = $CompleteSignature{$LibVersion}{$Symbol}{"Return"})
6557    { # add return type name
6558        $Signature_M = $TypeInfo{$LibVersion}{$RTid}{"Name"}." ".$Signature_M;
6559    }
6560    return $Signature_M;
6561}
6562
6563sub get_Signature($$)
6564{
6565    my ($Symbol, $LibVersion) = @_;
6566    if($Cache{"get_Signature"}{$LibVersion}{$Symbol}) {
6567        return $Cache{"get_Signature"}{$LibVersion}{$Symbol};
6568    }
6569    my ($MnglName, $VersionSpec, $SymbolVersion) = separate_symbol($Symbol);
6570    if(isPrivateData($MnglName) or not $CompleteSignature{$LibVersion}{$Symbol}{"Header"})
6571    { # non-public global data
6572        return get_SignatureNoInfo($Symbol, $LibVersion);
6573    }
6574    my ($Func_Signature, @Param_Types_FromUnmangledName) = ();
6575    my $ShortName = $CompleteSignature{$LibVersion}{$Symbol}{"ShortName"};
6576    if($Symbol=~/\A(_Z|\?)/)
6577    {
6578        if(my $ClassId = $CompleteSignature{$LibVersion}{$Symbol}{"Class"}) {
6579            $Func_Signature = $TypeInfo{$LibVersion}{$ClassId}{"Name"}."::".(($CompleteSignature{$LibVersion}{$Symbol}{"Destructor"})?"~":"").$ShortName;
6580        }
6581        elsif(my $NameSpace = $CompleteSignature{$LibVersion}{$Symbol}{"NameSpace"}) {
6582            $Func_Signature = $NameSpace."::".$ShortName;
6583        }
6584        else {
6585            $Func_Signature = $ShortName;
6586        }
6587        @Param_Types_FromUnmangledName = get_s_params($tr_name{$MnglName}, 0);
6588    }
6589    else {
6590        $Func_Signature = $MnglName;
6591    }
6592    my @ParamArray = ();
6593    foreach my $Pos (sort {int($a) <=> int($b)} keys(%{$CompleteSignature{$LibVersion}{$Symbol}{"Param"}}))
6594    {
6595        next if($Pos eq "");
6596        my $ParamTypeId = $CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$Pos}{"type"};
6597        next if(not $ParamTypeId);
6598        my $ParamTypeName = $TypeInfo{$LibVersion}{$ParamTypeId}{"Name"};
6599        if(not $ParamTypeName) {
6600            $ParamTypeName = $Param_Types_FromUnmangledName[$Pos];
6601        }
6602        foreach my $Typedef (keys(%ChangedTypedef))
6603        {
6604            my $Base = $Typedef_BaseName{$LibVersion}{$Typedef};
6605            $ParamTypeName=~s/\b\Q$Typedef\E\b/$Base/g;
6606        }
6607        if(my $ParamName = $CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$Pos}{"name"}) {
6608            push(@ParamArray, create_member_decl($ParamTypeName, $ParamName));
6609        }
6610        else {
6611            push(@ParamArray, $ParamTypeName);
6612        }
6613    }
6614    if($CompleteSignature{$LibVersion}{$Symbol}{"Data"}
6615    or $GlobalDataObject{$LibVersion}{$Symbol}) {
6616        $Func_Signature .= " [data]";
6617    }
6618    else
6619    {
6620        if(my $ChargeLevel = get_ChargeLevel($Symbol, $LibVersion))
6621        { # add [in-charge]
6622            $Func_Signature .= " ".$ChargeLevel;
6623        }
6624        $Func_Signature .= " (".join(", ", @ParamArray).")";
6625        if($CompleteSignature{$LibVersion}{$Symbol}{"Const"}
6626        or $Symbol=~/\A_ZN(V|)K/) {
6627            $Func_Signature .= " const";
6628        }
6629        if($CompleteSignature{$LibVersion}{$Symbol}{"Volatile"}
6630        or $Symbol=~/\A_ZN(K|)V/) {
6631            $Func_Signature .= " volatile";
6632        }
6633        if($CompleteSignature{$LibVersion}{$Symbol}{"Static"}
6634        and $Symbol=~/\A(_Z|\?)/)
6635        {# for static methods
6636            $Func_Signature .= " [static]";
6637        }
6638    }
6639    if(defined $ShowRetVal
6640    and my $ReturnTId = $CompleteSignature{$LibVersion}{$Symbol}{"Return"}) {
6641        $Func_Signature .= ":".$TypeInfo{$LibVersion}{$ReturnTId}{"Name"};
6642    }
6643    if($SymbolVersion) {
6644        $Func_Signature .= $VersionSpec.$SymbolVersion;
6645    }
6646    return ($Cache{"get_Signature"}{$LibVersion}{$Symbol} = $Func_Signature);
6647}
6648
6649sub create_member_decl($$)
6650{
6651    my ($TName, $Member) = @_;
6652    if($TName=~/\([\*]+\)/)
6653    {
6654        $TName=~s/\(([\*]+)\)/\($1$Member\)/;
6655        return $TName;
6656    }
6657    else
6658    {
6659        my @ArraySizes = ();
6660        while($TName=~s/(\[[^\[\]]*\])\Z//) {
6661            push(@ArraySizes, $1);
6662        }
6663        return $TName." ".$Member.join("", @ArraySizes);
6664    }
6665}
6666
6667sub getFuncType($)
6668{
6669    if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
6670    {
6671        if($Info=~/type[ ]*:[ ]*@(\d+) /)
6672        {
6673            if(my $Type = $LibInfo{$Version}{"info_type"}{$1})
6674            {
6675                if($Type eq "method_type") {
6676                    return "Method";
6677                }
6678                elsif($Type eq "function_type") {
6679                    return "Function";
6680                }
6681                else {
6682                    return "Other";
6683                }
6684            }
6685        }
6686    }
6687    return ""
6688}
6689
6690sub getFuncTypeId($)
6691{
6692    if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
6693    {
6694        if($Info=~/type[ ]*:[ ]*@(\d+)( |\Z)/) {
6695            return $1;
6696        }
6697    }
6698    return 0;
6699}
6700
6701sub isNotAnon($) {
6702    return (not isAnon($_[0]));
6703}
6704
6705sub isAnon($)
6706{ # "._N" or "$_N" in older GCC versions
6707    return ($_[0] and $_[0]=~/(\.|\$)\_\d+|anon\-/);
6708}
6709
6710sub formatName($)
6711{ # type name correction
6712    if(defined $Cache{"formatName"}{$_[0]}) {
6713        return $Cache{"formatName"}{$_[0]};
6714    }
6715
6716    $_ = $_[0];
6717
6718    s/\A[ ]+|[ ]+\Z//g;
6719    s/[ ]{2,}/ /g;
6720    s/[ ]*(\W)[ ]*/$1/g;
6721
6722    s/\bvolatile const\b/const volatile/g;
6723
6724    s/\b(long long|short|long) unsigned\b/unsigned $1/g;
6725    s/\b(short|long) int\b/$1/g;
6726
6727    s/([\)\]])(const|volatile)\b/$1 $2/g;
6728
6729    while(s/>>/> >/g) {};
6730
6731    s/\b(operator[ ]*)> >/$1>>/;
6732
6733    return ($Cache{"formatName"}{$_[0]}=$_);
6734}
6735
6736sub get_HeaderDeps($$)
6737{
6738    my ($AbsPath, $LibVersion) = @_;
6739    return () if(not $AbsPath or not $LibVersion);
6740    if(defined $Cache{"get_HeaderDeps"}{$LibVersion}{$AbsPath}) {
6741        return @{$Cache{"get_HeaderDeps"}{$LibVersion}{$AbsPath}};
6742    }
6743    my %IncDir = ();
6744    detect_recursive_includes($AbsPath, $LibVersion);
6745    foreach my $HeaderPath (keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}}))
6746    {
6747        next if(not $HeaderPath);
6748        next if($MAIN_CPP_DIR and $HeaderPath=~/\A\Q$MAIN_CPP_DIR\E([\/\\]|\Z)/);
6749        my $Dir = get_dirname($HeaderPath);
6750        foreach my $Prefix (keys(%{$Header_Include_Prefix{$LibVersion}{$AbsPath}{$HeaderPath}}))
6751        {
6752            my $Dep = $Dir;
6753            if($Prefix)
6754            {
6755                if($OSgroup eq "windows")
6756                { # case insensitive seach on windows
6757                    if(not $Dep=~s/[\/\\]+\Q$Prefix\E\Z//ig) {
6758                        next;
6759                    }
6760                }
6761                elsif($OSgroup eq "macos")
6762                { # seach in frameworks
6763                    if(not $Dep=~s/[\/\\]+\Q$Prefix\E\Z//g)
6764                    {
6765                        if($HeaderPath=~/(.+\.framework)\/Headers\/([^\/]+)/)
6766                        {# frameworks
6767                            my ($HFramework, $HName) = ($1, $2);
6768                            $Dep = $HFramework;
6769                        }
6770                        else
6771                        {# mismatch
6772                            next;
6773                        }
6774                    }
6775                }
6776                elsif(not $Dep=~s/[\/\\]+\Q$Prefix\E\Z//g)
6777                { # Linux, FreeBSD
6778                    next;
6779                }
6780            }
6781            if(not $Dep)
6782            { # nothing to include
6783                next;
6784            }
6785            if(is_default_include_dir($Dep))
6786            { # included by the compiler
6787                next;
6788            }
6789            if(get_depth($Dep)==1)
6790            { # too short
6791                next;
6792            }
6793            if(isLibcDir($Dep))
6794            { # do NOT include /usr/include/{sys,bits}
6795                next;
6796            }
6797            $IncDir{$Dep}=1;
6798        }
6799    }
6800    $Cache{"get_HeaderDeps"}{$LibVersion}{$AbsPath} = sortIncPaths([keys(%IncDir)], $LibVersion);
6801    return @{$Cache{"get_HeaderDeps"}{$LibVersion}{$AbsPath}};
6802}
6803
6804sub sortIncPaths($$)
6805{
6806    my ($ArrRef, $LibVersion) = @_;
6807    if(not $ArrRef or $#{$ArrRef}<0) {
6808        return $ArrRef;
6809    }
6810    @{$ArrRef} = sort {$b cmp $a} @{$ArrRef};
6811    @{$ArrRef} = sort {get_depth($a)<=>get_depth($b)} @{$ArrRef};
6812    @{$ArrRef} = sort {sortDeps($b, $a, $LibVersion)} @{$ArrRef};
6813    return $ArrRef;
6814}
6815
6816sub sortDeps($$$)
6817{
6818    if($Header_Dependency{$_[2]}{$_[0]}
6819    and not $Header_Dependency{$_[2]}{$_[1]}) {
6820        return 1;
6821    }
6822    elsif(not $Header_Dependency{$_[2]}{$_[0]}
6823    and $Header_Dependency{$_[2]}{$_[1]}) {
6824        return -1;
6825    }
6826    return 0;
6827}
6828
6829sub joinPath($$) {
6830    return join($SLASH, @_);
6831}
6832
6833sub get_namespace_additions($)
6834{
6835    my $NameSpaces = $_[0];
6836    my ($Additions, $AddNameSpaceId) = ("", 1);
6837    foreach my $NS (sort {$a=~/_/ <=> $b=~/_/} sort {lc($a) cmp lc($b)} keys(%{$NameSpaces}))
6838    {
6839        next if($SkipNameSpaces{$Version}{$NS});
6840        next if(not $NS or $NameSpaces->{$NS}==-1);
6841        next if($NS=~/(\A|::)iterator(::|\Z)/i);
6842        next if($NS=~/\A__/i);
6843        next if(($NS=~/\Astd::/ or $NS=~/\A(std|tr1|rel_ops|fcntl)\Z/) and not $STDCXX_TESTING);
6844        $NestedNameSpaces{$Version}{$NS} = 1; # for future use in reports
6845        my ($TypeDecl_Prefix, $TypeDecl_Suffix) = ();
6846        my @NS_Parts = split(/::/, $NS);
6847        next if($#NS_Parts==-1);
6848        next if($NS_Parts[0]=~/\A(random|or)\Z/);
6849        foreach my $NS_Part (@NS_Parts)
6850        {
6851            $TypeDecl_Prefix .= "namespace $NS_Part\{";
6852            $TypeDecl_Suffix .= "}";
6853        }
6854        my $TypeDecl = $TypeDecl_Prefix."typedef int tmp_add_type_$AddNameSpaceId;".$TypeDecl_Suffix;
6855        my $FuncDecl = "$NS\:\:tmp_add_type_$AddNameSpaceId tmp_add_func_$AddNameSpaceId(){return 0;};";
6856        $Additions.="  $TypeDecl\n  $FuncDecl\n";
6857        $AddNameSpaceId+=1;
6858    }
6859    return $Additions;
6860}
6861
6862sub path_format($$)
6863{ # forward slash to pass into MinGW GCC
6864    my ($Path, $Fmt) = @_;
6865    if($Fmt eq "windows")
6866    {
6867        $Path=~s/\//\\/g;
6868        $Path=lc($Path);
6869    }
6870    else {
6871        $Path=~s/\\/\//g;
6872    }
6873    return $Path;
6874}
6875
6876sub inc_opt($$)
6877{
6878    my ($Path, $Style) = @_;
6879    if($Style eq "GCC")
6880    { # GCC options
6881        if($OSgroup eq "windows")
6882        { # to MinGW GCC
6883            return "-I\"".path_format($Path, "unix")."\"";
6884        }
6885        elsif($OSgroup eq "macos"
6886        and $Path=~/\.framework\Z/)
6887        {# to Apple's GCC
6888            return "-F".esc(get_dirname($Path));
6889        }
6890        else {
6891            return "-I".esc($Path);
6892        }
6893    }
6894    elsif($Style eq "CL") {
6895        return "/I \"".$Path."\"";
6896    }
6897    return "";
6898}
6899
6900sub platformSpecs($)
6901{
6902    my $LibVersion = $_[0];
6903    my $Arch = getArch($LibVersion);
6904    if($OStarget eq "symbian")
6905    { # options for GCCE compiler
6906        my %Symbian_Opts = map {$_=>1} (
6907            "-D__GCCE__",
6908            "-DUNICODE",
6909            "-fexceptions",
6910            "-D__SYMBIAN32__",
6911            "-D__MARM_INTERWORK__",
6912            "-D_UNICODE",
6913            "-D__S60_50__",
6914            "-D__S60_3X__",
6915            "-D__SERIES60_3X__",
6916            "-D__EPOC32__",
6917            "-D__MARM__",
6918            "-D__EABI__",
6919            "-D__MARM_ARMV5__",
6920            "-D__SUPPORT_CPP_EXCEPTIONS__",
6921            "-march=armv5t",
6922            "-mapcs",
6923            "-mthumb-interwork",
6924            "-DEKA2",
6925            "-DSYMBIAN_ENABLE_SPLIT_HEADERS"
6926        );
6927        return join(" ", keys(%Symbian_Opts));
6928    }
6929    elsif($OSgroup eq "windows"
6930    and get_dumpmachine($GCC_PATH)=~/mingw/i)
6931    { # add options to MinGW compiler
6932      # to simulate the MSVC compiler
6933        my %MinGW_Opts = map {$_=>1} (
6934            "-D_WIN32",
6935            "-D_STDCALL_SUPPORTED",
6936            "-D__int64=\"long long\"",
6937            "-D__int32=int",
6938            "-D__int16=short",
6939            "-D__int8=char",
6940            "-D__possibly_notnullterminated=\" \"",
6941            "-D__nullterminated=\" \"",
6942            "-D__nullnullterminated=\" \"",
6943            "-D__w64=\" \"",
6944            "-D__ptr32=\" \"",
6945            "-D__ptr64=\" \"",
6946            "-D__forceinline=inline",
6947            "-D__inline=inline",
6948            "-D__uuidof(x)=IID()",
6949            "-D__try=",
6950            "-D__except(x)=",
6951            "-D__declspec(x)=__attribute__((x))",
6952            "-D__pragma(x)=",
6953            "-D_inline=inline",
6954            "-D__forceinline=__inline",
6955            "-D__stdcall=__attribute__((__stdcall__))",
6956            "-D__cdecl=__attribute__((__cdecl__))",
6957            "-D__fastcall=__attribute__((__fastcall__))",
6958            "-D__thiscall=__attribute__((__thiscall__))",
6959            "-D_stdcall=__attribute__((__stdcall__))",
6960            "-D_cdecl=__attribute__((__cdecl__))",
6961            "-D_fastcall=__attribute__((__fastcall__))",
6962            "-D_thiscall=__attribute__((__thiscall__))",
6963            "-DSHSTDAPI_(x)=x",
6964            "-D_MSC_EXTENSIONS",
6965            "-DSECURITY_WIN32",
6966            "-D_MSC_VER=1500",
6967            "-D_USE_DECLSPECS_FOR_SAL",
6968            "-D__noop=\" \"",
6969            "-DDECLSPEC_DEPRECATED=\" \"",
6970            "-D__builtin_alignof(x)=__alignof__(x)",
6971            "-DSORTPP_PASS");
6972        if($Arch eq "x86") {
6973            $MinGW_Opts{"-D_M_IX86=300"}=1;
6974        }
6975        elsif($Arch eq "x86_64") {
6976            $MinGW_Opts{"-D_M_AMD64=300"}=1;
6977        }
6978        elsif($Arch eq "ia64") {
6979            $MinGW_Opts{"-D_M_IA64=300"}=1;
6980        }
6981        return join(" ", keys(%MinGW_Opts));
6982    }
6983    return "";
6984}
6985
6986my %C_Structure = map {$_=>1} (
6987# FIXME: Can't separate union and struct data types before dumping,
6988# so it sometimes cause compilation errors for unknown reason
6989# when trying to declare TYPE* tmp_add_class_N
6990# This is a list of such structures + list of other C structures
6991    "sigval",
6992    "sigevent",
6993    "sigaction",
6994    "sigvec",
6995    "sigstack",
6996    "timeval",
6997    "timezone",
6998    "rusage",
6999    "rlimit",
7000    "wait",
7001    "flock",
7002    "stat",
7003    "_stat",
7004    "stat32",
7005    "_stat32",
7006    "stat64",
7007    "_stat64",
7008    "_stati64",
7009    "if_nameindex",
7010    "usb_device",
7011    "sigaltstack",
7012    "sysinfo",
7013    "timeLocale",
7014    "tcp_debug",
7015    "rpc_createerr",
7016# Other C structures appearing in every dump
7017    "timespec",
7018    "random_data",
7019    "drand48_data",
7020    "_IO_marker",
7021    "_IO_FILE",
7022    "lconv",
7023    "sched_param",
7024    "tm",
7025    "itimerspec",
7026    "_pthread_cleanup_buffer",
7027    "fd_set",
7028    "siginfo"
7029);
7030
7031sub getCompileCmd($$$)
7032{
7033    my ($Path, $Opt, $Inc) = @_;
7034    my $GccCall = $GCC_PATH;
7035    if($Opt) {
7036        $GccCall .= " ".$Opt;
7037    }
7038    $GccCall .= " -x ";
7039    if($OSgroup eq "macos") {
7040        $GccCall .= "objective-";
7041    }
7042    if(check_gcc($GCC_PATH, "4"))
7043    { # compile as "C++" header
7044      # to obtain complete dump using GCC 4.0
7045        $GccCall .= "c++-header";
7046    }
7047    else
7048    { # compile as "C++" source
7049      # GCC 3.3 cannot compile headers
7050        $GccCall .= "c++";
7051    }
7052    if(my $Opts = platformSpecs($Version))
7053    {# platform-specific options
7054        $GccCall .= " ".$Opts;
7055    }
7056    # allow extra qualifications
7057    # and other nonconformant code
7058    $GccCall .= " -fpermissive -w";
7059    if($NoStdInc)
7060    {
7061        $GccCall .= " -nostdinc";
7062        $GccCall .= " -nostdinc++";
7063    }
7064    if($CompilerOptions{$Version})
7065    { # user-defined options
7066        $GccCall .= " ".$CompilerOptions{$Version};
7067    }
7068    $GccCall .= " \"$Path\"";
7069    if($Inc)
7070    { # include paths
7071        $GccCall .= " ".$Inc;
7072    }
7073    return $GccCall;
7074}
7075
7076sub getDump()
7077{
7078    if(not $GCC_PATH) {
7079        exitStatus("Error", "internal error - GCC path is not set");
7080    }
7081    my %HeaderElems = (
7082        # Types
7083        "stdio.h" => ["FILE", "va_list"],
7084        "stddef.h" => ["NULL", "ptrdiff_t"],
7085        "stdint.h" => ["uint32_t", "int32_t", "uint64_t"],
7086        "time.h" => ["time_t"],
7087        "sys/types.h" => ["ssize_t", "u_int32_t", "u_short", "u_char",
7088             "u_int", "off_t", "u_quad_t", "u_long", "size_t", "mode_t"],
7089        "unistd.h" => ["gid_t", "uid_t"],
7090        "stdbool.h" => ["_Bool"],
7091        "rpc/xdr.h" => ["bool_t"],
7092        "in_systm.h" => ["n_long", "n_short"],
7093        # Fields
7094        "arpa/inet.h" => ["fw_src", "ip_src"],
7095        # Functions
7096        "stdlib.h" => ["free", "malloc"],
7097        "string.h" => ["memmove", "strcmp"]
7098    );
7099    my %AutoPreamble = ();
7100    foreach (keys(%HeaderElems))
7101    {
7102        foreach my $Elem (@{$HeaderElems{$_}}) {
7103            $AutoPreamble{$Elem}=$_;
7104        }
7105    }
7106    my $TmpHeaderPath = $TMP_DIR."/dump".$Version.".h";
7107    my $MHeaderPath = $TmpHeaderPath;
7108    open(TMP_HEADER, ">", $TmpHeaderPath) || die ("can't open file \'$TmpHeaderPath\': $!\n");
7109    if(my $AddDefines = $Descriptor{$Version}{"Defines"})
7110    {
7111        $AddDefines=~s/\n\s+/\n  /g;
7112        print TMP_HEADER "\n  // add defines\n  ".$AddDefines."\n";
7113    }
7114    print TMP_HEADER "\n  // add includes\n";
7115    my @PreambleHeaders = keys(%{$Include_Preamble{$Version}});
7116    @PreambleHeaders = sort {int($Include_Preamble{$Version}{$a}{"Position"})<=>int($Include_Preamble{$Version}{$b}{"Position"})} @PreambleHeaders;
7117    foreach my $Header_Path (@PreambleHeaders) {
7118        print TMP_HEADER "  #include \"".path_format($Header_Path, "unix")."\"\n";
7119    }
7120    my @Headers = keys(%{$Registered_Headers{$Version}});
7121    @Headers = sort {int($Registered_Headers{$Version}{$a}{"Pos"})<=>int($Registered_Headers{$Version}{$b}{"Pos"})} @Headers;
7122    foreach my $Header_Path (@Headers)
7123    {
7124        next if($Include_Preamble{$Version}{$Header_Path});
7125        print TMP_HEADER "  #include \"".path_format($Header_Path, "unix")."\"\n";
7126    }
7127    close(TMP_HEADER);
7128    my $IncludeString = getIncString(getIncPaths(@PreambleHeaders, @Headers), "GCC");
7129    if($Debug)
7130    { # debug mode
7131        writeFile($DEBUG_PATH{$Version}."/headers/direct-includes.txt", Dumper($Header_Includes{$Version}));
7132        writeFile($DEBUG_PATH{$Version}."/headers/recursive-includes.txt", Dumper($RecursiveIncludes{$Version}));
7133        writeFile($DEBUG_PATH{$Version}."/headers/include-paths.txt", Dumper($Cache{"get_HeaderDeps"}{$Version}));
7134        writeFile($DEBUG_PATH{$Version}."/headers/default-paths.txt", Dumper(\%DefaultIncPaths));
7135    }
7136
7137    if(not keys(%{$TargetHeaders{$Version}}))
7138    { # Target headers
7139        addTargetHeaders($Version);
7140    }
7141
7142    # clean memory
7143    %RecursiveIncludes = ();
7144    %Header_Include_Prefix = ();
7145    %Header_Includes = ();
7146
7147    # clean cache
7148    delete($Cache{"identifyHeader"});
7149    delete($Cache{"detect_header_includes"});
7150    delete($Cache{"selectSystemHeader"});
7151
7152    # preprocessing stage
7153    checkPreprocessedUnit(callPreprocessor($TmpHeaderPath, $IncludeString, $Version));
7154
7155    # clean memory
7156    delete($Include_Neighbors{$Version});
7157
7158    my $MContent = "";
7159    my $PreprocessCmd = getCompileCmd($TmpHeaderPath, "-E", $IncludeString);
7160    if($OStarget eq "windows"
7161    and get_dumpmachine($GCC_PATH)=~/mingw/i
7162    and $MinGWMode{$Version}!=-1)
7163    { # modify headers to compile by MinGW
7164        if(not $MContent)
7165        { # preprocessing
7166            $MContent = `$PreprocessCmd 2>\"$TMP_DIR/null\"`;
7167        }
7168        if($MContent=~s/__asm\s*(\{[^{}]*?\}|[^{};]*)//g)
7169        { # __asm { ... }
7170            $MinGWMode{$Version}=1;
7171        }
7172        if($MContent=~s/\s+(\/ \/.*?)\n/\n/g)
7173        { # comments after preprocessing
7174            $MinGWMode{$Version}=1;
7175        }
7176        if($MContent=~s/(\W)(0x[a-f]+|\d+)(i|ui)(8|16|32|64)(\W)/$1$2$5/g)
7177        { # 0xffui8
7178            $MinGWMode{$Version}=1;
7179        }
7180        if($MinGWMode{$Version})
7181        {
7182            printMsg("INFO", "Using MinGW compatibility mode");
7183            $MHeaderPath = $TMP_DIR."/dump$Version.i";
7184        }
7185    }
7186    if(($COMMON_LANGUAGE{$Version} eq "C" or $CheckHeadersOnly)
7187    and $C99Mode{$Version}!=-1 and not $Cpp2003)
7188    { # rename C++ keywords in C code
7189        if(not $MContent)
7190        { # preprocessing
7191            $MContent = `$PreprocessCmd 2>\"$TMP_DIR/null\"`;
7192        }
7193        my $RegExp_C = join("|", keys(%CppKeywords_C));
7194        my $RegExp_F = join("|", keys(%CppKeywords_F));
7195        my $RegExp_O = join("|", keys(%CppKeywords_O));
7196        while($MContent=~s/(\A|\n[^\#\/\n][^\n]*?|\n)(\*\s*|\s+|\@|\,|\()($RegExp_C|$RegExp_F)(\s*(\,|\)|\;|\-\>|\.|\:\s*\d))/$1$2c99_$3$4/g)
7197        { # MATCH:
7198          # int foo(int new, int class, int (*new)(int));
7199          # unsigned private: 8;
7200          # DO NOT MATCH:
7201          # #pragma GCC visibility push(default)
7202            $C99Mode{$Version} = 1;
7203        }
7204        if($MContent=~s/([^\w\s]|\w\s+)(?<!operator )(delete)(\s*\()/$1c99_$2$3/g)
7205        { # MATCH:
7206          # int delete(...);
7207          # int explicit(...);
7208          # DO NOT MATCH:
7209          # void operator delete(...)
7210            $C99Mode{$Version} = 1;
7211        }
7212        if($MContent=~s/(\s+)($RegExp_O)(\s*(\;|\:))/$1c99_$2$3/g)
7213        { # MATCH:
7214          # int bool;
7215          # DO NOT MATCH:
7216          # bool X;
7217          # return *this;
7218          # throw;
7219            $C99Mode{$Version} = 1;
7220        }
7221        if($MContent=~s/(\s+)(operator)(\s*(\(\s*\)\s*[^\(\s]|\(\s*[^\)\s]))/$1c99_$2$3/g)
7222        { # MATCH:
7223          # int operator(...);
7224          # DO NOT MATCH:
7225          # int operator()(...);
7226            $C99Mode{$Version} = 1;
7227        }
7228        if($MContent=~s/([^\w\(\,\s]\s*|\s+)(operator)(\s*(\,\s*[^\(\s]|\)))/$1c99_$2$3/g)
7229        { # MATCH:
7230          # int foo(int operator);
7231          # int foo(int operator, int other);
7232          # DO NOT MATCH:
7233          # int operator,(...);
7234            $C99Mode{$Version} = 1;
7235        }
7236        if($MContent=~s/(\*\s*|\w\s+)(bool)(\s*(\,|\)))/$1c99_$2$3/g)
7237        { # MATCH:
7238          # int foo(gboolean *bool);
7239          # DO NOT MATCH:
7240          # void setTabEnabled(int index, bool);
7241            $C99Mode{$Version} = 1;
7242        }
7243        if($MContent=~s/(\w)([^\w\(\,\s]\s*|\s+)(this)(\s*(\,|\)))/$1$2c99_$3$4/g)
7244        { # MATCH:
7245          # int foo(int* this);
7246          # int bar(int this);
7247          # DO NOT MATCH:
7248          # baz(X, this);
7249            $C99Mode{$Version} = 1;
7250        }
7251        if($C99Mode{$Version}==1)
7252        { # try to change C++ "keyword" to "c99_keyword"
7253            printMsg("INFO", "Using C99 compatibility mode");
7254            $MHeaderPath = $TMP_DIR."/dump$Version.i";
7255        }
7256    }
7257    if($C99Mode{$Version}==1
7258    or $MinGWMode{$Version}==1)
7259    { # compile the corrected preprocessor output
7260        writeFile($MHeaderPath, $MContent);
7261    }
7262
7263    # clean memory
7264    undef $MContent;
7265
7266    if($COMMON_LANGUAGE{$Version} eq "C++")
7267    { # add classes and namespaces to the dump
7268        my $CHdump = "-fdump-class-hierarchy -c";
7269        if($C99Mode{$Version}==1
7270        or $MinGWMode{$Version}==1) {
7271            $CHdump .= " -fpreprocessed";
7272        }
7273        my $ClassHierarchyCmd = getCompileCmd($MHeaderPath, $CHdump, $IncludeString);
7274        chdir($TMP_DIR);
7275        system($ClassHierarchyCmd." >null 2>&1");
7276        chdir($ORIG_DIR);
7277        if(my $ClassDump = (cmd_find($TMP_DIR,"f","*.class",1))[0])
7278        {
7279            my %AddClasses = ();
7280            my $Content = readFile($ClassDump);
7281            foreach my $ClassInfo (split(/\n\n/, $Content))
7282            {
7283                if($ClassInfo=~/\AClass\s+(.+)\s*/i)
7284                {
7285                    my $CName = $1;
7286                    next if($CName=~/\A(__|_objc_|_opaque_)/);
7287                    $TUnit_NameSpaces{$Version}{$CName} = -1;
7288                    if($CName=~/\A[\w:]+\Z/)
7289                    { # classes
7290                        $AddClasses{$CName} = 1;
7291                    }
7292                    if($CName=~/(\w[\w:]*)::/)
7293                    { # namespaces
7294                        my $NS = $1;
7295                        if(not defined $TUnit_NameSpaces{$Version}{$NS}) {
7296                            $TUnit_NameSpaces{$Version}{$NS} = 1;
7297                        }
7298                    }
7299                }
7300                elsif($ClassInfo=~/\AVtable\s+for\s+(.+)\n((.|\n)+)\Z/i)
7301                { # read v-tables (advanced approach)
7302                    my ($CName, $VTable) = ($1, $2);
7303                    $ClassVTable_Content{$Version}{$CName} = $VTable;
7304                }
7305            }
7306            foreach my $NS (keys(%{$AddNameSpaces{$Version}}))
7307            { # add user-defined namespaces
7308                $TUnit_NameSpaces{$Version}{$NS} = 1;
7309            }
7310            if($Debug)
7311            { # debug mode
7312                mkpath($DEBUG_PATH{$Version});
7313                copy($ClassDump, $DEBUG_PATH{$Version}."/class-hierarchy-dump.txt");
7314            }
7315            unlink($ClassDump);
7316            if(my $NS_Add = get_namespace_additions($TUnit_NameSpaces{$Version}))
7317            { # GCC on all supported platforms does not include namespaces to the dump by default
7318                appendFile($MHeaderPath, "\n  // add namespaces\n".$NS_Add);
7319            }
7320            # some GCC versions don't include class methods to the TU dump by default
7321            my ($AddClass, $ClassNum) = ("", 0);
7322            foreach my $CName (sort keys(%AddClasses))
7323            {
7324                next if($C_Structure{$CName});
7325                next if(not $STDCXX_TESTING and $CName=~/\Astd::/);
7326                next if(($CName=~tr![:]!!)>2);
7327                next if($SkipTypes{$Version}{$CName});
7328                if($CName=~/\A(.+)::[^:]+\Z/
7329                and $AddClasses{$1}) {
7330                    next;
7331                }
7332                $AddClass .= "  $CName* tmp_add_class_".($ClassNum++).";\n";
7333            }
7334            appendFile($MHeaderPath, "\n  // add classes\n".$AddClass);
7335        }
7336    }
7337    writeLog($Version, "Temporary header file \'$TmpHeaderPath\' with the following content will be compiled to create GCC translation unit dump:\n".readFile($TmpHeaderPath)."\n");
7338    # create TU dump
7339    my $TUdump = "-fdump-translation-unit -fkeep-inline-functions -c";
7340    if($C99Mode{$Version}==1
7341    or $MinGWMode{$Version}==1) {
7342        $TUdump .= " -fpreprocessed";
7343    }
7344    my $SyntaxTreeCmd = getCompileCmd($MHeaderPath, $TUdump, $IncludeString);
7345    writeLog($Version, "The GCC parameters:\n  $SyntaxTreeCmd\n\n");
7346    chdir($TMP_DIR);
7347    system($SyntaxTreeCmd." >\"$TMP_DIR/tu_errors\" 2>&1");
7348    if($?)
7349    { # failed to compile, but the TU dump still can be created
7350        my $Errors = readFile($TMP_DIR."/tu_errors");
7351        if($Errors=~/c99_/)
7352        { # disable c99 mode
7353            $C99Mode{$Version}=-1;
7354            printMsg("INFO", "Disabling C99 compatibility mode");
7355            resetLogging($Version);
7356            $TMP_DIR = tempdir(CLEANUP=>1);
7357            return getDump();
7358        }
7359        elsif($AutoPreambleMode{$Version}!=-1
7360        and my $TErrors = $Errors)
7361        {
7362            my %Types = ();
7363            while($TErrors=~s/error\:\s*(field\s*|)\W+(.+?)\W+//)
7364            { # error: 'FILE' has not been declared
7365                $Types{$2}=1;
7366            }
7367            my %AddHeaders = ();
7368            foreach my $Type (keys(%Types))
7369            {
7370                if(my $Header = $AutoPreamble{$Type}) {
7371                    $AddHeaders{path_format($Header, $OSgroup)}=$Type;
7372                }
7373            }
7374            if(my @Headers = sort {$b cmp $a} keys(%AddHeaders))
7375            { # sys/types.h should be the first
7376                foreach my $Num (0 .. $#Headers)
7377                {
7378                    my $Name = $Headers[$Num];
7379                    if(my $Path = identifyHeader($Name, $Version))
7380                    { # add automatic preamble headers
7381                        if(defined $Include_Preamble{$Version}{$Path})
7382                        { # already added
7383                            next;
7384                        }
7385                        $Include_Preamble{$Version}{$Path}{"Position"} = keys(%{$Include_Preamble{$Version}});
7386                        my $Type = $AddHeaders{$Name};
7387                        printMsg("INFO", "Add \'$Name\' preamble header for \'$Type\'");
7388                    }
7389                }
7390                $AutoPreambleMode{$Version}=-1;
7391                resetLogging($Version);
7392                $TMP_DIR = tempdir(CLEANUP=>1);
7393                return getDump();
7394            }
7395        }
7396        elsif($MinGWMode{$Version}!=-1)
7397        {
7398            $MinGWMode{$Version}=-1;
7399            resetLogging($Version);
7400            $TMP_DIR = tempdir(CLEANUP=>1);
7401            return getDump();
7402        }
7403        # FIXME: handle other errors and try to recompile
7404        writeLog($Version, $Errors);
7405        printMsg("ERROR", "some errors occurred when compiling headers");
7406        printErrorLog($Version);
7407        $COMPILE_ERRORS = $ERROR_CODE{"Compile_Error"};
7408        writeLog($Version, "\n");# new line
7409    }
7410    chdir($ORIG_DIR);
7411    unlink($TmpHeaderPath, $MHeaderPath);
7412    return (cmd_find($TMP_DIR,"f","*.tu",1))[0];
7413}
7414
7415sub cmd_file($)
7416{
7417    my $Path = $_[0];
7418    return "" if(not $Path or not -e $Path);
7419    if(my $CmdPath = get_CmdPath("file")) {
7420        return `$CmdPath -b \"$Path\"`;
7421    }
7422    return "";
7423}
7424
7425sub getIncString($$)
7426{
7427    my ($ArrRef, $Style) = @_;
7428    return "" if(not $ArrRef or $#{$ArrRef}<0);
7429    my $String = "";
7430    foreach (@{$ArrRef}) {
7431        $String .= " ".inc_opt($_, $Style);
7432    }
7433    return $String;
7434}
7435
7436sub getIncPaths(@)
7437{
7438    my @HeaderPaths = @_;
7439    my @IncPaths = ();
7440    if($INC_PATH_AUTODETECT{$Version})
7441    { # auto-detecting dependencies
7442        my %Includes = ();
7443        foreach my $HPath (@HeaderPaths)
7444        {
7445            foreach my $Dir (get_HeaderDeps($HPath, $Version))
7446            {
7447                if($Skip_Include_Paths{$Version}{$Dir}) {
7448                    next;
7449                }
7450                if($SystemRoot)
7451                {
7452                    if($Skip_Include_Paths{$Version}{$SystemRoot.$Dir}) {
7453                        next;
7454                    }
7455                }
7456                $Includes{$Dir}=1;
7457            }
7458        }
7459        foreach my $Dir (keys(%{$Add_Include_Paths{$Version}}))
7460        { # added by user
7461            next if($Includes{$Dir});
7462            push(@IncPaths, $Dir);
7463        }
7464        foreach my $Dir (@{sortIncPaths([keys(%Includes)], $Version)}) {
7465            push(@IncPaths, $Dir);
7466        }
7467    }
7468    else
7469    { # user-defined paths
7470        foreach my $Dir (sort {get_depth($a)<=>get_depth($b)}
7471        sort {$b cmp $a} keys(%{$Include_Paths{$Version}})) {
7472            push(@IncPaths, $Dir);
7473        }
7474    }
7475    return \@IncPaths;
7476}
7477
7478sub callPreprocessor($$$)
7479{
7480    my ($Path, $Inc, $LibVersion) = @_;
7481    return "" if(not $Path or not -f $Path);
7482    my $IncludeString=$Inc;
7483    if(not $Inc) {
7484        $IncludeString = getIncString(getIncPaths($Path), "GCC");
7485    }
7486    my $Cmd = getCompileCmd($Path, "-dD -E", $IncludeString);
7487    my $Out = $TMP_DIR."/preprocessed";
7488    system($Cmd." >\"$Out\" 2>\"$TMP_DIR/null\"");
7489    return $Out;
7490}
7491
7492sub cmd_find($$$$)
7493{ # native "find" is much faster than File::Find (~6x)
7494  # also the File::Find doesn't support --maxdepth N option
7495  # so using the cross-platform wrapper for the native one
7496    my ($Path, $Type, $Name, $MaxDepth) = @_;
7497    return () if(not $Path or not -e $Path);
7498    if($OSgroup eq "windows")
7499    {
7500        my $DirCmd = get_CmdPath("dir");
7501        if(not $DirCmd) {
7502            exitStatus("Not_Found", "can't find \"dir\" command");
7503        }
7504        $Path=~s/[\\]+\Z//;
7505        $Path = get_abs_path($Path);
7506        $Path = path_format($Path, $OSgroup);
7507        my $Cmd = $DirCmd." \"$Path\" /B /O";
7508        if($MaxDepth!=1) {
7509            $Cmd .= " /S";
7510        }
7511        if($Type eq "d") {
7512            $Cmd .= " /AD";
7513        }
7514        my @Files = ();
7515        if($Name)
7516        { # FIXME: how to search file names in MS shell?
7517            $Name=~s/\*/.*/g if($Name!~/\]/);
7518            foreach my $File (split(/\n/, `$Cmd`))
7519            {
7520                if($File=~/$Name\Z/i) {
7521                    push(@Files, $File);
7522                }
7523            }
7524        }
7525        else {
7526            @Files = split(/\n/, `$Cmd 2>\"$TMP_DIR/null\"`);
7527        }
7528        my @AbsPaths = ();
7529        foreach my $File (@Files)
7530        {
7531            if(not is_abs($File)) {
7532                $File = joinPath($Path, $File);
7533            }
7534            if($Type eq "f" and not -f $File)
7535            { # skip dirs
7536                next;
7537            }
7538            push(@AbsPaths, path_format($File, $OSgroup));
7539        }
7540        if($Type eq "d") {
7541            push(@AbsPaths, $Path);
7542        }
7543        return @AbsPaths;
7544    }
7545    else
7546    {
7547        my $FindCmd = get_CmdPath("find");
7548        if(not $FindCmd) {
7549            exitStatus("Not_Found", "can't find a \"find\" command");
7550        }
7551        $Path = get_abs_path($Path);
7552        if(-d $Path and -l $Path
7553        and $Path!~/\/\Z/)
7554        { # for directories that are symlinks
7555            $Path.="/";
7556        }
7557        my $Cmd = $FindCmd." \"$Path\"";
7558        if($MaxDepth) {
7559            $Cmd .= " -maxdepth $MaxDepth";
7560        }
7561        if($Type) {
7562            $Cmd .= " -type $Type";
7563        }
7564        if($Name)
7565        { # file name
7566            if($Name=~/\]/) {
7567                $Cmd .= " -regex \"$Name\"";
7568            }
7569            else {
7570                $Cmd .= " -name \"$Name\"";
7571            }
7572        }
7573        return split(/\n/, `$Cmd 2>\"$TMP_DIR/null\"`);
7574    }
7575}
7576
7577sub unpackDump($)
7578{
7579    my $Path = $_[0];
7580    return "" if(not $Path or not -e $Path);
7581    $Path = get_abs_path($Path);
7582    $Path = path_format($Path, $OSgroup);
7583    my ($Dir, $FileName) = separate_path($Path);
7584    my $UnpackDir = $TMP_DIR."/unpack";
7585    rmtree($UnpackDir);
7586    mkpath($UnpackDir);
7587    if($FileName=~s/\Q.zip\E\Z//g)
7588    { # *.zip
7589        my $UnzipCmd = get_CmdPath("unzip");
7590        if(not $UnzipCmd) {
7591            exitStatus("Not_Found", "can't find \"unzip\" command");
7592        }
7593        chdir($UnpackDir);
7594        system("$UnzipCmd \"$Path\" >contents.txt");
7595        if($?) {
7596            exitStatus("Error", "can't extract \'$Path\'");
7597        }
7598        chdir($ORIG_DIR);
7599        my @Contents = ();
7600        foreach (split("\n", readFile("$UnpackDir/contents.txt")))
7601        {
7602            if(/inflating:\s*([^\s]+)/) {
7603                push(@Contents, $1);
7604            }
7605        }
7606        if(not @Contents) {
7607            exitStatus("Error", "can't extract \'$Path\'");
7608        }
7609        return joinPath($UnpackDir, $Contents[0]);
7610    }
7611    elsif($FileName=~s/\Q.tar.gz\E\Z//g)
7612    { # *.tar.gz
7613        if($OSgroup eq "windows")
7614        { # -xvzf option is not implemented in tar.exe (2003)
7615          # use "gzip.exe -k -d -f" + "tar.exe -xvf" instead
7616            my $TarCmd = get_CmdPath("tar");
7617            if(not $TarCmd) {
7618                exitStatus("Not_Found", "can't find \"tar\" command");
7619            }
7620            my $GzipCmd = get_CmdPath("gzip");
7621            if(not $GzipCmd) {
7622                exitStatus("Not_Found", "can't find \"gzip\" command");
7623            }
7624            chdir($UnpackDir);
7625            system("$GzipCmd -k -d -f \"$Path\""); # keep input files (-k)
7626            if($?) {
7627                exitStatus("Error", "can't extract \'$Path\'");
7628            }
7629            system("$TarCmd -xvf \"$Dir\\$FileName.tar\" >contents.txt");
7630            if($?) {
7631                exitStatus("Error", "can't extract \'$Path\'");
7632            }
7633            chdir($ORIG_DIR);
7634            unlink($Dir."/".$FileName.".tar");
7635            my @Contents = split("\n", readFile("$UnpackDir/contents.txt"));
7636            if(not @Contents) {
7637                exitStatus("Error", "can't extract \'$Path\'");
7638            }
7639            return joinPath($UnpackDir, $Contents[0]);
7640        }
7641        else
7642        { # Unix
7643            my $TarCmd = get_CmdPath("tar");
7644            if(not $TarCmd) {
7645                exitStatus("Not_Found", "can't find \"tar\" command");
7646            }
7647            chdir($UnpackDir);
7648            system("$TarCmd -xvzf \"$Path\" >contents.txt");
7649            if($?) {
7650                exitStatus("Error", "can't extract \'$Path\'");
7651            }
7652            chdir($ORIG_DIR);
7653            # The content file name may be different
7654            # from the package file name
7655            my @Contents = split("\n", readFile("$UnpackDir/contents.txt"));
7656            if(not @Contents) {
7657                exitStatus("Error", "can't extract \'$Path\'");
7658            }
7659            return joinPath($UnpackDir, $Contents[0]);
7660        }
7661    }
7662}
7663
7664sub createArchive($$)
7665{
7666    my ($Path, $To) = @_;
7667    if(not $To) {
7668        $To = ".";
7669    }
7670    if(not $Path or not -e $Path
7671    or not -d $To) {
7672        return "";
7673    }
7674    my ($From, $Name) = separate_path($Path);
7675    if($OSgroup eq "windows")
7676    { # *.zip
7677        my $ZipCmd = get_CmdPath("zip");
7678        if(not $ZipCmd) {
7679            exitStatus("Not_Found", "can't find \"zip\"");
7680        }
7681        my $Pkg = $To."/".$Name.".zip";
7682        unlink($Pkg);
7683        chdir($To);
7684        system("$ZipCmd -j \"$Name.zip\" \"$Path\" >\"$TMP_DIR/null\"");
7685        if($?)
7686        { # cannot allocate memory (or other problems with "zip")
7687            unlink($Path);
7688            exitStatus("Error", "can't pack the ABI dump: ".$!);
7689        }
7690        chdir($ORIG_DIR);
7691        unlink($Path);
7692        return $Pkg;
7693    }
7694    else
7695    { # *.tar.gz
7696        my $TarCmd = get_CmdPath("tar");
7697        if(not $TarCmd) {
7698            exitStatus("Not_Found", "can't find \"tar\"");
7699        }
7700        my $GzipCmd = get_CmdPath("gzip");
7701        if(not $GzipCmd) {
7702            exitStatus("Not_Found", "can't find \"gzip\"");
7703        }
7704        my $Pkg = abs_path($To)."/".$Name.".tar.gz";
7705        unlink($Pkg);
7706        chdir($From);
7707        system($TarCmd, "-czf", $Pkg, $Name);
7708        if($?)
7709        { # cannot allocate memory (or other problems with "tar")
7710            unlink($Path);
7711            exitStatus("Error", "can't pack the ABI dump: ".$!);
7712        }
7713        chdir($ORIG_DIR);
7714        unlink($Path);
7715        return $To."/".$Name.".tar.gz";
7716    }
7717}
7718
7719sub is_header_file($)
7720{
7721    if($_[0]=~/\.($HEADER_EXT)\Z/i) {
7722        return $_[0];
7723    }
7724    return 0;
7725}
7726
7727sub is_not_header($)
7728{
7729    if($_[0]=~/\.\w+\Z/
7730    and $_[0]!~/\.($HEADER_EXT)\Z/i) {
7731        return 1;
7732    }
7733    return 0;
7734}
7735
7736sub is_header($$$)
7737{
7738    my ($Header, $UserDefined, $LibVersion) = @_;
7739    return 0 if(-d $Header);
7740    if(-f $Header) {
7741        $Header = get_abs_path($Header);
7742    }
7743    else
7744    {
7745        if(is_abs($Header))
7746        { # incorrect absolute path
7747            return 0;
7748        }
7749        if(my $HPath = identifyHeader($Header, $LibVersion)) {
7750            $Header = $HPath;
7751        }
7752        else
7753        { # can't find header
7754            return 0;
7755        }
7756    }
7757    if($Header=~/\.\w+\Z/)
7758    { # have an extension
7759        return is_header_file($Header);
7760    }
7761    else
7762    {
7763        if($UserDefined==2)
7764        { # specified on the command line
7765            if(cmd_file($Header)!~/HTML|XML/i) {
7766                return $Header;
7767            }
7768        }
7769        elsif($UserDefined)
7770        { # specified in the XML-descriptor
7771          # header file without an extension
7772            return $Header;
7773        }
7774        else
7775        {
7776            if($Header=~/\/include\//
7777            or cmd_file($Header)=~/C[\+]*\s+program/i)
7778            { # !~/HTML|XML|shared|dynamic/i
7779                return $Header;
7780            }
7781        }
7782    }
7783    return 0;
7784}
7785
7786sub addTargetHeaders($)
7787{
7788    my $LibVersion = $_[0];
7789    foreach my $RegHeader (keys(%{$Registered_Headers{$LibVersion}}))
7790    {
7791        my $RegDir = get_dirname($RegHeader);
7792        $TargetHeaders{$LibVersion}{get_filename($RegHeader)}=1;
7793        foreach my $RecInc (keys(%{$RecursiveIncludes{$LibVersion}{$RegHeader}}))
7794        {
7795            my $Dir = get_dirname($RecInc);
7796            if($Dir=~/\A\Q$RegDir\E([\/\\]|\Z)/
7797            or $RecursiveIncludes{$LibVersion}{$RegHeader}{$RecInc}!=1)
7798            { # in the same directory or included by #include "..."
7799                $TargetHeaders{$LibVersion}{get_filename($RecInc)}=1;
7800            }
7801        }
7802    }
7803}
7804
7805sub readHeaders($)
7806{
7807    $Version = $_[0];
7808    printMsg("INFO", "checking header(s) ".$Descriptor{$Version}{"Version"}." ...");
7809    my $DumpPath = getDump();
7810    if(not $DumpPath) {
7811        exitStatus("Cannot_Compile", "can't compile header(s)");
7812    }
7813    if($Debug)
7814    { # debug mode
7815        mkpath($DEBUG_PATH{$Version});
7816        copy($DumpPath, $DEBUG_PATH{$Version}."/translation-unit-dump.txt");
7817    }
7818    getInfo($DumpPath);
7819}
7820
7821sub prepareTypes($)
7822{
7823    my $LibVersion = $_[0];
7824    if(not checkDump($LibVersion, "2.0"))
7825    { # support for old ABI dumps
7826      # type names have been corrected in ACC 1.22 (dump 2.0 format)
7827        foreach my $TypeId (keys(%{$TypeInfo{$LibVersion}}))
7828        {
7829            my $TName = $TypeInfo{$LibVersion}{$TypeId}{"Name"};
7830            if($TName=~/\A(\w+)::(\w+)/) {
7831                my ($P1, $P2) = ($1, $2);
7832                if($P1 eq $P2) {
7833                    $TName=~s/\A$P1:\:$P1(\W)/$P1$1/;
7834                }
7835                else {
7836                    $TName=~s/\A(\w+:\:)$P2:\:$P2(\W)/$1$P2$2/;
7837                }
7838            }
7839            $TypeInfo{$LibVersion}{$TypeId}{"Name"} = $TName;
7840        }
7841    }
7842    if(not checkDump($LibVersion, "2.5"))
7843    { # support for old ABI dumps
7844      # V < 2.5: array size == "number of elements"
7845      # V >= 2.5: array size in bytes
7846        foreach my $TypeId (sort {int($a)<=>int($b)} keys(%{$TypeInfo{$LibVersion}}))
7847        {
7848            my %Type = get_PureType($TypeId, $LibVersion);
7849            if($Type{"Type"} eq "Array")
7850            {
7851                if($Type{"Size"})
7852                { # array[N]
7853                    my %Base = get_OneStep_BaseType($Type{"Tid"}, $LibVersion);
7854                    $TypeInfo{$LibVersion}{$TypeId}{"Size"} = $Type{"Size"}*$Base{"Size"};
7855                }
7856                else
7857                { # array[] is a pointer
7858                    $TypeInfo{$LibVersion}{$TypeId}{"Size"} = $WORD_SIZE{$LibVersion};
7859                }
7860            }
7861        }
7862    }
7863    my $V2 = ($LibVersion==1)?2:1;
7864    if(not checkDump($LibVersion, "2.7"))
7865    { # support for old ABI dumps
7866      # size of "method ptr" corrected in 2.7
7867        foreach my $TypeId (sort {int($a)<=>int($b)} keys(%{$TypeInfo{$LibVersion}}))
7868        {
7869            my %PureType = get_PureType($TypeId, $LibVersion);
7870            if($PureType{"Type"} eq "MethodPtr")
7871            {
7872                my %Type = get_Type($TypeId, $LibVersion);
7873                my $TypeId_2 = getTypeIdByName($PureType{"Name"}, $V2);
7874                my %Type2 = get_Type($TypeId_2, $V2);
7875                if($Type{"Size"} ne $Type2{"Size"}) {
7876                    $TypeInfo{$LibVersion}{$TypeId}{"Size"} = $Type2{"Size"};
7877                }
7878            }
7879        }
7880    }
7881}
7882
7883sub prepareSymbols($)
7884{
7885    my $LibVersion = $_[0];
7886
7887    if(not keys(%{$SymbolInfo{$LibVersion}}))
7888    { # check if input is valid
7889        if(not $ExtendedCheck and not $CheckObjectsOnly)
7890        {
7891            if($CheckHeadersOnly) {
7892                exitStatus("Empty_Set", "the set of public symbols is empty (".$Descriptor{$LibVersion}{"Version"}.")");
7893            }
7894            else {
7895                exitStatus("Empty_Intersection", "the sets of public symbols in headers and libraries have empty intersection (".$Descriptor{$LibVersion}{"Version"}.")");
7896            }
7897        }
7898    }
7899
7900    my $Remangle = 0;
7901    if(not checkDump(1, "2.10")
7902    or not checkDump(2, "2.10"))
7903    { # different formats
7904        $Remangle = 1;
7905    }
7906    if($CheckHeadersOnly)
7907    { # different languages
7908        if($UserLang)
7909        { # --lang=LANG for both versions
7910            if(($UsedDump{1}{"V"} and $UserLang ne $UsedDump{1}{"L"})
7911            or ($UsedDump{2}{"V"} and $UserLang ne $UsedDump{2}{"L"}))
7912            {
7913                if($UserLang eq "C++")
7914                { # remangle symbols
7915                    $Remangle = 1;
7916                }
7917                elsif($UserLang eq "C")
7918                { # remove mangling
7919                    $Remangle = -1;
7920                }
7921            }
7922        }
7923    }
7924
7925    foreach my $InfoId (sort {int($b)<=>int($a)} keys(%{$SymbolInfo{$LibVersion}}))
7926    { # reverse order: D0, D1, D2, D0 (artificial, GCC < 4.5), C1, C2
7927        if(not checkDump($LibVersion, "2.13"))
7928        { # support for old ABI dumps
7929            if(defined $SymbolInfo{$LibVersion}{$InfoId}{"Param"})
7930            {
7931                foreach my $P (keys(%{$SymbolInfo{$LibVersion}{$InfoId}{"Param"}}))
7932                {
7933                    my $TypeId = $SymbolInfo{$LibVersion}{$InfoId}{"Param"}{$P}{"type"};
7934                    my $DVal = $SymbolInfo{$LibVersion}{$InfoId}{"Param"}{$P}{"default"};
7935                    my $TName = $TypeInfo{$LibVersion}{$TypeId}{"Name"};
7936                    if(defined $DVal and $DVal ne "")
7937                    {
7938                        if($TName eq "char") {
7939                            $SymbolInfo{$LibVersion}{$InfoId}{"Param"}{$P}{"default"} = chr($DVal);
7940                        }
7941                        elsif($TName eq "bool") {
7942                            $SymbolInfo{$LibVersion}{$InfoId}{"Param"}{$P}{"default"} = $DVal?"true":"false";
7943                        }
7944                    }
7945                }
7946            }
7947        }
7948        if($SymbolInfo{$LibVersion}{$InfoId}{"Destructor"})
7949        {
7950            if(defined $SymbolInfo{$LibVersion}{$InfoId}{"Param"}
7951            and keys(%{$SymbolInfo{$LibVersion}{$InfoId}{"Param"}})
7952            and $SymbolInfo{$LibVersion}{$InfoId}{"Param"}{0}{"name"})
7953            { # support for old GCC < 4.5: skip artificial ~dtor(int __in_chrg)
7954              # + support for old ABI dumps
7955                next;
7956            }
7957        }
7958        my $MnglName = $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"};
7959        my $ShortName = $SymbolInfo{$LibVersion}{$InfoId}{"ShortName"};
7960        my $ClassID = $SymbolInfo{$LibVersion}{$InfoId}{"Class"};
7961        my $Return = $SymbolInfo{$LibVersion}{$InfoId}{"Return"};
7962
7963        if(not $MnglName)
7964        { # ABI dumps have no mangled names for C-functions
7965            $MnglName = $ShortName;
7966            $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"} = $MnglName;
7967        }
7968
7969        my $SRemangle = 0;
7970        if(not checkDump(1, "2.12")
7971        or not checkDump(2, "2.12"))
7972        { # support for old ABI dumps
7973            if($ShortName eq "operator>>")
7974            {
7975                if(not $SymbolInfo{$LibVersion}{$InfoId}{"Class"})
7976                { # corrected mangling of operator>>
7977                    $SRemangle = 1;
7978                }
7979            }
7980            if($SymbolInfo{$LibVersion}{$InfoId}{"Data"})
7981            {
7982                if(not $SymbolInfo{$LibVersion}{$InfoId}{"Class"}
7983                and isConstType($Return, $LibVersion) and $MnglName!~/L\d+$ShortName/)
7984                { # corrected mangling of const global data
7985                  # some global data is not mangled in the TU dump: qt_sine_table (Qt 4.8)
7986                  # and incorrectly mangled by old ACC versions
7987                    $SRemangle = 1;
7988                }
7989            }
7990        }
7991        if(not $CheckHeadersOnly)
7992        { # support for old ABI dumps
7993            if(not checkDump(1, "2.17")
7994            or not checkDump(2, "2.17"))
7995            {
7996                if($SymbolInfo{$LibVersion}{$InfoId}{"Data"})
7997                {
7998                    if(not $SymbolInfo{$LibVersion}{$InfoId}{"Class"})
7999                    {
8000                        if(link_symbol($ShortName, $LibVersion, "-Deps"))
8001                        {
8002                            $MnglName = $ShortName;
8003                            $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"} = $MnglName;
8004                        }
8005                    }
8006                }
8007            }
8008        }
8009        if($Remangle==1 or $SRemangle==1)
8010        { # support for old ABI dumps: some symbols are not mangled in old dumps
8011          # mangle both sets of symbols (old and new)
8012          # NOTE: remangling all symbols by the same mangler
8013            if($MnglName=~/\A_ZN(V|)K/)
8014            { # mangling may be incorrect on old ABI dumps
8015              # because of absent "Const" attribute
8016                $SymbolInfo{$LibVersion}{$InfoId}{"Const"} = 1;
8017            }
8018            if($MnglName=~/\A_ZN(K|)V/)
8019            { # mangling may be incorrect on old ABI dumps
8020              # because of absent "Volatile" attribute
8021                $SymbolInfo{$LibVersion}{$InfoId}{"Volatile"} = 1;
8022            }
8023            if(($ClassID and $MnglName!~/\A(_Z|\?)/)
8024            or (not $ClassID and $CheckHeadersOnly)
8025            or (not $ClassID and not link_symbol($MnglName, $LibVersion, "-Deps")))
8026            { # support for old ABI dumps, GCC >= 4.0
8027              # remangling all manually mangled symbols
8028                if($MnglName = mangle_symbol($InfoId, $LibVersion, "GCC"))
8029                {
8030                    $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"} = $MnglName;
8031                    $MangledNames{$LibVersion}{$MnglName} = 1;
8032                }
8033            }
8034        }
8035        elsif($Remangle==-1)
8036        { # remove mangling
8037            $MnglName = "";
8038            $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"} = "";
8039        }
8040        if(not $MnglName) {
8041            next;
8042        }
8043        if(not $CompleteSignature{$LibVersion}{$MnglName}{"MnglName"})
8044        { # NOTE: global data may enter here twice
8045            %{$CompleteSignature{$LibVersion}{$MnglName}} = %{$SymbolInfo{$LibVersion}{$InfoId}};
8046
8047        }
8048        if(not checkDump($LibVersion, "2.6"))
8049        { # support for old dumps
8050          # add "Volatile" attribute
8051            if($MnglName=~/_Z(K|)V/) {
8052                $CompleteSignature{$LibVersion}{$MnglName}{"Volatile"}=1;
8053            }
8054        }
8055        # symbol and its symlink have same signatures
8056        if($SymVer{$LibVersion}{$MnglName}) {
8057            %{$CompleteSignature{$LibVersion}{$SymVer{$LibVersion}{$MnglName}}} = %{$SymbolInfo{$LibVersion}{$InfoId}};
8058        }
8059
8060        # clean memory
8061        delete($SymbolInfo{$LibVersion}{$InfoId});
8062    }
8063    if($COMMON_LANGUAGE{$LibVersion} eq "C++" or $OSgroup eq "windows") {
8064        translateSymbols(keys(%{$CompleteSignature{$LibVersion}}), $LibVersion);
8065    }
8066    if($ExtendedCheck)
8067    { # --ext option
8068        addExtension($LibVersion);
8069    }
8070
8071    # clean memory
8072    delete($SymbolInfo{$LibVersion});
8073
8074    foreach my $Symbol (keys(%{$CompleteSignature{$LibVersion}}))
8075    { # detect allocable classes with public exported constructors
8076      # or classes with auto-generated or inline-only constructors
8077        if(my $ClassId = $CompleteSignature{$LibVersion}{$Symbol}{"Class"})
8078        {
8079            my $ClassName = $TypeInfo{$LibVersion}{$ClassId}{"Name"};
8080            if($CompleteSignature{$LibVersion}{$Symbol}{"Constructor"}
8081            and not $CompleteSignature{$LibVersion}{$Symbol}{"InLine"})
8082            { # Class() { ... } will not be exported
8083                if(not $CompleteSignature{$LibVersion}{$Symbol}{"Private"})
8084                {
8085                    if($CheckHeadersOnly or link_symbol($Symbol, $LibVersion, "-Deps")) {
8086                        $AllocableClass{$LibVersion}{$ClassName} = 1;
8087                    }
8088                }
8089            }
8090            if(not $CompleteSignature{$LibVersion}{$Symbol}{"Private"})
8091            { # all imported class methods
8092                if(symbolFilter($Symbol, $LibVersion, "Affected", "Binary"))
8093                {
8094                    if($CheckHeadersOnly)
8095                    {
8096                        if(not $CompleteSignature{$LibVersion}{$Symbol}{"InLine"}
8097                        or $CompleteSignature{$LibVersion}{$Symbol}{"Virt"})
8098                        { # all symbols except non-virtual inline
8099                            $ClassMethods{"Binary"}{$LibVersion}{$ClassName}{$Symbol} = 1;
8100                        }
8101                    }
8102                    else {
8103                        $ClassMethods{"Binary"}{$LibVersion}{$ClassName}{$Symbol} = 1;
8104                    }
8105                }
8106                if(symbolFilter($Symbol, $LibVersion, "Affected", "Source")) {
8107                    $ClassMethods{"Source"}{$LibVersion}{$ClassName}{$Symbol} = 1;
8108                }
8109            }
8110            $ClassNames{$LibVersion}{$ClassName} = 1;
8111        }
8112        if(my $RetId = $CompleteSignature{$LibVersion}{$Symbol}{"Return"})
8113        {
8114            my %Base = get_BaseType($RetId, $LibVersion);
8115            if(defined $Base{"Type"}
8116            and $Base{"Type"}=~/Struct|Class/)
8117            {
8118                my $Name = $TypeInfo{$LibVersion}{$Base{"Tid"}}{"Name"};
8119                if($Name=~/<([^<>\s]+)>/)
8120                {
8121                    if(my $Tid = getTypeIdByName($1, $LibVersion)) {
8122                        $ReturnedClass{$LibVersion}{$Tid} = 1;
8123                    }
8124                }
8125                else {
8126                    $ReturnedClass{$LibVersion}{$Base{"Tid"}} = 1;
8127                }
8128            }
8129        }
8130        foreach my $Num (keys(%{$CompleteSignature{$LibVersion}{$Symbol}{"Param"}}))
8131        {
8132            my $PId = $CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$Num}{"type"};
8133            if(get_PLevel($PId, $LibVersion)>=1)
8134            {
8135                if(my %Base = get_BaseType($PId, $LibVersion))
8136                {
8137                    if($Base{"Type"}=~/Struct|Class/)
8138                    {
8139                        $ParamClass{$LibVersion}{$Base{"Tid"}}{$Symbol} = 1;
8140                        foreach my $SubId (get_sub_classes($Base{"Tid"}, $LibVersion, 1))
8141                        { # mark all derived classes
8142                            $ParamClass{$LibVersion}{$SubId}{$Symbol} = 1;
8143                        }
8144                    }
8145                }
8146            }
8147        }
8148    }
8149    foreach my $MnglName (keys(%VTableClass))
8150    { # reconstruct header name for v-tables
8151        if($MnglName=~/\A_ZTV/)
8152        {
8153            if(my $ClassName = $VTableClass{$MnglName})
8154            {
8155                if(my $ClassId = $TName_Tid{$LibVersion}{$ClassName}) {
8156                    $CompleteSignature{$LibVersion}{$MnglName}{"Header"} = $TypeInfo{$LibVersion}{$ClassId}{"Header"};
8157                }
8158            }
8159        }
8160    }
8161
8162    # types
8163    foreach my $TypeId (keys(%{$TypeInfo{$LibVersion}}))
8164    {
8165        if(my $TName = $TypeInfo{$LibVersion}{$TypeId}{"Name"})
8166        {
8167            if(defined $TypeInfo{$LibVersion}{$TypeId}{"VTable"}) {
8168                $ClassNames{$LibVersion}{$TName} = 1;
8169            }
8170            if(defined $TypeInfo{$LibVersion}{$TypeId}{"Base"})
8171            {
8172                $ClassNames{$LibVersion}{$TName} = 1;
8173                foreach my $Bid (keys(%{$TypeInfo{$LibVersion}{$TypeId}{"Base"}}))
8174                {
8175                    if(my $BName = $TypeInfo{$LibVersion}{$Bid}{"Name"}) {
8176                        $ClassNames{$LibVersion}{$BName} = 1;
8177                    }
8178                }
8179            }
8180        }
8181    }
8182}
8183
8184sub register_TypeUsage($$)
8185{
8186    my ($TypeId, $LibVersion) = @_;
8187    if(not $TypeId) {
8188        return 0;
8189    }
8190    if($UsedType{$LibVersion}{$TypeId})
8191    { # already registered
8192        return 1;
8193    }
8194    my %TInfo = get_Type($TypeId, $LibVersion);
8195    if($TInfo{"Type"})
8196    {
8197        if($TInfo{"Type"}=~/\A(Struct|Union|Class|FuncPtr|MethodPtr|FieldPtr|Enum)\Z/)
8198        {
8199            $UsedType{$LibVersion}{$TypeId} = 1;
8200            if($TInfo{"Type"}=~/\A(Struct|Class)\Z/)
8201            {
8202                foreach my $BaseId (keys(%{$TInfo{"Base"}}))
8203                { # register base classes
8204                    register_TypeUsage($BaseId, $LibVersion);
8205                }
8206                foreach my $TPos (keys(%{$TInfo{"TParam"}}))
8207                {
8208                    my $TPName = $TInfo{"TParam"}{$TPos}{"name"};
8209                    if(my $TTid = $TName_Tid{$LibVersion}{$TPName}) {
8210                        register_TypeUsage($TTid, $LibVersion);
8211                    }
8212                }
8213            }
8214            foreach my $Memb_Pos (keys(%{$TInfo{"Memb"}}))
8215            {
8216                if(my $MTid = $TInfo{"Memb"}{$Memb_Pos}{"type"}) {
8217                    register_TypeUsage($MTid, $LibVersion);
8218                }
8219            }
8220            if($TInfo{"Type"} eq "FuncPtr"
8221            or $TInfo{"Type"} eq "MethodPtr")
8222            {
8223                if(my $RTid = $TInfo{"Return"}) {
8224                    register_TypeUsage($RTid, $LibVersion);
8225                }
8226                foreach my $Memb_Pos (keys(%{$TInfo{"Param"}}))
8227                {
8228                    if(my $MTid = $TInfo{"Param"}{$Memb_Pos}{"type"}) {
8229                        register_TypeUsage($MTid, $LibVersion);
8230                    }
8231                }
8232            }
8233            return 1;
8234        }
8235        elsif($TInfo{"Type"}=~/\A(Const|ConstVolatile|Volatile|Pointer|Ref|Restrict|Array|Typedef)\Z/)
8236        {
8237            $UsedType{$LibVersion}{$TypeId} = 1;
8238            register_TypeUsage($TInfo{"BaseType"}{"Tid"}, $LibVersion);
8239            return 1;
8240        }
8241        elsif($TInfo{"Type"} eq "Intrinsic")
8242        {
8243            $UsedType{$LibVersion}{$TypeId} = 1;
8244            return 1;
8245        }
8246    }
8247    return 0;
8248}
8249
8250sub selectSymbol($$$$)
8251{ # select symbol to check or to dump
8252    my ($Symbol, $SInfo, $Level, $LibVersion) = @_;
8253
8254    if($Level eq "Dump")
8255    {
8256        if($SInfo->{"Virt"} or $SInfo->{"PureVirt"})
8257        { # TODO: check if this symbol is from
8258          # base classes of other target symbols
8259            return 1;
8260        }
8261    }
8262
8263    if(not $STDCXX_TESTING and $Symbol=~/\A(_ZS|_ZNS|_ZNKS)/)
8264    { # stdc++ interfaces
8265        return 0;
8266    }
8267
8268    my $Target = 0;
8269    if(my $Header = $SInfo->{"Header"}) {
8270        $Target = (is_target_header($Header, 1) or is_target_header($Header, 2));
8271    }
8272    if($CheckHeadersOnly)
8273    {
8274        if($Target)
8275        {
8276            if($Level eq "Dump")
8277            { # dumped
8278                if($BinaryOnly)
8279                {
8280                    if(not $SInfo->{"InLine"} or $SInfo->{"Data"}) {
8281                        return 1;
8282                    }
8283                }
8284                else {
8285                    return 1;
8286                }
8287            }
8288            elsif($Level eq "Source")
8289            { # checked
8290                return 1;
8291            }
8292            elsif($Level eq "Binary")
8293            { # checked
8294                if(not $SInfo->{"InLine"} or $SInfo->{"Data"}
8295                or $SInfo->{"Virt"} or $SInfo->{"PureVirt"}) {
8296                    return 1;
8297                }
8298            }
8299        }
8300    }
8301    else
8302    { # library is available
8303        if(link_symbol($Symbol, $LibVersion, "-Deps"))
8304        { # exported symbols
8305            return 1;
8306        }
8307        if($Level eq "Dump")
8308        { # dumped
8309            if($BinaryOnly)
8310            {
8311                if($SInfo->{"Data"})
8312                {
8313                    if($Target) {
8314                        return 1;
8315                    }
8316                }
8317            }
8318            else
8319            { # SrcBin
8320                if($Target) {
8321                    return 1;
8322                }
8323            }
8324        }
8325        elsif($Level eq "Source")
8326        { # checked
8327            if($SInfo->{"PureVirt"} or $SInfo->{"Data"} or $SInfo->{"InLine"})
8328            { # skip LOCAL symbols
8329                if($Target) {
8330                    return 1;
8331                }
8332            }
8333        }
8334        elsif($Level eq "Binary")
8335        { # checked
8336            if($SInfo->{"PureVirt"} or $SInfo->{"Data"})
8337            {
8338                if($Target) {
8339                    return 1;
8340                }
8341            }
8342        }
8343    }
8344    return 0;
8345}
8346
8347sub cleanDump($)
8348{ # clean data
8349    my $LibVersion = $_[0];
8350    foreach my $InfoId (keys(%{$SymbolInfo{$LibVersion}}))
8351    {
8352        my $MnglName = $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"};
8353        if(not $MnglName) {
8354            delete($SymbolInfo{$LibVersion}{$InfoId});
8355            next;
8356        }
8357        my $ShortName = $SymbolInfo{$LibVersion}{$InfoId}{"ShortName"};
8358        if(not $ShortName) {
8359            delete($SymbolInfo{$LibVersion}{$InfoId});
8360            next;
8361        }
8362        if($MnglName eq $ShortName)
8363        { # remove duplicate data
8364            delete($SymbolInfo{$LibVersion}{$InfoId}{"MnglName"});
8365        }
8366        if(not keys(%{$SymbolInfo{$LibVersion}{$InfoId}{"Param"}})) {
8367            delete($SymbolInfo{$LibVersion}{$InfoId}{"Param"});
8368        }
8369    }
8370    foreach my $Tid (keys(%{$TypeInfo{$LibVersion}}))
8371    {
8372        foreach my $Attr ("Header", "Line", "Size", "NameSpace")
8373        {
8374            if(not $TypeInfo{$LibVersion}{$Tid}{$Attr}) {
8375                delete($TypeInfo{$LibVersion}{$Tid}{$Attr});
8376            }
8377        }
8378    }
8379}
8380
8381sub selectType($$)
8382{
8383    my ($Tid, $LibVersion) = @_;
8384    if(my $THeader = $TypeInfo{$LibVersion}{$Tid}{"Header"})
8385    {
8386        if(not isBuiltIn($THeader))
8387        {
8388            if($TypeInfo{$LibVersion}{$Tid}{"Type"}=~/Class|Struct|Union|Enum|Typedef/)
8389            {
8390                if(not isAnon($TypeInfo{$LibVersion}{$Tid}{"Name"}))
8391                {
8392                    if(is_target_header($THeader, $LibVersion))
8393                    { # from target headers
8394                        if(not selfTypedef($Tid, $LibVersion)) {
8395                            return 1;
8396                        }
8397                    }
8398                }
8399            }
8400        }
8401    }
8402    return 0;
8403}
8404
8405sub removeUnused($$)
8406{ # remove unused data types from the ABI dump
8407    my ($LibVersion, $Kind) = @_;
8408    foreach my $InfoId (keys(%{$SymbolInfo{$LibVersion}}))
8409    {
8410        my %FuncInfo = %{$SymbolInfo{$LibVersion}{$InfoId}};
8411        if(my $RTid = $FuncInfo{"Return"}) {
8412            register_TypeUsage($RTid, $LibVersion);
8413        }
8414        if(my $FCid = $FuncInfo{"Class"})
8415        {
8416            register_TypeUsage($FCid, $LibVersion);
8417            if(my $ThisId = getTypeIdByName($TypeInfo{$LibVersion}{$FCid}{"Name"}."*const", $LibVersion))
8418            { # register "this" pointer
8419                $UsedType{$LibVersion}{$ThisId} = 1;
8420                if(my %ThisType = get_Type($ThisId, $LibVersion)) {
8421                    register_TypeUsage($ThisType{"BaseType"}{"Tid"}, $LibVersion);
8422                }
8423            }
8424        }
8425        foreach my $PPos (keys(%{$FuncInfo{"Param"}}))
8426        {
8427            if(my $PTid = $FuncInfo{"Param"}{$PPos}{"type"}) {
8428                register_TypeUsage($PTid, $LibVersion);
8429            }
8430        }
8431        foreach my $TPos (keys(%{$FuncInfo{"TParam"}}))
8432        {
8433            my $TPName = $FuncInfo{"TParam"}{$TPos}{"name"};
8434            if(my $TTid = $TName_Tid{$LibVersion}{$TPName}) {
8435                register_TypeUsage($TTid, $LibVersion);
8436            }
8437        }
8438    }
8439    foreach my $Tid (keys(%{$TypeInfo{$LibVersion}}))
8440    {
8441        if($UsedType{$LibVersion}{$Tid})
8442        { # All & Derived
8443            next;
8444        }
8445
8446        if($Kind eq "Derived")
8447        {
8448            if(selectType($Tid, $LibVersion)) {
8449                register_TypeUsage($Tid, $LibVersion);
8450            }
8451        }
8452    }
8453    foreach my $Tid (keys(%{$TypeInfo{$LibVersion}}))
8454    { # remove unused types
8455        if($UsedType{$LibVersion}{$Tid})
8456        { # All & Derived
8457            next;
8458        }
8459        # remove type
8460        delete($TypeInfo{$LibVersion}{$Tid});
8461    }
8462
8463    # clean memory
8464    %UsedType = ();
8465}
8466
8467sub selfTypedef($$)
8468{
8469    my ($TypeId, $LibVersion) = @_;
8470    my %Type = get_Type($TypeId, $LibVersion);
8471    if($Type{"Type"} eq "Typedef")
8472    {
8473        my %Base = get_OneStep_BaseType($TypeId, $LibVersion);
8474        if($Base{"Type"}=~/Class|Struct/)
8475        {
8476            if($Type{"Name"} eq $Base{"Name"}) {
8477                return 1;
8478            }
8479            elsif($Type{"Name"}=~/::(\w+)\Z/)
8480            {
8481                if($Type{"Name"} eq $Base{"Name"}."::".$1)
8482                { # QPointer<QWidget>::QPointer
8483                    return 1;
8484                }
8485            }
8486        }
8487    }
8488    return 0;
8489}
8490
8491sub addExtension($)
8492{
8493    my $LibVersion = $_[0];
8494    foreach my $Tid (keys(%{$TypeInfo{$LibVersion}}))
8495    {
8496        if(selectType($Tid, $LibVersion))
8497        {
8498            my $Symbol = "external_func_".$TypeInfo{$LibVersion}{$Tid}{"Name"};
8499
8500            %{$CompleteSignature{$LibVersion}{$Symbol}} = (
8501                "Header" => "extended.h",
8502                "ShortName" => $Symbol,
8503                "MnglName" => $Symbol,
8504                "Param" => { 0 => { "type"=>$Tid, "name"=>"p1" } }
8505            );
8506
8507            $ExtendedSymbols{$Symbol}=1;
8508            $CheckedSymbols{"Binary"}{$Symbol}=1;
8509            $CheckedSymbols{"Source"}{$Symbol}=1;
8510        }
8511    }
8512    $ExtendedSymbols{"external_func_0"}=1;
8513    $CheckedSymbols{"Binary"}{"external_func_0"}=1;
8514    $CheckedSymbols{"Source"}{"external_func_0"}=1;
8515}
8516
8517sub findMethod($$$)
8518{
8519    my ($VirtFunc, $ClassId, $LibVersion) = @_;
8520    foreach my $BaseClass_Id (keys(%{$TypeInfo{$LibVersion}{$ClassId}{"Base"}}))
8521    {
8522        if(my $VirtMethodInClass = findMethod_Class($VirtFunc, $BaseClass_Id, $LibVersion)) {
8523            return $VirtMethodInClass;
8524        }
8525        elsif(my $VirtMethodInBaseClasses = findMethod($VirtFunc, $BaseClass_Id, $LibVersion)) {
8526            return $VirtMethodInBaseClasses;
8527        }
8528    }
8529    return "";
8530}
8531
8532sub findMethod_Class($$$)
8533{
8534    my ($VirtFunc, $ClassId, $LibVersion) = @_;
8535    my $ClassName = $TypeInfo{$LibVersion}{$ClassId}{"Name"};
8536    return "" if(not defined $VirtualTable{$LibVersion}{$ClassName});
8537    my $TargetSuffix = get_symbol_suffix($VirtFunc, 1);
8538    my $TargetShortName = $CompleteSignature{$LibVersion}{$VirtFunc}{"ShortName"};
8539    foreach my $Candidate (keys(%{$VirtualTable{$LibVersion}{$ClassName}}))
8540    { # search for interface with the same parameters suffix (overridden)
8541        if($TargetSuffix eq get_symbol_suffix($Candidate, 1))
8542        {
8543            if($CompleteSignature{$LibVersion}{$VirtFunc}{"Destructor"}) {
8544                if($CompleteSignature{$LibVersion}{$Candidate}{"Destructor"})
8545                {
8546                    if(($VirtFunc=~/D0E/ and $Candidate=~/D0E/)
8547                    or ($VirtFunc=~/D1E/ and $Candidate=~/D1E/)
8548                    or ($VirtFunc=~/D2E/ and $Candidate=~/D2E/)) {
8549                        return $Candidate;
8550                    }
8551                }
8552            }
8553            else {
8554                if($TargetShortName eq $CompleteSignature{$LibVersion}{$Candidate}{"ShortName"}) {
8555                    return $Candidate;
8556                }
8557            }
8558        }
8559    }
8560    return "";
8561}
8562
8563sub registerVTable($)
8564{
8565    my $LibVersion = $_[0];
8566    foreach my $Symbol (keys(%{$CompleteSignature{$LibVersion}}))
8567    {
8568        if($CompleteSignature{$LibVersion}{$Symbol}{"Virt"}
8569        or $CompleteSignature{$LibVersion}{$Symbol}{"PureVirt"})
8570        {
8571            my $ClassName = $TypeInfo{$LibVersion}{$CompleteSignature{$LibVersion}{$Symbol}{"Class"}}{"Name"};
8572            next if(not $STDCXX_TESTING and $ClassName=~/\A(std::|__cxxabi)/);
8573            if($CompleteSignature{$LibVersion}{$Symbol}{"Destructor"}
8574            and $Symbol=~/D2E/)
8575            { # pure virtual D2-destructors are marked as "virt" in the dump
8576              # virtual D2-destructors are NOT marked as "virt" in the dump
8577              # both destructors are not presented in the v-table
8578                next;
8579            }
8580            my ($MnglName, $VersionSpec, $SymbolVersion) = separate_symbol($Symbol);
8581            $VirtualTable{$LibVersion}{$ClassName}{$MnglName} = 1;
8582        }
8583    }
8584}
8585
8586sub registerOverriding($)
8587{
8588    my $LibVersion = $_[0];
8589    my @Classes = keys(%{$VirtualTable{$LibVersion}});
8590    @Classes = sort {int($TName_Tid{$LibVersion}{$a})<=>int($TName_Tid{$LibVersion}{$b})} @Classes;
8591    foreach my $ClassName (@Classes)
8592    {
8593        foreach my $VirtFunc (keys(%{$VirtualTable{$LibVersion}{$ClassName}}))
8594        {
8595            if($CompleteSignature{$LibVersion}{$VirtFunc}{"PureVirt"})
8596            { # pure virtuals
8597                next;
8598            }
8599            my $ClassId = $TName_Tid{$LibVersion}{$ClassName};
8600            if(my $Overridden = findMethod($VirtFunc, $ClassId, $LibVersion))
8601            {
8602                if($CompleteSignature{$LibVersion}{$Overridden}{"Virt"}
8603                or $CompleteSignature{$LibVersion}{$Overridden}{"PureVirt"})
8604                { # both overridden virtual methods
8605                  # and implemented pure virtual methods
8606                    $CompleteSignature{$LibVersion}{$VirtFunc}{"Override"} = $Overridden;
8607                    $OverriddenMethods{$LibVersion}{$Overridden}{$VirtFunc} = 1;
8608                    delete($VirtualTable{$LibVersion}{$ClassName}{$VirtFunc}); # remove from v-table model
8609                }
8610            }
8611        }
8612        if(not keys(%{$VirtualTable{$LibVersion}{$ClassName}})) {
8613            delete($VirtualTable{$LibVersion}{$ClassName});
8614        }
8615    }
8616}
8617
8618sub setVirtFuncPositions($)
8619{
8620    my $LibVersion = $_[0];
8621    foreach my $ClassName (keys(%{$VirtualTable{$LibVersion}}))
8622    {
8623        my ($Num, $RelPos, $AbsNum) = (1, 0, 1);
8624        foreach my $VirtFunc (sort {int($CompleteSignature{$LibVersion}{$a}{"Line"}) <=> int($CompleteSignature{$LibVersion}{$b}{"Line"})}
8625        sort keys(%{$VirtualTable{$LibVersion}{$ClassName}}))
8626        {
8627            $VirtualTable{$LibVersion}{$ClassName}{$VirtFunc}=$Num++;
8628
8629            # set relative positions
8630            if(defined $VirtualTable{1}{$ClassName} and defined $VirtualTable{1}{$ClassName}{$VirtFunc}
8631            and defined $VirtualTable{2}{$ClassName} and defined $VirtualTable{2}{$ClassName}{$VirtFunc})
8632            { # relative position excluding added and removed virtual functions
8633                if(not $CompleteSignature{1}{$VirtFunc}{"Override"}
8634                and not $CompleteSignature{2}{$VirtFunc}{"Override"}) {
8635                    $CompleteSignature{$LibVersion}{$VirtFunc}{"RelPos"} = $RelPos++;
8636                }
8637            }
8638        }
8639    }
8640    foreach my $ClassName (keys(%{$ClassNames{$LibVersion}}))
8641    {
8642        my $AbsNum = 1;
8643        foreach my $VirtFunc (getVTable_Model($TName_Tid{$LibVersion}{$ClassName}, $LibVersion)) {
8644            $VirtualTable_Model{$LibVersion}{$ClassName}{$VirtFunc}=$AbsNum++;
8645        }
8646    }
8647}
8648
8649sub get_sub_classes($$$)
8650{
8651    my ($ClassId, $LibVersion, $Recursive) = @_;
8652    return () if(not defined $Class_SubClasses{$LibVersion}{$ClassId});
8653    my @Subs = ();
8654    foreach my $SubId (keys(%{$Class_SubClasses{$LibVersion}{$ClassId}}))
8655    {
8656        if($Recursive)
8657        {
8658            foreach my $SubSubId (get_sub_classes($SubId, $LibVersion, $Recursive)) {
8659                push(@Subs, $SubSubId);
8660            }
8661        }
8662        push(@Subs, $SubId);
8663    }
8664    return @Subs;
8665}
8666
8667sub get_base_classes($$$)
8668{
8669    my ($ClassId, $LibVersion, $Recursive) = @_;
8670    my %ClassType = get_Type($ClassId, $LibVersion);
8671    return () if(not defined $ClassType{"Base"});
8672    my @Bases = ();
8673    foreach my $BaseId (sort {int($ClassType{"Base"}{$a}{"pos"})<=>int($ClassType{"Base"}{$b}{"pos"})}
8674    keys(%{$ClassType{"Base"}}))
8675    {
8676        if($Recursive)
8677        {
8678            foreach my $SubBaseId (get_base_classes($BaseId, $LibVersion, $Recursive)) {
8679                push(@Bases, $SubBaseId);
8680            }
8681        }
8682        push(@Bases, $BaseId);
8683    }
8684    return @Bases;
8685}
8686
8687sub getVTable_Model($$)
8688{ # return an ordered list of v-table elements
8689    my ($ClassId, $LibVersion) = @_;
8690    my @Bases = get_base_classes($ClassId, $LibVersion, 1);
8691    my @Elements = ();
8692    foreach my $BaseId (@Bases, $ClassId)
8693    {
8694        if(my $BName = $TypeInfo{$LibVersion}{$BaseId}{"Name"})
8695        {
8696            if(defined $VirtualTable{$LibVersion}{$BName})
8697            {
8698                my @VFunctions = keys(%{$VirtualTable{$LibVersion}{$BName}});
8699                @VFunctions = sort {int($CompleteSignature{$LibVersion}{$a}{"Line"}) <=> int($CompleteSignature{$LibVersion}{$b}{"Line"})} @VFunctions;
8700                foreach my $VFunc (@VFunctions) {
8701                    push(@Elements, $VFunc);
8702                }
8703            }
8704        }
8705    }
8706    return @Elements;
8707}
8708
8709sub getVShift($$)
8710{
8711    my ($ClassId, $LibVersion) = @_;
8712    my @Bases = get_base_classes($ClassId, $LibVersion, 1);
8713    my $VShift = 0;
8714    foreach my $BaseId (@Bases)
8715    {
8716        if(my $BName = $TypeInfo{$LibVersion}{$BaseId}{"Name"})
8717        {
8718            if(defined $VirtualTable{$LibVersion}{$BName}) {
8719                $VShift+=keys(%{$VirtualTable{$LibVersion}{$BName}});
8720            }
8721        }
8722    }
8723    return $VShift;
8724}
8725
8726sub getShift($$)
8727{
8728    my ($ClassId, $LibVersion) = @_;
8729    my @Bases = get_base_classes($ClassId, $LibVersion, 0);
8730    my $Shift = 0;
8731    foreach my $BaseId (@Bases)
8732    {
8733        if(my $Size = $TypeInfo{$LibVersion}{$BaseId}{"Size"})
8734        {
8735            if($Size!=1)
8736            { # not empty base class
8737                $Shift+=$Size;
8738            }
8739        }
8740    }
8741    return $Shift;
8742}
8743
8744sub getVTable_Size($$)
8745{ # number of v-table elements
8746    my ($ClassName, $LibVersion) = @_;
8747    my $Size = 0;
8748    # three approaches
8749    if(not $Size)
8750    { # real size
8751        if(my %VTable = getVTable_Real($ClassName, $LibVersion)) {
8752            $Size = keys(%VTable);
8753        }
8754    }
8755    if(not $Size)
8756    { # shared library symbol size
8757        if($Size = getSymbolSize($ClassVTable{$ClassName}, $LibVersion)) {
8758            $Size /= $WORD_SIZE{$LibVersion};
8759        }
8760    }
8761    if(not $Size)
8762    { # model size
8763        if(defined $VirtualTable_Model{$LibVersion}{$ClassName}) {
8764            $Size = keys(%{$VirtualTable_Model{$LibVersion}{$ClassName}}) + 2;
8765        }
8766    }
8767    return $Size;
8768}
8769
8770sub isCopyingClass($$)
8771{
8772    my ($TypeId, $LibVersion) = @_;
8773    return $TypeInfo{$LibVersion}{$TypeId}{"Copied"};
8774}
8775
8776sub isLeafClass($$)
8777{
8778    my ($ClassId, $LibVersion) = @_;
8779    return (not keys(%{$Class_SubClasses{$LibVersion}{$ClassId}}));
8780}
8781
8782sub havePubFields($)
8783{ # check structured type for public fields
8784    return isAccessible($_[0], {}, 0, -1);
8785}
8786
8787sub isAccessible($$$$)
8788{ # check interval in structured type for public fields
8789    my ($TypePtr, $Skip, $Start, $End) = @_;
8790    return 0 if(not $TypePtr);
8791    if($End==-1) {
8792        $End = keys(%{$TypePtr->{"Memb"}})-1;
8793    }
8794    foreach my $MemPos (keys(%{$TypePtr->{"Memb"}}))
8795    {
8796        if($Skip and $Skip->{$MemPos})
8797        { # skip removed/added fields
8798            next;
8799        }
8800        if(int($MemPos)>=$Start and int($MemPos)<=$End)
8801        {
8802            if(isPublic($TypePtr, $MemPos)) {
8803                return ($MemPos+1);
8804            }
8805        }
8806    }
8807    return 0;
8808}
8809
8810sub getAlignment($$$)
8811{
8812    my ($Pos, $TypePtr, $LibVersion) = @_;
8813    my $Tid = $TypePtr->{"Memb"}{$Pos}{"type"};
8814    my %Type = get_PureType($Tid, $LibVersion);
8815    my $TSize = $Type{"Size"}*$BYTE_SIZE;
8816    my $MSize = $Type{"Size"}*$BYTE_SIZE;
8817    if(my $BSize = $TypePtr->{"Memb"}{$Pos}{"bitfield"})
8818    { # bitfields
8819        ($TSize, $MSize) = ($WORD_SIZE{$LibVersion}*$BYTE_SIZE, $BSize);
8820    }
8821    elsif($Type{"Type"} eq "Array")
8822    { # in the context of function parameter
8823      # it's passed through the pointer
8824    }
8825    # alignment
8826    my $Alignment = $WORD_SIZE{$LibVersion}*$BYTE_SIZE; # default
8827    if(my $Computed = $TypePtr->{"Memb"}{$Pos}{"algn"})
8828    { # computed by GCC
8829        $Alignment = $Computed*$BYTE_SIZE;
8830    }
8831    elsif($TypePtr->{"Memb"}{$Pos}{"bitfield"})
8832    { # bitfields are 1 bit aligned
8833        $Alignment = 1;
8834    }
8835    elsif($TSize and $TSize<$WORD_SIZE{$LibVersion}*$BYTE_SIZE)
8836    { # model
8837        $Alignment = $TSize;
8838    }
8839    return ($Alignment, $MSize);
8840}
8841
8842sub getOffset($$$)
8843{ # offset of the field including padding
8844    my ($FieldPos, $TypePtr, $LibVersion) = @_;
8845    my $Offset = 0;
8846    foreach my $Pos (0 .. keys(%{$TypePtr->{"Memb"}})-1)
8847    {
8848        my ($Alignment, $MSize) = getAlignment($Pos, $TypePtr, $LibVersion);
8849        # padding
8850        my $Padding = 0;
8851        if($Offset % $Alignment!=0)
8852        { # not aligned, add padding
8853            $Padding = $Alignment - $Offset % $Alignment;
8854        }
8855        $Offset += $Padding;
8856        if($Pos==$FieldPos)
8857        { # after the padding
8858          # before the field
8859            return $Offset;
8860        }
8861        $Offset += $MSize;
8862    }
8863    return $FieldPos;# if something is going wrong
8864}
8865
8866sub isMemPadded($$$$$)
8867{ # check if the target field can be added/removed/changed
8868  # without shifting other fields because of padding bits
8869    my ($FieldPos, $Size, $TypePtr, $Skip, $LibVersion) = @_;
8870    return 0 if($FieldPos==0);
8871    if(defined $TypePtr->{"Memb"}{""})
8872    {
8873        delete($TypePtr->{"Memb"}{""});
8874        if($Debug) {
8875            printMsg("WARNING", "internal error detected");
8876        }
8877    }
8878    my $Offset = 0;
8879    my (%Alignment, %MSize) = ();
8880    my $MaxAlgn = 0;
8881    my $End = keys(%{$TypePtr->{"Memb"}})-1;
8882    my $NextField = $FieldPos+1;
8883    foreach my $Pos (0 .. $End)
8884    {
8885        if($Skip and $Skip->{$Pos})
8886        { # skip removed/added fields
8887            if($Pos > $FieldPos)
8888            { # after the target
8889                $NextField += 1;
8890                next;
8891            }
8892        }
8893        ($Alignment{$Pos}, $MSize{$Pos}) = getAlignment($Pos, $TypePtr, $LibVersion);
8894        if($Alignment{$Pos}>$MaxAlgn) {
8895            $MaxAlgn = $Alignment{$Pos};
8896        }
8897        if($Pos==$FieldPos)
8898        {
8899            if($Size==-1)
8900            { # added/removed fields
8901                if($Pos!=$End)
8902                { # skip target field and see
8903                  # if enough padding will be
8904                  # created on the next step
8905                  # to include this field
8906                    next;
8907                }
8908            }
8909        }
8910        # padding
8911        my $Padding = 0;
8912        if($Offset % $Alignment{$Pos}!=0)
8913        { # not aligned, add padding
8914            $Padding = $Alignment{$Pos} - $Offset % $Alignment{$Pos};
8915        }
8916        if($Pos==$NextField)
8917        { # try to place target field in the padding
8918            if($Size==-1)
8919            { # added/removed fields
8920                my $TPadding = 0;
8921                if($Offset % $Alignment{$FieldPos}!=0)
8922                {# padding of the target field
8923                    $TPadding = $Alignment{$FieldPos} - $Offset % $Alignment{$FieldPos};
8924                }
8925                if($TPadding+$MSize{$FieldPos}<=$Padding)
8926                { # enough padding to place target field
8927                    return 1;
8928                }
8929                else {
8930                    return 0;
8931                }
8932            }
8933            else
8934            { # changed fields
8935                my $Delta = $Size-$MSize{$FieldPos};
8936                if($Delta>=0)
8937                { # increased
8938                    if($Size-$MSize{$FieldPos}<=$Padding)
8939                    { # enough padding to change target field
8940                        return 1;
8941                    }
8942                    else {
8943                        return 0;
8944                    }
8945                }
8946                else
8947                { # decreased
8948                    $Delta = abs($Delta);
8949                    if($Delta+$Padding>=$MSize{$Pos})
8950                    { # try to place the next field
8951                        if(($Offset-$Delta) % $Alignment{$Pos} != 0)
8952                        { # padding of the next field in new place
8953                            my $NPadding = $Alignment{$Pos} - ($Offset-$Delta) % $Alignment{$Pos};
8954                            if($NPadding+$MSize{$Pos}<=$Delta+$Padding)
8955                            { # enough delta+padding to store next field
8956                                return 0;
8957                            }
8958                        }
8959                        else
8960                        {
8961                            return 0;
8962                        }
8963                    }
8964                    return 1;
8965                }
8966            }
8967        }
8968        elsif($Pos==$End)
8969        { # target field is the last field
8970            if($Size==-1)
8971            { # added/removed fields
8972                if($Offset % $MaxAlgn!=0)
8973                { # tail padding
8974                    my $TailPadding = $MaxAlgn - $Offset % $MaxAlgn;
8975                    if($Padding+$MSize{$Pos}<=$TailPadding)
8976                    { # enough tail padding to place the last field
8977                        return 1;
8978                    }
8979                }
8980                return 0;
8981            }
8982            else
8983            { # changed fields
8984                # scenario #1
8985                my $Offset1 = $Offset+$Padding+$MSize{$Pos};
8986                if($Offset1 % $MaxAlgn != 0)
8987                { # tail padding
8988                    $Offset1 += $MaxAlgn - $Offset1 % $MaxAlgn;
8989                }
8990                # scenario #2
8991                my $Offset2 = $Offset+$Padding+$Size;
8992                if($Offset2 % $MaxAlgn != 0)
8993                { # tail padding
8994                    $Offset2 += $MaxAlgn - $Offset2 % $MaxAlgn;
8995                }
8996                if($Offset1!=$Offset2)
8997                { # different sizes of structure
8998                    return 0;
8999                }
9000                return 1;
9001            }
9002        }
9003        $Offset += $Padding+$MSize{$Pos};
9004    }
9005    return 0;
9006}
9007
9008sub isReserved($)
9009{ # reserved fields == private
9010    my $MName = $_[0];
9011    if($MName=~/reserved|padding|f_spare/i) {
9012        return 1;
9013    }
9014    if($MName=~/\A[_]*(spare|pad|unused)[_]*\Z/i) {
9015        return 1;
9016    }
9017    if($MName=~/(pad\d+)/i) {
9018        return 1;
9019    }
9020    return 0;
9021}
9022
9023sub isPublic($$)
9024{
9025    my ($TypePtr, $FieldPos) = @_;
9026    return 0 if(not $TypePtr);
9027    return 0 if(not defined $TypePtr->{"Memb"}{$FieldPos});
9028    return 0 if(not defined $TypePtr->{"Memb"}{$FieldPos}{"name"});
9029    if(not $TypePtr->{"Memb"}{$FieldPos}{"access"})
9030    { # by name in C language
9031      # FIXME: add other methods to detect private members
9032        my $MName = $TypePtr->{"Memb"}{$FieldPos}{"name"};
9033        if($MName=~/priv|abidata|parent_object/i)
9034        { # C-styled private data
9035            return 0;
9036        }
9037        if(lc($MName) eq "abi")
9038        { # ABI information/reserved field
9039            return 0;
9040        }
9041        if(isReserved($MName))
9042        { # reserved fields
9043            return 0;
9044        }
9045        return 1;
9046    }
9047    elsif($TypePtr->{"Memb"}{$FieldPos}{"access"} ne "private")
9048    { # by access in C++ language
9049        return 1;
9050    }
9051    return 0;
9052}
9053
9054sub getVTable_Real($$)
9055{
9056    my ($ClassName, $LibVersion) = @_;
9057    if(my $ClassId = $TName_Tid{$LibVersion}{$ClassName})
9058    {
9059        my %Type = get_Type($ClassId, $LibVersion);
9060        if(defined $Type{"VTable"}) {
9061            return %{$Type{"VTable"}};
9062        }
9063    }
9064    return ();
9065}
9066
9067sub cmpVTables($)
9068{
9069    my $ClassName = $_[0];
9070    my $Res = cmpVTables_Real($ClassName, 1);
9071    if($Res==-1) {
9072        $Res = cmpVTables_Model($ClassName);
9073    }
9074    return $Res;
9075}
9076
9077sub cmpVTables_Model($)
9078{
9079    my $ClassName = $_[0];
9080    foreach my $Symbol (keys(%{$VirtualTable_Model{1}{$ClassName}}))
9081    {
9082        if(not defined $VirtualTable_Model{2}{$ClassName}{$Symbol}) {
9083            return 1;
9084        }
9085    }
9086    return 0;
9087}
9088
9089sub cmpVTables_Real($$)
9090{
9091    my ($ClassName, $Strong) = @_;
9092    if(defined $Cache{"cmpVTables_Real"}{$Strong}{$ClassName}) {
9093        return $Cache{"cmpVTables_Real"}{$Strong}{$ClassName};
9094    }
9095    my %VTable_Old = getVTable_Real($ClassName, 1);
9096    my %VTable_New = getVTable_Real($ClassName, 2);
9097    if(not %VTable_Old or not %VTable_New)
9098    { # old ABI dumps
9099        return ($Cache{"cmpVTables_Real"}{$Strong}{$ClassName} = -1);
9100    }
9101    my %Indexes = map {$_=>1} (keys(%VTable_Old), keys(%VTable_New));
9102    foreach my $Offset (sort {int($a)<=>int($b)} keys(%Indexes))
9103    {
9104        if(not defined $VTable_Old{$Offset})
9105        { # v-table v.1 < v-table v.2
9106            return ($Cache{"cmpVTables_Real"}{$Strong}{$ClassName} = $Strong);
9107        }
9108        my $Entry1 = $VTable_Old{$Offset};
9109        if(not defined $VTable_New{$Offset})
9110        { # v-table v.1 > v-table v.2
9111            return ($Cache{"cmpVTables_Real"}{$Strong}{$ClassName} = ($Strong or $Entry1!~/__cxa_pure_virtual/));
9112        }
9113        my $Entry2 = $VTable_New{$Offset};
9114        $Entry1 = simpleVEntry($Entry1);
9115        $Entry2 = simpleVEntry($Entry2);
9116        if($Entry1 ne $Entry2)
9117        { # register as changed
9118            if($Entry1=~/::([^:]+)\Z/)
9119            {
9120                my $M1 = $1;
9121                if($Entry2=~/::([^:]+)\Z/)
9122                {
9123                    my $M2 = $1;
9124                    if($M1 eq $M2)
9125                    { # overridden
9126                        next;
9127                    }
9128                }
9129            }
9130            if(differentDumps("G"))
9131            {
9132                if($Entry1=~/\A\-(0x|\d+)/ and $Entry2=~/\A\-(0x|\d+)/)
9133                {
9134                    # GCC 4.6.1: -0x00000000000000010
9135                    # GCC 4.7.0: -16
9136                    next;
9137                }
9138            }
9139            return ($Cache{"cmpVTables_Real"}{$Strong}{$ClassName} = 1);
9140        }
9141    }
9142    return ($Cache{"cmpVTables_Real"}{$Strong}{$ClassName} = 0);
9143}
9144
9145sub mergeVTables($)
9146{ # merging v-tables without diagnostics
9147    my $Level = $_[0];
9148    foreach my $ClassName (keys(%{$VirtualTable{1}}))
9149    {
9150        if($VTableChanged_M{$ClassName})
9151        { # already registered
9152            next;
9153        }
9154        if(cmpVTables_Real($ClassName, 0)==1)
9155        {
9156            my @Affected = (keys(%{$ClassMethods{$Level}{1}{$ClassName}}));
9157            foreach my $Symbol (@Affected)
9158            {
9159                %{$CompatProblems{$Level}{$Symbol}{"Virtual_Table_Changed_Unknown"}{$ClassName}}=(
9160                    "Type_Name"=>$ClassName,
9161                    "Type_Type"=>"Class",
9162                    "Target"=>$ClassName);
9163            }
9164        }
9165    }
9166}
9167
9168sub mergeBases($)
9169{
9170    my $Level = $_[0];
9171    foreach my $ClassName (keys(%{$ClassNames{1}}))
9172    { # detect added and removed virtual functions
9173        my $ClassId = $TName_Tid{1}{$ClassName};
9174        next if(not $ClassId);
9175        if(defined $VirtualTable{2}{$ClassName})
9176        {
9177            foreach my $Symbol (keys(%{$VirtualTable{2}{$ClassName}}))
9178            {
9179                if($TName_Tid{1}{$ClassName}
9180                and not defined $VirtualTable{1}{$ClassName}{$Symbol})
9181                { # added to v-table
9182                    if(defined $CompleteSignature{1}{$Symbol}
9183                    and $CompleteSignature{1}{$Symbol}{"Virt"})
9184                    { # override some method in v.1
9185                        next;
9186                    }
9187                    $AddedInt_Virt{$Level}{$ClassName}{$Symbol} = 1;
9188                }
9189            }
9190        }
9191        if(defined $VirtualTable{1}{$ClassName})
9192        {
9193            foreach my $Symbol (keys(%{$VirtualTable{1}{$ClassName}}))
9194            {
9195                if($TName_Tid{2}{$ClassName}
9196                and not defined $VirtualTable{2}{$ClassName}{$Symbol})
9197                { # removed from v-table
9198                    if(defined $CompleteSignature{2}{$Symbol}
9199                    and $CompleteSignature{2}{$Symbol}{"Virt"})
9200                    { # override some method in v.2
9201                        next;
9202                    }
9203                    $RemovedInt_Virt{$Level}{$ClassName}{$Symbol} = 1;
9204                }
9205            }
9206        }
9207        if($Level eq "Binary")
9208        { # Binary-level
9209            my %Class_Type = get_Type($ClassId, 1);
9210            foreach my $AddedVFunc (keys(%{$AddedInt_Virt{$Level}{$ClassName}}))
9211            { # check replacements, including pure virtual methods
9212                my $AddedPos = $VirtualTable{2}{$ClassName}{$AddedVFunc};
9213                foreach my $RemovedVFunc (keys(%{$RemovedInt_Virt{$Level}{$ClassName}}))
9214                {
9215                    my $RemovedPos = $VirtualTable{1}{$ClassName}{$RemovedVFunc};
9216                    if($AddedPos==$RemovedPos)
9217                    {
9218                        $VirtualReplacement{$AddedVFunc} = $RemovedVFunc;
9219                        $VirtualReplacement{$RemovedVFunc} = $AddedVFunc;
9220                        last; # other methods will be reported as "added" or "removed"
9221                    }
9222                }
9223                if(my $RemovedVFunc = $VirtualReplacement{$AddedVFunc})
9224                {
9225                    if(lc($AddedVFunc) eq lc($RemovedVFunc))
9226                    { # skip: DomUi => DomUI parameter (Qt 4.2.3 to 4.3.0)
9227                        next;
9228                    }
9229                    my $ProblemType = "Virtual_Replacement";
9230                    my @Affected = ($RemovedVFunc);
9231                    if($CompleteSignature{1}{$RemovedVFunc}{"PureVirt"})
9232                    { # pure methods
9233                        if(not isUsedClass($ClassId, 1, $Level))
9234                        { # not a parameter of some exported method
9235                            next;
9236                        }
9237                        $ProblemType = "Pure_Virtual_Replacement";
9238                        @Affected = (keys(%{$ClassMethods{$Level}{1}{$ClassName}}))
9239                    }
9240                    foreach my $AffectedInt (@Affected)
9241                    {
9242                        if($CompleteSignature{1}{$AffectedInt}{"PureVirt"})
9243                        { # affected exported methods only
9244                            next;
9245                        }
9246                        %{$CompatProblems{$Level}{$AffectedInt}{$ProblemType}{$tr_name{$AddedVFunc}}}=(
9247                            "Type_Name"=>$Class_Type{"Name"},
9248                            "Type_Type"=>"Class",
9249                            "Target"=>get_Signature($AddedVFunc, 2),
9250                            "Old_Value"=>get_Signature($RemovedVFunc, 1));
9251                    }
9252                }
9253            }
9254        }
9255    }
9256    if(not checkDump(1, "2.0")
9257    or not checkDump(2, "2.0"))
9258    { # support for old ABI dumps
9259      # "Base" attribute introduced in ACC 1.22 (dump 2.0 format)
9260        return;
9261    }
9262    foreach my $ClassName (sort keys(%{$ClassNames{1}}))
9263    {
9264        my $ClassId_Old = $TName_Tid{1}{$ClassName};
9265        next if(not $ClassId_Old);
9266        if(not isCreatable($ClassId_Old, 1))
9267        { # skip classes without public constructors (including auto-generated)
9268          # example: class has only a private exported or private inline constructor
9269            next;
9270        }
9271        if($ClassName=~/>/)
9272        { # skip affected template instances
9273            next;
9274        }
9275        my %Class_Old = get_Type($ClassId_Old, 1);
9276        my $ClassId_New = $TName_Tid{2}{$ClassName};
9277        if(not $ClassId_New) {
9278            next;
9279        }
9280        my %Class_New = get_Type($ClassId_New, 2);
9281        if($Class_New{"Type"}!~/Class|Struct/)
9282        { # became typedef
9283            if($Level eq "Binary") {
9284                next;
9285            }
9286            if($Level eq "Source")
9287            {
9288                %Class_New = get_PureType($ClassId_New, 2);
9289                if($Class_New{"Type"}!~/Class|Struct/) {
9290                    next;
9291                }
9292                $ClassId_New = $Class_New{"Tid"};
9293            }
9294        }
9295        my @Bases_Old = sort {$Class_Old{"Base"}{$a}{"pos"}<=>$Class_Old{"Base"}{$b}{"pos"}} keys(%{$Class_Old{"Base"}});
9296        my @Bases_New = sort {$Class_New{"Base"}{$a}{"pos"}<=>$Class_New{"Base"}{$b}{"pos"}} keys(%{$Class_New{"Base"}});
9297        my ($BNum1, $BNum2) = (1, 1);
9298        my %BasePos_Old = map {$TypeInfo{1}{$_}{"Name"} => $BNum1++} @Bases_Old;
9299        my %BasePos_New = map {$TypeInfo{2}{$_}{"Name"} => $BNum2++} @Bases_New;
9300        my %ShortBase_Old = map {get_ShortType($_, 1) => 1} @Bases_Old;
9301        my %ShortBase_New = map {get_ShortType($_, 2) => 1} @Bases_New;
9302        my $Shift_Old = getShift($ClassId_Old, 1);
9303        my $Shift_New = getShift($ClassId_New, 2);
9304        my %BaseId_New = map {$TypeInfo{2}{$_}{"Name"} => $_} @Bases_New;
9305        my ($Added, $Removed) = (0, 0);
9306        my @StableBases_Old = ();
9307        foreach my $BaseId (@Bases_Old)
9308        {
9309            my $BaseName = $TypeInfo{1}{$BaseId}{"Name"};
9310            if($BasePos_New{$BaseName}) {
9311                push(@StableBases_Old, $BaseId);
9312            }
9313            elsif(not $ShortBase_New{$BaseName}
9314            and not $ShortBase_New{get_ShortType($BaseId, 1)})
9315            { # removed base
9316              # excluding namespace::SomeClass to SomeClass renaming
9317                my $ProblemKind = "Removed_Base_Class";
9318                if($Level eq "Binary")
9319                { # Binary-level
9320                    if($Shift_Old ne $Shift_New)
9321                    { # affected fields
9322                        if(havePubFields(\%Class_Old)) {
9323                            $ProblemKind .= "_And_Shift";
9324                        }
9325                        elsif($Class_Old{"Size"} ne $Class_New{"Size"}) {
9326                            $ProblemKind .= "_And_Size";
9327                        }
9328                    }
9329                    if(keys(%{$VirtualTable_Model{1}{$BaseName}})
9330                    and cmpVTables($ClassName)==1)
9331                    { # affected v-table
9332                        $ProblemKind .= "_And_VTable";
9333                        $VTableChanged_M{$ClassName}=1;
9334                    }
9335                }
9336                my @Affected = keys(%{$ClassMethods{$Level}{1}{$ClassName}});
9337                foreach my $SubId (get_sub_classes($ClassId_Old, 1, 1))
9338                {
9339                    my $SubName = $TypeInfo{1}{$SubId}{"Name"};
9340                    push(@Affected, keys(%{$ClassMethods{$Level}{1}{$SubName}}));
9341                    if($ProblemKind=~/VTable/) {
9342                        $VTableChanged_M{$SubName}=1;
9343                    }
9344                }
9345                foreach my $Interface (@Affected)
9346                {
9347                    %{$CompatProblems{$Level}{$Interface}{$ProblemKind}{"this"}}=(
9348                        "Type_Name"=>$ClassName,
9349                        "Type_Type"=>"Class",
9350                        "Target"=>$BaseName,
9351                        "Old_Size"=>$Class_Old{"Size"}*$BYTE_SIZE,
9352                        "New_Size"=>$Class_New{"Size"}*$BYTE_SIZE,
9353                        "Shift"=>abs($Shift_New-$Shift_Old)  );
9354                }
9355                $Removed+=1;
9356            }
9357        }
9358        my @StableBases_New = ();
9359        foreach my $BaseId (@Bases_New)
9360        {
9361            my $BaseName = $TypeInfo{2}{$BaseId}{"Name"};
9362            if($BasePos_Old{$BaseName}) {
9363                push(@StableBases_New, $BaseId);
9364            }
9365            elsif(not $ShortBase_Old{$BaseName}
9366            and not $ShortBase_Old{get_ShortType($BaseId, 2)})
9367            { # added base
9368              # excluding namespace::SomeClass to SomeClass renaming
9369                my $ProblemKind = "Added_Base_Class";
9370                if($Level eq "Binary")
9371                { # Binary-level
9372                    if($Shift_Old ne $Shift_New)
9373                    { # affected fields
9374                        if(havePubFields(\%Class_Old)) {
9375                            $ProblemKind .= "_And_Shift";
9376                        }
9377                        elsif($Class_Old{"Size"} ne $Class_New{"Size"}) {
9378                            $ProblemKind .= "_And_Size";
9379                        }
9380                    }
9381                    if(keys(%{$VirtualTable_Model{2}{$BaseName}})
9382                    and cmpVTables($ClassName)==1)
9383                    { # affected v-table
9384                        $ProblemKind .= "_And_VTable";
9385                        $VTableChanged_M{$ClassName}=1;
9386                    }
9387                }
9388                my @Affected = keys(%{$ClassMethods{$Level}{1}{$ClassName}});
9389                foreach my $SubId (get_sub_classes($ClassId_Old, 1, 1))
9390                {
9391                    my $SubName = $TypeInfo{1}{$SubId}{"Name"};
9392                    push(@Affected, keys(%{$ClassMethods{$Level}{1}{$SubName}}));
9393                    if($ProblemKind=~/VTable/) {
9394                        $VTableChanged_M{$SubName}=1;
9395                    }
9396                }
9397                foreach my $Interface (@Affected)
9398                {
9399                    %{$CompatProblems{$Level}{$Interface}{$ProblemKind}{"this"}}=(
9400                        "Type_Name"=>$ClassName,
9401                        "Type_Type"=>"Class",
9402                        "Target"=>$BaseName,
9403                        "Old_Size"=>$Class_Old{"Size"}*$BYTE_SIZE,
9404                        "New_Size"=>$Class_New{"Size"}*$BYTE_SIZE,
9405                        "Shift"=>abs($Shift_New-$Shift_Old)  );
9406                }
9407                $Added+=1;
9408            }
9409        }
9410        if($Level eq "Binary")
9411        { # Binary-level
9412            ($BNum1, $BNum2) = (1, 1);
9413            my %BaseRelPos_Old = map {$TypeInfo{1}{$_}{"Name"} => $BNum1++} @StableBases_Old;
9414            my %BaseRelPos_New = map {$TypeInfo{2}{$_}{"Name"} => $BNum2++} @StableBases_New;
9415            foreach my $BaseId (@Bases_Old)
9416            {
9417                my $BaseName = $TypeInfo{1}{$BaseId}{"Name"};
9418                if(my $NewPos = $BaseRelPos_New{$BaseName})
9419                {
9420                    my $BaseNewId = $BaseId_New{$BaseName};
9421                    my $OldPos = $BaseRelPos_Old{$BaseName};
9422                    if($NewPos!=$OldPos)
9423                    { # changed position of the base class
9424                        foreach my $Interface (keys(%{$ClassMethods{$Level}{1}{$ClassName}}))
9425                        {
9426                            %{$CompatProblems{$Level}{$Interface}{"Base_Class_Position"}{"this"}}=(
9427                                "Type_Name"=>$ClassName,
9428                                "Type_Type"=>"Class",
9429                                "Target"=>$BaseName,
9430                                "Old_Value"=>$OldPos-1,
9431                                "New_Value"=>$NewPos-1  );
9432                        }
9433                    }
9434                    if($Class_Old{"Base"}{$BaseId}{"virtual"}
9435                    and not $Class_New{"Base"}{$BaseNewId}{"virtual"})
9436                    { # became non-virtual base
9437                        foreach my $Interface (keys(%{$ClassMethods{$Level}{1}{$ClassName}}))
9438                        {
9439                            %{$CompatProblems{$Level}{$Interface}{"Base_Class_Became_Non_Virtually_Inherited"}{"this->".$BaseName}}=(
9440                                "Type_Name"=>$ClassName,
9441                                "Type_Type"=>"Class",
9442                                "Target"=>$BaseName  );
9443                        }
9444                    }
9445                    elsif(not $Class_Old{"Base"}{$BaseId}{"virtual"}
9446                    and $Class_New{"Base"}{$BaseNewId}{"virtual"})
9447                    { # became virtual base
9448                        foreach my $Interface (keys(%{$ClassMethods{$Level}{1}{$ClassName}}))
9449                        {
9450                            %{$CompatProblems{$Level}{$Interface}{"Base_Class_Became_Virtually_Inherited"}{"this->".$BaseName}}=(
9451                                "Type_Name"=>$ClassName,
9452                                "Type_Type"=>"Class",
9453                                "Target"=>$BaseName  );
9454                        }
9455                    }
9456                }
9457            }
9458            # detect size changes in base classes
9459            if($Shift_Old!=$Shift_New)
9460            { # size of allocable class
9461                foreach my $BaseId (@StableBases_Old)
9462                { # search for changed base
9463                    my %BaseType = get_Type($BaseId, 1);
9464                    my $Size_Old = $TypeInfo{1}{$BaseId}{"Size"};
9465                    my $Size_New = $TypeInfo{2}{$BaseId_New{$BaseType{"Name"}}}{"Size"};
9466                    if($Size_Old ne $Size_New
9467                    and $Size_Old and $Size_New)
9468                    {
9469                        my $ProblemType = "";
9470                        if(isCopyingClass($BaseId, 1)) {
9471                            $ProblemType = "Size_Of_Copying_Class";
9472                        }
9473                        elsif($AllocableClass{1}{$BaseType{"Name"}})
9474                        {
9475                            if($Size_New>$Size_Old)
9476                            { # increased size
9477                                $ProblemType = "Size_Of_Allocable_Class_Increased";
9478                            }
9479                            else
9480                            { # decreased size
9481                                $ProblemType = "Size_Of_Allocable_Class_Decreased";
9482                                if(not havePubFields(\%Class_Old))
9483                                { # affected class has no public members
9484                                    next;
9485                                }
9486                            }
9487                        }
9488                        next if(not $ProblemType);
9489                        foreach my $Interface (keys(%{$ClassMethods{$Level}{1}{$ClassName}}))
9490                        { # base class size changes affecting current class
9491                            %{$CompatProblems{$Level}{$Interface}{$ProblemType}{"this->".$BaseType{"Name"}}}=(
9492                                "Type_Name"=>$BaseType{"Name"},
9493                                "Type_Type"=>"Class",
9494                                "Target"=>$BaseType{"Name"},
9495                                "Old_Size"=>$Size_Old*$BYTE_SIZE,
9496                                "New_Size"=>$Size_New*$BYTE_SIZE  );
9497                        }
9498                    }
9499                }
9500            }
9501            if(defined $VirtualTable{1}{$ClassName}
9502            and cmpVTables_Real($ClassName, 1)==1
9503            and my @VFunctions = keys(%{$VirtualTable{1}{$ClassName}}))
9504            { # compare virtual tables size in base classes
9505                my $VShift_Old = getVShift($ClassId_Old, 1);
9506                my $VShift_New = getVShift($ClassId_New, 2);
9507                if($VShift_Old ne $VShift_New)
9508                { # changes in the base class or changes in the list of base classes
9509                    my @AllBases_Old = get_base_classes($ClassId_Old, 1, 1);
9510                    my @AllBases_New = get_base_classes($ClassId_New, 2, 1);
9511                    ($BNum1, $BNum2) = (1, 1);
9512                    my %StableBase = map {$TypeInfo{2}{$_}{"Name"} => $_} @AllBases_New;
9513                    foreach my $BaseId (@AllBases_Old)
9514                    {
9515                        my %BaseType = get_Type($BaseId, 1);
9516                        if(not $StableBase{$BaseType{"Name"}})
9517                        { # lost base
9518                            next;
9519                        }
9520                        my $VSize_Old = getVTable_Size($BaseType{"Name"}, 1);
9521                        my $VSize_New = getVTable_Size($BaseType{"Name"}, 2);
9522                        if($VSize_Old!=$VSize_New)
9523                        {
9524                            foreach my $Symbol (@VFunctions)
9525                            {
9526                                if(not defined $VirtualTable{2}{$ClassName}{$Symbol})
9527                                { # Removed_Virtual_Method, will be registered in mergeVirtualTables()
9528                                    next;
9529                                }
9530                                if($VirtualTable_Model{2}{$ClassName}{$Symbol}-$VirtualTable_Model{1}{$ClassName}{$Symbol}==0)
9531                                { # skip interfaces that have not changed the absolute virtual position
9532                                    next;
9533                                }
9534                                if(not symbolFilter($Symbol, 1, "Affected", $Level)) {
9535                                    next;
9536                                }
9537                                $VTableChanged_M{$BaseType{"Name"}} = 1;
9538                                $VTableChanged_M{$ClassName} = 1;
9539                                foreach my $VirtFunc (keys(%{$AddedInt_Virt{$Level}{$BaseType{"Name"}}}))
9540                                { # the reason of the layout change: added virtual functions
9541                                    next if($VirtualReplacement{$VirtFunc});
9542                                    my $ProblemType = "Added_Virtual_Method";
9543                                    if($CompleteSignature{2}{$VirtFunc}{"PureVirt"}) {
9544                                        $ProblemType = "Added_Pure_Virtual_Method";
9545                                    }
9546                                    %{$CompatProblems{$Level}{$Symbol}{$ProblemType}{get_Signature($VirtFunc, 2)}}=(
9547                                        "Type_Name"=>$BaseType{"Name"},
9548                                        "Type_Type"=>"Class",
9549                                        "Target"=>get_Signature($VirtFunc, 2)  );
9550                                }
9551                                foreach my $VirtFunc (keys(%{$RemovedInt_Virt{$Level}{$BaseType{"Name"}}}))
9552                                { # the reason of the layout change: removed virtual functions
9553                                    next if($VirtualReplacement{$VirtFunc});
9554                                    my $ProblemType = "Removed_Virtual_Method";
9555                                    if($CompleteSignature{1}{$VirtFunc}{"PureVirt"}) {
9556                                        $ProblemType = "Removed_Pure_Virtual_Method";
9557                                    }
9558                                    %{$CompatProblems{$Level}{$Symbol}{$ProblemType}{get_Signature($VirtFunc, 1)}}=(
9559                                        "Type_Name"=>$BaseType{"Name"},
9560                                        "Type_Type"=>"Class",
9561                                        "Target"=>get_Signature($VirtFunc, 1)  );
9562                                }
9563                            }
9564                        }
9565                    }
9566                }
9567            }
9568        }
9569    }
9570}
9571
9572sub isCreatable($$)
9573{
9574    my ($ClassId, $LibVersion) = @_;
9575    if($AllocableClass{$LibVersion}{$TypeInfo{$LibVersion}{$ClassId}{"Name"}}
9576    or isCopyingClass($ClassId, $LibVersion)) {
9577        return 1;
9578    }
9579    if(keys(%{$Class_SubClasses{$LibVersion}{$ClassId}}))
9580    { # Fix for incomplete data: if this class has
9581      # a base class then it should also has a constructor
9582        return 1;
9583    }
9584    if($ReturnedClass{$LibVersion}{$ClassId})
9585    { # returned by some method of this class
9586      # or any other class
9587        return 1;
9588    }
9589    return 0;
9590}
9591
9592sub isUsedClass($$$)
9593{
9594    my ($ClassId, $LibVersion, $Level) = @_;
9595    if(keys(%{$ParamClass{$LibVersion}{$ClassId}}))
9596    { # parameter of some exported method
9597        return 1;
9598    }
9599    my $CName = $TypeInfo{$LibVersion}{$ClassId}{"Name"};
9600    if(keys(%{$ClassMethods{$Level}{$LibVersion}{$CName}}))
9601    { # method from target class
9602        return 1;
9603    }
9604    return 0;
9605}
9606
9607sub mergeVirtualTables($$)
9608{ # check for changes in the virtual table
9609    my ($Interface, $Level) = @_;
9610    # affected methods:
9611    #  - virtual
9612    #  - pure-virtual
9613    #  - non-virtual
9614    if($CompleteSignature{1}{$Interface}{"Data"})
9615    { # global data is not affected
9616        return;
9617    }
9618    my $Class_Id = $CompleteSignature{1}{$Interface}{"Class"};
9619    if(not $Class_Id) {
9620        return;
9621    }
9622    my $CName = $TypeInfo{1}{$Class_Id}{"Name"};
9623    if(cmpVTables_Real($CName, 1)==0)
9624    { # no changes
9625        return;
9626    }
9627    $CheckedTypes{$Level}{$CName} = 1;
9628    if($Level eq "Binary")
9629    { # Binary-level
9630        if($CompleteSignature{1}{$Interface}{"PureVirt"}
9631        and not isUsedClass($Class_Id, 1, $Level))
9632        { # pure virtuals should not be affected
9633          # if there are no exported methods using this class
9634            return;
9635        }
9636    }
9637    foreach my $Func (keys(%{$VirtualTable{1}{$CName}}))
9638    {
9639        if(defined $VirtualTable{2}{$CName}{$Func}
9640        and defined $CompleteSignature{2}{$Func})
9641        {
9642            if(not $CompleteSignature{1}{$Func}{"PureVirt"}
9643            and $CompleteSignature{2}{$Func}{"PureVirt"})
9644            { # became pure virtual
9645                %{$CompatProblems{$Level}{$Interface}{"Virtual_Method_Became_Pure"}{$tr_name{$Func}}}=(
9646                    "Type_Name"=>$CName,
9647                    "Type_Type"=>"Class",
9648                    "Target"=>get_Signature_M($Func, 1)  );
9649                $VTableChanged_M{$CName} = 1;
9650            }
9651            elsif($CompleteSignature{1}{$Func}{"PureVirt"}
9652            and not $CompleteSignature{2}{$Func}{"PureVirt"})
9653            { # became non-pure virtual
9654                %{$CompatProblems{$Level}{$Interface}{"Virtual_Method_Became_Non_Pure"}{$tr_name{$Func}}}=(
9655                    "Type_Name"=>$CName,
9656                    "Type_Type"=>"Class",
9657                    "Target"=>get_Signature_M($Func, 1)  );
9658                $VTableChanged_M{$CName} = 1;
9659            }
9660        }
9661    }
9662    if($Level eq "Binary")
9663    { # Binary-level
9664        # check virtual table structure
9665        foreach my $AddedVFunc (keys(%{$AddedInt_Virt{$Level}{$CName}}))
9666        {
9667            next if($Interface eq $AddedVFunc);
9668            next if($VirtualReplacement{$AddedVFunc});
9669            my $VPos_Added = $VirtualTable{2}{$CName}{$AddedVFunc};
9670            if($CompleteSignature{2}{$AddedVFunc}{"PureVirt"})
9671            { # pure virtual methods affect all others (virtual and non-virtual)
9672                %{$CompatProblems{$Level}{$Interface}{"Added_Pure_Virtual_Method"}{$tr_name{$AddedVFunc}}}=(
9673                    "Type_Name"=>$CName,
9674                    "Type_Type"=>"Class",
9675                    "Target"=>get_Signature($AddedVFunc, 2)  );
9676                $VTableChanged_M{$CName} = 1;
9677            }
9678            elsif(not defined $VirtualTable{1}{$CName}
9679            or $VPos_Added>keys(%{$VirtualTable{1}{$CName}}))
9680            { # added virtual function at the end of v-table
9681                if(not keys(%{$VirtualTable_Model{1}{$CName}}))
9682                { # became polymorphous class, added v-table pointer
9683                    %{$CompatProblems{$Level}{$Interface}{"Added_First_Virtual_Method"}{$tr_name{$AddedVFunc}}}=(
9684                        "Type_Name"=>$CName,
9685                        "Type_Type"=>"Class",
9686                        "Target"=>get_Signature($AddedVFunc, 2)  );
9687                    $VTableChanged_M{$CName} = 1;
9688                }
9689                else
9690                {
9691                    my $VSize_Old = getVTable_Size($CName, 1);
9692                    my $VSize_New = getVTable_Size($CName, 2);
9693                    next if($VSize_Old==$VSize_New);# exception: register as removed and added virtual method
9694                    if(isCopyingClass($Class_Id, 1))
9695                    { # class has no constructors and v-table will be copied by applications, this may affect all methods
9696                        my $ProblemType = "Added_Virtual_Method";
9697                        if(isLeafClass($Class_Id, 1)) {
9698                            $ProblemType = "Added_Virtual_Method_At_End_Of_Leaf_Copying_Class";
9699                        }
9700                        %{$CompatProblems{$Level}{$Interface}{$ProblemType}{$tr_name{$AddedVFunc}}}=(
9701                            "Type_Name"=>$CName,
9702                            "Type_Type"=>"Class",
9703                            "Target"=>get_Signature($AddedVFunc, 2)  );
9704                        $VTableChanged_M{$CName} = 1;
9705                    }
9706                    else
9707                    {
9708                        my $ProblemType = "Added_Virtual_Method";
9709                        if(isLeafClass($Class_Id, 1)) {
9710                            $ProblemType = "Added_Virtual_Method_At_End_Of_Leaf_Allocable_Class";
9711                        }
9712                        %{$CompatProblems{$Level}{$Interface}{$ProblemType}{$tr_name{$AddedVFunc}}}=(
9713                            "Type_Name"=>$CName,
9714                            "Type_Type"=>"Class",
9715                            "Target"=>get_Signature($AddedVFunc, 2)  );
9716                        $VTableChanged_M{$CName} = 1;
9717                    }
9718                }
9719            }
9720            elsif($CompleteSignature{1}{$Interface}{"Virt"}
9721            or $CompleteSignature{1}{$Interface}{"PureVirt"})
9722            {
9723                if(defined $VirtualTable{1}{$CName}
9724                and defined $VirtualTable{2}{$CName})
9725                {
9726                    my $VPos_Old = $VirtualTable{1}{$CName}{$Interface};
9727                    my $VPos_New = $VirtualTable{2}{$CName}{$Interface};
9728                    if($VPos_Added<=$VPos_Old and $VPos_Old!=$VPos_New)
9729                    {
9730                        my @Affected = ($Interface, keys(%{$OverriddenMethods{1}{$Interface}}));
9731                        foreach my $ASymbol (@Affected)
9732                        {
9733                            if(not $CompleteSignature{1}{$ASymbol}{"PureVirt"})
9734                            {
9735                                if(symbolFilter($ASymbol, 1, "Affected", $Level)) {
9736                                    next;
9737                                }
9738                            }
9739                            $CheckedSymbols{$Level}{$ASymbol} = 1;
9740                            %{$CompatProblems{$Level}{$ASymbol}{"Added_Virtual_Method"}{$tr_name{$AddedVFunc}}}=(
9741                                "Type_Name"=>$CName,
9742                                "Type_Type"=>"Class",
9743                                "Target"=>get_Signature($AddedVFunc, 2)  );
9744                            $VTableChanged_M{$TypeInfo{1}{$CompleteSignature{1}{$ASymbol}{"Class"}}{"Name"}} = 1;
9745                        }
9746                    }
9747                }
9748            }
9749            else {
9750                # safe
9751            }
9752        }
9753        foreach my $RemovedVFunc (keys(%{$RemovedInt_Virt{$Level}{$CName}}))
9754        {
9755            next if($VirtualReplacement{$RemovedVFunc});
9756            if($RemovedVFunc eq $Interface
9757            and $CompleteSignature{1}{$RemovedVFunc}{"PureVirt"})
9758            { # This case is for removed virtual methods
9759            # implemented in both versions of a library
9760                next;
9761            }
9762            if(not keys(%{$VirtualTable_Model{2}{$CName}}))
9763            { # became non-polymorphous class, removed v-table pointer
9764                %{$CompatProblems{$Level}{$Interface}{"Removed_Last_Virtual_Method"}{$tr_name{$RemovedVFunc}}}=(
9765                    "Type_Name"=>$CName,
9766                    "Type_Type"=>"Class",
9767                    "Target"=>get_Signature($RemovedVFunc, 1)  );
9768                $VTableChanged_M{$CName} = 1;
9769            }
9770            elsif($CompleteSignature{1}{$Interface}{"Virt"}
9771            or $CompleteSignature{1}{$Interface}{"PureVirt"})
9772            {
9773                if(defined $VirtualTable{1}{$CName} and defined $VirtualTable{2}{$CName})
9774                {
9775                    if(not defined $VirtualTable{1}{$CName}{$Interface}) {
9776                        next;
9777                    }
9778                    my $VPos_New = -1;
9779                    if(defined $VirtualTable{2}{$CName}{$Interface})
9780                    {
9781                        $VPos_New = $VirtualTable{2}{$CName}{$Interface};
9782                    }
9783                    else
9784                    {
9785                        if($Interface ne $RemovedVFunc) {
9786                            next;
9787                        }
9788                    }
9789                    my $VPos_Removed = $VirtualTable{1}{$CName}{$RemovedVFunc};
9790                    my $VPos_Old = $VirtualTable{1}{$CName}{$Interface};
9791                    if($VPos_Removed<=$VPos_Old and $VPos_Old!=$VPos_New)
9792                    {
9793                        my @Affected = ($Interface, keys(%{$OverriddenMethods{1}{$Interface}}));
9794                        foreach my $ASymbol (@Affected)
9795                        {
9796                            if(not $CompleteSignature{1}{$ASymbol}{"PureVirt"})
9797                            {
9798                                if(symbolFilter($ASymbol, 1, "Affected", $Level)) {
9799                                    next;
9800                                }
9801                            }
9802                            my $ProblemType = "Removed_Virtual_Method";
9803                            if($CompleteSignature{1}{$RemovedVFunc}{"PureVirt"}) {
9804                                $ProblemType = "Removed_Pure_Virtual_Method";
9805                            }
9806                            $CheckedSymbols{$Level}{$ASymbol} = 1;
9807                            %{$CompatProblems{$Level}{$ASymbol}{$ProblemType}{$tr_name{$RemovedVFunc}}}=(
9808                                "Type_Name"=>$CName,
9809                                "Type_Type"=>"Class",
9810                                "Target"=>get_Signature($RemovedVFunc, 1)  );
9811                            $VTableChanged_M{$TypeInfo{1}{$CompleteSignature{1}{$ASymbol}{"Class"}}{"Name"}} = 1;
9812                        }
9813                    }
9814                }
9815            }
9816        }
9817    }
9818    else
9819    { # Source-level
9820        foreach my $AddedVFunc (keys(%{$AddedInt_Virt{$Level}{$CName}}))
9821        {
9822            next if($Interface eq $AddedVFunc);
9823            if($CompleteSignature{2}{$AddedVFunc}{"PureVirt"})
9824            {
9825                %{$CompatProblems{$Level}{$Interface}{"Added_Pure_Virtual_Method"}{$tr_name{$AddedVFunc}}}=(
9826                    "Type_Name"=>$CName,
9827                    "Type_Type"=>"Class",
9828                    "Target"=>get_Signature($AddedVFunc, 2)  );
9829            }
9830        }
9831        foreach my $RemovedVFunc (keys(%{$RemovedInt_Virt{$Level}{$CName}}))
9832        {
9833            if($CompleteSignature{1}{$RemovedVFunc}{"PureVirt"})
9834            {
9835                %{$CompatProblems{$Level}{$Interface}{"Removed_Pure_Virtual_Method"}{$tr_name{$RemovedVFunc}}}=(
9836                    "Type_Name"=>$CName,
9837                    "Type_Type"=>"Class",
9838                    "Target"=>get_Signature($RemovedVFunc, 1)  );
9839            }
9840        }
9841    }
9842}
9843
9844sub find_MemberPair_Pos_byName($$)
9845{
9846    my ($Member_Name, $Pair_Type) = @_;
9847    $Member_Name=~s/\A[_]+|[_]+\Z//g;
9848    foreach my $MemberPair_Pos (sort {int($a)<=>int($b)} keys(%{$Pair_Type->{"Memb"}}))
9849    {
9850        if(defined $Pair_Type->{"Memb"}{$MemberPair_Pos})
9851        {
9852            my $Name = $Pair_Type->{"Memb"}{$MemberPair_Pos}{"name"};
9853            $Name=~s/\A[_]+|[_]+\Z//g;
9854            if($Name eq $Member_Name) {
9855                return $MemberPair_Pos;
9856            }
9857        }
9858    }
9859    return "lost";
9860}
9861
9862sub find_MemberPair_Pos_byVal($$)
9863{
9864    my ($Member_Value, $Pair_Type) = @_;
9865    foreach my $MemberPair_Pos (sort {int($a)<=>int($b)} keys(%{$Pair_Type->{"Memb"}}))
9866    {
9867        if(defined $Pair_Type->{"Memb"}{$MemberPair_Pos}
9868        and $Pair_Type->{"Memb"}{$MemberPair_Pos}{"value"} eq $Member_Value) {
9869            return $MemberPair_Pos;
9870        }
9871    }
9872    return "lost";
9873}
9874
9875my %Severity_Val=(
9876    "High"=>3,
9877    "Medium"=>2,
9878    "Low"=>1,
9879    "Safe"=>-1
9880);
9881
9882sub maxSeverity($$)
9883{
9884    my ($S1, $S2) = @_;
9885    if(cmpSeverities($S1, $S2)) {
9886        return $S1;
9887    }
9888    else {
9889        return $S2;
9890    }
9891}
9892
9893sub cmpSeverities($$)
9894{
9895    my ($S1, $S2) = @_;
9896    if(not $S1) {
9897        return 0;
9898    }
9899    elsif(not $S2) {
9900        return 1;
9901    }
9902    return ($Severity_Val{$S1}>$Severity_Val{$S2});
9903}
9904
9905sub getProblemSeverity($$)
9906{
9907    my ($Level, $Kind) = @_;
9908    return $CompatRules{$Level}{$Kind}{"Severity"};
9909}
9910
9911sub isRecurType($$)
9912{
9913    foreach (@RecurTypes)
9914    {
9915        if( $_->{"T1"} eq $_[0]
9916        and $_->{"T2"} eq $_[1] )
9917        {
9918            return 1;
9919        }
9920    }
9921    return 0;
9922}
9923
9924sub pushType($$)
9925{
9926    my %TypeIDs=(
9927        "T1" => $_[0], #Tid1
9928        "T2" => $_[1] #Tid2
9929    );
9930    push(@RecurTypes, \%TypeIDs);
9931}
9932
9933sub isRenamed($$$$$)
9934{
9935    my ($MemPos, $Type1, $LVersion1, $Type2, $LVersion2) = @_;
9936    my $Member_Name = $Type1->{"Memb"}{$MemPos}{"name"};
9937    my $MemberType_Id = $Type1->{"Memb"}{$MemPos}{"type"};
9938    my %MemberType_Pure = get_PureType($MemberType_Id, $LVersion1);
9939    if(not defined $Type2->{"Memb"}{$MemPos}) {
9940        return "";
9941    }
9942    my $PairType_Id = $Type2->{"Memb"}{$MemPos}{"type"};
9943    my %PairType_Pure = get_PureType($PairType_Id, $LVersion2);
9944
9945    my $Pair_Name = $Type2->{"Memb"}{$MemPos}{"name"};
9946    my $MemberPair_Pos_Rev = ($Member_Name eq $Pair_Name)?$MemPos:find_MemberPair_Pos_byName($Pair_Name, $Type1);
9947    if($MemberPair_Pos_Rev eq "lost")
9948    {
9949        if($MemberType_Pure{"Name"} eq $PairType_Pure{"Name"})
9950        { # base type match
9951            return $Pair_Name;
9952        }
9953        if($TypeInfo{$LVersion1}{$MemberType_Id}{"Name"} eq $TypeInfo{$LVersion2}{$PairType_Id}{"Name"})
9954        { # exact type match
9955            return $Pair_Name;
9956        }
9957        if($MemberType_Pure{"Size"} eq $PairType_Pure{"Size"})
9958        { # size match
9959            return $Pair_Name;
9960        }
9961        if(isReserved($Pair_Name))
9962        { # reserved fields
9963            return $Pair_Name;
9964        }
9965    }
9966    return "";
9967}
9968
9969sub isLastElem($$)
9970{
9971    my ($Pos, $TypeRef) = @_;
9972    my $Name = $TypeRef->{"Memb"}{$Pos}{"name"};
9973    if($Name=~/last|count|max|total/i)
9974    { # GST_LEVEL_COUNT, GST_RTSP_ELAST
9975        return 1;
9976    }
9977    elsif($Name=~/END|NLIMITS\Z/)
9978    { # __RLIMIT_NLIMITS
9979        return 1;
9980    }
9981    elsif($Name=~/\AN[A-Z](.+)[a-z]+s\Z/
9982    and $Pos+1==keys(%{$TypeRef->{"Memb"}}))
9983    { # NImageFormats, NColorRoles
9984        return 1;
9985    }
9986    return 0;
9987}
9988
9989sub nonComparable($$)
9990{
9991    my ($T1, $T2) = @_;
9992    if($T1->{"Name"} ne $T2->{"Name"}
9993    and not isAnon($T1->{"Name"})
9994    and not isAnon($T2->{"Name"}))
9995    { # different names
9996        if($T1->{"Type"} ne "Pointer"
9997        or $T2->{"Type"} ne "Pointer")
9998        { # compare base types
9999            return 1;
10000        }
10001        if($T1->{"Name"}!~/\Avoid\s*\*/
10002        and $T2->{"Name"}=~/\Avoid\s*\*/)
10003        {
10004            return 1;
10005        }
10006    }
10007    elsif($T1->{"Type"} ne $T2->{"Type"})
10008    { # different types
10009        if($T1->{"Type"} eq "Class"
10010        and $T2->{"Type"} eq "Struct")
10011        { # "class" to "struct"
10012            return 0;
10013        }
10014        elsif($T2->{"Type"} eq "Class"
10015        and $T1->{"Type"} eq "Struct")
10016        { # "struct" to "class"
10017            return 0;
10018        }
10019        else
10020        { # "class" to "enum"
10021          # "union" to "class"
10022          #  ...
10023            return 1;
10024        }
10025    }
10026    return 0;
10027}
10028
10029sub mergeTypes($$$)
10030{
10031    my ($Type1_Id, $Type2_Id, $Level) = @_;
10032    return () if(not $Type1_Id or not $Type2_Id);
10033    my (%Sub_SubProblems, %SubProblems) = ();
10034    if($Cache{"mergeTypes"}{$Level}{$Type1_Id}{$Type2_Id})
10035    { # already merged
10036        return %{$Cache{"mergeTypes"}{$Level}{$Type1_Id}{$Type2_Id}};
10037    }
10038    my %Type1 = get_Type($Type1_Id, 1);
10039    my %Type2 = get_Type($Type2_Id, 2);
10040    if(not $Type1{"Name"} or not $Type2{"Name"}) {
10041        return ();
10042    }
10043    $CheckedTypes{$Level}{$Type1{"Name"}}=1;
10044    my %Type1_Pure = get_PureType($Type1_Id, 1);
10045    my %Type2_Pure = get_PureType($Type2_Id, 2);
10046    $CheckedTypes{$Level}{$Type1_Pure{"Name"}}=1;
10047    if(not $Type1_Pure{"Size"} or not $Type2_Pure{"Size"})
10048    { # including a case when "class Class { ... };" changed to "class Class;"
10049        return ();
10050    }
10051    if(isRecurType($Type1_Pure{"Tid"}, $Type2_Pure{"Tid"}))
10052    { # skip recursive declarations
10053        return ();
10054    }
10055    return () if(not $Type1_Pure{"Name"} or not $Type2_Pure{"Name"});
10056    return () if($SkipTypes{1}{$Type1_Pure{"Name"}});
10057    return () if($SkipTypes{1}{$Type1{"Name"}});
10058
10059    my %Typedef_1 = goToFirst($Type1{"Tid"}, 1, "Typedef");
10060    my %Typedef_2 = goToFirst($Type2{"Tid"}, 2, "Typedef");
10061    if(not $UseOldDumps and %Typedef_1 and %Typedef_2
10062    and $Typedef_1{"Type"} eq "Typedef" and $Typedef_2{"Type"} eq "Typedef"
10063    and $Typedef_1{"Name"} eq $Typedef_2{"Name"})
10064    {
10065        my %Base_1 = get_OneStep_BaseType($Typedef_1{"Tid"}, 1);
10066        my %Base_2 = get_OneStep_BaseType($Typedef_2{"Tid"}, 2);
10067        if($Base_1{"Name"} ne $Base_2{"Name"})
10068        {
10069            if(differentDumps("G")
10070            or differentDumps("V"))
10071            { # different GCC versions or different dumps
10072                $Base_1{"Name"} = uncover_typedefs($Base_1{"Name"}, 1);
10073                $Base_2{"Name"} = uncover_typedefs($Base_2{"Name"}, 2);
10074                # std::__va_list and __va_list
10075                $Base_1{"Name"}=~s/\A(\w+::)+//;
10076                $Base_2{"Name"}=~s/\A(\w+::)+//;
10077                $Base_1{"Name"} = formatName($Base_1{"Name"});
10078                $Base_2{"Name"} = formatName($Base_2{"Name"});
10079            }
10080        }
10081        if($Base_1{"Name"}!~/anon\-/ and $Base_2{"Name"}!~/anon\-/
10082        and $Base_1{"Name"} ne $Base_2{"Name"})
10083        {
10084            if($Level eq "Binary"
10085            and $Type1{"Size"} ne $Type2{"Size"})
10086            {
10087                %{$SubProblems{"DataType_Size"}{$Typedef_1{"Name"}}}=(
10088                    "Target"=>$Typedef_1{"Name"},
10089                    "Type_Name"=>$Typedef_1{"Name"},
10090                    "Type_Type"=>"Typedef",
10091                    "Old_Size"=>$Type1{"Size"}*$BYTE_SIZE,
10092                    "New_Size"=>$Type2{"Size"}*$BYTE_SIZE  );
10093            }
10094            %{$SubProblems{"Typedef_BaseType"}{$Typedef_1{"Name"}}}=(
10095                "Target"=>$Typedef_1{"Name"},
10096                "Type_Name"=>$Typedef_1{"Name"},
10097                "Type_Type"=>"Typedef",
10098                "Old_Value"=>$Base_1{"Name"},
10099                "New_Value"=>$Base_2{"Name"}  );
10100        }
10101    }
10102    if(nonComparable(\%Type1_Pure, \%Type2_Pure))
10103    { # different types (reported in detectTypeChange(...))
10104        if($Type1_Pure{"Name"} eq $Type2_Pure{"Name"}
10105        and $Type1_Pure{"Type"} ne $Type2_Pure{"Type"}
10106        and $Type1_Pure{"Type"}!~/Intrinsic|Pointer|Ref|Typedef/)
10107        { # different type of the type
10108            %{$SubProblems{"DataType_Type"}{$Type1_Pure{"Name"}}}=(
10109                "Target"=>$Type1_Pure{"Name"},
10110                "Type_Name"=>$Type1_Pure{"Name"},
10111                "Type_Type"=>$Type1_Pure{"Type"},
10112                "Old_Value"=>lc($Type1_Pure{"Type"}),
10113                "New_Value"=>lc($Type2_Pure{"Type"})  );
10114        }
10115        %{$Cache{"mergeTypes"}{$Level}{$Type1_Id}{$Type2_Id}} = %SubProblems;
10116        return %SubProblems;
10117    }
10118    pushType($Type1_Pure{"Tid"}, $Type2_Pure{"Tid"});
10119    if(($Type1_Pure{"Name"} eq $Type2_Pure{"Name"}
10120    or (isAnon($Type1_Pure{"Name"}) and isAnon($Type2_Pure{"Name"})))
10121    and $Type1_Pure{"Type"}=~/\A(Struct|Class|Union)\Z/)
10122    { # checking size
10123        if($Level eq "Binary"
10124        and $Type1_Pure{"Size"} ne $Type2_Pure{"Size"})
10125        {
10126            my $ProblemKind = "DataType_Size";
10127            if($Type1_Pure{"Type"} eq "Class"
10128            and keys(%{$ClassMethods{$Level}{1}{$Type1_Pure{"Name"}}}))
10129            {
10130                if(isCopyingClass($Type1_Pure{"Tid"}, 1)) {
10131                    $ProblemKind = "Size_Of_Copying_Class";
10132                }
10133                elsif($AllocableClass{1}{$Type1_Pure{"Name"}})
10134                {
10135                    if(int($Type2_Pure{"Size"})>int($Type1_Pure{"Size"})) {
10136                        $ProblemKind = "Size_Of_Allocable_Class_Increased";
10137                    }
10138                    else {
10139                        # descreased size of allocable class
10140                        # it has no special effects
10141                    }
10142                }
10143            }
10144            %{$SubProblems{$ProblemKind}{$Type1_Pure{"Name"}}}=(
10145                "Target"=>$Type1_Pure{"Name"},
10146                "Type_Name"=>$Type1_Pure{"Name"},
10147                "Type_Type"=>$Type1_Pure{"Type"},
10148                "Old_Size"=>$Type1_Pure{"Size"}*$BYTE_SIZE,
10149                "New_Size"=>$Type2_Pure{"Size"}*$BYTE_SIZE,
10150                "InitialType_Type"=>$Type1_Pure{"Type"}  );
10151        }
10152    }
10153    if(defined $Type1_Pure{"BaseType"} and $Type1_Pure{"BaseType"}{"Tid"}
10154    and defined $Type2_Pure{"BaseType"} and $Type2_Pure{"BaseType"}{"Tid"})
10155    { # checking base types
10156        %Sub_SubProblems = mergeTypes($Type1_Pure{"BaseType"}{"Tid"}, $Type2_Pure{"BaseType"}{"Tid"}, $Level);
10157        foreach my $Sub_SubProblemType (keys(%Sub_SubProblems))
10158        {
10159            foreach my $Sub_SubLocation (keys(%{$Sub_SubProblems{$Sub_SubProblemType}}))
10160            {
10161                foreach my $Attr (keys(%{$Sub_SubProblems{$Sub_SubProblemType}{$Sub_SubLocation}})) {
10162                    $SubProblems{$Sub_SubProblemType}{$Sub_SubLocation}{$Attr} = $Sub_SubProblems{$Sub_SubProblemType}{$Sub_SubLocation}{$Attr};
10163                }
10164                $SubProblems{$Sub_SubProblemType}{$Sub_SubLocation}{"InitialType_Type"} = $Type1_Pure{"Type"};
10165            }
10166        }
10167    }
10168    my (%AddedField, %RemovedField, %RenamedField, %RenamedField_Rev, %RelatedField, %RelatedField_Rev) = ();
10169    my %NameToPosA = map {$Type1_Pure{"Memb"}{$_}{"name"}=>$_} keys(%{$Type1_Pure{"Memb"}});
10170    my %NameToPosB = map {$Type2_Pure{"Memb"}{$_}{"name"}=>$_} keys(%{$Type2_Pure{"Memb"}});
10171    foreach my $Member_Pos (sort {int($a) <=> int($b)} keys(%{$Type1_Pure{"Memb"}}))
10172    { # detect removed and renamed fields
10173        my $Member_Name = $Type1_Pure{"Memb"}{$Member_Pos}{"name"};
10174        next if(not $Member_Name);
10175        my $MemberPair_Pos = (defined $Type2_Pure{"Memb"}{$Member_Pos} and $Type2_Pure{"Memb"}{$Member_Pos}{"name"} eq $Member_Name)?$Member_Pos:find_MemberPair_Pos_byName($Member_Name, \%Type2_Pure);
10176        if($MemberPair_Pos eq "lost")
10177        {
10178            if($Type2_Pure{"Type"}=~/\A(Struct|Class|Union)\Z/)
10179            {
10180                if(isUnnamed($Member_Name))
10181                { # support for old-version dumps
10182                  # unnamed fields have been introduced in the ACC 1.23 (dump 2.1 format)
10183                    if(not checkDump(2, "2.1")) {
10184                        next;
10185                    }
10186                }
10187                if(my $RenamedTo = isRenamed($Member_Pos, \%Type1_Pure, 1, \%Type2_Pure, 2))
10188                { # renamed
10189                    $RenamedField{$Member_Pos}=$RenamedTo;
10190                    $RenamedField_Rev{$NameToPosB{$RenamedTo}}=$Member_Name;
10191                }
10192                else
10193                { # removed
10194                    $RemovedField{$Member_Pos}=1;
10195                }
10196            }
10197            elsif($Type1_Pure{"Type"} eq "Enum")
10198            {
10199                my $Member_Value1 = $Type1_Pure{"Memb"}{$Member_Pos}{"value"};
10200                next if($Member_Value1 eq "");
10201                $MemberPair_Pos = find_MemberPair_Pos_byVal($Member_Value1, \%Type2_Pure);
10202                if($MemberPair_Pos ne "lost")
10203                { # renamed
10204                    my $RenamedTo = $Type2_Pure{"Memb"}{$MemberPair_Pos}{"name"};
10205                    my $MemberPair_Pos_Rev = find_MemberPair_Pos_byName($RenamedTo, \%Type1_Pure);
10206                    if($MemberPair_Pos_Rev eq "lost")
10207                    {
10208                        $RenamedField{$Member_Pos}=$RenamedTo;
10209                        $RenamedField_Rev{$NameToPosB{$RenamedTo}}=$Member_Name;
10210                    }
10211                    else {
10212                        $RemovedField{$Member_Pos}=1;
10213                    }
10214                }
10215                else
10216                { # removed
10217                    $RemovedField{$Member_Pos}=1;
10218                }
10219            }
10220        }
10221        else
10222        { # related
10223            $RelatedField{$Member_Pos} = $MemberPair_Pos;
10224            $RelatedField_Rev{$MemberPair_Pos} = $Member_Pos;
10225        }
10226    }
10227    foreach my $Member_Pos (sort {int($a) <=> int($b)} keys(%{$Type2_Pure{"Memb"}}))
10228    { # detect added fields
10229        my $Member_Name = $Type2_Pure{"Memb"}{$Member_Pos}{"name"};
10230        next if(not $Member_Name);
10231        my $MemberPair_Pos = (defined $Type1_Pure{"Memb"}{$Member_Pos} and $Type1_Pure{"Memb"}{$Member_Pos}{"name"} eq $Member_Name)?$Member_Pos:find_MemberPair_Pos_byName($Member_Name, \%Type1_Pure);
10232        if($MemberPair_Pos eq "lost")
10233        {
10234            if(isUnnamed($Member_Name))
10235            { # support for old-version dumps
10236            # unnamed fields have been introduced in the ACC 1.23 (dump 2.1 format)
10237                if(not checkDump(1, "2.1")) {
10238                    next;
10239                }
10240            }
10241            if($Type2_Pure{"Type"}=~/\A(Struct|Class|Union|Enum)\Z/)
10242            {
10243                if(not $RenamedField_Rev{$Member_Pos})
10244                { # added
10245                    $AddedField{$Member_Pos}=1;
10246                }
10247            }
10248        }
10249    }
10250    if($Type2_Pure{"Type"}=~/\A(Struct|Class)\Z/)
10251    { # detect moved fields
10252        my (%RelPos, %RelPosName, %AbsPos) = ();
10253        my $Pos = 0;
10254        foreach my $Member_Pos (sort {int($a) <=> int($b)} keys(%{$Type1_Pure{"Memb"}}))
10255        { # relative positions in 1st version
10256            my $Member_Name = $Type1_Pure{"Memb"}{$Member_Pos}{"name"};
10257            next if(not $Member_Name);
10258            if(not $RemovedField{$Member_Pos})
10259            { # old type without removed fields
10260                $RelPos{1}{$Member_Name}=$Pos;
10261                $RelPosName{1}{$Pos} = $Member_Name;
10262                $AbsPos{1}{$Pos++} = $Member_Pos;
10263            }
10264        }
10265        $Pos = 0;
10266        foreach my $Member_Pos (sort {int($a) <=> int($b)} keys(%{$Type2_Pure{"Memb"}}))
10267        { # relative positions in 2nd version
10268            my $Member_Name = $Type2_Pure{"Memb"}{$Member_Pos}{"name"};
10269            next if(not $Member_Name);
10270            if(not $AddedField{$Member_Pos})
10271            { # new type without added fields
10272                $RelPos{2}{$Member_Name}=$Pos;
10273                $RelPosName{2}{$Pos} = $Member_Name;
10274                $AbsPos{2}{$Pos++} = $Member_Pos;
10275            }
10276        }
10277        foreach my $Member_Name (keys(%{$RelPos{1}}))
10278        {
10279            my $RPos1 = $RelPos{1}{$Member_Name};
10280            my $AbsPos1 = $NameToPosA{$Member_Name};
10281            my $Member_Name2 = $Member_Name;
10282            if(my $RenamedTo = $RenamedField{$AbsPos1})
10283            { # renamed
10284                $Member_Name2 = $RenamedTo;
10285            }
10286            my $RPos2 = $RelPos{2}{$Member_Name2};
10287            if($RPos2 ne "" and $RPos1 ne $RPos2)
10288            { # different relative positions
10289                my $AbsPos2 = $NameToPosB{$Member_Name2};
10290                if($AbsPos1 ne $AbsPos2)
10291                { # different absolute positions
10292                    my $ProblemType = "Moved_Field";
10293                    if(not isPublic(\%Type1_Pure, $AbsPos1))
10294                    { # may change layout and size of type
10295                        if($Level eq "Source") {
10296                            next;
10297                        }
10298                        $ProblemType = "Moved_Private_Field";
10299                    }
10300                    if($Level eq "Binary"
10301                    and $Type1_Pure{"Size"} ne $Type2_Pure{"Size"})
10302                    { # affected size
10303                        my $MemSize1 = $TypeInfo{1}{$Type1_Pure{"Memb"}{$AbsPos1}{"type"}}{"Size"};
10304                        my $MovedAbsPos = $AbsPos{1}{$RPos2};
10305                        my $MemSize2 = $TypeInfo{1}{$Type1_Pure{"Memb"}{$MovedAbsPos}{"type"}}{"Size"};
10306                        if($MemSize1 ne $MemSize2) {
10307                            $ProblemType .= "_And_Size";
10308                        }
10309                    }
10310                    if($ProblemType eq "Moved_Private_Field") {
10311                        next;
10312                    }
10313                    %{$SubProblems{$ProblemType}{$Member_Name}}=(
10314                        "Target"=>$Member_Name,
10315                        "Type_Name"=>$Type1_Pure{"Name"},
10316                        "Type_Type"=>$Type1_Pure{"Type"},
10317                        "Old_Value"=>$RPos1,
10318                        "New_Value"=>$RPos2 );
10319                }
10320            }
10321        }
10322    }
10323    foreach my $Member_Pos (sort {int($a) <=> int($b)} keys(%{$Type1_Pure{"Memb"}}))
10324    { # check older fields, public and private
10325        my $Member_Name = $Type1_Pure{"Memb"}{$Member_Pos}{"name"};
10326        next if(not $Member_Name);
10327        if(my $RenamedTo = $RenamedField{$Member_Pos})
10328        { # renamed
10329            if($Type2_Pure{"Type"}=~/\A(Struct|Class|Union)\Z/)
10330            {
10331                if(isPublic(\%Type1_Pure, $Member_Pos))
10332                {
10333                    %{$SubProblems{"Renamed_Field"}{$Member_Name}}=(
10334                        "Target"=>$Member_Name,
10335                        "Type_Name"=>$Type1_Pure{"Name"},
10336                        "Type_Type"=>$Type1_Pure{"Type"},
10337                        "Old_Value"=>$Member_Name,
10338                        "New_Value"=>$RenamedTo  );
10339                }
10340            }
10341            elsif($Type1_Pure{"Type"} eq "Enum")
10342            {
10343                %{$SubProblems{"Enum_Member_Name"}{$Type1_Pure{"Memb"}{$Member_Pos}{"value"}}}=(
10344                    "Target"=>$Type1_Pure{"Memb"}{$Member_Pos}{"value"},
10345                    "Type_Name"=>$Type1_Pure{"Name"},
10346                    "Type_Type"=>$Type1_Pure{"Type"},
10347                    "Old_Value"=>$Member_Name,
10348                    "New_Value"=>$RenamedTo  );
10349            }
10350        }
10351        elsif($RemovedField{$Member_Pos})
10352        { # removed
10353            if($Type2_Pure{"Type"}=~/\A(Struct|Class)\Z/)
10354            {
10355                my $ProblemType = "Removed_Field";
10356                if(not isPublic(\%Type1_Pure, $Member_Pos)
10357                or isUnnamed($Member_Name))
10358                {
10359                    if($Level eq "Source") {
10360                        next;
10361                    }
10362                    $ProblemType = "Removed_Private_Field";
10363                }
10364                if($Level eq "Binary"
10365                and not isMemPadded($Member_Pos, -1, \%Type1_Pure, \%RemovedField, 1))
10366                {
10367                    if(my $MNum = isAccessible(\%Type1_Pure, \%RemovedField, $Member_Pos+1, -1))
10368                    { # affected fields
10369                        if(getOffset($MNum-1, \%Type1_Pure, 1)!=getOffset($RelatedField{$MNum-1}, \%Type2_Pure, 2))
10370                        { # changed offset
10371                            $ProblemType .= "_And_Layout";
10372                        }
10373                    }
10374                    if($Type1_Pure{"Size"} ne $Type2_Pure{"Size"})
10375                    { # affected size
10376                        $ProblemType .= "_And_Size";
10377                    }
10378                }
10379                if($ProblemType eq "Removed_Private_Field") {
10380                    next;
10381                }
10382                %{$SubProblems{$ProblemType}{$Member_Name}}=(
10383                    "Target"=>$Member_Name,
10384                    "Type_Name"=>$Type1_Pure{"Name"},
10385                    "Type_Type"=>$Type1_Pure{"Type"}  );
10386            }
10387            elsif($Type2_Pure{"Type"} eq "Union")
10388            {
10389                if($Level eq "Binary"
10390                and $Type1_Pure{"Size"} ne $Type2_Pure{"Size"})
10391                {
10392                    %{$SubProblems{"Removed_Union_Field_And_Size"}{$Member_Name}}=(
10393                        "Target"=>$Member_Name,
10394                        "Type_Name"=>$Type1_Pure{"Name"},
10395                        "Type_Type"=>$Type1_Pure{"Type"}  );
10396                }
10397                else
10398                {
10399                    %{$SubProblems{"Removed_Union_Field"}{$Member_Name}}=(
10400                        "Target"=>$Member_Name,
10401                        "Type_Name"=>$Type1_Pure{"Name"},
10402                        "Type_Type"=>$Type1_Pure{"Type"}  );
10403                }
10404            }
10405            elsif($Type1_Pure{"Type"} eq "Enum")
10406            {
10407                %{$SubProblems{"Enum_Member_Removed"}{$Member_Name}}=(
10408                    "Target"=>$Member_Name,
10409                    "Type_Name"=>$Type1_Pure{"Name"},
10410                    "Type_Type"=>$Type1_Pure{"Type"},
10411                    "Old_Value"=>$Member_Name  );
10412            }
10413        }
10414        else
10415        { # changed
10416            my $MemberPair_Pos = $RelatedField{$Member_Pos};
10417            if($Type1_Pure{"Type"} eq "Enum")
10418            {
10419                my $Member_Value1 = $Type1_Pure{"Memb"}{$Member_Pos}{"value"};
10420                next if($Member_Value1 eq "");
10421                my $Member_Value2 = $Type2_Pure{"Memb"}{$MemberPair_Pos}{"value"};
10422                next if($Member_Value2 eq "");
10423                if($Member_Value1 ne $Member_Value2)
10424                {
10425                    my $ProblemType = "Enum_Member_Value";
10426                    if(isLastElem($Member_Pos, \%Type1_Pure)) {
10427                        $ProblemType = "Enum_Last_Member_Value";
10428                    }
10429                    %{$SubProblems{$ProblemType}{$Member_Name}}=(
10430                        "Target"=>$Member_Name,
10431                        "Type_Name"=>$Type1_Pure{"Name"},
10432                        "Type_Type"=>$Type1_Pure{"Type"},
10433                        "Old_Value"=>$Member_Value1,
10434                        "New_Value"=>$Member_Value2  );
10435                }
10436            }
10437            elsif($Type2_Pure{"Type"}=~/\A(Struct|Class|Union)\Z/)
10438            {
10439                my $MemberType1_Id = $Type1_Pure{"Memb"}{$Member_Pos}{"type"};
10440                my $MemberType2_Id = $Type2_Pure{"Memb"}{$MemberPair_Pos}{"type"};
10441                my $SizeV1 = $TypeInfo{1}{$MemberType1_Id}{"Size"}*$BYTE_SIZE;
10442                if(my $BSize1 = $Type1_Pure{"Memb"}{$Member_Pos}{"bitfield"}) {
10443                    $SizeV1 = $BSize1;
10444                }
10445                my $SizeV2 = $TypeInfo{2}{$MemberType2_Id}{"Size"}*$BYTE_SIZE;
10446                if(my $BSize2 = $Type2_Pure{"Memb"}{$MemberPair_Pos}{"bitfield"}) {
10447                    $SizeV2 = $BSize2;
10448                }
10449                my $MemberType1_Name = $TypeInfo{1}{$MemberType1_Id}{"Name"};
10450                my $MemberType2_Name = $TypeInfo{2}{$MemberType2_Id}{"Name"};
10451                if($Level eq "Binary"
10452                and $SizeV1 ne $SizeV2)
10453                {
10454                    if($MemberType1_Name eq $MemberType2_Name or (isAnon($MemberType1_Name) and isAnon($MemberType2_Name))
10455                    or ($Type1_Pure{"Memb"}{$Member_Pos}{"bitfield"} and $Type2_Pure{"Memb"}{$MemberPair_Pos}{"bitfield"}))
10456                    { # field size change (including anon-structures and unions)
10457                      # - same types
10458                      # - unnamed types
10459                      # - bitfields
10460                        my $ProblemType = "Field_Size";
10461                        if(not isPublic(\%Type1_Pure, $Member_Pos)
10462                        or isUnnamed($Member_Name))
10463                        { # should not be accessed by applications, goes to "Low Severity"
10464                          # example: "abidata" members in GStreamer types
10465                            $ProblemType = "Private_".$ProblemType;
10466                        }
10467                        if(not isMemPadded($Member_Pos, $TypeInfo{2}{$MemberType2_Id}{"Size"}*$BYTE_SIZE, \%Type1_Pure, \%RemovedField, 1))
10468                        { # check an effect
10469                            if(my $MNum = isAccessible(\%Type1_Pure, \%RemovedField, $Member_Pos+1, -1))
10470                            { # public fields after the current
10471                                if(getOffset($MNum-1, \%Type1_Pure, 1)!=getOffset($RelatedField{$MNum-1}, \%Type2_Pure, 2))
10472                                { # changed offset
10473                                    $ProblemType .= "_And_Layout";
10474                                }
10475                            }
10476                            if($Type1_Pure{"Size"} ne $Type2_Pure{"Size"}) {
10477                                $ProblemType .= "_And_Type_Size";
10478                            }
10479                        }
10480                        if($ProblemType eq "Private_Field_Size")
10481                        { # private field size with no effect
10482                            $ProblemType = "";
10483                        }
10484                        if($ProblemType)
10485                        { # register a problem
10486                            %{$SubProblems{$ProblemType}{$Member_Name}}=(
10487                                "Target"=>$Member_Name,
10488                                "Type_Name"=>$Type1_Pure{"Name"},
10489                                "Type_Type"=>$Type1_Pure{"Type"},
10490                                "Old_Size"=>$SizeV1,
10491                                "New_Size"=>$SizeV2);
10492                        }
10493                    }
10494                }
10495                if($Type1_Pure{"Memb"}{$Member_Pos}{"bitfield"}
10496                or $Type2_Pure{"Memb"}{$MemberPair_Pos}{"bitfield"})
10497                { # do NOT check bitfield type changes
10498                    next;
10499                }
10500                if(checkDump(1, "2.13") and checkDump(2, "2.13"))
10501                {
10502                    if(not $Type1_Pure{"Memb"}{$Member_Pos}{"mutable"}
10503                    and $Type2_Pure{"Memb"}{$MemberPair_Pos}{"mutable"})
10504                    {
10505                        %{$SubProblems{"Field_Became_Mutable"}{$Member_Name}}=(
10506                            "Target"=>$Member_Name,
10507                            "Type_Name"=>$Type1_Pure{"Name"},
10508                            "Type_Type"=>$Type1_Pure{"Type"});
10509                    }
10510                    elsif($Type1_Pure{"Memb"}{$Member_Pos}{"mutable"}
10511                    and not $Type2_Pure{"Memb"}{$MemberPair_Pos}{"mutable"})
10512                    {
10513                        %{$SubProblems{"Field_Became_NonMutable"}{$Member_Name}}=(
10514                            "Target"=>$Member_Name,
10515                            "Type_Name"=>$Type1_Pure{"Name"},
10516                            "Type_Type"=>$Type1_Pure{"Type"});
10517                    }
10518                }
10519                %Sub_SubProblems = detectTypeChange($MemberType1_Id, $MemberType2_Id, "Field", $Level);
10520                foreach my $ProblemType (keys(%Sub_SubProblems))
10521                {
10522                    my $Old_Value = $Sub_SubProblems{$ProblemType}{"Old_Value"};
10523                    my $New_Value = $Sub_SubProblems{$ProblemType}{"New_Value"};
10524                    if($ProblemType eq "Field_Type"
10525                    or $ProblemType eq "Field_Type_And_Size")
10526                    {
10527                        if(checkDump(1, "2.6") and checkDump(2, "2.6"))
10528                        {
10529                            if(my $RA = addedQual($Old_Value, $New_Value, "volatile"))
10530                            {
10531                                %{$Sub_SubProblems{"Field_Became_Volatile"}} = %{$Sub_SubProblems{$ProblemType}};
10532                                if($Level eq "Source"
10533                                and cmpBTypes($Old_Value, $New_Value, 1, 2)) {
10534                                    delete($Sub_SubProblems{$ProblemType});
10535                                }
10536                            }
10537                            elsif(my $RR = removedQual($Old_Value, $New_Value, "volatile"))
10538                            {
10539                                %{$Sub_SubProblems{"Field_Became_NonVolatile"}} = %{$Sub_SubProblems{$ProblemType}};
10540                                if($Level eq "Source"
10541                                and cmpBTypes($Old_Value, $New_Value, 1, 2)) {
10542                                    delete($Sub_SubProblems{$ProblemType});
10543                                }
10544                            }
10545                        }
10546                        if(my $RA = addedQual($Old_Value, $New_Value, "const"))
10547                        {
10548                            if($RA==2) {
10549                                %{$Sub_SubProblems{"Field_Added_Const"}} = %{$Sub_SubProblems{$ProblemType}};
10550                            }
10551                            else {
10552                                %{$Sub_SubProblems{"Field_Became_Const"}} = %{$Sub_SubProblems{$ProblemType}};
10553                            }
10554                            if($Level eq "Source"
10555                            and cmpBTypes($Old_Value, $New_Value, 1, 2)) {
10556                                delete($Sub_SubProblems{$ProblemType});
10557                            }
10558                        }
10559                        elsif(my $RR = removedQual($Old_Value, $New_Value, "const"))
10560                        {
10561                            if($RR==2) {
10562                                %{$Sub_SubProblems{"Field_Removed_Const"}} = %{$Sub_SubProblems{$ProblemType}};
10563                            }
10564                            else {
10565                                %{$Sub_SubProblems{"Field_Became_NonConst"}} = %{$Sub_SubProblems{$ProblemType}};
10566                            }
10567                            if($Level eq "Source"
10568                            and cmpBTypes($Old_Value, $New_Value, 1, 2)) {
10569                                delete($Sub_SubProblems{$ProblemType});
10570                            }
10571                        }
10572                    }
10573                }
10574                foreach my $ProblemType (keys(%Sub_SubProblems))
10575                {
10576                    my $ProblemType_Init = $ProblemType;
10577                    if($ProblemType eq "Field_Type_And_Size")
10578                    { # Binary
10579                        if(not isPublic(\%Type1_Pure, $Member_Pos)
10580                        or isUnnamed($Member_Name)) {
10581                            $ProblemType = "Private_".$ProblemType;
10582                        }
10583                        if(not isMemPadded($Member_Pos, $TypeInfo{2}{$MemberType2_Id}{"Size"}*$BYTE_SIZE, \%Type1_Pure, \%RemovedField, 1))
10584                        { # check an effect
10585                            if(my $MNum = isAccessible(\%Type1_Pure, \%RemovedField, $Member_Pos+1, -1))
10586                            { # public fields after the current
10587                                if(getOffset($MNum-1, \%Type1_Pure, 1)!=getOffset($RelatedField{$MNum-1}, \%Type2_Pure, 2))
10588                                { # changed offset
10589                                    $ProblemType .= "_And_Layout";
10590                                }
10591                            }
10592                            if($Type1_Pure{"Size"} ne $Type2_Pure{"Size"}) {
10593                                $ProblemType .= "_And_Type_Size";
10594                            }
10595                        }
10596                    }
10597                    else
10598                    {
10599                        if(not isPublic(\%Type1_Pure, $Member_Pos)
10600                        or isUnnamed($Member_Name)) {
10601                            next;
10602                        }
10603                    }
10604                    if($ProblemType eq "Private_Field_Type_And_Size")
10605                    { # private field change with no effect
10606                        next;
10607                    }
10608                    %{$SubProblems{$ProblemType}{$Member_Name}}=(
10609                        "Target"=>$Member_Name,
10610                        "Type_Name"=>$Type1_Pure{"Name"},
10611                        "Type_Type"=>$Type1_Pure{"Type"}  );
10612                    foreach my $Attr (keys(%{$Sub_SubProblems{$ProblemType_Init}}))
10613                    { # other properties
10614                        $SubProblems{$ProblemType}{$Member_Name}{$Attr} = $Sub_SubProblems{$ProblemType_Init}{$Attr};
10615                    }
10616                }
10617                if(not isPublic(\%Type1_Pure, $Member_Pos))
10618                { # do NOT check internal type changes
10619                    next;
10620                }
10621                if($MemberType1_Id and $MemberType2_Id)
10622                {# checking member type changes (replace)
10623                    %Sub_SubProblems = mergeTypes($MemberType1_Id, $MemberType2_Id, $Level);
10624                    foreach my $Sub_SubProblemType (keys(%Sub_SubProblems))
10625                    {
10626                        foreach my $Sub_SubLocation (keys(%{$Sub_SubProblems{$Sub_SubProblemType}}))
10627                        {
10628                            my $NewLocation = ($Sub_SubLocation)?$Member_Name."->".$Sub_SubLocation:$Member_Name;
10629                            $SubProblems{$Sub_SubProblemType}{$NewLocation}{"IsInTypeInternals"}=1;
10630                            foreach my $Attr (keys(%{$Sub_SubProblems{$Sub_SubProblemType}{$Sub_SubLocation}})) {
10631                                $SubProblems{$Sub_SubProblemType}{$NewLocation}{$Attr} = $Sub_SubProblems{$Sub_SubProblemType}{$Sub_SubLocation}{$Attr};
10632                            }
10633                            if($Sub_SubLocation!~/\-\>/) {
10634                                $SubProblems{$Sub_SubProblemType}{$NewLocation}{"Start_Type_Name"} = $MemberType1_Name;
10635                            }
10636                        }
10637                    }
10638                }
10639            }
10640        }
10641    }
10642    foreach my $Member_Pos (sort {int($a) <=> int($b)} keys(%{$Type2_Pure{"Memb"}}))
10643    { # checking added members, public and private
10644        my $Member_Name = $Type2_Pure{"Memb"}{$Member_Pos}{"name"};
10645        next if(not $Member_Name);
10646        if($AddedField{$Member_Pos})
10647        { # added
10648            if($Type2_Pure{"Type"}=~/\A(Struct|Class)\Z/)
10649            {
10650                my $ProblemType = "Added_Field";
10651                if(not isPublic(\%Type2_Pure, $Member_Pos)
10652                or isUnnamed($Member_Name))
10653                {
10654                    if($Level eq "Source") {
10655                        next;
10656                    }
10657                    $ProblemType = "Added_Private_Field";
10658                }
10659                if($Level eq "Binary"
10660                and not isMemPadded($Member_Pos, -1, \%Type2_Pure, \%AddedField, 2))
10661                {
10662                    if(my $MNum = isAccessible(\%Type2_Pure, \%AddedField, $Member_Pos, -1))
10663                    { # public fields after the current
10664                        if(getOffset($MNum-1, \%Type2_Pure, 2)!=getOffset($RelatedField_Rev{$MNum-1}, \%Type1_Pure, 1))
10665                        { # changed offset
10666                            $ProblemType .= "_And_Layout";
10667                        }
10668                    }
10669                    if($Type1_Pure{"Size"} ne $Type2_Pure{"Size"}) {
10670                        $ProblemType .= "_And_Size";
10671                    }
10672                }
10673                if($ProblemType eq "Added_Private_Field")
10674                { # skip added private fields
10675                    next;
10676                }
10677                %{$SubProblems{$ProblemType}{$Member_Name}}=(
10678                    "Target"=>$Member_Name,
10679                    "Type_Name"=>$Type1_Pure{"Name"},
10680                    "Type_Type"=>$Type1_Pure{"Type"}  );
10681            }
10682            elsif($Type2_Pure{"Type"} eq "Union")
10683            {
10684                if($Level eq "Binary"
10685                and $Type1_Pure{"Size"} ne $Type2_Pure{"Size"})
10686                {
10687                    %{$SubProblems{"Added_Union_Field_And_Size"}{$Member_Name}}=(
10688                        "Target"=>$Member_Name,
10689                        "Type_Name"=>$Type1_Pure{"Name"},
10690                        "Type_Type"=>$Type1_Pure{"Type"}  );
10691                }
10692                else
10693                {
10694                    %{$SubProblems{"Added_Union_Field"}{$Member_Name}}=(
10695                        "Target"=>$Member_Name,
10696                        "Type_Name"=>$Type1_Pure{"Name"},
10697                        "Type_Type"=>$Type1_Pure{"Type"}  );
10698                }
10699            }
10700            elsif($Type2_Pure{"Type"} eq "Enum")
10701            {
10702                my $Member_Value = $Type2_Pure{"Memb"}{$Member_Pos}{"value"};
10703                next if($Member_Value eq "");
10704                %{$SubProblems{"Added_Enum_Member"}{$Member_Name}}=(
10705                    "Target"=>$Member_Name,
10706                    "Type_Name"=>$Type2_Pure{"Name"},
10707                    "Type_Type"=>$Type2_Pure{"Type"},
10708                    "New_Value"=>$Member_Value  );
10709            }
10710        }
10711    }
10712    %{$Cache{"mergeTypes"}{$Level}{$Type1_Id}{$Type2_Id}} = %SubProblems;
10713    pop(@RecurTypes);
10714    return %SubProblems;
10715}
10716
10717sub isUnnamed($) {
10718    return $_[0]=~/\Aunnamed\d+\Z/;
10719}
10720
10721sub get_ShortType($$)
10722{
10723    my ($TypeId, $LibVersion) = @_;
10724    my $TypeName = $TypeInfo{$LibVersion}{$TypeId}{"Name"};
10725    if(my $NameSpace = $TypeInfo{$LibVersion}{$TypeId}{"NameSpace"}) {
10726        $TypeName=~s/\A$NameSpace\:\://g;
10727    }
10728    return $TypeName;
10729}
10730
10731sub goToFirst($$$)
10732{
10733    my ($TypeId, $LibVersion, $Type_Type) = @_;
10734    return () if(not $TypeId);
10735    if(defined $Cache{"goToFirst"}{$TypeId}{$LibVersion}{$Type_Type}) {
10736        return %{$Cache{"goToFirst"}{$TypeId}{$LibVersion}{$Type_Type}};
10737    }
10738    return () if(not $TypeInfo{$LibVersion}{$TypeId});
10739    my %Type = %{$TypeInfo{$LibVersion}{$TypeId}};
10740    return () if(not $Type{"Type"});
10741    if($Type{"Type"} ne $Type_Type)
10742    {
10743        return () if(not defined $Type{"BaseType"});
10744        return () if(not $Type{"BaseType"}{"Tid"});
10745        %Type = goToFirst($Type{"BaseType"}{"Tid"}, $LibVersion, $Type_Type);
10746    }
10747    $Cache{"goToFirst"}{$TypeId}{$LibVersion}{$Type_Type} = \%Type;
10748    return %Type;
10749}
10750
10751my %TypeSpecAttributes = (
10752    "Const" => 1,
10753    "Volatile" => 1,
10754    "ConstVolatile" => 1,
10755    "Restrict" => 1,
10756    "Typedef" => 1
10757);
10758
10759sub get_PureType($$)
10760{
10761    my ($TypeId, $LibVersion) = @_;
10762    return () if(not $TypeId);
10763    if(defined $Cache{"get_PureType"}{$TypeId}{$LibVersion}) {
10764        return %{$Cache{"get_PureType"}{$TypeId}{$LibVersion}};
10765    }
10766    return () if(not $TypeInfo{$LibVersion}{$TypeId});
10767    my %Type = %{$TypeInfo{$LibVersion}{$TypeId}};
10768    return %Type if(not defined $Type{"BaseType"});
10769    return %Type if(not $Type{"BaseType"}{"Tid"});
10770    if($TypeSpecAttributes{$Type{"Type"}}) {
10771        %Type = get_PureType($Type{"BaseType"}{"Tid"}, $LibVersion);
10772    }
10773    $Cache{"get_PureType"}{$TypeId}{$LibVersion} = \%Type;
10774    return %Type;
10775}
10776
10777sub get_PLevel($$)
10778{
10779    my ($TypeId, $LibVersion) = @_;
10780    return 0 if(not $TypeId);
10781    if(defined $Cache{"get_PLevel"}{$TypeId}{$LibVersion}) {
10782        return $Cache{"get_PLevel"}{$TypeId}{$LibVersion};
10783    }
10784    return 0 if(not $TypeInfo{$LibVersion}{$TypeId});
10785    my %Type = %{$TypeInfo{$LibVersion}{$TypeId}};
10786    return 1 if($Type{"Type"}=~/FuncPtr|MethodPtr|FieldPtr/);
10787    return 0 if(not defined $Type{"BaseType"});
10788    return 0 if(not $Type{"BaseType"}{"Tid"});
10789    my $PointerLevel = 0;
10790    if($Type{"Type"} =~/Pointer|Ref|FuncPtr|MethodPtr|FieldPtr/) {
10791        $PointerLevel += 1;
10792    }
10793    $PointerLevel += get_PLevel($Type{"BaseType"}{"Tid"}, $LibVersion);
10794    $Cache{"get_PLevel"}{$TypeId}{$LibVersion} = $PointerLevel;
10795    return $PointerLevel;
10796}
10797
10798sub get_BaseType($$)
10799{
10800    my ($TypeId, $LibVersion) = @_;
10801    return () if(not $TypeId);
10802    if(defined $Cache{"get_BaseType"}{$TypeId}{$LibVersion}) {
10803        return %{$Cache{"get_BaseType"}{$TypeId}{$LibVersion}};
10804    }
10805    return () if(not $TypeInfo{$LibVersion}{$TypeId});
10806    my %Type = %{$TypeInfo{$LibVersion}{$TypeId}};
10807    return %Type if(not defined $Type{"BaseType"});
10808    return %Type if(not $Type{"BaseType"}{"Tid"});
10809    %Type = get_BaseType($Type{"BaseType"}{"Tid"}, $LibVersion);
10810    $Cache{"get_BaseType"}{$TypeId}{$LibVersion} = \%Type;
10811    return %Type;
10812}
10813
10814sub get_BaseTypeQual($$)
10815{
10816    my ($TypeId, $LibVersion) = @_;
10817    return "" if(not $TypeId);
10818    return "" if(not $TypeInfo{$LibVersion}{$TypeId});
10819    my %Type = %{$TypeInfo{$LibVersion}{$TypeId}};
10820    return "" if(not defined $Type{"BaseType"});
10821    return "" if(not $Type{"BaseType"}{"Tid"});
10822    my $Qual = "";
10823    if($Type{"Type"} eq "Pointer") {
10824        $Qual .= "*";
10825    }
10826    elsif($Type{"Type"} eq "Ref") {
10827        $Qual .= "&";
10828    }
10829    elsif($Type{"Type"} eq "ConstVolatile") {
10830        $Qual .= "const volatile";
10831    }
10832    elsif($Type{"Type"} eq "Const"
10833    or $Type{"Type"} eq "Volatile"
10834    or $Type{"Type"} eq "Restrict") {
10835        $Qual .= lc($Type{"Type"});
10836    }
10837    my $BQual = get_BaseTypeQual($Type{"BaseType"}{"Tid"}, $LibVersion);
10838    return $BQual.$Qual;
10839}
10840
10841sub get_OneStep_BaseType($$)
10842{
10843    my ($TypeId, $LibVersion) = @_;
10844    return () if(not $TypeId);
10845    return () if(not $TypeInfo{$LibVersion}{$TypeId});
10846    my %Type = %{$TypeInfo{$LibVersion}{$TypeId}};
10847    return %Type if(not defined $Type{"BaseType"});
10848    return %Type if(not $Type{"BaseType"}{"Tid"});
10849    return get_Type($Type{"BaseType"}{"Tid"}, $LibVersion);
10850}
10851
10852sub get_Type($$)
10853{
10854    my ($TypeId, $LibVersion) = @_;
10855    return () if(not $TypeId);
10856    return () if(not $TypeInfo{$LibVersion}{$TypeId});
10857    return %{$TypeInfo{$LibVersion}{$TypeId}};
10858}
10859
10860sub isPrivateData($)
10861{ # non-public global data
10862    my $Symbol = $_[0];
10863    return ($Symbol=~/\A(_ZGV|_ZTI|_ZTS|_ZTT|_ZTV|_ZTC|_ZThn|_ZTv0_n)/);
10864}
10865
10866sub isTemplateInstance($$)
10867{
10868    my ($Symbol, $LibVersion) = @_;
10869    if($CheckObjectsOnly)
10870    {
10871        if($Symbol!~/\A(_Z|\?)/) {
10872            return 0;
10873        }
10874        if(my $Signature = $tr_name{$Symbol})
10875        {
10876            if(index($Signature,">")==-1) {
10877                return 0;
10878            }
10879            if(my $ShortName = substr($Signature, 0, find_center($Signature, "(")))
10880            {
10881                if($ShortName=~/<.+>/) {
10882                    return 1;
10883                }
10884            }
10885        }
10886    }
10887    else
10888    {
10889        if(my $ClassId = $CompleteSignature{$LibVersion}{$Symbol}{"Class"})
10890        {
10891            if(my $ClassName = $TypeInfo{$LibVersion}{$ClassId}{"Name"})
10892            {
10893                if(index($ClassName,"<")!=-1) {
10894                    return 1;
10895                }
10896            }
10897        }
10898        if(my $ShortName = $CompleteSignature{$LibVersion}{$Symbol}{"ShortName"})
10899        {
10900            if($ShortName=~/<.+>/) {
10901                return 1;
10902            }
10903        }
10904    }
10905    return 0;
10906}
10907
10908sub isTemplateSpec($$)
10909{
10910    my ($Symbol, $LibVersion) = @_;
10911    if(my $ClassId = $CompleteSignature{$LibVersion}{$Symbol}{"Class"})
10912    {
10913        if($TypeInfo{$LibVersion}{$ClassId}{"Spec"})
10914        { # class specialization
10915            return 1;
10916        }
10917        elsif($CompleteSignature{$LibVersion}{$Symbol}{"Spec"})
10918        { # method specialization
10919            return 1;
10920        }
10921    }
10922    return 0;
10923}
10924
10925sub symbolFilter($$$$)
10926{ # some special cases when the symbol cannot be imported
10927    my ($Symbol, $LibVersion, $Type, $Level) = @_;
10928    if(isPrivateData($Symbol))
10929    { # non-public global data
10930        return 0;
10931    }
10932    if($CheckObjectsOnly) {
10933        return 0 if($Symbol=~/\A(_init|_fini)\Z/);
10934    }
10935    if($CheckHeadersOnly and not checkDump($LibVersion, "2.7"))
10936    { # support for old ABI dumps in --headers-only mode
10937        foreach my $Pos (keys(%{$CompleteSignature{$LibVersion}{$Symbol}{"Param"}}))
10938        {
10939            if(my $Pid = $CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$Pos}{"type"})
10940            {
10941                my $PType = $TypeInfo{$LibVersion}{$Pid}{"Type"};
10942                if(not $PType or $PType eq "Unknown") {
10943                    return 0;
10944                }
10945            }
10946        }
10947    }
10948    if($Type=~/Affected/)
10949    {
10950        my $ClassId = $CompleteSignature{$LibVersion}{$Symbol}{"Class"};
10951        if($SkipSymbols{$LibVersion}{$Symbol})
10952        { # user defined symbols to ignore
10953            return 0;
10954        }
10955        my $NameSpace = $CompleteSignature{$LibVersion}{$Symbol}{"NameSpace"};
10956        if(not $NameSpace and $ClassId)
10957        { # class methods have no "NameSpace" attribute
10958            $NameSpace = $TypeInfo{$LibVersion}{$ClassId}{"NameSpace"};
10959        }
10960        if($NameSpace)
10961        { # user defined namespaces to ignore
10962            if($SkipNameSpaces{$LibVersion}{$NameSpace}) {
10963                return 0;
10964            }
10965            foreach my $NS (keys(%{$SkipNameSpaces{$LibVersion}}))
10966            { # nested namespaces
10967                if($NameSpace=~/\A\Q$NS\E(\:\:|\Z)/) {
10968                    return 0;
10969                }
10970            }
10971        }
10972        if(my $Header = $CompleteSignature{$LibVersion}{$Symbol}{"Header"})
10973        {
10974            if(my $Skip = skipHeader($Header, $LibVersion))
10975            { # --skip-headers or <skip_headers> (not <skip_including>)
10976                if($Skip==1) {
10977                    return 0;
10978                }
10979            }
10980        }
10981        if($SymbolsListPath and not $SymbolsList{$Symbol})
10982        { # user defined symbols
10983            return 0;
10984        }
10985        if($AppPath and not $SymbolsList_App{$Symbol})
10986        { # user defined symbols (in application)
10987            return 0;
10988        }
10989        if(not selectSymbol($Symbol, $CompleteSignature{$LibVersion}{$Symbol}, $Level, $LibVersion))
10990        { # non-target symbols
10991            return 0;
10992        }
10993        if($Level eq "Binary")
10994        {
10995            if($CheckObjectsOnly)
10996            {
10997                if(isTemplateInstance($Symbol, $LibVersion)) {
10998                    return 0;
10999                }
11000            }
11001            else
11002            {
11003                if($CompleteSignature{$LibVersion}{$Symbol}{"InLine"}
11004                or (isTemplateInstance($Symbol, $LibVersion) and not isTemplateSpec($Symbol, $LibVersion)))
11005                {
11006                    if($ClassId and $CompleteSignature{$LibVersion}{$Symbol}{"Virt"})
11007                    { # inline virtual methods
11008                        if($Type=~/InlineVirt/) {
11009                            return 1;
11010                        }
11011                        my $Allocable = (not isCopyingClass($ClassId, $LibVersion));
11012                        if(not $Allocable)
11013                        { # check bases
11014                            foreach my $DCId (get_sub_classes($ClassId, $LibVersion, 1))
11015                            {
11016                                if(not isCopyingClass($DCId, $LibVersion))
11017                                { # exists a derived class without default c-tor
11018                                    $Allocable=1;
11019                                    last;
11020                                }
11021                            }
11022                        }
11023                        if(not $Allocable) {
11024                            return 0;
11025                        }
11026                    }
11027                    else
11028                    { # inline non-virtual methods
11029                        return 0;
11030                    }
11031                }
11032            }
11033        }
11034    }
11035    return 1;
11036}
11037
11038sub mergeImpl()
11039{
11040    my $DiffCmd = get_CmdPath("diff");
11041    if(not $DiffCmd) {
11042        exitStatus("Not_Found", "can't find \"diff\"");
11043    }
11044    foreach my $Interface (sort keys(%{$Symbol_Library{1}}))
11045    { # implementation changes
11046        next if($CompleteSignature{1}{$Interface}{"Private"});
11047        next if(not $CompleteSignature{1}{$Interface}{"Header"} and not $CheckObjectsOnly);
11048        next if(not $Symbol_Library{2}{$Interface} and not $Symbol_Library{2}{$SymVer{2}{$Interface}});
11049        if(not symbolFilter($Interface, 1, "Affected", "Binary")) {
11050            next;
11051        }
11052        my $Impl1 = canonifyImpl($Interface_Impl{1}{$Interface});
11053        next if(not $Impl1);
11054        my $Impl2 = canonifyImpl($Interface_Impl{2}{$Interface});
11055        next if(not $Impl2);
11056        if($Impl1 ne $Impl2)
11057        {
11058            writeFile("$TMP_DIR/impl1", $Impl1);
11059            writeFile("$TMP_DIR/impl2", $Impl2);
11060            my $Diff = `$DiffCmd -rNau \"$TMP_DIR/impl1\" \"$TMP_DIR/impl2\"`;
11061            $Diff=~s/(---|\+\+\+).+\n//g;
11062            $Diff=~s/[ ]{3,}/ /g;
11063            $Diff=~s/\n\@\@/\n \n\@\@/g;
11064            unlink("$TMP_DIR/impl1");
11065            unlink("$TMP_DIR/impl2");
11066            %{$ImplProblems{$Interface}}=(
11067                "Diff" => get_CodeView($Diff)  );
11068        }
11069    }
11070
11071    # clean memory
11072    %Interface_Impl = ();
11073}
11074
11075sub canonifyImpl($)
11076{
11077    my $FuncBody=  $_[0];
11078    return "" if(not $FuncBody);
11079    $FuncBody=~s/0x[a-f\d]+/0x?/g;# addr
11080    $FuncBody=~s/((\A|\n)[a-z]+[\t ]+)[a-f\d]+([^x]|\Z)/$1?$3/g;# call, jump
11081    $FuncBody=~s/# [a-f\d]+ /# ? /g;# call, jump
11082    $FuncBody=~s/%([a-z]+[a-f\d]*)/\%reg/g;# registers
11083    while($FuncBody=~s/\nnop[ \t]*(\n|\Z)/$1/g){};# empty op
11084    $FuncBody=~s/<.+?\.cpp.+?>/<name.cpp>/g;
11085    $FuncBody=~s/(\A|\n)[a-f\d]+ </$1? </g;# 5e74 <_ZN...
11086    $FuncBody=~s/\.L\d+/.L/g;
11087    $FuncBody=~s/#(-?)\d+/#$1?/g;# r3, [r3, #120]
11088    $FuncBody=~s/[\n]{2,}/\n/g;
11089    return $FuncBody;
11090}
11091
11092sub get_CodeView($)
11093{
11094    my $Code = $_[0];
11095    my $View = "";
11096    foreach my $Line (split(/\n/, $Code))
11097    {
11098        if($Line=~s/\A(\+|-)/$1 /g)
11099        { # bold line
11100            $View .= "<tr><td><b>".htmlSpecChars($Line)."</b></td></tr>\n";
11101        }
11102        else {
11103            $View .= "<tr><td>".htmlSpecChars($Line)."</td></tr>\n";
11104        }
11105    }
11106    return "<table class='code_view'>$View</table>\n";
11107}
11108
11109sub getImplementations($$)
11110{
11111    my ($LibVersion, $Path) = @_;
11112    return if(not $LibVersion or not -e $Path);
11113    if($OSgroup eq "macos")
11114    {
11115        my $OtoolCmd = get_CmdPath("otool");
11116        if(not $OtoolCmd) {
11117            exitStatus("Not_Found", "can't find \"otool\"");
11118        }
11119        my $CurInterface = "";
11120        foreach my $Line (split(/\n/, `$OtoolCmd -tv \"$Path\" 2>\"$TMP_DIR/null\"`))
11121        {
11122            if($Line=~/\A\s*_(\w+)\s*:/i) {
11123                $CurInterface = $1;
11124            }
11125            elsif($Line=~/\A\s*[\da-z]+\s+(.+?)\Z/i) {
11126                $Interface_Impl{$LibVersion}{$CurInterface} .= $1."\n";
11127            }
11128        }
11129    }
11130    else
11131    {
11132        my $ObjdumpCmd = get_CmdPath("objdump");
11133        if(not $ObjdumpCmd) {
11134            exitStatus("Not_Found", "can't find \"objdump\"");
11135        }
11136        my $CurInterface = "";
11137        foreach my $Line (split(/\n/, `$ObjdumpCmd -d \"$Path\" 2>\"$TMP_DIR/null\"`))
11138        {
11139            if($Line=~/\A[\da-z]+\s+<(\w+)>/i) {
11140                $CurInterface = $1;
11141            }
11142            else
11143            { # x86:    51fa:(\t)89 e5               (\t)mov    %esp,%ebp
11144              # arm:    5020:(\t)e24cb004(\t)sub(\t)fp, ip, #4(\t); 0x4
11145                if($Line=~/\A\s*[a-f\d]+:\s+([a-f\d]+\s+)+([a-z]+\s+.*?)\s*(;.*|)\Z/i) {
11146                    $Interface_Impl{$LibVersion}{$CurInterface} .= $2."\n";
11147                }
11148            }
11149        }
11150    }
11151}
11152
11153sub detectAdded($)
11154{
11155    my $Level = $_[0];
11156    foreach my $Symbol (keys(%{$Symbol_Library{2}}))
11157    {
11158        if(link_symbol($Symbol, 1, "+Deps"))
11159        { # linker can find a new symbol
11160          # in the old-version library
11161          # So, it's not a new symbol
11162            next;
11163        }
11164        if(my $VSym = $SymVer{2}{$Symbol}
11165        and index($Symbol,"\@")==-1) {
11166            next;
11167        }
11168        $AddedInt{$Level}{$Symbol} = 1;
11169    }
11170}
11171
11172sub detectRemoved($)
11173{
11174    my $Level = $_[0];
11175    foreach my $Symbol (keys(%{$Symbol_Library{1}}))
11176    {
11177        if($CheckObjectsOnly) {
11178            $CheckedSymbols{"Binary"}{$Symbol} = 1;
11179        }
11180        if(link_symbol($Symbol, 2, "+Deps"))
11181        { # linker can find an old symbol
11182          # in the new-version library
11183            next;
11184        }
11185        if(my $VSym = $SymVer{1}{$Symbol}
11186        and index($Symbol,"\@")==-1) {
11187            next;
11188        }
11189        $RemovedInt{$Level}{$Symbol} = 1;
11190    }
11191}
11192
11193sub mergeLibs($)
11194{
11195    my $Level = $_[0];
11196    foreach my $Symbol (sort keys(%{$AddedInt{$Level}}))
11197    { # checking added symbols
11198        next if($CompleteSignature{2}{$Symbol}{"Private"});
11199        next if(not $CompleteSignature{2}{$Symbol}{"Header"} and not $CheckObjectsOnly);
11200        next if(not symbolFilter($Symbol, 2, "Affected", $Level));
11201        %{$CompatProblems{$Level}{$Symbol}{"Added_Symbol"}{""}}=();
11202    }
11203    foreach my $Symbol (sort keys(%{$RemovedInt{$Level}}))
11204    { # checking removed symbols
11205        next if($CompleteSignature{1}{$Symbol}{"Private"});
11206        next if(not $CompleteSignature{1}{$Symbol}{"Header"} and not $CheckObjectsOnly);
11207        if($Symbol=~/\A_ZTV/)
11208        { # skip v-tables for templates, that should not be imported by applications
11209            next if($tr_name{$Symbol}=~/</);
11210            if(my $CName = $VTableClass{$Symbol})
11211            {
11212                if(not keys(%{$ClassMethods{$Level}{1}{$CName}}))
11213                { # vtables for "private" classes
11214                  # use case: vtable for QDragManager (Qt 4.5.3 to 4.6.0) became HIDDEN symbol
11215                    next;
11216                }
11217            }
11218        }
11219        else {
11220            next if(not symbolFilter($Symbol, 1, "Affected", $Level));
11221        }
11222        if($CompleteSignature{1}{$Symbol}{"PureVirt"})
11223        { # symbols for pure virtual methods cannot be called by clients
11224            next;
11225        }
11226        %{$CompatProblems{$Level}{$Symbol}{"Removed_Symbol"}{""}}=();
11227    }
11228}
11229
11230sub checkDump($$)
11231{
11232    my ($LibVersion, $V) = @_;
11233    if(defined $Cache{"checkDump"}{$LibVersion}{$V}) {
11234        return $Cache{"checkDump"}{$LibVersion}{$V};
11235    }
11236    return ($Cache{"checkDump"}{$LibVersion}{$V} = (not $UsedDump{$LibVersion}{"V"} or cmpVersions($UsedDump{$LibVersion}{"V"}, $V)>=0));
11237}
11238
11239sub detectAdded_H($)
11240{
11241    my $Level = $_[0];
11242    foreach my $Symbol (sort keys(%{$CompleteSignature{2}}))
11243    {
11244        if($Level eq "Source")
11245        { # remove symbol version
11246            my ($SN, $SS, $SV) = separate_symbol($Symbol);
11247            $Symbol=$SN;
11248
11249            if($CompleteSignature{2}{$Symbol}{"Artificial"})
11250            { # skip artificial constructors
11251                next;
11252            }
11253        }
11254        if(not $CompleteSignature{2}{$Symbol}{"Header"}
11255        or not $CompleteSignature{2}{$Symbol}{"MnglName"}) {
11256            next;
11257        }
11258        if($ExtendedSymbols{$Symbol}) {
11259            next;
11260        }
11261        if(not defined $CompleteSignature{1}{$Symbol}
11262        or not $CompleteSignature{1}{$Symbol}{"MnglName"})
11263        {
11264            if($UsedDump{2}{"SrcBin"})
11265            {
11266                if($UsedDump{1}{"BinOnly"} or not checkDump(1, "2.11"))
11267                { # support for old and different (!) ABI dumps
11268                    if(not $CompleteSignature{2}{$Symbol}{"Virt"}
11269                    and not $CompleteSignature{2}{$Symbol}{"PureVirt"})
11270                    {
11271                        if($CheckHeadersOnly)
11272                        {
11273                            if(my $Lang = $CompleteSignature{2}{$Symbol}{"Lang"})
11274                            {
11275                                if($Lang eq "C")
11276                                { # support for old ABI dumps: missed extern "C" functions
11277                                    next;
11278                                }
11279                            }
11280                        }
11281                        else
11282                        {
11283                            if(not link_symbol($Symbol, 2, "-Deps"))
11284                            { # skip added inline symbols and const global data
11285                                next;
11286                            }
11287                        }
11288                    }
11289                }
11290            }
11291            $AddedInt{$Level}{$Symbol} = 1;
11292        }
11293    }
11294}
11295
11296sub detectRemoved_H($)
11297{
11298    my $Level = $_[0];
11299    foreach my $Symbol (sort keys(%{$CompleteSignature{1}}))
11300    {
11301        if($Level eq "Source")
11302        { # remove symbol version
11303            my ($SN, $SS, $SV) = separate_symbol($Symbol);
11304            $Symbol=$SN;
11305        }
11306        if(not $CompleteSignature{1}{$Symbol}{"Header"}
11307        or not $CompleteSignature{1}{$Symbol}{"MnglName"}) {
11308            next;
11309        }
11310        if($ExtendedSymbols{$Symbol}) {
11311            next;
11312        }
11313        if(not defined $CompleteSignature{2}{$Symbol}
11314        or not $CompleteSignature{2}{$Symbol}{"MnglName"})
11315        {
11316            if($UsedDump{1}{"SrcBin"})
11317            {
11318                if($UsedDump{2}{"BinOnly"} or not checkDump(2, "2.11"))
11319                { # support for old and different (!) ABI dumps
11320                    if(not $CompleteSignature{1}{$Symbol}{"Virt"}
11321                    and not $CompleteSignature{1}{$Symbol}{"PureVirt"})
11322                    {
11323                        if($CheckHeadersOnly)
11324                        { # skip all removed symbols
11325                            if(my $Lang = $CompleteSignature{1}{$Symbol}{"Lang"})
11326                            {
11327                                if($Lang eq "C")
11328                                { # support for old ABI dumps: missed extern "C" functions
11329                                    next;
11330                                }
11331                            }
11332                        }
11333                        else
11334                        {
11335                            if(not link_symbol($Symbol, 1, "-Deps"))
11336                            { # skip removed inline symbols
11337                                next;
11338                            }
11339                        }
11340                    }
11341                }
11342            }
11343            if(not checkDump(1, "2.15"))
11344            {
11345                if($Symbol=~/_IT_E\Z/)
11346                { # _ZN28QExplicitlySharedDataPointerI22QSslCertificatePrivateEC1IT_EERKS_IT_E
11347                    next;
11348                }
11349            }
11350            $RemovedInt{$Level}{$Symbol} = 1;
11351            if($Level eq "Source")
11352            { # search for a source-compatible equivalent
11353                setAlternative($Symbol, $Level);
11354            }
11355        }
11356    }
11357}
11358
11359sub mergeHeaders($)
11360{
11361    my $Level = $_[0];
11362    foreach my $Symbol (sort keys(%{$AddedInt{$Level}}))
11363    { # checking added symbols
11364        next if($CompleteSignature{2}{$Symbol}{"PureVirt"});
11365        if($Level eq "Binary")
11366        {
11367            if($CompleteSignature{2}{$Symbol}{"InLine"})
11368            {
11369                if(not $CompleteSignature{2}{$Symbol}{"Virt"})
11370                { # skip inline non-virtual functions
11371                    next;
11372                }
11373            }
11374        }
11375        else
11376        { # Source
11377            if($SourceAlternative_B{$Symbol}) {
11378                next;
11379            }
11380        }
11381        next if($CompleteSignature{2}{$Symbol}{"Private"});
11382        next if(not symbolFilter($Symbol, 2, "Affected", $Level));
11383        %{$CompatProblems{$Level}{$Symbol}{"Added_Symbol"}{""}}=();
11384    }
11385    foreach my $Symbol (sort keys(%{$RemovedInt{$Level}}))
11386    { # checking removed symbols
11387        next if($CompleteSignature{1}{$Symbol}{"PureVirt"});
11388        if($Level eq "Binary")
11389        {
11390            if($CompleteSignature{1}{$Symbol}{"InLine"})
11391            {
11392                if(not $CompleteSignature{1}{$Symbol}{"Virt"})
11393                { # skip inline non-virtual functions
11394                    next;
11395                }
11396            }
11397        }
11398        else
11399        { # Source
11400            if(my $Alt = $SourceAlternative{$Symbol})
11401            {
11402                if(defined $CompleteSignature{1}{$Alt}
11403                and $CompleteSignature{1}{$Symbol}{"Const"})
11404                {
11405                    my $Cid = $CompleteSignature{1}{$Symbol}{"Class"};
11406                    %{$CompatProblems{$Level}{$Symbol}{"Removed_Const_Overload"}{$tr_name{$Symbol}}}=(
11407                        "Type_Name"=>$TypeInfo{1}{$Cid}{"Name"},
11408                        "Type_Type"=>"Class",
11409                        "Target"=>get_Signature($Alt, 1)  );
11410                }
11411                else
11412                { # do NOT show removed symbol
11413                    next;
11414                }
11415            }
11416        }
11417        next if($CompleteSignature{1}{$Symbol}{"Private"});
11418        next if(not symbolFilter($Symbol, 1, "Affected", $Level));
11419        %{$CompatProblems{$Level}{$Symbol}{"Removed_Symbol"}{""}}=();
11420    }
11421}
11422
11423sub addParamNames($)
11424{
11425    my $LibraryVersion = $_[0];
11426    return if(not keys(%AddIntParams));
11427    my $SecondVersion = $LibraryVersion==1?2:1;
11428    foreach my $Interface (sort keys(%{$CompleteSignature{$LibraryVersion}}))
11429    {
11430        next if(not keys(%{$AddIntParams{$Interface}}));
11431        foreach my $ParamPos (sort {int($a)<=>int($b)} keys(%{$CompleteSignature{$LibraryVersion}{$Interface}{"Param"}}))
11432        { # add absent parameter names
11433            my $ParamName = $CompleteSignature{$LibraryVersion}{$Interface}{"Param"}{$ParamPos}{"name"};
11434            if($ParamName=~/\Ap\d+\Z/ and my $NewParamName = $AddIntParams{$Interface}{$ParamPos})
11435            { # names from the external file
11436                if(defined $CompleteSignature{$SecondVersion}{$Interface}
11437                and defined $CompleteSignature{$SecondVersion}{$Interface}{"Param"}{$ParamPos})
11438                {
11439                    if($CompleteSignature{$SecondVersion}{$Interface}{"Param"}{$ParamPos}{"name"}=~/\Ap\d+\Z/) {
11440                        $CompleteSignature{$LibraryVersion}{$Interface}{"Param"}{$ParamPos}{"name"} = $NewParamName;
11441                    }
11442                }
11443                else {
11444                    $CompleteSignature{$LibraryVersion}{$Interface}{"Param"}{$ParamPos}{"name"} = $NewParamName;
11445                }
11446            }
11447        }
11448    }
11449}
11450
11451sub detectChangedTypedefs()
11452{ # detect changed typedefs to show
11453  # correct function signatures
11454    foreach my $Typedef (keys(%{$Typedef_BaseName{1}}))
11455    {
11456        next if(not $Typedef);
11457        my $BName1 = $Typedef_BaseName{1}{$Typedef};
11458        if(not $BName1 or isAnon($BName1)) {
11459            next;
11460        }
11461        my $BName2 = $Typedef_BaseName{2}{$Typedef};
11462        if(not $BName2 or isAnon($BName2)) {
11463            next;
11464        }
11465        if($BName1 ne $BName2) {
11466            $ChangedTypedef{$Typedef} = 1;
11467        }
11468    }
11469}
11470
11471sub get_symbol_suffix($$)
11472{
11473    my ($Symbol, $Full) = @_;
11474    my ($SN, $SO, $SV) = separate_symbol($Symbol);
11475    $Symbol=$SN;# remove version
11476    my $Signature = $tr_name{$Symbol};
11477    my $Suffix = substr($Signature, find_center($Signature, "("));
11478    if(not $Full) {
11479        $Suffix=~s/(\))\s*(const volatile|volatile const|const|volatile)\Z/$1/g;
11480    }
11481    return $Suffix;
11482}
11483
11484sub get_symbol_prefix($$)
11485{
11486    my ($Symbol, $LibVersion) = @_;
11487    my $ShortName = $CompleteSignature{$LibVersion}{$Symbol}{"ShortName"};
11488    if(my $ClassId = $CompleteSignature{$LibVersion}{$Symbol}{"Class"})
11489    { # methods
11490        $ShortName = $TypeInfo{$LibVersion}{$ClassId}{"Name"}."::".$ShortName;
11491    }
11492    return $ShortName;
11493}
11494
11495sub setAlternative($)
11496{
11497    my $Symbol = $_[0];
11498    my $PSymbol = $Symbol;
11499    if(not defined $CompleteSignature{2}{$PSymbol}
11500    or (not $CompleteSignature{2}{$PSymbol}{"MnglName"}
11501    and not $CompleteSignature{2}{$PSymbol}{"ShortName"}))
11502    { # search for a pair
11503        if(my $ShortName = $CompleteSignature{1}{$PSymbol}{"ShortName"})
11504        {
11505            if($CompleteSignature{1}{$PSymbol}{"Data"})
11506            {
11507                if($PSymbol=~s/L(\d+$ShortName(E)\Z)/$1/
11508                or $PSymbol=~s/(\d+$ShortName(E)\Z)/L$1/)
11509                {
11510                    if(defined $CompleteSignature{2}{$PSymbol}
11511                    and $CompleteSignature{2}{$PSymbol}{"MnglName"})
11512                    {
11513                        $SourceAlternative{$Symbol} = $PSymbol;
11514                        $SourceAlternative_B{$PSymbol} = $Symbol;
11515                        if(not defined $CompleteSignature{1}{$PSymbol}
11516                        or not $CompleteSignature{1}{$PSymbol}{"MnglName"}) {
11517                            $SourceReplacement{$Symbol} = $PSymbol;
11518                        }
11519                    }
11520                }
11521            }
11522            else
11523            {
11524                foreach my $Sp ("KV", "VK", "K", "V")
11525                {
11526                    if($PSymbol=~s/\A_ZN$Sp/_ZN/
11527                    or $PSymbol=~s/\A_ZN/_ZN$Sp/)
11528                    {
11529                        if(defined $CompleteSignature{2}{$PSymbol}
11530                        and $CompleteSignature{2}{$PSymbol}{"MnglName"})
11531                        {
11532                            $SourceAlternative{$Symbol} = $PSymbol;
11533                            $SourceAlternative_B{$PSymbol} = $Symbol;
11534                            if(not defined $CompleteSignature{1}{$PSymbol}
11535                            or not $CompleteSignature{1}{$PSymbol}{"MnglName"}) {
11536                                $SourceReplacement{$Symbol} = $PSymbol;
11537                            }
11538                        }
11539                    }
11540                    $PSymbol = $Symbol;
11541                }
11542            }
11543        }
11544    }
11545    return "";
11546}
11547
11548sub getSymKind($$)
11549{
11550    my ($Symbol, $LibVersion) = @_;
11551    if($CompleteSignature{$LibVersion}{$Symbol}{"Data"})
11552    {
11553        return "Global_Data";
11554    }
11555    elsif($CompleteSignature{$LibVersion}{$Symbol}{"Class"})
11556    {
11557        return "Method";
11558    }
11559    return "Function";
11560}
11561
11562sub mergeSignatures($)
11563{
11564    my $Level = $_[0];
11565    my %SubProblems = ();
11566
11567    mergeBases($Level);
11568
11569    my %AddedOverloads = ();
11570    foreach my $Symbol (sort keys(%{$AddedInt{$Level}}))
11571    { # check all added exported symbols
11572        if(not $CompleteSignature{2}{$Symbol}{"Header"}) {
11573            next;
11574        }
11575        if(defined $CompleteSignature{1}{$Symbol}
11576        and $CompleteSignature{1}{$Symbol}{"Header"})
11577        { # double-check added symbol
11578            next;
11579        }
11580        if(not symbolFilter($Symbol, 2, "Affected", $Level)) {
11581            next;
11582        }
11583        if($Symbol=~/\A(_Z|\?)/)
11584        { # C++
11585            $AddedOverloads{get_symbol_prefix($Symbol, 2)}{get_symbol_suffix($Symbol, 1)} = $Symbol;
11586        }
11587        if(my $OverriddenMethod = $CompleteSignature{2}{$Symbol}{"Override"})
11588        { # register virtual overridings
11589            my $Cid = $CompleteSignature{2}{$Symbol}{"Class"};
11590            my $AffectedClass_Name = $TypeInfo{2}{$Cid}{"Name"};
11591            if(defined $CompleteSignature{1}{$OverriddenMethod} and $CompleteSignature{1}{$OverriddenMethod}{"Virt"}
11592            and not $CompleteSignature{1}{$OverriddenMethod}{"Private"})
11593            {
11594                if($TName_Tid{1}{$AffectedClass_Name})
11595                { # class should exist in previous version
11596                    if(not isCopyingClass($TName_Tid{1}{$AffectedClass_Name}, 1))
11597                    { # old v-table is NOT copied by old applications
11598                        %{$CompatProblems{$Level}{$OverriddenMethod}{"Overridden_Virtual_Method"}{$tr_name{$Symbol}}}=(
11599                            "Type_Name"=>$AffectedClass_Name,
11600                            "Type_Type"=>"Class",
11601                            "Target"=>get_Signature($Symbol, 2),
11602                            "Old_Value"=>get_Signature($OverriddenMethod, 2),
11603                            "New_Value"=>get_Signature($Symbol, 2)  );
11604                    }
11605                }
11606            }
11607        }
11608    }
11609    foreach my $Symbol (sort keys(%{$RemovedInt{$Level}}))
11610    { # check all removed exported symbols
11611        if(not $CompleteSignature{1}{$Symbol}{"Header"}) {
11612            next;
11613        }
11614        if(defined $CompleteSignature{2}{$Symbol}
11615        and $CompleteSignature{2}{$Symbol}{"Header"})
11616        { # double-check removed symbol
11617            next;
11618        }
11619        if($CompleteSignature{1}{$Symbol}{"Private"})
11620        { # skip private methods
11621            next;
11622        }
11623        if(not symbolFilter($Symbol, 1, "Affected", $Level)) {
11624            next;
11625        }
11626        $CheckedSymbols{$Level}{$Symbol} = 1;
11627        if(my $OverriddenMethod = $CompleteSignature{1}{$Symbol}{"Override"})
11628        { # register virtual overridings
11629            my $Cid = $CompleteSignature{1}{$Symbol}{"Class"};
11630            my $AffectedClass_Name = $TypeInfo{1}{$Cid}{"Name"};
11631            if(defined $CompleteSignature{2}{$OverriddenMethod}
11632            and $CompleteSignature{2}{$OverriddenMethod}{"Virt"})
11633            {
11634                if($TName_Tid{2}{$AffectedClass_Name})
11635                { # class should exist in newer version
11636                    if(not isCopyingClass($CompleteSignature{1}{$Symbol}{"Class"}, 1))
11637                    { # old v-table is NOT copied by old applications
11638                        %{$CompatProblems{$Level}{$Symbol}{"Overridden_Virtual_Method_B"}{$tr_name{$OverriddenMethod}}}=(
11639                            "Type_Name"=>$AffectedClass_Name,
11640                            "Type_Type"=>"Class",
11641                            "Target"=>get_Signature($OverriddenMethod, 1),
11642                            "Old_Value"=>get_Signature($Symbol, 1),
11643                            "New_Value"=>get_Signature($OverriddenMethod, 1)  );
11644                    }
11645                }
11646            }
11647        }
11648        if($Level eq "Binary"
11649        and $OSgroup eq "windows")
11650        { # register the reason of symbol name change
11651            if(my $NewSym = $mangled_name{2}{$tr_name{$Symbol}})
11652            {
11653                if($AddedInt{$Level}{$NewSym})
11654                {
11655                    if($CompleteSignature{1}{$Symbol}{"Static"} ne $CompleteSignature{2}{$NewSym}{"Static"})
11656                    {
11657                        if($CompleteSignature{2}{$NewSym}{"Static"})
11658                        {
11659                            %{$CompatProblems{$Level}{$Symbol}{"Symbol_Became_Static"}{$tr_name{$Symbol}}}=(
11660                                "Target"=>$tr_name{$Symbol},
11661                                "Old_Value"=>$Symbol,
11662                                "New_Value"=>$NewSym  );
11663                        }
11664                        else
11665                        {
11666                            %{$CompatProblems{$Level}{$Symbol}{"Symbol_Became_NonStatic"}{$tr_name{$Symbol}}}=(
11667                                "Target"=>$tr_name{$Symbol},
11668                                "Old_Value"=>$Symbol,
11669                                "New_Value"=>$NewSym  );
11670                        }
11671                    }
11672                    if($CompleteSignature{1}{$Symbol}{"Virt"} ne $CompleteSignature{2}{$NewSym}{"Virt"})
11673                    {
11674                        if($CompleteSignature{2}{$NewSym}{"Virt"})
11675                        {
11676                            %{$CompatProblems{$Level}{$Symbol}{"Symbol_Became_Virtual"}{$tr_name{$Symbol}}}=(
11677                                "Target"=>$tr_name{$Symbol},
11678                                "Old_Value"=>$Symbol,
11679                                "New_Value"=>$NewSym  );
11680                        }
11681                        else
11682                        {
11683                            %{$CompatProblems{$Level}{$Symbol}{"Symbol_Became_NonVirtual"}{$tr_name{$Symbol}}}=(
11684                                "Target"=>$tr_name{$Symbol},
11685                                "Old_Value"=>$Symbol,
11686                                "New_Value"=>$NewSym  );
11687                        }
11688                    }
11689                    my $RTId1 = $CompleteSignature{1}{$Symbol}{"Return"};
11690                    my $RTId2 = $CompleteSignature{2}{$NewSym}{"Return"};
11691                    my $RTName1 = $TypeInfo{1}{$RTId1}{"Name"};
11692                    my $RTName2 = $TypeInfo{2}{$RTId2}{"Name"};
11693                    if($RTName1 ne $RTName2)
11694                    {
11695                        my $ProblemType = "Symbol_Changed_Return";
11696                        if($CompleteSignature{1}{$Symbol}{"Data"}) {
11697                            $ProblemType = "Global_Data_Symbol_Changed_Type";
11698                        }
11699                        %{$CompatProblems{$Level}{$Symbol}{$ProblemType}{$tr_name{$Symbol}}}=(
11700                            "Target"=>$tr_name{$Symbol},
11701                            "Old_Type"=>$RTName1,
11702                            "New_Type"=>$RTName2,
11703                            "Old_Value"=>$Symbol,
11704                            "New_Value"=>$NewSym  );
11705                    }
11706                }
11707            }
11708        }
11709        if($Symbol=~/\A(_Z|\?)/)
11710        { # C++
11711            my $Prefix = get_symbol_prefix($Symbol, 1);
11712            if(my @Overloads = sort keys(%{$AddedOverloads{$Prefix}})
11713            and not $AddedOverloads{$Prefix}{get_symbol_suffix($Symbol, 1)})
11714            { # changed signature: params, "const"-qualifier
11715                my $NewSym = $AddedOverloads{$Prefix}{$Overloads[0]};
11716                if($CompleteSignature{1}{$Symbol}{"Constructor"})
11717                {
11718                    if($Symbol=~/(C1E|C2E)/)
11719                    {
11720                        my $CtorType = $1;
11721                        $NewSym=~s/(C1E|C2E)/$CtorType/g;
11722                    }
11723                }
11724                elsif($CompleteSignature{1}{$Symbol}{"Destructor"})
11725                {
11726                    if($Symbol=~/(D0E|D1E|D2E)/)
11727                    {
11728                        my $DtorType = $1;
11729                        $NewSym=~s/(D0E|D1E|D2E)/$DtorType/g;
11730                    }
11731                }
11732                my $NS1 = $CompleteSignature{1}{$Symbol}{"NameSpace"};
11733                my $NS2 = $CompleteSignature{2}{$NewSym}{"NameSpace"};
11734                if((not $NS1 and not $NS2) or ($NS1 and $NS2 and $NS1 eq $NS2))
11735                { # from the same class and namespace
11736                    if($CompleteSignature{1}{$Symbol}{"Const"}
11737                    and not $CompleteSignature{2}{$NewSym}{"Const"})
11738                    { # "const" to non-"const"
11739                        %{$CompatProblems{$Level}{$Symbol}{"Method_Became_NonConst"}{$tr_name{$Symbol}}}=(
11740                            "Type_Name"=>$TypeInfo{1}{$CompleteSignature{1}{$Symbol}{"Class"}}{"Name"},
11741                            "Target"=>$tr_name{$Symbol},
11742                            "New_Signature"=>get_Signature($NewSym, 2),
11743                            "Old_Value"=>$Symbol,
11744                            "New_Value"=>$NewSym  );
11745                    }
11746                    elsif(not $CompleteSignature{1}{$Symbol}{"Const"}
11747                    and $CompleteSignature{2}{$NewSym}{"Const"})
11748                    { # non-"const" to "const"
11749                        %{$CompatProblems{$Level}{$Symbol}{"Method_Became_Const"}{$tr_name{$Symbol}}}=(
11750                            "Target"=>$tr_name{$Symbol},
11751                            "New_Signature"=>get_Signature($NewSym, 2),
11752                            "Old_Value"=>$Symbol,
11753                            "New_Value"=>$NewSym  );
11754                    }
11755                    if($CompleteSignature{1}{$Symbol}{"Volatile"}
11756                    and not $CompleteSignature{2}{$NewSym}{"Volatile"})
11757                    { # "volatile" to non-"volatile"
11758
11759                        %{$CompatProblems{$Level}{$Symbol}{"Method_Became_NonVolatile"}{$tr_name{$Symbol}}}=(
11760                            "Target"=>$tr_name{$Symbol},
11761                            "New_Signature"=>get_Signature($NewSym, 2),
11762                            "Old_Value"=>$Symbol,
11763                            "New_Value"=>$NewSym  );
11764                    }
11765                    elsif(not $CompleteSignature{1}{$Symbol}{"Volatile"}
11766                    and $CompleteSignature{2}{$NewSym}{"Volatile"})
11767                    { # non-"volatile" to "volatile"
11768                        %{$CompatProblems{$Level}{$Symbol}{"Method_Became_Volatile"}{$tr_name{$Symbol}}}=(
11769                            "Target"=>$tr_name{$Symbol},
11770                            "New_Signature"=>get_Signature($NewSym, 2),
11771                            "Old_Value"=>$Symbol,
11772                            "New_Value"=>$NewSym  );
11773                    }
11774                    if(get_symbol_suffix($Symbol, 0) ne get_symbol_suffix($NewSym, 0))
11775                    { # params list
11776                        %{$CompatProblems{$Level}{$Symbol}{"Symbol_Changed_Parameters"}{$tr_name{$Symbol}}}=(
11777                            "Target"=>$tr_name{$Symbol},
11778                            "New_Signature"=>get_Signature($NewSym, 2),
11779                            "Old_Value"=>$Symbol,
11780                            "New_Value"=>$NewSym  );
11781                    }
11782                }
11783            }
11784        }
11785    }
11786    foreach my $Symbol (sort keys(%{$CompleteSignature{1}}))
11787    { # checking symbols
11788        my ($SN, $SS, $SV) = separate_symbol($Symbol);
11789        if($Level eq "Source")
11790        { # remove symbol version
11791            $Symbol=$SN;
11792        }
11793        else
11794        { # Binary
11795            if(not $SV)
11796            { # symbol without version
11797                if(my $VSym = $SymVer{1}{$Symbol})
11798                { # the symbol is linked with versioned symbol
11799                    if($CompleteSignature{2}{$VSym}{"MnglName"})
11800                    { # show report for symbol@ver only
11801                        next;
11802                    }
11803                    elsif(not link_symbol($VSym, 2, "-Deps"))
11804                    { # changed version: sym@v1 to sym@v2
11805                      # do NOT show report for symbol
11806                        next;
11807                    }
11808                }
11809            }
11810        }
11811        my $PSymbol = $Symbol;
11812        if($Level eq "Source"
11813        and my $S = $SourceReplacement{$Symbol})
11814        { # take a source-compatible replacement function
11815            $PSymbol = $S;
11816        }
11817        if($CompleteSignature{1}{$Symbol}{"Private"})
11818        { # private symbols
11819            next;
11820        }
11821        if(not defined $CompleteSignature{1}{$Symbol}
11822        or not defined $CompleteSignature{2}{$PSymbol})
11823        { # no info
11824            next;
11825        }
11826        if(not $CompleteSignature{1}{$Symbol}{"MnglName"}
11827        or not $CompleteSignature{2}{$PSymbol}{"MnglName"})
11828        { # no mangled name
11829            next;
11830        }
11831        if(not $CompleteSignature{1}{$Symbol}{"Header"}
11832        or not $CompleteSignature{2}{$PSymbol}{"Header"})
11833        { # without a header
11834            next;
11835        }
11836        if(checkDump(1, "2.13") and checkDump(2, "2.13"))
11837        {
11838            if($CompleteSignature{1}{$Symbol}{"Data"}
11839            and $CompleteSignature{2}{$PSymbol}{"Data"})
11840            {
11841                my $Value1 = $CompleteSignature{1}{$Symbol}{"Value"};
11842                my $Value2 = $CompleteSignature{2}{$PSymbol}{"Value"};
11843                if(defined $Value1)
11844                {
11845                    $Value1 = showVal($Value1, $CompleteSignature{1}{$Symbol}{"Return"}, 1);
11846                    if(defined $Value2)
11847                    {
11848                        $Value2 = showVal($Value2, $CompleteSignature{2}{$PSymbol}{"Return"}, 2);
11849                        if($Value1 ne $Value2)
11850                        {
11851                            %{$CompatProblems{$Level}{$Symbol}{"Global_Data_Value_Changed"}{""}}=(
11852                                "Old_Value"=>$Value1,
11853                                "New_Value"=>$Value2,
11854                                "Target"=>get_Signature($Symbol, 1)  );
11855                        }
11856                    }
11857                }
11858            }
11859        }
11860
11861        if(not $CompleteSignature{1}{$Symbol}{"PureVirt"}
11862        and $CompleteSignature{2}{$PSymbol}{"PureVirt"})
11863        { # became pure
11864            next;
11865        }
11866        if($CompleteSignature{1}{$Symbol}{"PureVirt"}
11867        and not $CompleteSignature{2}{$PSymbol}{"PureVirt"})
11868        { # became non-pure
11869            next;
11870        }
11871
11872        if(not symbolFilter($Symbol, 1, "Affected + InlineVirt", $Level))
11873        { # exported, target, inline virtual and pure virtual
11874            next;
11875        }
11876        if(not symbolFilter($PSymbol, 2, "Affected + InlineVirt", $Level))
11877        { # exported, target, inline virtual and pure virtual
11878            next;
11879        }
11880
11881        if($CompleteSignature{2}{$PSymbol}{"Private"})
11882        {
11883            %{$CompatProblems{$Level}{$Symbol}{getSymKind($Symbol, 1)."_Became_Private"}{""}}=(
11884                "Target"=>get_Signature_M($PSymbol, 2)  );
11885        }
11886        elsif(not $CompleteSignature{1}{$Symbol}{"Protected"}
11887        and $CompleteSignature{2}{$PSymbol}{"Protected"})
11888        {
11889            %{$CompatProblems{$Level}{$Symbol}{getSymKind($Symbol, 1)."_Became_Protected"}{""}}=(
11890                "Target"=>get_Signature_M($PSymbol, 2)  );
11891        }
11892        elsif($CompleteSignature{1}{$Symbol}{"Protected"}
11893        and not $CompleteSignature{2}{$PSymbol}{"Protected"})
11894        {
11895            %{$CompatProblems{$Level}{$Symbol}{getSymKind($Symbol, 1)."_Became_Public"}{""}}=(
11896                "Target"=>get_Signature_M($PSymbol, 2)  );
11897        }
11898
11899        # checking virtual table
11900        mergeVirtualTables($Symbol, $Level);
11901
11902        if($COMPILE_ERRORS)
11903        { # if some errors occurred at the compiling stage
11904          # then some false positives can be skipped here
11905            if(not $CompleteSignature{1}{$Symbol}{"Data"} and $CompleteSignature{2}{$PSymbol}{"Data"}
11906            and not $GlobalDataObject{2}{$Symbol})
11907            { # missed information about parameters in newer version
11908                next;
11909            }
11910            if($CompleteSignature{1}{$Symbol}{"Data"} and not $GlobalDataObject{1}{$Symbol}
11911            and not $CompleteSignature{2}{$PSymbol}{"Data"})
11912            {# missed information about parameters in older version
11913                next;
11914            }
11915        }
11916        my ($MnglName, $VersionSpec, $SymbolVersion) = separate_symbol($Symbol);
11917        # checking attributes
11918        if($CompleteSignature{2}{$PSymbol}{"Static"}
11919        and not $CompleteSignature{1}{$Symbol}{"Static"} and $Symbol=~/\A(_Z|\?)/) {
11920            %{$CompatProblems{$Level}{$Symbol}{"Method_Became_Static"}{""}}=(
11921                "Target"=>get_Signature($Symbol, 1)
11922            );
11923        }
11924        elsif(not $CompleteSignature{2}{$PSymbol}{"Static"}
11925        and $CompleteSignature{1}{$Symbol}{"Static"} and $Symbol=~/\A(_Z|\?)/) {
11926            %{$CompatProblems{$Level}{$Symbol}{"Method_Became_NonStatic"}{""}}=(
11927                "Target"=>get_Signature($Symbol, 1)
11928            );
11929        }
11930        if(($CompleteSignature{1}{$Symbol}{"Virt"} and $CompleteSignature{2}{$PSymbol}{"Virt"})
11931        or ($CompleteSignature{1}{$Symbol}{"PureVirt"} and $CompleteSignature{2}{$PSymbol}{"PureVirt"}))
11932        { # relative position of virtual and pure virtual methods
11933            if($Level eq "Binary")
11934            {
11935                if(defined $CompleteSignature{1}{$Symbol}{"RelPos"} and defined $CompleteSignature{2}{$PSymbol}{"RelPos"}
11936                and $CompleteSignature{1}{$Symbol}{"RelPos"}!=$CompleteSignature{2}{$PSymbol}{"RelPos"})
11937                { # top-level virtual methods only
11938                    my $Class_Id = $CompleteSignature{1}{$Symbol}{"Class"};
11939                    my $Class_Name = $TypeInfo{1}{$Class_Id}{"Name"};
11940                    if(defined $VirtualTable{1}{$Class_Name} and defined $VirtualTable{2}{$Class_Name}
11941                    and $VirtualTable{1}{$Class_Name}{$Symbol}!=$VirtualTable{2}{$Class_Name}{$Symbol})
11942                    { # check the absolute position of virtual method (including added and removed methods)
11943                        my %Class_Type = get_Type($Class_Id, 1);
11944                        my $ProblemType = "Virtual_Method_Position";
11945                        if($CompleteSignature{1}{$Symbol}{"PureVirt"}) {
11946                            $ProblemType = "Pure_Virtual_Method_Position";
11947                        }
11948                        if(isUsedClass($Class_Id, 1, $Level))
11949                        {
11950                            my @Affected = ($Symbol, keys(%{$OverriddenMethods{1}{$Symbol}}));
11951                            foreach my $AffectedInterface (@Affected)
11952                            {
11953                                %{$CompatProblems{$Level}{$AffectedInterface}{$ProblemType}{$tr_name{$MnglName}}}=(
11954                                    "Type_Name"=>$Class_Type{"Name"},
11955                                    "Type_Type"=>"Class",
11956                                    "Old_Value"=>$CompleteSignature{1}{$Symbol}{"RelPos"},
11957                                    "New_Value"=>$CompleteSignature{2}{$PSymbol}{"RelPos"},
11958                                    "Target"=>get_Signature($Symbol, 1)  );
11959                            }
11960                            $VTableChanged_M{$Class_Type{"Name"}} = 1;
11961                        }
11962                    }
11963                }
11964            }
11965        }
11966        if($CompleteSignature{1}{$Symbol}{"PureVirt"}
11967        or $CompleteSignature{2}{$PSymbol}{"PureVirt"})
11968        { # do NOT check type changes in pure virtuals
11969            next;
11970        }
11971        $CheckedSymbols{$Level}{$Symbol}=1;
11972        if($Symbol=~/\A(_Z|\?)/
11973        or keys(%{$CompleteSignature{1}{$Symbol}{"Param"}})==keys(%{$CompleteSignature{2}{$PSymbol}{"Param"}}))
11974        { # C/C++: changes in parameters
11975            foreach my $ParamPos (sort {int($a) <=> int($b)} keys(%{$CompleteSignature{1}{$Symbol}{"Param"}}))
11976            { # checking parameters
11977                mergeParameters($Symbol, $PSymbol, $ParamPos, $ParamPos, $Level);
11978            }
11979        }
11980        else
11981        { # C: added/removed parameters
11982            foreach my $ParamPos (sort {int($a) <=> int($b)} keys(%{$CompleteSignature{2}{$PSymbol}{"Param"}}))
11983            { # checking added parameters
11984                my $PType2_Id = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos}{"type"};
11985                my $PType2_Name = $TypeInfo{2}{$PType2_Id}{"Name"};
11986                last if($PType2_Name eq "...");
11987                my $PName = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos}{"name"};
11988                my $PName_Old = (defined $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos})?$CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos}{"name"}:"";
11989                my $ParamPos_Prev = "-1";
11990                if($PName=~/\Ap\d+\Z/i)
11991                { # added unnamed parameter ( pN )
11992                    my @Positions1 = find_ParamPair_Pos_byTypeAndPos($PType2_Name, $ParamPos, "backward", $Symbol, 1);
11993                    my @Positions2 = find_ParamPair_Pos_byTypeAndPos($PType2_Name, $ParamPos, "backward", $Symbol, 2);
11994                    if($#Positions1==-1 or $#Positions2>$#Positions1) {
11995                        $ParamPos_Prev = "lost";
11996                    }
11997                }
11998                else {
11999                    $ParamPos_Prev = find_ParamPair_Pos_byName($PName, $Symbol, 1);
12000                }
12001                if($ParamPos_Prev eq "lost")
12002                {
12003                    if($ParamPos>keys(%{$CompleteSignature{1}{$Symbol}{"Param"}})-1)
12004                    {
12005                        my $ProblemType = "Added_Parameter";
12006                        if($PName=~/\Ap\d+\Z/) {
12007                            $ProblemType = "Added_Unnamed_Parameter";
12008                        }
12009                        %{$CompatProblems{$Level}{$Symbol}{$ProblemType}{showPos($ParamPos)." Parameter"}}=(
12010                            "Target"=>$PName,
12011                            "Param_Pos"=>$ParamPos,
12012                            "Param_Type"=>$PType2_Name,
12013                            "New_Signature"=>get_Signature($Symbol, 2)  );
12014                    }
12015                    else
12016                    {
12017                        my %ParamType_Pure = get_PureType($PType2_Id, 2);
12018                        my $PairType_Id = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos}{"type"};
12019                        my %PairType_Pure = get_PureType($PairType_Id, 1);
12020                        if(($ParamType_Pure{"Name"} eq $PairType_Pure{"Name"} or $PType2_Name eq $TypeInfo{1}{$PairType_Id}{"Name"})
12021                        and find_ParamPair_Pos_byName($PName_Old, $Symbol, 2) eq "lost")
12022                        {
12023                            if($PName_Old!~/\Ap\d+\Z/ and $PName!~/\Ap\d+\Z/)
12024                            {
12025                                %{$CompatProblems{$Level}{$Symbol}{"Renamed_Parameter"}{showPos($ParamPos)." Parameter"}}=(
12026                                    "Target"=>$PName_Old,
12027                                    "Param_Pos"=>$ParamPos,
12028                                    "Param_Type"=>$PType2_Name,
12029                                    "Old_Value"=>$PName_Old,
12030                                    "New_Value"=>$PName,
12031                                    "New_Signature"=>get_Signature($Symbol, 2)  );
12032                            }
12033                        }
12034                        else
12035                        {
12036                            my $ProblemType = "Added_Middle_Parameter";
12037                            if($PName=~/\Ap\d+\Z/) {
12038                                $ProblemType = "Added_Middle_Unnamed_Parameter";
12039                            }
12040                            %{$CompatProblems{$Level}{$Symbol}{$ProblemType}{showPos($ParamPos)." Parameter"}}=(
12041                                "Target"=>$PName,
12042                                "Param_Pos"=>$ParamPos,
12043                                "Param_Type"=>$PType2_Name,
12044                                "New_Signature"=>get_Signature($Symbol, 2)  );
12045                        }
12046                    }
12047                }
12048            }
12049            foreach my $ParamPos (sort {int($a) <=> int($b)} keys(%{$CompleteSignature{1}{$Symbol}{"Param"}}))
12050            { # check relevant parameters
12051                my $PType1_Id = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos}{"type"};
12052                my $ParamName1 = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos}{"name"};
12053                # FIXME: find relevant parameter by name
12054                if(defined $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos})
12055                {
12056                    my $PType2_Id = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos}{"type"};
12057                    my $ParamName2 = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos}{"name"};
12058                    if($TypeInfo{1}{$PType1_Id}{"Name"} eq $TypeInfo{2}{$PType2_Id}{"Name"}
12059                    or ($ParamName1!~/\Ap\d+\Z/i and $ParamName1 eq $ParamName2)) {
12060                        mergeParameters($Symbol, $PSymbol, $ParamPos, $ParamPos, $Level);
12061                    }
12062                }
12063            }
12064            foreach my $ParamPos (sort {int($a) <=> int($b)} keys(%{$CompleteSignature{1}{$Symbol}{"Param"}}))
12065            { # checking removed parameters
12066                my $PType1_Id = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos}{"type"};
12067                my $PType1_Name = $TypeInfo{1}{$PType1_Id}{"Name"};
12068                last if($PType1_Name eq "...");
12069                my $Parameter_Name = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos}{"name"};
12070                my $Parameter_NewName = (defined $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos})?$CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos}{"name"}:"";
12071                my $ParamPos_New = "-1";
12072                if($Parameter_Name=~/\Ap\d+\Z/i)
12073                { # removed unnamed parameter ( pN )
12074                    my @Positions1 = find_ParamPair_Pos_byTypeAndPos($PType1_Name, $ParamPos, "forward", $Symbol, 1);
12075                    my @Positions2 = find_ParamPair_Pos_byTypeAndPos($PType1_Name, $ParamPos, "forward", $Symbol, 2);
12076                    if($#Positions2==-1 or $#Positions2<$#Positions1) {
12077                        $ParamPos_New = "lost";
12078                    }
12079                }
12080                else {
12081                    $ParamPos_New = find_ParamPair_Pos_byName($Parameter_Name, $Symbol, 2);
12082                }
12083                if($ParamPos_New eq "lost")
12084                {
12085                    if($ParamPos>keys(%{$CompleteSignature{2}{$PSymbol}{"Param"}})-1)
12086                    {
12087                        my $ProblemType = "Removed_Parameter";
12088                        if($Parameter_Name=~/\Ap\d+\Z/) {
12089                            $ProblemType = "Removed_Unnamed_Parameter";
12090                        }
12091                        %{$CompatProblems{$Level}{$Symbol}{$ProblemType}{showPos($ParamPos)." Parameter"}}=(
12092                            "Target"=>$Parameter_Name,
12093                            "Param_Pos"=>$ParamPos,
12094                            "Param_Type"=>$PType1_Name,
12095                            "New_Signature"=>get_Signature($Symbol, 2)  );
12096                    }
12097                    elsif($ParamPos<keys(%{$CompleteSignature{1}{$Symbol}{"Param"}})-1)
12098                    {
12099                        my %ParamType_Pure = get_PureType($PType1_Id, 1);
12100                        my $PairType_Id = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos}{"type"};
12101                        my %PairType_Pure = get_PureType($PairType_Id, 2);
12102                        if(($ParamType_Pure{"Name"} eq $PairType_Pure{"Name"} or $PType1_Name eq $TypeInfo{2}{$PairType_Id}{"Name"})
12103                        and find_ParamPair_Pos_byName($Parameter_NewName, $Symbol, 1) eq "lost")
12104                        {
12105                            if($Parameter_NewName!~/\Ap\d+\Z/ and $Parameter_Name!~/\Ap\d+\Z/)
12106                            {
12107                                %{$CompatProblems{$Level}{$Symbol}{"Renamed_Parameter"}{showPos($ParamPos)." Parameter"}}=(
12108                                    "Target"=>$Parameter_Name,
12109                                    "Param_Pos"=>$ParamPos,
12110                                    "Param_Type"=>$PType1_Name,
12111                                    "Old_Value"=>$Parameter_Name,
12112                                    "New_Value"=>$Parameter_NewName,
12113                                    "New_Signature"=>get_Signature($Symbol, 2)  );
12114                            }
12115                        }
12116                        else
12117                        {
12118                            my $ProblemType = "Removed_Middle_Parameter";
12119                            if($Parameter_Name=~/\Ap\d+\Z/) {
12120                                $ProblemType = "Removed_Middle_Unnamed_Parameter";
12121                            }
12122                            %{$CompatProblems{$Level}{$Symbol}{$ProblemType}{showPos($ParamPos)." Parameter"}}=(
12123                                "Target"=>$Parameter_Name,
12124                                "Param_Pos"=>$ParamPos,
12125                                "Param_Type"=>$PType1_Name,
12126                                "New_Signature"=>get_Signature($Symbol, 2)  );
12127                        }
12128                    }
12129                }
12130            }
12131        }
12132        # checking return type
12133        my $ReturnType1_Id = $CompleteSignature{1}{$Symbol}{"Return"};
12134        my $ReturnType2_Id = $CompleteSignature{2}{$PSymbol}{"Return"};
12135        %SubProblems = detectTypeChange($ReturnType1_Id, $ReturnType2_Id, "Return", $Level);
12136        foreach my $SubProblemType (keys(%SubProblems))
12137        {
12138            my $New_Value = $SubProblems{$SubProblemType}{"New_Value"};
12139            my $Old_Value = $SubProblems{$SubProblemType}{"Old_Value"};
12140            my $NewProblemType = $SubProblemType;
12141            if($Level eq "Binary" and $SubProblemType eq "Return_Type_Became_Void"
12142            and keys(%{$CompleteSignature{1}{$Symbol}{"Param"}}))
12143            { # parameters stack has been affected
12144                $NewProblemType = "Return_Type_Became_Void_And_Stack_Layout";
12145            }
12146            elsif($Level eq "Binary"
12147            and $SubProblemType eq "Return_Type_From_Void")
12148            { # parameters stack has been affected
12149                if(keys(%{$CompleteSignature{1}{$Symbol}{"Param"}})) {
12150                    $NewProblemType = "Return_Type_From_Void_And_Stack_Layout";
12151                }
12152                else
12153                { # safe
12154                    delete($SubProblems{$SubProblemType});
12155                    next;
12156                }
12157            }
12158            elsif($SubProblemType eq "Return_Type_And_Size"
12159            and $CompleteSignature{1}{$Symbol}{"Data"}) {
12160                $NewProblemType = "Global_Data_Type_And_Size";
12161            }
12162            elsif($SubProblemType eq "Return_Type")
12163            {
12164                if($CompleteSignature{1}{$Symbol}{"Data"})
12165                {
12166                    if(removedQual($Old_Value, $New_Value, "const"))
12167                    { # const -> non-const global data
12168                        $NewProblemType = "Global_Data_Became_Non_Const";
12169                    }
12170                    elsif(addedQual($Old_Value, $New_Value, "const"))
12171                    { # non-const -> const global data
12172                        $NewProblemType = "Global_Data_Became_Const";
12173                    }
12174                    else {
12175                        $NewProblemType = "Global_Data_Type";
12176                    }
12177                }
12178                else
12179                {
12180                    if(addedQual($Old_Value, $New_Value, "const")) {
12181                        $NewProblemType = "Return_Type_Became_Const";
12182                    }
12183                }
12184            }
12185            elsif($SubProblemType eq "Return_Type_Format")
12186            {
12187                if($CompleteSignature{1}{$Symbol}{"Data"}) {
12188                    $NewProblemType = "Global_Data_Type_Format";
12189                }
12190            }
12191            @{$CompatProblems{$Level}{$Symbol}{$NewProblemType}{"retval"}}{keys(%{$SubProblems{$SubProblemType}})} = values %{$SubProblems{$SubProblemType}};
12192        }
12193        if($ReturnType1_Id and $ReturnType2_Id)
12194        {
12195            @RecurTypes = ();
12196            %SubProblems = mergeTypes($ReturnType1_Id, $ReturnType2_Id, $Level);
12197            foreach my $SubProblemType (keys(%SubProblems))
12198            { # add "Global_Data_Size" problem
12199                my $New_Value = $SubProblems{$SubProblemType}{"New_Value"};
12200                my $Old_Value = $SubProblems{$SubProblemType}{"Old_Value"};
12201                if($SubProblemType eq "DataType_Size"
12202                and $CompleteSignature{1}{$Symbol}{"Data"}
12203                and get_PLevel($ReturnType1_Id, 1)==0)
12204                { # add a new problem
12205                    %{$SubProblems{"Global_Data_Size"}} = %{$SubProblems{$SubProblemType}};
12206                }
12207            }
12208            foreach my $SubProblemType (keys(%SubProblems))
12209            {
12210                foreach my $SubLocation (keys(%{$SubProblems{$SubProblemType}}))
12211                {
12212                    my $NewLocation = ($SubLocation)?"retval->".$SubLocation:"retval";
12213                    %{$CompatProblems{$Level}{$Symbol}{$SubProblemType}{$NewLocation}}=(
12214                        "Return_Type_Name"=>$TypeInfo{1}{$ReturnType1_Id}{"Name"} );
12215                    @{$CompatProblems{$Level}{$Symbol}{$SubProblemType}{$NewLocation}}{keys(%{$SubProblems{$SubProblemType}{$SubLocation}})} = values %{$SubProblems{$SubProblemType}{$SubLocation}};
12216                    if($SubLocation!~/\-\>/) {
12217                        $CompatProblems{$Level}{$Symbol}{$SubProblemType}{$NewLocation}{"Start_Type_Name"} = $TypeInfo{1}{$ReturnType1_Id}{"Name"};
12218                    }
12219                }
12220            }
12221        }
12222
12223        # checking object type
12224        my $ObjTId1 = $CompleteSignature{1}{$Symbol}{"Class"};
12225        my $ObjTId2 = $CompleteSignature{2}{$PSymbol}{"Class"};
12226        if($ObjTId1 and $ObjTId2
12227        and not $CompleteSignature{1}{$Symbol}{"Static"})
12228        {
12229            my $ThisPtr1_Id = getTypeIdByName($TypeInfo{1}{$ObjTId1}{"Name"}."*const", 1);
12230            my $ThisPtr2_Id = getTypeIdByName($TypeInfo{2}{$ObjTId2}{"Name"}."*const", 2);
12231            if($ThisPtr1_Id and $ThisPtr2_Id)
12232            {
12233                @RecurTypes = ();
12234                %SubProblems = mergeTypes($ThisPtr1_Id, $ThisPtr2_Id, $Level);
12235                foreach my $SubProblemType (keys(%SubProblems))
12236                {
12237                    foreach my $SubLocation (keys(%{$SubProblems{$SubProblemType}}))
12238                    {
12239                        my $NewLocation = ($SubLocation)?"this->".$SubLocation:"this";
12240                        %{$CompatProblems{$Level}{$Symbol}{$SubProblemType}{$NewLocation}}=(
12241                            "Object_Type_Name"=>$TypeInfo{1}{$ObjTId1}{"Name"} );
12242                        @{$CompatProblems{$Level}{$Symbol}{$SubProblemType}{$NewLocation}}{keys(%{$SubProblems{$SubProblemType}{$SubLocation}})} = values %{$SubProblems{$SubProblemType}{$SubLocation}};
12243                        if($SubLocation!~/\-\>/) {
12244                            $CompatProblems{$Level}{$Symbol}{$SubProblemType}{$NewLocation}{"Start_Type_Name"} = $TypeInfo{1}{$ObjTId1}{"Name"};
12245                        }
12246                    }
12247                }
12248            }
12249        }
12250    }
12251    if($Level eq "Binary") {
12252        mergeVTables($Level);
12253    }
12254    foreach my $Symbol (keys(%{$CompatProblems{$Level}})) {
12255        $CheckedSymbols{$Level}{$Symbol} = 1;
12256    }
12257}
12258
12259sub rmQuals($$)
12260{
12261    my ($Value, $Qual) = @_;
12262    if(not $Qual) {
12263        return $Value;
12264    }
12265    if($Qual eq "all")
12266    { # all quals
12267        $Qual = "const|volatile|restrict";
12268    }
12269    while($Value=~s/\b$Qual\b//) {
12270        $Value = formatName($Value);
12271    }
12272    return $Value;
12273}
12274
12275sub cmpBTypes($$$$)
12276{
12277    my ($T1, $T2, $V1, $V2) = @_;
12278    $T1 = uncover_typedefs($T1, $V1);
12279    $T2 = uncover_typedefs($T2, $V2);
12280    return (rmQuals($T1, "all") eq rmQuals($T2, "all"));
12281}
12282
12283sub addedQual($$$)
12284{
12285    my ($Old_Value, $New_Value, $Qual) = @_;
12286    return removedQual_($New_Value, $Old_Value, 2, 1, $Qual);
12287}
12288
12289sub removedQual($$$)
12290{
12291    my ($Old_Value, $New_Value, $Qual) = @_;
12292    return removedQual_($Old_Value, $New_Value, 1, 2, $Qual);
12293}
12294
12295sub removedQual_($$$$$)
12296{
12297    my ($Old_Value, $New_Value, $V1, $V2, $Qual) = @_;
12298    $Old_Value = uncover_typedefs($Old_Value, $V1);
12299    $New_Value = uncover_typedefs($New_Value, $V2);
12300    if($Old_Value eq $New_Value)
12301    { # equal types
12302        return 0;
12303    }
12304    if($Old_Value!~/\b$Qual\b/)
12305    { # without a qual
12306        return 0;
12307    }
12308    elsif($New_Value!~/\b$Qual\b/)
12309    { # became non-qual
12310        return 1;
12311    }
12312    else
12313    {
12314        my @BQ1 = getQualModel($Old_Value, $Qual);
12315        my @BQ2 = getQualModel($New_Value, $Qual);
12316        foreach (0 .. $#BQ1)
12317        { # removed qual
12318            if($BQ1[$_]==1
12319            and $BQ2[$_]!=1)
12320            {
12321                return 2;
12322            }
12323        }
12324    }
12325    return 0;
12326}
12327
12328sub getQualModel($$)
12329{
12330    my ($Value, $Qual) = @_;
12331    if(not $Qual) {
12332        return $Value;
12333    }
12334
12335    # cleaning
12336    while($Value=~/(\w+)/ and $1 ne $Qual) {
12337        $Value=~s/\b$1\b//g;
12338    }
12339    $Value=~s/[^\*\&\w]+//g;
12340
12341    # modeling
12342    # int*const*const == 011
12343    # int**const == 001
12344    my @Model = ();
12345    my @Elems = split(/[\*\&]/, $Value);
12346    if(not @Elems) {
12347        return (0);
12348    }
12349    foreach (@Elems)
12350    {
12351        if($_ eq $Qual) {
12352            push(@Model, 1);
12353        }
12354        else {
12355            push(@Model, 0);
12356        }
12357    }
12358
12359    return @Model;
12360}
12361
12362sub showVal($$$)
12363{
12364    my ($Value, $TypeId, $LibVersion) = @_;
12365    my %PureType = get_PureType($TypeId, $LibVersion);
12366    my $TName = uncover_typedefs($PureType{"Name"}, $LibVersion);
12367    if($TName=~/\A(char(| const)\*|std::(string|basic_string<char>)(|&))\Z/)
12368    { # strings
12369        return "\"$Value\"";
12370    }
12371    elsif($TName=~/\Achar(| const)\Z/)
12372    { # characters
12373        return "\'$Value\'";
12374    }
12375    return $Value;
12376}
12377
12378sub mergeParameters($$$$$)
12379{
12380    my ($Symbol, $PSymbol, $ParamPos1, $ParamPos2, $Level) = @_;
12381    if(not $Symbol) {
12382        return;
12383    }
12384    my $PType1_Id = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos1}{"type"};
12385    my $PName1 = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos1}{"name"};
12386    my $PType2_Id = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos2}{"type"};
12387    my $PName2 = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos2}{"name"};
12388    if(not $PType1_Id
12389    or not $PType2_Id) {
12390        return;
12391    }
12392    my %Type1 = get_Type($PType1_Id, 1);
12393    my %Type2 = get_Type($PType2_Id, 2);
12394    my %BaseType1 = get_BaseType($PType1_Id, 1);
12395    my %BaseType2 = get_BaseType($PType2_Id, 2);
12396    my $Parameter_Location = ($PName1)?$PName1:showPos($ParamPos1)." Parameter";
12397    if($Level eq "Binary")
12398    {
12399        if(checkDump(1, "2.6.1") and checkDump(2, "2.6.1"))
12400        { # "reg" attribute added in ACC 1.95.1 (dump 2.6.1 format)
12401            if($CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos1}{"reg"}
12402            and not $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos2}{"reg"})
12403            {
12404                %{$CompatProblems{$Level}{$Symbol}{"Parameter_Became_Non_Register"}{$Parameter_Location}}=(
12405                    "Target"=>$PName1,
12406                    "Param_Pos"=>$ParamPos1  );
12407            }
12408            elsif(not $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos1}{"reg"}
12409            and $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos2}{"reg"})
12410            {
12411                %{$CompatProblems{$Level}{$Symbol}{"Parameter_Became_Register"}{$Parameter_Location}}=(
12412                    "Target"=>$PName1,
12413                    "Param_Pos"=>$ParamPos1  );
12414            }
12415        }
12416    }
12417    if(checkDump(1, "2.0") and checkDump(2, "2.0"))
12418    { # "default" attribute added in ACC 1.22 (dump 2.0 format)
12419        my $Value_Old = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos1}{"default"};
12420        my $Value_New = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos2}{"default"};
12421        if(not checkDump(1, "2.13")
12422        and checkDump(2, "2.13"))
12423        { # support for old ABI dumps
12424            if(defined $Value_Old and defined $Value_New)
12425            {
12426                if($Type1{"Name"} eq "bool"
12427                and $Value_Old eq "false" and $Value_New eq "0")
12428                { # int class::method ( bool p = 0 );
12429                  # old ABI dumps: "false"
12430                  # new ABI dumps: "0"
12431                    $Value_Old = "0";
12432                }
12433            }
12434        }
12435        if(defined $Value_Old)
12436        {
12437            $Value_Old = showVal($Value_Old, $PType1_Id, 1);
12438            if(defined $Value_New)
12439            {
12440                $Value_New = showVal($Value_New, $PType2_Id, 2);
12441                if($Value_Old ne $Value_New)
12442                { # FIXME: how to distinguish "0" and 0 (NULL)
12443                    %{$CompatProblems{$Level}{$Symbol}{"Parameter_Default_Value_Changed"}{$Parameter_Location}}=(
12444                        "Target"=>$PName1,
12445                        "Param_Pos"=>$ParamPos1,
12446                        "Old_Value"=>$Value_Old,
12447                        "New_Value"=>$Value_New  );
12448                }
12449            }
12450            else
12451            {
12452                %{$CompatProblems{$Level}{$Symbol}{"Parameter_Default_Value_Removed"}{$Parameter_Location}}=(
12453                    "Target"=>$PName1,
12454                    "Param_Pos"=>$ParamPos1,
12455                    "Old_Value"=>$Value_Old  );
12456            }
12457        }
12458        elsif(defined $Value_New)
12459        {
12460            $Value_New = showVal($Value_New, $PType2_Id, 2);
12461            %{$CompatProblems{$Level}{$Symbol}{"Parameter_Default_Value_Added"}{$Parameter_Location}}=(
12462                "Target"=>$PName1,
12463                "Param_Pos"=>$ParamPos1,
12464                "New_Value"=>$Value_New  );
12465        }
12466    }
12467    if($PName1 and $PName2 and $PName1 ne $PName2
12468    and $PType1_Id!=-1 and $PType2_Id!=-1
12469    and $PName1!~/\Ap\d+\Z/ and $PName2!~/\Ap\d+\Z/)
12470    { # except unnamed "..." value list (Id=-1)
12471        %{$CompatProblems{$Level}{$Symbol}{"Renamed_Parameter"}{showPos($ParamPos1)." Parameter"}}=(
12472            "Target"=>$PName1,
12473            "Param_Pos"=>$ParamPos1,
12474            "Param_Type"=>$TypeInfo{1}{$PType1_Id}{"Name"},
12475            "Old_Value"=>$PName1,
12476            "New_Value"=>$PName2,
12477            "New_Signature"=>get_Signature($Symbol, 2)  );
12478    }
12479    # checking type change (replace)
12480    my %SubProblems = detectTypeChange($PType1_Id, $PType2_Id, "Parameter", $Level);
12481    foreach my $SubProblemType (keys(%SubProblems))
12482    { # add new problems, remove false alarms
12483        my $New_Value = $SubProblems{$SubProblemType}{"New_Value"};
12484        my $Old_Value = $SubProblems{$SubProblemType}{"Old_Value"};
12485        if($SubProblemType eq "Parameter_Type")
12486        {
12487            if(checkDump(1, "2.6") and checkDump(2, "2.6"))
12488            {
12489                if(my $RA = addedQual($Old_Value, $New_Value, "restrict"))
12490                {
12491                    %{$SubProblems{"Parameter_Became_Restrict"}} = %{$SubProblems{$SubProblemType}};
12492                    if($Level eq "Source"
12493                    and cmpBTypes($Old_Value, $New_Value, 1, 2)) {
12494                        delete($SubProblems{$SubProblemType});
12495                    }
12496                }
12497                elsif(my $RR = removedQual($Old_Value, $New_Value, "restrict"))
12498                {
12499                    %{$SubProblems{"Parameter_Became_NonRestrict"}} = %{$SubProblems{$SubProblemType}};
12500                    if($Level eq "Source"
12501                    and cmpBTypes($Old_Value, $New_Value, 1, 2)) {
12502                        delete($SubProblems{$SubProblemType});
12503                    }
12504                }
12505            }
12506            if($Type2{"Type"} eq "Const" and $BaseType2{"Name"} eq $Type1{"Name"}
12507            and $Type1{"Type"}=~/Intrinsic|Class|Struct|Union|Enum/)
12508            { # int to "int const"
12509                delete($SubProblems{$SubProblemType});
12510            }
12511            if($Type1{"Type"} eq "Const" and $BaseType1{"Name"} eq $Type2{"Name"}
12512            and $Type2{"Type"}=~/Intrinsic|Class|Struct|Union|Enum/)
12513            { # "int const" to int
12514                delete($SubProblems{$SubProblemType});
12515            }
12516        }
12517    }
12518    foreach my $SubProblemType (keys(%SubProblems))
12519    { # modify/register problems
12520        my $New_Value = $SubProblems{$SubProblemType}{"New_Value"};
12521        my $Old_Value = $SubProblems{$SubProblemType}{"Old_Value"};
12522        my $NewProblemType = $SubProblemType;
12523        if($Old_Value eq "..." and $New_Value ne "...")
12524        { # change from "..." to "int"
12525            if($ParamPos1==0)
12526            { # ISO C requires a named argument before "..."
12527                next;
12528            }
12529            $NewProblemType = "Parameter_Became_NonVaList";
12530        }
12531        elsif($New_Value eq "..." and $Old_Value ne "...")
12532        { # change from "int" to "..."
12533            if($ParamPos2==0)
12534            { # ISO C requires a named argument before "..."
12535                next;
12536            }
12537            $NewProblemType = "Parameter_Became_VaList";
12538        }
12539        elsif($SubProblemType eq "Parameter_Type"
12540        and removedQual($Old_Value, $New_Value, "const"))
12541        { # parameter: "const" to non-"const"
12542            $NewProblemType = "Parameter_Became_Non_Const";
12543        }
12544        elsif($Level eq "Binary" and ($SubProblemType eq "Parameter_Type_And_Size"
12545        or $SubProblemType eq "Parameter_Type"))
12546        {
12547            my ($Arch1, $Arch2) = (getArch(1), getArch(2));
12548            if($Arch1 eq "unknown" or $Arch2 eq "unknown")
12549            { # if one of the architectures is unknown
12550                # then set other arhitecture to unknown too
12551                ($Arch1, $Arch2) = ("unknown", "unknown");
12552            }
12553            my ($Method1, $Passed1, $SizeOnStack1, $RegName1) = callingConvention($Symbol, $ParamPos1, 1, $Arch1);
12554            my ($Method2, $Passed2, $SizeOnStack2, $RegName2) = callingConvention($Symbol, $ParamPos2, 2, $Arch2);
12555            if($Method1 eq $Method2)
12556            {
12557                if($Method1 eq "stack" and $SizeOnStack1 ne $SizeOnStack2) {
12558                    $NewProblemType = "Parameter_Type_And_Stack";
12559                }
12560                elsif($Method1 eq "register" and $RegName1 ne $RegName2) {
12561                    $NewProblemType = "Parameter_Type_And_Register";
12562                }
12563            }
12564            else
12565            {
12566                if($Method1 eq "stack") {
12567                    $NewProblemType = "Parameter_Type_And_Pass_Through_Register";
12568                }
12569                elsif($Method1 eq "register") {
12570                    $NewProblemType = "Parameter_Type_And_Pass_Through_Stack";
12571                }
12572            }
12573            $SubProblems{$SubProblemType}{"Old_Reg"} = $RegName1;
12574            $SubProblems{$SubProblemType}{"New_Reg"} = $RegName2;
12575        }
12576        %{$CompatProblems{$Level}{$Symbol}{$NewProblemType}{$Parameter_Location}}=(
12577            "Target"=>$PName1,
12578            "Param_Pos"=>$ParamPos1,
12579            "New_Signature"=>get_Signature($Symbol, 2) );
12580        @{$CompatProblems{$Level}{$Symbol}{$NewProblemType}{$Parameter_Location}}{keys(%{$SubProblems{$SubProblemType}})} = values %{$SubProblems{$SubProblemType}};
12581    }
12582    @RecurTypes = ();
12583    # checking type definition changes
12584    my %SubProblems_Merge = mergeTypes($PType1_Id, $PType2_Id, $Level);
12585    foreach my $SubProblemType (keys(%SubProblems_Merge))
12586    {
12587        foreach my $SubLocation (keys(%{$SubProblems_Merge{$SubProblemType}}))
12588        {
12589            my $NewProblemType = $SubProblemType;
12590            if($SubProblemType eq "DataType_Size")
12591            {
12592                my $InitialType_Type = $SubProblems_Merge{$SubProblemType}{$SubLocation}{"InitialType_Type"};
12593                if($InitialType_Type!~/\A(Pointer|Ref)\Z/ and $SubLocation!~/\-\>/)
12594                { # stack has been affected
12595                    $NewProblemType = "DataType_Size_And_Stack";
12596                }
12597            }
12598            my $NewLocation = ($SubLocation)?$Parameter_Location."->".$SubLocation:$Parameter_Location;
12599            %{$CompatProblems{$Level}{$Symbol}{$NewProblemType}{$NewLocation}}=(
12600                "Param_Type"=>$TypeInfo{1}{$PType1_Id}{"Name"},
12601                "Param_Pos"=>$ParamPos1,
12602                "Param_Name"=>$PName1  );
12603            @{$CompatProblems{$Level}{$Symbol}{$NewProblemType}{$NewLocation}}{keys(%{$SubProblems_Merge{$SubProblemType}{$SubLocation}})} = values %{$SubProblems_Merge{$SubProblemType}{$SubLocation}};
12604            if($SubLocation!~/\-\>/) {
12605                $CompatProblems{$Level}{$Symbol}{$NewProblemType}{$NewLocation}{"Start_Type_Name"} = $TypeInfo{1}{$PType1_Id}{"Name"};
12606            }
12607        }
12608    }
12609}
12610
12611sub callingConvention($$$$)
12612{ # calling conventions for different compilers and operating systems
12613    my ($Symbol, $ParamPos, $LibVersion, $Arch) = @_;
12614    my $ParamTypeId = $CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$ParamPos}{"type"};
12615    my %Type = get_PureType($ParamTypeId, $LibVersion);
12616    my ($Method, $Alignment, $Passed, $Register) = ("", 0, "", "");
12617    if($OSgroup=~/\A(linux|macos|freebsd)\Z/)
12618    { # GCC
12619        if($Arch eq "x86")
12620        { # System V ABI Intel386 ("Function Calling Sequence")
12621          # The stack is word aligned. Although the architecture does not require any
12622          # alignment of the stack, software convention and the operating system
12623          # requires that the stack be aligned on a word boundary.
12624
12625          # Argument words are pushed onto the stack in reverse order (that is, the
12626          # rightmost argument in C call syntax has the highest address), preserving the
12627          # stack’s word alignment. All incoming arguments appear on the stack, residing
12628          # in the stack frame of the caller.
12629
12630          # An argument’s size is increased, if necessary, to make it a multiple of words.
12631          # This may require tail padding, depending on the size of the argument.
12632
12633          # Other areas depend on the compiler and the code being compiled. The stan-
12634          # dard calling sequence does not define a maximum stack frame size, nor does
12635          # it restrict how a language system uses the ‘‘unspecified’’ area of the stan-
12636          # dard stack frame.
12637            ($Method, $Alignment) = ("stack", 4);
12638        }
12639        elsif($Arch eq "x86_64")
12640        { # System V AMD64 ABI ("Function Calling Sequence")
12641            ($Method, $Alignment) = ("stack", 8);# eightbyte aligned
12642        }
12643        elsif($Arch eq "arm")
12644        { # Procedure Call Standard for the ARM Architecture
12645          # The stack must be double-word aligned
12646            ($Method, $Alignment) = ("stack", 8);# double-word
12647        }
12648    }
12649    elsif($OSgroup eq "windows")
12650    { # MS C++ Compiler
12651        if($Arch eq "x86")
12652        {
12653            if($ParamPos==0) {
12654                ($Method, $Register, $Passed) = ("register", "ecx", "value");
12655            }
12656            elsif($ParamPos==1) {
12657                ($Method, $Register, $Passed) = ("register", "edx", "value");
12658            }
12659            else {
12660                ($Method, $Alignment) = ("stack", 4);
12661            }
12662        }
12663        elsif($Arch eq "x86_64")
12664        {
12665            if($ParamPos<=3)
12666            {
12667                if($Type{"Name"}=~/\A(float|double|long double)\Z/) {
12668                    ($Method, $Passed) = ("xmm".$ParamPos, "value");
12669                }
12670                elsif(isScalar($Type{"Name"})
12671                or $Type{"Type"}=~/\A(Struct|Union|Enum|Array)\Z/
12672                or $Type{"Name"}=~/\A(__m64|__m128)\Z/)
12673                {
12674                    if($ParamPos==0) {
12675                        ($Method, $Register, $Passed) = ("register", "rcx", "value");
12676                    }
12677                    elsif($ParamPos==1) {
12678                        ($Method, $Register, $Passed) = ("register", "rdx", "value");
12679                    }
12680                    elsif($ParamPos==2) {
12681                        ($Method, $Register, $Passed) = ("register", "r8", "value");
12682                    }
12683                    elsif($ParamPos==3) {
12684                        ($Method, $Register, $Passed) = ("register", "r9", "value");
12685                    }
12686                    if($Type{"Size"}>64
12687                    or $Type{"Type"} eq "Array") {
12688                        $Passed = "pointer";
12689                    }
12690                }
12691            }
12692            else {
12693                ($Method, $Alignment) = ("stack", 8);# word alignment
12694            }
12695        }
12696    }
12697    if($Method eq "register") {
12698        return ("register", $Passed, "", $Register);
12699    }
12700    else
12701    { # on the stack
12702        if(not $Alignment)
12703        { # default convention
12704            $Alignment = $WORD_SIZE{$LibVersion};
12705        }
12706        if(not $Passed)
12707        { # default convention
12708            $Passed = "value";
12709        }
12710        my $SizeOnStack = $Type{"Size"};
12711        # FIXME: improve stack alignment
12712        if($SizeOnStack!=$Alignment) {
12713            $SizeOnStack = int(($Type{"Size"}+$Alignment)/$Alignment)*$Alignment;
12714        }
12715        return ("stack", $Passed, $SizeOnStack, "");
12716    }
12717}
12718
12719sub find_ParamPair_Pos_byName($$$)
12720{
12721    my ($Name, $Symbol, $LibVersion) = @_;
12722    foreach my $ParamPos (sort {int($a)<=>int($b)} keys(%{$CompleteSignature{$LibVersion}{$Symbol}{"Param"}}))
12723    {
12724        next if(not defined $CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$ParamPos});
12725        if($CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$ParamPos}{"name"} eq $Name)
12726        {
12727            return $ParamPos;
12728        }
12729    }
12730    return "lost";
12731}
12732
12733sub find_ParamPair_Pos_byTypeAndPos($$$$$)
12734{
12735    my ($TypeName, $MediumPos, $Order, $Symbol, $LibVersion) = @_;
12736    my @Positions = ();
12737    foreach my $ParamPos (sort {int($a)<=>int($b)} keys(%{$CompleteSignature{$LibVersion}{$Symbol}{"Param"}}))
12738    {
12739        next if($Order eq "backward" and $ParamPos>$MediumPos);
12740        next if($Order eq "forward" and $ParamPos<$MediumPos);
12741        next if(not defined $CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$ParamPos});
12742        my $PTypeId = $CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$ParamPos}{"type"};
12743        if($TypeInfo{$LibVersion}{$PTypeId}{"Name"} eq $TypeName) {
12744            push(@Positions, $ParamPos);
12745        }
12746    }
12747    return @Positions;
12748}
12749
12750sub getTypeIdByName($$)
12751{
12752    my ($TypeName, $Version) = @_;
12753    return $TName_Tid{$Version}{formatName($TypeName)};
12754}
12755
12756sub checkFormatChange($$$)
12757{
12758    my ($Type1_Id, $Type2_Id, $Level) = @_;
12759    my %Type1_Pure = get_PureType($Type1_Id, 1);
12760    my %Type2_Pure = get_PureType($Type2_Id, 2);
12761    if($Type1_Pure{"Name"} eq $Type2_Pure{"Name"})
12762    { # equal types
12763        return 0;
12764    }
12765    if($Type1_Pure{"Name"}=~/\*/
12766    or $Type2_Pure{"Name"}=~/\*/)
12767    { # compared in detectTypeChange()
12768        return 0;
12769    }
12770    my %FloatType = map {$_=>1} (
12771        "float",
12772        "double",
12773        "long double"
12774    );
12775    if($Type1_Pure{"Type"} ne $Type2_Pure{"Type"})
12776    { # different types
12777        if($Type1_Pure{"Type"} eq "Intrinsic"
12778        and $Type2_Pure{"Type"} eq "Enum")
12779        { # "int" to "enum"
12780            return 0;
12781        }
12782        elsif($Type2_Pure{"Type"} eq "Intrinsic"
12783        and $Type1_Pure{"Type"} eq "Enum")
12784        { # "enum" to "int"
12785            return 0;
12786        }
12787        else
12788        { # "union" to "struct"
12789          #  ...
12790            return 1;
12791        }
12792    }
12793    else
12794    {
12795        if($Type1_Pure{"Type"} eq "Intrinsic")
12796        {
12797            if($FloatType{$Type1_Pure{"Name"}}
12798            or $FloatType{$Type2_Pure{"Name"}})
12799            { # "float" to "double"
12800              # "float" to "int"
12801                if($Level eq "Source")
12802                { # Safe
12803                    return 0;
12804                }
12805                else {
12806                    return 1;
12807                }
12808            }
12809        }
12810        elsif($Type1_Pure{"Type"}=~/Class|Struct|Union|Enum/)
12811        {
12812            my @Membs1 = keys(%{$Type1_Pure{"Memb"}});
12813            my @Membs2 = keys(%{$Type2_Pure{"Memb"}});
12814            if($#Membs1!=$#Membs2)
12815            { # different number of elements
12816                return 1;
12817            }
12818            if($Type1_Pure{"Type"} eq "Enum")
12819            {
12820                foreach my $Pos (@Membs1)
12821                { # compare elements by name and value
12822                    if($Type1_Pure{"Memb"}{$Pos}{"name"} ne $Type2_Pure{"Memb"}{$Pos}{"name"}
12823                    or $Type1_Pure{"Memb"}{$Pos}{"value"} ne $Type2_Pure{"Memb"}{$Pos}{"value"})
12824                    { # different names
12825                        return 1;
12826                    }
12827                }
12828            }
12829            else
12830            {
12831                foreach my $Pos (@Membs1)
12832                { # compare elements by type name
12833                    my $MT1 = $TypeInfo{1}{$Type1_Pure{"Memb"}{$Pos}{"type"}}{"Name"};
12834                    my $MT2 = $TypeInfo{2}{$Type2_Pure{"Memb"}{$Pos}{"type"}}{"Name"};
12835                    if($MT1 ne $MT2)
12836                    { # different types
12837                        return 1;
12838                    }
12839                    if($Level eq "Source")
12840                    {
12841                        if($Type1_Pure{"Memb"}{$Pos}{"name"} ne $Type2_Pure{"Memb"}{$Pos}{"name"})
12842                        { # different names
12843                            return 1;
12844                        }
12845                    }
12846                }
12847            }
12848        }
12849    }
12850    return 0;
12851}
12852
12853sub isScalar($) {
12854    return ($_[0]=~/\A(unsigned |)(short|int|long|long long)\Z/);
12855}
12856
12857sub isFloat($) {
12858    return ($_[0]=~/\A(float|double|long double)\Z/);
12859}
12860
12861sub detectTypeChange($$$$)
12862{
12863    my ($Type1_Id, $Type2_Id, $Prefix, $Level) = @_;
12864    if(not $Type1_Id or not $Type2_Id) {
12865        return ();
12866    }
12867    my %LocalProblems = ();
12868    my %Type1 = get_Type($Type1_Id, 1);
12869    my %Type2 = get_Type($Type2_Id, 2);
12870    my %Type1_Pure = get_PureType($Type1_Id, 1);
12871    my %Type2_Pure = get_PureType($Type2_Id, 2);
12872    my %Type1_Base = ($Type1_Pure{"Type"} eq "Array")?get_OneStep_BaseType($Type1_Pure{"Tid"}, 1):get_BaseType($Type1_Id, 1);
12873    my %Type2_Base = ($Type2_Pure{"Type"} eq "Array")?get_OneStep_BaseType($Type2_Pure{"Tid"}, 2):get_BaseType($Type2_Id, 2);
12874    my $Type1_PLevel = get_PLevel($Type1_Id, 1);
12875    my $Type2_PLevel = get_PLevel($Type2_Id, 2);
12876    return () if(not $Type1{"Name"} or not $Type2{"Name"});
12877    return () if(not $Type1_Base{"Name"} or not $Type2_Base{"Name"});
12878    return () if($Type1_PLevel eq "" or $Type2_PLevel eq "");
12879    if($Type1_Base{"Name"} ne $Type2_Base{"Name"}
12880    and ($Type1{"Name"} eq $Type2{"Name"} or ($Type1_PLevel>=1 and $Type1_PLevel==$Type2_PLevel
12881    and $Type1_Base{"Name"} ne "void" and $Type2_Base{"Name"} ne "void")))
12882    { # base type change
12883        if($Type1{"Type"} eq "Typedef" and $Type2{"Type"} eq "Typedef"
12884        and $Type1{"Name"} eq $Type2{"Name"})
12885        { # will be reported in mergeTypes() as typedef problem
12886            return ();
12887        }
12888        if($Type1_Base{"Name"}!~/anon\-/ and $Type2_Base{"Name"}!~/anon\-/)
12889        {
12890            if($Level eq "Binary"
12891            and $Type1_Base{"Size"} ne $Type2_Base{"Size"}
12892            and $Type1_Base{"Size"} and $Type2_Base{"Size"})
12893            {
12894                %{$LocalProblems{$Prefix."_BaseType_And_Size"}}=(
12895                    "Old_Value"=>$Type1_Base{"Name"},
12896                    "New_Value"=>$Type2_Base{"Name"},
12897                    "Old_Size"=>$Type1_Base{"Size"}*$BYTE_SIZE,
12898                    "New_Size"=>$Type2_Base{"Size"}*$BYTE_SIZE,
12899                    "InitialType_Type"=>$Type1_Pure{"Type"});
12900            }
12901            else
12902            {
12903                if(checkFormatChange($Type1_Base{"Tid"}, $Type2_Base{"Tid"}, $Level))
12904                { # format change
12905                    %{$LocalProblems{$Prefix."_BaseType_Format"}}=(
12906                        "Old_Value"=>$Type1_Base{"Name"},
12907                        "New_Value"=>$Type2_Base{"Name"},
12908                        "InitialType_Type"=>$Type1_Pure{"Type"});
12909                }
12910                elsif(tNameLock($Type1_Base{"Tid"}, $Type2_Base{"Tid"}))
12911                {
12912                    %{$LocalProblems{$Prefix."_BaseType"}}=(
12913                        "Old_Value"=>$Type1_Base{"Name"},
12914                        "New_Value"=>$Type2_Base{"Name"},
12915                        "InitialType_Type"=>$Type1_Pure{"Type"});
12916                }
12917            }
12918        }
12919    }
12920    elsif($Type1{"Name"} ne $Type2{"Name"})
12921    { # type change
12922        if($Type1{"Name"}!~/anon\-/ and $Type2{"Name"}!~/anon\-/)
12923        {
12924            if($Prefix eq "Return" and $Type1{"Name"} eq "void"
12925            and $Type2_Pure{"Type"}=~/Intrinsic|Enum/) {
12926                # safe change
12927            }
12928            elsif($Level eq "Binary"
12929            and $Prefix eq "Return"
12930            and $Type1_Pure{"Name"} eq "void")
12931            {
12932                %{$LocalProblems{"Return_Type_From_Void"}}=(
12933                    "New_Value"=>$Type2{"Name"},
12934                    "New_Size"=>$Type2{"Size"}*$BYTE_SIZE,
12935                    "InitialType_Type"=>$Type1_Pure{"Type"});
12936            }
12937            elsif($Level eq "Binary"
12938            and $Prefix eq "Return" and $Type1_Pure{"Type"}=~/Intrinsic|Enum/
12939            and $Type2_Pure{"Type"}=~/Struct|Class|Union/)
12940            { # returns into hidden first parameter instead of a register
12941
12942                # System V ABI Intel386 ("Function Calling Sequence")
12943                # A function that returns an integral or pointer value places its result in register %eax.
12944
12945                # A floating-point return value appears on the top of the Intel387 register stack. The
12946                # caller then must remove the value from the Intel387 stack, even if it doesn’t use the
12947                # value.
12948
12949                # If a function returns a structure or union, then the caller provides space for the
12950                # return value and places its address on the stack as argument word zero. In effect,
12951                # this address becomes a ‘‘hidden’’ first argument.
12952
12953                %{$LocalProblems{"Return_Type_From_Register_To_Stack"}}=(
12954                    "Old_Value"=>$Type1{"Name"},
12955                    "New_Value"=>$Type2{"Name"},
12956                    "Old_Size"=>$Type1{"Size"}*$BYTE_SIZE,
12957                    "New_Size"=>$Type2{"Size"}*$BYTE_SIZE,
12958                    "InitialType_Type"=>$Type1_Pure{"Type"});
12959            }
12960            elsif($Prefix eq "Return"
12961            and $Type2_Pure{"Name"} eq "void")
12962            {
12963                %{$LocalProblems{"Return_Type_Became_Void"}}=(
12964                    "Old_Value"=>$Type1{"Name"},
12965                    "Old_Size"=>$Type1{"Size"}*$BYTE_SIZE,
12966                    "InitialType_Type"=>$Type1_Pure{"Type"});
12967            }
12968            elsif($Level eq "Binary" and $Prefix eq "Return"
12969            and ((isScalar($Type1_Pure{"Name"}) and isFloat($Type2_Pure{"Name"}))
12970            or (isScalar($Type2_Pure{"Name"}) and isFloat($Type1_Pure{"Name"}))))
12971            { # The scalar and floating-point values are passed in different registers
12972                %{$LocalProblems{"Return_Type_And_Register"}}=(
12973                    "Old_Value"=>$Type1{"Name"},
12974                    "New_Value"=>$Type2{"Name"},
12975                    "Old_Size"=>$Type1{"Size"}*$BYTE_SIZE,
12976                    "New_Size"=>$Type2{"Size"}*$BYTE_SIZE,
12977                    "InitialType_Type"=>$Type1_Pure{"Type"});
12978            }
12979            elsif($Level eq "Binary"
12980            and $Prefix eq "Return" and $Type2_Pure{"Type"}=~/Intrinsic|Enum/
12981            and $Type1_Pure{"Type"}=~/Struct|Class|Union/)
12982            { # returns in a register instead of a hidden first parameter
12983                %{$LocalProblems{"Return_Type_From_Stack_To_Register"}}=(
12984                    "Old_Value"=>$Type1{"Name"},
12985                    "New_Value"=>$Type2{"Name"},
12986                    "Old_Size"=>$Type1{"Size"}*$BYTE_SIZE,
12987                    "New_Size"=>$Type2{"Size"}*$BYTE_SIZE,
12988                    "InitialType_Type"=>$Type1_Pure{"Type"});
12989            }
12990            else
12991            {
12992                if($Level eq "Binary"
12993                and $Type1{"Size"} and $Type2{"Size"}
12994                and $Type1{"Size"} ne $Type2{"Size"})
12995                {
12996                    %{$LocalProblems{$Prefix."_Type_And_Size"}}=(
12997                        "Old_Value"=>$Type1{"Name"},
12998                        "New_Value"=>$Type2{"Name"},
12999                        "Old_Size"=>$Type1{"Size"}*$BYTE_SIZE,
13000                        "New_Size"=>$Type2{"Size"}*$BYTE_SIZE,
13001                        "InitialType_Type"=>$Type1_Pure{"Type"});
13002                }
13003                else
13004                {
13005                    if(checkFormatChange($Type1_Id, $Type2_Id, $Level))
13006                    { # format change
13007                        %{$LocalProblems{$Prefix."_Type_Format"}}=(
13008                            "Old_Value"=>$Type1{"Name"},
13009                            "New_Value"=>$Type2{"Name"},
13010                            "InitialType_Type"=>$Type1_Pure{"Type"});
13011                    }
13012                    elsif(tNameLock($Type1_Id, $Type2_Id))
13013                    { # FIXME: correct this condition
13014                        %{$LocalProblems{$Prefix."_Type"}}=(
13015                            "Old_Value"=>$Type1{"Name"},
13016                            "New_Value"=>$Type2{"Name"},
13017                            "InitialType_Type"=>$Type1_Pure{"Type"});
13018                    }
13019                }
13020            }
13021        }
13022    }
13023    if($Type1_PLevel!=$Type2_PLevel)
13024    {
13025        if($Type1{"Name"} ne "void" and $Type1{"Name"} ne "..."
13026        and $Type2{"Name"} ne "void" and $Type2{"Name"} ne "...")
13027        {
13028            if($Level eq "Source")
13029            {
13030                %{$LocalProblems{$Prefix."_PointerLevel"}}=(
13031                    "Old_Value"=>$Type1_PLevel,
13032                    "New_Value"=>$Type2_PLevel);
13033            }
13034            else
13035            {
13036                if($Type2_PLevel>$Type1_PLevel) {
13037                    %{$LocalProblems{$Prefix."_PointerLevel_Increased"}}=(
13038                        "Old_Value"=>$Type1_PLevel,
13039                        "New_Value"=>$Type2_PLevel);
13040                }
13041                else {
13042                    %{$LocalProblems{$Prefix."_PointerLevel_Decreased"}}=(
13043                        "Old_Value"=>$Type1_PLevel,
13044                        "New_Value"=>$Type2_PLevel);
13045                }
13046            }
13047        }
13048    }
13049    if($Type1_Pure{"Type"} eq "Array")
13050    { # base_type[N] -> base_type[N]
13051      # base_type: older_structure -> typedef to newer_structure
13052        my %SubProblems = detectTypeChange($Type1_Base{"Tid"}, $Type2_Base{"Tid"}, $Prefix, $Level);
13053        foreach my $SubProblemType (keys(%SubProblems))
13054        {
13055            $SubProblemType=~s/_Type/_BaseType/g;
13056            next if(defined $LocalProblems{$SubProblemType});
13057            foreach my $Attr (keys(%{$SubProblems{$SubProblemType}})) {
13058                $LocalProblems{$SubProblemType}{$Attr} = $SubProblems{$SubProblemType}{$Attr};
13059            }
13060        }
13061    }
13062    return %LocalProblems;
13063}
13064
13065sub tNameLock($$)
13066{
13067    my ($Tid1, $Tid2) = @_;
13068    my $Changed = 0;
13069    if(differentDumps("G"))
13070    { # different GCC versions
13071        $Changed = 1;
13072    }
13073    elsif(differentDumps("V"))
13074    { # different versions of ABI dumps
13075        if(not checkDump(1, "2.13")
13076        or not checkDump(2, "2.13"))
13077        { # latest names update
13078          # 2.6: added restrict qualifier
13079          # 2.13: added missed typedefs to qualified types
13080            $Changed = 1;
13081        }
13082    }
13083    if($Changed)
13084    { # different formats
13085        if($UseOldDumps)
13086        { # old dumps
13087            return 0;
13088        }
13089        my $TN1 = $TypeInfo{1}{$Tid1}{"Name"};
13090        my $TN2 = $TypeInfo{2}{$Tid2}{"Name"};
13091
13092        my $TT1 = $TypeInfo{1}{$Tid1}{"Type"};
13093        my $TT2 = $TypeInfo{2}{$Tid2}{"Type"};
13094
13095        my %Base1 = get_Type($Tid1, 1);
13096        while(defined $Base1{"Type"} and $Base1{"Type"} eq "Typedef") {
13097            %Base1 = get_OneStep_BaseType($Base1{"Tid"}, 1);
13098        }
13099        my %Base2 = get_Type($Tid2, 2);
13100        while(defined $Base2{"Type"} and $Base2{"Type"} eq "Typedef") {
13101            %Base2 = get_OneStep_BaseType($Base2{"Tid"}, 2);
13102        }
13103        my $BName1 = uncover_typedefs($Base1{"Name"}, 1);
13104        my $BName2 = uncover_typedefs($Base2{"Name"}, 2);
13105        if($BName1 eq $BName2)
13106        { # equal base types
13107            return 0;
13108        }
13109
13110        if(not checkDump(1, "2.13")
13111        or not checkDump(2, "2.13"))
13112        { # broken array names in ABI dumps < 2.13
13113            if($TT1 eq "Array"
13114            and $TT2 eq "Array")
13115            {
13116                return 0;
13117            }
13118        }
13119
13120        if(not checkDump(1, "2.6")
13121        or not checkDump(2, "2.6"))
13122        { # added restrict attribute in 2.6
13123            if($TN1!~/\brestrict\b/
13124            and $TN2=~/\brestrict\b/)
13125            {
13126                return 0;
13127            }
13128        }
13129    }
13130    return 1;
13131}
13132
13133sub differentDumps($)
13134{
13135    my $Check = $_[0];
13136    if(defined $Cache{"differentDumps"}{$Check}) {
13137        return $Cache{"differentDumps"}{$Check};
13138    }
13139    if($UsedDump{1}{"V"} and $UsedDump{2}{"V"})
13140    {
13141        if($Check eq "G")
13142        {
13143            if(getGccVersion(1) ne getGccVersion(2))
13144            { # different GCC versions
13145                return ($Cache{"differentDumps"}{$Check}=1);
13146            }
13147        }
13148        if($Check eq "V")
13149        {
13150            if(cmpVersions(formatVersion($UsedDump{1}{"V"}, 2),
13151            formatVersion($UsedDump{2}{"V"}, 2))!=0)
13152            { # different dump versions (skip micro version)
13153                return ($Cache{"differentDumps"}{$Check}=1);
13154            }
13155        }
13156    }
13157    return ($Cache{"differentDumps"}{$Check}=0);
13158}
13159
13160sub formatVersion($$)
13161{ # cut off version digits
13162    my ($V, $Digits) = @_;
13163    my @Elems = split(/\./, $V);
13164    return join(".", splice(@Elems, 0, $Digits));
13165}
13166
13167sub htmlSpecChars($)
13168{
13169    my $Str = $_[0];
13170    if(not $Str) {
13171        return $Str;
13172    }
13173    $Str=~s/\&([^#]|\Z)/&amp;$1/g;
13174    $Str=~s/</&lt;/g;
13175    $Str=~s/\-\>/&#45;&gt;/g; # &minus;
13176    $Str=~s/>/&gt;/g;
13177    $Str=~s/([^ ])( )([^ ])/$1\@ALONE_SP\@$3/g;
13178    $Str=~s/ /&#160;/g; # &nbsp;
13179    $Str=~s/\@ALONE_SP\@/ /g;
13180    $Str=~s/\n/<br\/>/g;
13181    $Str=~s/\"/&quot;/g;
13182    $Str=~s/\'/&#39;/g;
13183    return $Str;
13184}
13185
13186sub xmlSpecChars($)
13187{
13188    my $Str = $_[0];
13189    if(not $Str) {
13190        return $Str;
13191    }
13192
13193    $Str=~s/\&([^#]|\Z)/&amp;$1/g;
13194    $Str=~s/</&lt;/g;
13195    $Str=~s/>/&gt;/g;
13196
13197    $Str=~s/\"/&quot;/g;
13198    $Str=~s/\'/&#39;/g;
13199
13200    return $Str;
13201}
13202
13203sub black_name($)
13204{
13205    my $Name = $_[0];
13206    return "<span class='iname_b'>".highLight_Signature($Name)."</span>";
13207}
13208
13209sub highLight_Signature($)
13210{
13211    my $Signature = $_[0];
13212    return highLight_Signature_PPos_Italic($Signature, "", 0, 0, 0);
13213}
13214
13215sub highLight_Signature_Italic_Color($)
13216{
13217    my $Signature = $_[0];
13218    return highLight_Signature_PPos_Italic($Signature, "", 1, 1, 1);
13219}
13220
13221sub separate_symbol($)
13222{
13223    my $Symbol = $_[0];
13224    my ($Name, $Spec, $Ver) = ($Symbol, "", "");
13225    if($Symbol=~/\A([^\@\$\?]+)([\@\$]+)([^\@\$]+)\Z/) {
13226        ($Name, $Spec, $Ver) = ($1, $2, $3);
13227    }
13228    return ($Name, $Spec, $Ver);
13229}
13230
13231sub cut_f_attrs($)
13232{
13233    if($_[0]=~s/(\))((| (const volatile|const|volatile))(| \[static\]))\Z/$1/) {
13234        return $2;
13235    }
13236    return "";
13237}
13238
13239sub highLight_Signature_PPos_Italic($$$$$)
13240{
13241    my ($FullSignature, $Param_Pos, $ItalicParams, $ColorParams, $ShowReturn) = @_;
13242    $Param_Pos = "" if(not defined $Param_Pos);
13243    if($CheckObjectsOnly) {
13244        $ItalicParams=$ColorParams=0;
13245    }
13246    my ($Signature, $VersionSpec, $SymbolVersion) = separate_symbol($FullSignature);
13247    my $Return = "";
13248    if($ShowRetVal and $Signature=~s/([^:]):([^:].+?)\Z/$1/g) {
13249        $Return = $2;
13250    }
13251    my $SCenter = find_center($Signature, "(");
13252    if(not $SCenter)
13253    { # global data
13254        $Signature = htmlSpecChars($Signature);
13255        $Signature=~s!(\[data\])!<span style='color:Black;font-weight:normal;'>$1</span>!g;
13256        $Signature .= (($SymbolVersion)?"<span class='sym_ver'>&#160;$VersionSpec&#160;$SymbolVersion</span>":"");
13257        if($Return and $ShowReturn) {
13258            $Signature .= "<span class='sym_p nowrap'> &#160;<b>:</b>&#160;&#160;".htmlSpecChars($Return)."</span>";
13259        }
13260        return $Signature;
13261    }
13262    my ($Begin, $End) = (substr($Signature, 0, $SCenter), "");
13263    $Begin.=" " if($Begin!~/ \Z/);
13264    $End = cut_f_attrs($Signature);
13265    my @Parts = ();
13266    my @SParts = get_s_params($Signature, 1);
13267    foreach my $Pos (0 .. $#SParts)
13268    {
13269        my $Part = $SParts[$Pos];
13270        $Part=~s/\A\s+|\s+\Z//g;
13271        my ($Part_Styled, $ParamName) = (htmlSpecChars($Part), "");
13272        if($Part=~/\([\*]+(\w+)\)/i) {
13273            $ParamName = $1;#func-ptr
13274        }
13275        elsif($Part=~/(\w+)[\,\)]*\Z/i) {
13276            $ParamName = $1;
13277        }
13278        if(not $ParamName) {
13279            push(@Parts, $Part_Styled);
13280            next;
13281        }
13282        if($ItalicParams and not $TName_Tid{1}{$Part}
13283        and not $TName_Tid{2}{$Part})
13284        {
13285            my $Style = "param";
13286            if($Param_Pos ne ""
13287            and $Pos==$Param_Pos) {
13288                $Style = "focus_p";
13289            }
13290            elsif($ColorParams) {
13291                $Style = "color_p";
13292            }
13293            $Part_Styled =~ s!(\W)$ParamName([\,\)]|\Z)!$1<span class=\'$Style\'>$ParamName</span>$2!ig;
13294        }
13295        $Part_Styled=~s/,(\w)/, $1/g;
13296        push(@Parts, $Part_Styled);
13297    }
13298    if(@Parts)
13299    {
13300        foreach my $Num (0 .. $#Parts)
13301        {
13302            if($Num==$#Parts)
13303            { # add ")" to the last parameter
13304                $Parts[$Num] = "<span class='nowrap'>".$Parts[$Num]." )</span>";
13305            }
13306            elsif(length($Parts[$Num])<=45) {
13307                $Parts[$Num] = "<span class='nowrap'>".$Parts[$Num]."</span>";
13308            }
13309        }
13310        $Signature = htmlSpecChars($Begin)."<span class='sym_p'>(&#160;".join(" ", @Parts)."</span>".$End;
13311    }
13312    else {
13313        $Signature = htmlSpecChars($Begin)."<span class='sym_p'>(&#160;)</span>".$End;
13314    }
13315    if($Return and $ShowReturn) {
13316        $Signature .= "<span class='sym_p nowrap'> &#160;<b>:</b>&#160;&#160;".htmlSpecChars($Return)."</span>";
13317    }
13318    $Signature=~s!\[\]![&#160;]!g;
13319    $Signature=~s!operator=!operator&#160;=!g;
13320    $Signature=~s!(\[in-charge\]|\[not-in-charge\]|\[in-charge-deleting\]|\[static\])!<span class='sym_kind'>$1</span>!g;
13321    return $Signature.(($SymbolVersion)?"<span class='sym_ver'>&#160;$VersionSpec&#160;$SymbolVersion</span>":"");
13322}
13323
13324sub get_s_params($$)
13325{
13326    my ($Signature, $Comma) = @_;
13327    my @Parts = ();
13328    my $ShortName = substr($Signature, 0, find_center($Signature, "("));
13329    $Signature=~s/\A\Q$ShortName\E\(//g;
13330    cut_f_attrs($Signature);
13331    $Signature=~s/\)\Z//;
13332    return separate_params($Signature, $Comma);
13333}
13334
13335sub separate_params($$)
13336{
13337    my ($Params, $Comma) = @_;
13338    my @Parts = ();
13339    my %B = ( "("=>0, "<"=>0, ")"=>0, ">"=>0 );
13340    my $Part = 0;
13341    foreach my $Pos (0 .. length($Params) - 1)
13342    {
13343        my $S = substr($Params, $Pos, 1);
13344        if(defined $B{$S}) {
13345            $B{$S}+=1;
13346        }
13347        if($S eq "," and
13348        $B{"("}==$B{")"} and $B{"<"}==$B{">"})
13349        {
13350            if($Comma)
13351            { # include comma
13352                $Parts[$Part] .= $S;
13353            }
13354            $Part += 1;
13355        }
13356        else {
13357            $Parts[$Part] .= $S;
13358        }
13359    }
13360    return @Parts;
13361}
13362
13363sub find_center($$)
13364{
13365    my ($Sign, $Target) = @_;
13366    my %B = ( "("=>0, "<"=>0, ")"=>0, ">"=>0 );
13367    my $Center = 0;
13368    if($Sign=~s/(operator([^\w\s\(\)]+|\(\)))//g)
13369    { # operators
13370        $Center+=length($1);
13371    }
13372    foreach my $Pos (0 .. length($Sign)-1)
13373    {
13374        my $S = substr($Sign, $Pos, 1);
13375        if($S eq $Target)
13376        {
13377            if($B{"("}==$B{")"}
13378            and $B{"<"}==$B{">"}) {
13379                return $Center;
13380            }
13381        }
13382        if(defined $B{$S}) {
13383            $B{$S}+=1;
13384        }
13385        $Center+=1;
13386    }
13387    return 0;
13388}
13389
13390sub appendFile($$)
13391{
13392    my ($Path, $Content) = @_;
13393    return if(not $Path);
13394    if(my $Dir = get_dirname($Path)) {
13395        mkpath($Dir);
13396    }
13397    open(FILE, ">>", $Path) || die ("can't open file \'$Path\': $!\n");
13398    print FILE $Content;
13399    close(FILE);
13400}
13401
13402sub writeFile($$)
13403{
13404    my ($Path, $Content) = @_;
13405    return if(not $Path);
13406    if(my $Dir = get_dirname($Path)) {
13407        mkpath($Dir);
13408    }
13409    open(FILE, ">", $Path) || die ("can't open file \'$Path\': $!\n");
13410    print FILE $Content;
13411    close(FILE);
13412}
13413
13414sub readFile($)
13415{
13416    my $Path = $_[0];
13417    return "" if(not $Path or not -f $Path);
13418    open(FILE, $Path);
13419    local $/ = undef;
13420    my $Content = <FILE>;
13421    close(FILE);
13422    if($Path!~/\.(tu|class|abi)\Z/) {
13423        $Content=~s/\r/\n/g;
13424    }
13425    return $Content;
13426}
13427
13428sub get_filename($)
13429{ # much faster than basename() from File::Basename module
13430    if(defined $Cache{"get_filename"}{$_[0]}) {
13431        return $Cache{"get_filename"}{$_[0]};
13432    }
13433    if($_[0] and $_[0]=~/([^\/\\]+)[\/\\]*\Z/) {
13434        return ($Cache{"get_filename"}{$_[0]}=$1);
13435    }
13436    return ($Cache{"get_filename"}{$_[0]}="");
13437}
13438
13439sub get_dirname($)
13440{ # much faster than dirname() from File::Basename module
13441    if(defined $Cache{"get_dirname"}{$_[0]}) {
13442        return $Cache{"get_dirname"}{$_[0]};
13443    }
13444    if($_[0] and $_[0]=~/\A(.*?)[\/\\]+[^\/\\]*[\/\\]*\Z/) {
13445        return ($Cache{"get_dirname"}{$_[0]}=$1);
13446    }
13447    return ($Cache{"get_dirname"}{$_[0]}="");
13448}
13449
13450sub separate_path($) {
13451    return (get_dirname($_[0]), get_filename($_[0]));
13452}
13453
13454sub esc($)
13455{
13456    my $Str = $_[0];
13457    $Str=~s/([()\[\]{}$ &'"`;,<>\+])/\\$1/g;
13458    return $Str;
13459}
13460
13461sub readLineNum($$)
13462{
13463    my ($Path, $Num) = @_;
13464    return "" if(not $Path or not -f $Path);
13465    open(FILE, $Path);
13466    foreach (1 ... $Num) {
13467        <FILE>;
13468    }
13469    my $Line = <FILE>;
13470    close(FILE);
13471    return $Line;
13472}
13473
13474sub readAttributes($$)
13475{
13476    my ($Path, $Num) = @_;
13477    return () if(not $Path or not -f $Path);
13478    my %Attributes = ();
13479    if(readLineNum($Path, $Num)=~/<!--\s+(.+)\s+-->/)
13480    {
13481        foreach my $AttrVal (split(/;/, $1))
13482        {
13483            if($AttrVal=~/(.+):(.+)/)
13484            {
13485                my ($Name, $Value) = ($1, $2);
13486                $Attributes{$Name} = $Value;
13487            }
13488        }
13489    }
13490    return \%Attributes;
13491}
13492
13493sub is_abs($) {
13494    return ($_[0]=~/\A(\/|\w+:[\/\\])/);
13495}
13496
13497sub get_abs_path($)
13498{ # abs_path() should NOT be called for absolute inputs
13499  # because it can change them
13500    my $Path = $_[0];
13501    if(not is_abs($Path)) {
13502        $Path = abs_path($Path);
13503    }
13504    return $Path;
13505}
13506
13507sub get_OSgroup()
13508{
13509    $_ = $Config{"osname"};
13510    if(/macos|darwin|rhapsody/i) {
13511        return "macos";
13512    }
13513    elsif(/freebsd|openbsd|netbsd/i) {
13514        return "bsd";
13515    }
13516    elsif(/haiku|beos/i) {
13517        return "beos";
13518    }
13519    elsif(/symbian|epoc/i) {
13520        return "symbian";
13521    }
13522    elsif(/win/i) {
13523        return "windows";
13524    }
13525    else {
13526        return $_;
13527    }
13528}
13529
13530sub getGccVersion($)
13531{
13532    my $LibVersion = $_[0];
13533    if($GCC_VERSION{$LibVersion})
13534    { # dump version
13535        return $GCC_VERSION{$LibVersion};
13536    }
13537    elsif($UsedDump{$LibVersion}{"V"})
13538    { # old-version dumps
13539        return "unknown";
13540    }
13541    my $GccVersion = get_dumpversion($GCC_PATH); # host version
13542    if(not $GccVersion) {
13543        return "unknown";
13544    }
13545    return $GccVersion;
13546}
13547
13548sub showArch($)
13549{
13550    my $Arch = $_[0];
13551    if($Arch eq "arm"
13552    or $Arch eq "mips") {
13553        return uc($Arch);
13554    }
13555    return $Arch;
13556}
13557
13558sub getArch($)
13559{
13560    my $LibVersion = $_[0];
13561    if($CPU_ARCH{$LibVersion})
13562    { # dump version
13563        return $CPU_ARCH{$LibVersion};
13564    }
13565    elsif($UsedDump{$LibVersion}{"V"})
13566    { # old-version dumps
13567        return "unknown";
13568    }
13569    if(defined $Cache{"getArch"}{$LibVersion}) {
13570        return $Cache{"getArch"}{$LibVersion};
13571    }
13572    my $Arch = get_dumpmachine($GCC_PATH); # host version
13573    if(not $Arch) {
13574        return "unknown";
13575    }
13576    if($Arch=~/\A([\w]{3,})(-|\Z)/) {
13577        $Arch = $1;
13578    }
13579    $Arch = "x86" if($Arch=~/\Ai[3-7]86\Z/);
13580    if($OSgroup eq "windows") {
13581        $Arch = "x86" if($Arch=~/win32|mingw32/i);
13582        $Arch = "x86_64" if($Arch=~/win64|mingw64/i);
13583    }
13584    $Cache{"getArch"}{$LibVersion} = $Arch;
13585    return $Arch;
13586}
13587
13588sub get_Report_Header($)
13589{
13590    my $Level = $_[0];
13591    my $ArchInfo = " on <span style='color:Blue;'>".showArch(getArch(1))."</span>";
13592    if(getArch(1) ne getArch(2)
13593    or getArch(1) eq "unknown"
13594    or $Level eq "Source")
13595    { # don't show architecture in the header
13596        $ArchInfo="";
13597    }
13598    my $Report_Header = "<h1><span class='nowrap'>";
13599    if($Level eq "Source") {
13600        $Report_Header .= "Source compatibility";
13601    }
13602    elsif($Level eq "Binary") {
13603        $Report_Header .= "Binary compatibility";
13604    }
13605    else {
13606        $Report_Header .= "API compatibility";
13607    }
13608    $Report_Header .= " report for the <span style='color:Blue;'>$TargetLibraryFName</span> $TargetComponent</span>";
13609    $Report_Header .= " <span class='nowrap'>&#160;between <span style='color:Red;'>".$Descriptor{1}{"Version"}."</span> and <span style='color:Red;'>".$Descriptor{2}{"Version"}."</span> versions$ArchInfo</span>";
13610    if($AppPath) {
13611        $Report_Header .= " <span class='nowrap'>&#160;(relating to the portability of application <span style='color:Blue;'>".get_filename($AppPath)."</span>)</span>";
13612    }
13613    $Report_Header .= "</h1>\n";
13614    return $Report_Header;
13615}
13616
13617sub get_SourceInfo()
13618{
13619    my ($CheckedHeaders, $CheckedLibs) = ("", "");
13620    if(not $CheckObjectsOnly)
13621    {
13622        $CheckedHeaders = "<a name='Headers'></a><h2>Header Files (".keys(%{$Registered_Headers{1}}).")</h2><hr/>\n";
13623        $CheckedHeaders .= "<div class='h_list'>\n";
13624        foreach my $Header_Path (sort {lc($Registered_Headers{1}{$a}{"Identity"}) cmp lc($Registered_Headers{1}{$b}{"Identity"})} keys(%{$Registered_Headers{1}}))
13625        {
13626            my $Identity = $Registered_Headers{1}{$Header_Path}{"Identity"};
13627            my $Header_Name = get_filename($Identity);
13628            my $Dest_Comment = ($Identity=~/[\/\\]/)?" ($Identity)":"";
13629            $CheckedHeaders .= $Header_Name.$Dest_Comment."<br/>\n";
13630        }
13631        $CheckedHeaders .= "</div>\n";
13632        $CheckedHeaders .= "<br/>$TOP_REF<br/>\n";
13633    }
13634    if(not $CheckHeadersOnly)
13635    {
13636        $CheckedLibs = "<a name='Libs'></a><h2>".ucfirst($SLIB_TYPE)." Libraries (".keys(%{$Library_Symbol{1}}).")</h2><hr/>\n";
13637        $CheckedLibs .= "<div class='lib_list'>\n";
13638        foreach my $Library (sort {lc($a) cmp lc($b)}  keys(%{$Library_Symbol{1}}))
13639        {
13640            $Library.=" (.$LIB_EXT)" if($Library!~/\.\w+\Z/);
13641            $CheckedLibs .= $Library."<br/>\n";
13642        }
13643        $CheckedLibs .= "</div>\n";
13644        $CheckedLibs .= "<br/>$TOP_REF<br/>\n";
13645    }
13646    return $CheckedHeaders.$CheckedLibs;
13647}
13648
13649sub get_TypeProblems_Count($$$)
13650{
13651    my ($TypeChanges, $TargetPriority, $Level) = @_;
13652    my $Type_Problems_Count = 0;
13653    foreach my $Type_Name (sort keys(%{$TypeChanges}))
13654    {
13655        my %Kinds_Target = ();
13656        foreach my $Kind (keys(%{$TypeChanges->{$Type_Name}}))
13657        {
13658            foreach my $Location (keys(%{$TypeChanges->{$Type_Name}{$Kind}}))
13659            {
13660                my $Target = $TypeChanges->{$Type_Name}{$Kind}{$Location}{"Target"};
13661                my $Priority = getProblemSeverity($Level, $Kind);
13662                next if($Priority ne $TargetPriority);
13663                if($Kinds_Target{$Kind}{$Target}) {
13664                    next;
13665                }
13666                if(cmpSeverities($Type_MaxSeverity{$Level}{$Type_Name}{$Kind}{$Target}, $Priority))
13667                { # select a problem with the highest priority
13668                    next;
13669                }
13670                $Kinds_Target{$Kind}{$Target} = 1;
13671                $Type_Problems_Count += 1;
13672            }
13673        }
13674    }
13675    return $Type_Problems_Count;
13676}
13677
13678sub get_Summary($)
13679{
13680    my $Level = $_[0];
13681    my ($Added, $Removed, $I_Problems_High, $I_Problems_Medium, $I_Problems_Low, $T_Problems_High,
13682    $C_Problems_Low, $T_Problems_Medium, $T_Problems_Low, $I_Other, $T_Other) = (0,0,0,0,0,0,0,0,0,0,0);
13683    %{$RESULT{$Level}} = (
13684        "Problems"=>0,
13685        "Warnings"=>0,
13686        "Affected"=>0 );
13687    # check rules
13688    foreach my $Interface (sort keys(%{$CompatProblems{$Level}}))
13689    {
13690        foreach my $Kind (keys(%{$CompatProblems{$Level}{$Interface}}))
13691        {
13692            if(not defined $CompatRules{$Level}{$Kind})
13693            { # unknown rule
13694                if(not $UnknownRules{$Level}{$Kind})
13695                { # only one warning
13696                    printMsg("WARNING", "unknown rule \"$Kind\" (\"$Level\")");
13697                    $UnknownRules{$Level}{$Kind}=1;
13698                }
13699                delete($CompatProblems{$Level}{$Interface}{$Kind});
13700            }
13701        }
13702    }
13703    foreach my $Interface (sort keys(%{$CompatProblems{$Level}}))
13704    {
13705        foreach my $Kind (sort keys(%{$CompatProblems{$Level}{$Interface}}))
13706        {
13707            if($CompatRules{$Level}{$Kind}{"Kind"} eq "Symbols")
13708            {
13709                foreach my $Location (sort keys(%{$CompatProblems{$Level}{$Interface}{$Kind}}))
13710                {
13711                    my $Priority = getProblemSeverity($Level, $Kind);
13712                    if($Kind eq "Added_Symbol") {
13713                        $Added += 1;
13714                    }
13715                    elsif($Kind eq "Removed_Symbol")
13716                    {
13717                        $Removed += 1;
13718                        $TotalAffected{$Level}{$Interface} = $Priority;
13719                    }
13720                    else
13721                    {
13722                        if($Priority eq "Safe") {
13723                            $I_Other += 1;
13724                        }
13725                        elsif($Priority eq "High") {
13726                            $I_Problems_High += 1;
13727                        }
13728                        elsif($Priority eq "Medium") {
13729                            $I_Problems_Medium += 1;
13730                        }
13731                        elsif($Priority eq "Low") {
13732                            $I_Problems_Low += 1;
13733                        }
13734                        if(($Priority ne "Low" or $StrictCompat)
13735                        and $Priority ne "Safe") {
13736                            $TotalAffected{$Level}{$Interface} = $Priority;
13737                        }
13738                    }
13739                }
13740            }
13741        }
13742    }
13743    my %TypeChanges = ();
13744    foreach my $Interface (sort keys(%{$CompatProblems{$Level}}))
13745    {
13746        foreach my $Kind (keys(%{$CompatProblems{$Level}{$Interface}}))
13747        {
13748            if($CompatRules{$Level}{$Kind}{"Kind"} eq "Types")
13749            {
13750                foreach my $Location (sort {cmp_locations($b, $a)} sort keys(%{$CompatProblems{$Level}{$Interface}{$Kind}}))
13751                {
13752                    my $Type_Name = $CompatProblems{$Level}{$Interface}{$Kind}{$Location}{"Type_Name"};
13753                    my $Target = $CompatProblems{$Level}{$Interface}{$Kind}{$Location}{"Target"};
13754                    my $Priority = getProblemSeverity($Level, $Kind);
13755                    if(cmpSeverities($Type_MaxSeverity{$Level}{$Type_Name}{$Kind}{$Target}, $Priority))
13756                    { # select a problem with the highest priority
13757                        next;
13758                    }
13759                    if(($Priority ne "Low" or $StrictCompat)
13760                    and $Priority ne "Safe") {
13761                        $TotalAffected{$Level}{$Interface} = maxSeverity($TotalAffected{$Level}{$Interface}, $Priority);
13762                    }
13763                    %{$TypeChanges{$Type_Name}{$Kind}{$Location}} = %{$CompatProblems{$Level}{$Interface}{$Kind}{$Location}};
13764                    $Type_MaxSeverity{$Level}{$Type_Name}{$Kind}{$Target} = maxSeverity($Type_MaxSeverity{$Level}{$Type_Name}{$Kind}{$Target}, $Priority);
13765                }
13766            }
13767        }
13768    }
13769
13770    $T_Problems_High = get_TypeProblems_Count(\%TypeChanges, "High", $Level);
13771    $T_Problems_Medium = get_TypeProblems_Count(\%TypeChanges, "Medium", $Level);
13772    $T_Problems_Low = get_TypeProblems_Count(\%TypeChanges, "Low", $Level);
13773    $T_Other = get_TypeProblems_Count(\%TypeChanges, "Safe", $Level);
13774
13775    if($CheckObjectsOnly)
13776    { # only removed exported symbols
13777        $RESULT{$Level}{"Affected"} = $Removed*100/keys(%{$Symbol_Library{1}});
13778    }
13779    else
13780    { # changed and removed public symbols
13781        my $SCount = keys(%{$CheckedSymbols{$Level}});
13782        if($ExtendedCheck)
13783        { # don't count external_func_0 for constants
13784            $SCount-=1;
13785        }
13786        if($SCount)
13787        {
13788            my %Weight = (
13789                "High" => 100,
13790                "Medium" => 50,
13791                "Low" => 25
13792            );
13793            foreach (keys(%{$TotalAffected{$Level}})) {
13794                $RESULT{$Level}{"Affected"}+=$Weight{$TotalAffected{$Level}{$_}};
13795            }
13796            $RESULT{$Level}{"Affected"} = $RESULT{$Level}{"Affected"}/$SCount;
13797        }
13798        else {
13799            $RESULT{$Level}{"Affected"} = 0;
13800        }
13801    }
13802    $RESULT{$Level}{"Affected"} = show_number($RESULT{$Level}{"Affected"});
13803    if($RESULT{$Level}{"Affected"}>=100) {
13804        $RESULT{$Level}{"Affected"} = 100;
13805    }
13806
13807    $RESULT{$Level}{"Problems"} += $Removed;
13808    $RESULT{$Level}{"Problems"} += $T_Problems_High + $I_Problems_High;
13809    $RESULT{$Level}{"Problems"} += $T_Problems_Medium + $I_Problems_Medium;
13810    if($StrictCompat) {
13811        $RESULT{$Level}{"Problems"} += $T_Problems_Low + $I_Problems_Low;
13812    }
13813    else {
13814        $RESULT{$Level}{"Warnings"} += $T_Problems_Low + $I_Problems_Low;
13815    }
13816
13817    if($C_Problems_Low = keys(%{$ProblemsWithConstants{$Level}}))
13818    {
13819        if(defined $CompatRules{$Level}{"Changed_Constant"})
13820        {
13821            if($StrictCompat) {
13822                $RESULT{$Level}{"Problems"} += $C_Problems_Low;
13823            }
13824            else {
13825                $RESULT{$Level}{"Warnings"} += $C_Problems_Low;
13826            }
13827        }
13828        else
13829        {
13830            printMsg("WARNING", "unknown rule \"Changed_Constant\" (\"$Level\")");
13831            $C_Problems_Low = 0;
13832        }
13833    }
13834    if($CheckImpl and $Level eq "Binary")
13835    {
13836        if($StrictCompat) {
13837            $RESULT{$Level}{"Problems"} += keys(%ImplProblems);
13838        }
13839        else {
13840            $RESULT{$Level}{"Warnings"} += keys(%ImplProblems);
13841        }
13842    }
13843    if($RESULT{$Level}{"Problems"}
13844    and $RESULT{$Level}{"Affected"}) {
13845        $RESULT{$Level}{"Verdict"} = "incompatible";
13846    }
13847    else {
13848        $RESULT{$Level}{"Verdict"} = "compatible";
13849    }
13850
13851    my $TotalTypes = keys(%{$CheckedTypes{$Level}});
13852    if(not $TotalTypes)
13853    { # list all the types
13854        $TotalTypes = keys(%{$TName_Tid{1}});
13855    }
13856
13857    my ($Arch1, $Arch2) = (getArch(1), getArch(2));
13858    my ($GccV1, $GccV2) = (getGccVersion(1), getGccVersion(2));
13859
13860    my ($TestInfo, $TestResults, $Problem_Summary) = ();
13861
13862    if($ReportFormat eq "xml")
13863    { # XML
13864        # test info
13865        $TestInfo .= "  <library>$TargetLibraryName</library>\n";
13866        $TestInfo .= "  <version1>\n";
13867        $TestInfo .= "    <number>".$Descriptor{1}{"Version"}."</number>\n";
13868        $TestInfo .= "    <architecture>$Arch1</architecture>\n";
13869        $TestInfo .= "    <gcc>$GccV1</gcc>\n";
13870        $TestInfo .= "  </version1>\n";
13871
13872        $TestInfo .= "  <version2>\n";
13873        $TestInfo .= "    <number>".$Descriptor{2}{"Version"}."</number>\n";
13874        $TestInfo .= "    <architecture>$Arch2</architecture>\n";
13875        $TestInfo .= "    <gcc>$GccV2</gcc>\n";
13876        $TestInfo .= "  </version2>\n";
13877        $TestInfo = "<test_info>\n".$TestInfo."</test_info>\n\n";
13878
13879        # test results
13880        $TestResults .= "  <headers>\n";
13881        foreach my $Name (sort {lc($Registered_Headers{1}{$a}{"Identity"}) cmp lc($Registered_Headers{1}{$b}{"Identity"})} keys(%{$Registered_Headers{1}}))
13882        {
13883            my $Identity = $Registered_Headers{1}{$Name}{"Identity"};
13884            my $Comment = ($Identity=~/[\/\\]/)?" ($Identity)":"";
13885            $TestResults .= "    <name>".get_filename($Name).$Comment."</name>\n";
13886        }
13887        $TestResults .= "  </headers>\n";
13888
13889        $TestResults .= "  <libs>\n";
13890        foreach my $Library (sort {lc($a) cmp lc($b)}  keys(%{$Library_Symbol{1}}))
13891        {
13892            $Library.=" (.$LIB_EXT)" if($Library!~/\.\w+\Z/);
13893            $TestResults .= "    <name>$Library</name>\n";
13894        }
13895        $TestResults .= "  </libs>\n";
13896
13897        $TestResults .= "  <symbols>".(keys(%{$CheckedSymbols{$Level}}) - keys(%ExtendedSymbols))."</symbols>\n";
13898        $TestResults .= "  <types>".$TotalTypes."</types>\n";
13899
13900        $TestResults .= "  <verdict>".$RESULT{$Level}{"Verdict"}."</verdict>\n";
13901        $TestResults .= "  <affected>".$RESULT{$Level}{"Affected"}."</affected>\n";
13902        $TestResults = "<test_results>\n".$TestResults."</test_results>\n\n";
13903
13904        # problem summary
13905        $Problem_Summary .= "  <added_symbols>".$Added."</added_symbols>\n";
13906        $Problem_Summary .= "  <removed_symbols>".$Removed."</removed_symbols>\n";
13907
13908        $Problem_Summary .= "  <problems_with_types>\n";
13909        $Problem_Summary .= "    <high>$T_Problems_High</high>\n";
13910        $Problem_Summary .= "    <medium>$T_Problems_Medium</medium>\n";
13911        $Problem_Summary .= "    <low>$T_Problems_Low</low>\n";
13912        $Problem_Summary .= "    <safe>$T_Other</safe>\n";
13913        $Problem_Summary .= "  </problems_with_types>\n";
13914
13915        $Problem_Summary .= "  <problems_with_symbols>\n";
13916        $Problem_Summary .= "    <high>$I_Problems_High</high>\n";
13917        $Problem_Summary .= "    <medium>$I_Problems_Medium</medium>\n";
13918        $Problem_Summary .= "    <low>$I_Problems_Low</low>\n";
13919        $Problem_Summary .= "    <safe>$I_Other</safe>\n";
13920        $Problem_Summary .= "  </problems_with_symbols>\n";
13921
13922        $Problem_Summary .= "  <problems_with_constants>\n";
13923        $Problem_Summary .= "    <low>$C_Problems_Low</low>\n";
13924        $Problem_Summary .= "  </problems_with_constants>\n";
13925        if($CheckImpl and $Level eq "Binary")
13926        {
13927            $Problem_Summary .= "  <impl>\n";
13928            $Problem_Summary .= "    <low>".keys(%ImplProblems)."</low>\n";
13929            $Problem_Summary .= "  </impl>\n";
13930        }
13931        $Problem_Summary = "<problem_summary>\n".$Problem_Summary."</problem_summary>\n\n";
13932
13933        return ($TestInfo.$TestResults.$Problem_Summary, "");
13934    }
13935    else
13936    { # HTML
13937        # test info
13938        $TestInfo = "<h2>Test Info</h2><hr/>\n";
13939        $TestInfo .= "<table class='summary'>\n";
13940        $TestInfo .= "<tr><th>".ucfirst($TargetComponent)." Name</th><td>$TargetLibraryFName</td></tr>\n";
13941
13942        my (@VInf1, @VInf2, $AddTestInfo) = ();
13943        if($Arch1 ne "unknown"
13944        and $Arch2 ne "unknown")
13945        { # CPU arch
13946            if($Arch1 eq $Arch2)
13947            { # go to the separate section
13948                $AddTestInfo .= "<tr><th>CPU Type</th><td>".showArch($Arch1)."</td></tr>\n";
13949            }
13950            else
13951            { # go to the version number
13952                push(@VInf1, showArch($Arch1));
13953                push(@VInf2, showArch($Arch2));
13954            }
13955        }
13956        if($GccV1 ne "unknown"
13957        and $GccV2 ne "unknown"
13958        and $OStarget ne "windows")
13959        { # GCC version
13960            if($GccV1 eq $GccV2)
13961            { # go to the separate section
13962                $AddTestInfo .= "<tr><th>GCC Version</th><td>$GccV1</td></tr>\n";
13963            }
13964            else
13965            { # go to the version number
13966                push(@VInf1, "gcc ".$GccV1);
13967                push(@VInf2, "gcc ".$GccV2);
13968            }
13969        }
13970        # show long version names with GCC version and CPU architecture name (if different)
13971        $TestInfo .= "<tr><th>Version #1</th><td>".$Descriptor{1}{"Version"}.(@VInf1?" (".join(", ", reverse(@VInf1)).")":"")."</td></tr>\n";
13972        $TestInfo .= "<tr><th>Version #2</th><td>".$Descriptor{2}{"Version"}.(@VInf2?" (".join(", ", reverse(@VInf2)).")":"")."</td></tr>\n";
13973        $TestInfo .= $AddTestInfo;
13974        #if($COMMON_LANGUAGE{1}) {
13975        #    $TestInfo .= "<tr><th>Language</th><td>".$COMMON_LANGUAGE{1}."</td></tr>\n";
13976        #}
13977        if($ExtendedCheck) {
13978            $TestInfo .= "<tr><th>Mode</th><td>Extended</td></tr>\n";
13979        }
13980        if($JoinReport)
13981        {
13982            if($Level eq "Binary") {
13983                $TestInfo .= "<tr><th>Subject</th><td width='150px'>Binary Compatibility</td></tr>\n"; # Run-time
13984            }
13985            if($Level eq "Source") {
13986                $TestInfo .= "<tr><th>Subject</th><td width='150px'>Source Compatibility</td></tr>\n"; # Build-time
13987            }
13988        }
13989        $TestInfo .= "</table>\n";
13990
13991        # test results
13992        $TestResults = "<h2>Test Results</h2><hr/>\n";
13993        $TestResults .= "<table class='summary'>";
13994
13995        my $Headers_Link = "0";
13996        $Headers_Link = "<a href='#Headers' style='color:Blue;'>".keys(%{$Registered_Headers{1}})."</a>" if(keys(%{$Registered_Headers{1}})>0);
13997        $TestResults .= "<tr><th>Total Header Files</th><td>".($CheckObjectsOnly?"0&#160;(not&#160;analyzed)":$Headers_Link)."</td></tr>\n";
13998
13999        if(not $ExtendedCheck)
14000        {
14001            my $Libs_Link = "0";
14002            $Libs_Link = "<a href='#Libs' style='color:Blue;'>".keys(%{$Library_Symbol{1}})."</a>" if(keys(%{$Library_Symbol{1}})>0);
14003            $TestResults .= "<tr><th>Total ".ucfirst($SLIB_TYPE)." Libraries</th><td>".($CheckHeadersOnly?"0&#160;(not&#160;analyzed)":$Libs_Link)."</td></tr>\n";
14004        }
14005
14006        $TestResults .= "<tr><th>Total Symbols / Types</th><td>".(keys(%{$CheckedSymbols{$Level}}) - keys(%ExtendedSymbols))." / ".$TotalTypes."</td></tr>\n";
14007
14008        my $META_DATA = "verdict:".$RESULT{$Level}{"Verdict"}.";";
14009        if($JoinReport) {
14010            $META_DATA = "kind:".lc($Level).";".$META_DATA;
14011        }
14012        $TestResults .= "<tr><th>Verdict</th>";
14013        if($RESULT{$Level}{"Verdict"} eq "incompatible") {
14014            $TestResults .= "<td><span style='color:Red;'><b>Incompatible<br/>(".$RESULT{$Level}{"Affected"}."%)</b></span></td>";
14015        }
14016        else {
14017            $TestResults .= "<td><span style='color:Green;'><b>Compatible</b></span></td>";
14018        }
14019        $TestResults .= "</tr>\n";
14020        $TestResults .= "</table>\n";
14021
14022        $META_DATA .= "affected:".$RESULT{$Level}{"Affected"}.";";# in percents
14023        # problem summary
14024        $Problem_Summary = "<h2>Problem Summary</h2><hr/>\n";
14025        $Problem_Summary .= "<table class='summary'>";
14026        $Problem_Summary .= "<tr><th></th><th style='text-align:center;'>Severity</th><th style='text-align:center;'>Count</th></tr>";
14027
14028        my $Added_Link = "0";
14029        if($Added>0)
14030        {
14031            if($JoinReport) {
14032                $Added_Link = "<a href='#".$Level."_Added' style='color:Blue;'>$Added</a>";
14033            }
14034            else {
14035                $Added_Link = "<a href='#Added' style='color:Blue;'>$Added</a>";
14036            }
14037        }
14038        $META_DATA .= "added:$Added;";
14039        $Problem_Summary .= "<tr><th>Added Symbols</th><td>-</td><td".getStyle("I", "A", $Added).">$Added_Link</td></tr>\n";
14040
14041        my $Removed_Link = "0";
14042        if($Removed>0)
14043        {
14044            if($JoinReport) {
14045                $Removed_Link = "<a href='#".$Level."_Removed' style='color:Blue;'>$Removed</a>"
14046            }
14047            else {
14048                $Removed_Link = "<a href='#Removed' style='color:Blue;'>$Removed</a>"
14049            }
14050        }
14051        $META_DATA .= "removed:$Removed;";
14052        $Problem_Summary .= "<tr><th>Removed Symbols</th>";
14053        $Problem_Summary .= "<td>High</td><td".getStyle("I", "R", $Removed).">$Removed_Link</td></tr>\n";
14054
14055        my $TH_Link = "0";
14056        $TH_Link = "<a href='#".get_Anchor("Type", $Level, "High")."' style='color:Blue;'>$T_Problems_High</a>" if($T_Problems_High>0);
14057        $TH_Link = "n/a" if($CheckObjectsOnly);
14058        $META_DATA .= "type_problems_high:$T_Problems_High;";
14059        $Problem_Summary .= "<tr><th rowspan='3'>Problems with<br/>Data Types</th>";
14060        $Problem_Summary .= "<td>High</td><td".getStyle("T", "H", $T_Problems_High).">$TH_Link</td></tr>\n";
14061
14062        my $TM_Link = "0";
14063        $TM_Link = "<a href='#".get_Anchor("Type", $Level, "Medium")."' style='color:Blue;'>$T_Problems_Medium</a>" if($T_Problems_Medium>0);
14064        $TM_Link = "n/a" if($CheckObjectsOnly);
14065        $META_DATA .= "type_problems_medium:$T_Problems_Medium;";
14066        $Problem_Summary .= "<tr><td>Medium</td><td".getStyle("T", "M", $T_Problems_Medium).">$TM_Link</td></tr>\n";
14067
14068        my $TL_Link = "0";
14069        $TL_Link = "<a href='#".get_Anchor("Type", $Level, "Low")."' style='color:Blue;'>$T_Problems_Low</a>" if($T_Problems_Low>0);
14070        $TL_Link = "n/a" if($CheckObjectsOnly);
14071        $META_DATA .= "type_problems_low:$T_Problems_Low;";
14072        $Problem_Summary .= "<tr><td>Low</td><td".getStyle("T", "L", $T_Problems_Low).">$TL_Link</td></tr>\n";
14073
14074        my $IH_Link = "0";
14075        $IH_Link = "<a href='#".get_Anchor("Symbol", $Level, "High")."' style='color:Blue;'>$I_Problems_High</a>" if($I_Problems_High>0);
14076        $IH_Link = "n/a" if($CheckObjectsOnly);
14077        $META_DATA .= "interface_problems_high:$I_Problems_High;";
14078        $Problem_Summary .= "<tr><th rowspan='3'>Problems with<br/>Symbols</th>";
14079        $Problem_Summary .= "<td>High</td><td".getStyle("I", "H", $I_Problems_High).">$IH_Link</td></tr>\n";
14080
14081        my $IM_Link = "0";
14082        $IM_Link = "<a href='#".get_Anchor("Symbol", $Level, "Medium")."' style='color:Blue;'>$I_Problems_Medium</a>" if($I_Problems_Medium>0);
14083        $IM_Link = "n/a" if($CheckObjectsOnly);
14084        $META_DATA .= "interface_problems_medium:$I_Problems_Medium;";
14085        $Problem_Summary .= "<tr><td>Medium</td><td".getStyle("I", "M", $I_Problems_Medium).">$IM_Link</td></tr>\n";
14086
14087        my $IL_Link = "0";
14088        $IL_Link = "<a href='#".get_Anchor("Symbol", $Level, "Low")."' style='color:Blue;'>$I_Problems_Low</a>" if($I_Problems_Low>0);
14089        $IL_Link = "n/a" if($CheckObjectsOnly);
14090        $META_DATA .= "interface_problems_low:$I_Problems_Low;";
14091        $Problem_Summary .= "<tr><td>Low</td><td".getStyle("I", "L", $I_Problems_Low).">$IL_Link</td></tr>\n";
14092
14093        my $ChangedConstants_Link = "0";
14094        if(keys(%{$CheckedSymbols{$Level}}) and $C_Problems_Low)
14095        {
14096            if($JoinReport) {
14097                $ChangedConstants_Link = "<a href='#".$Level."_Changed_Constants' style='color:Blue;'>$C_Problems_Low</a>";
14098            }
14099            else {
14100                $ChangedConstants_Link = "<a href='#Changed_Constants' style='color:Blue;'>$C_Problems_Low</a>";
14101            }
14102        }
14103        $ChangedConstants_Link = "n/a" if($CheckObjectsOnly);
14104        $META_DATA .= "changed_constants:$C_Problems_Low;";
14105        $Problem_Summary .= "<tr><th>Problems with<br/>Constants</th><td>Low</td><td".getStyle("C", "L", $C_Problems_Low).">$ChangedConstants_Link</td></tr>\n";
14106
14107        if($CheckImpl and $Level eq "Binary")
14108        {
14109            my $ChangedImpl_Link = "0";
14110            $ChangedImpl_Link = "<a href='#Changed_Implementation' style='color:Blue;'>".keys(%ImplProblems)."</a>" if(keys(%ImplProblems)>0);
14111            $ChangedImpl_Link = "n/a" if($CheckHeadersOnly);
14112            $META_DATA .= "changed_implementation:".keys(%ImplProblems).";";
14113            $Problem_Summary .= "<tr><th>Problems with<br/>Implementation</th><td>Low</td><td".getStyle("Imp", "L", int(keys(%ImplProblems))).">$ChangedImpl_Link</td></tr>\n";
14114        }
14115        # Safe Changes
14116        if($T_Other and not $CheckObjectsOnly)
14117        {
14118            my $TS_Link = "<a href='#".get_Anchor("Type", $Level, "Safe")."' style='color:Blue;'>$T_Other</a>";
14119            $Problem_Summary .= "<tr><th>Other Changes<br/>in Data Types</th><td>-</td><td".getStyle("T", "S", $T_Other).">$TS_Link</td></tr>\n";
14120        }
14121
14122        if($I_Other and not $CheckObjectsOnly)
14123        {
14124            my $IS_Link = "<a href='#".get_Anchor("Symbol", $Level, "Safe")."' style='color:Blue;'>$I_Other</a>";
14125            $Problem_Summary .= "<tr><th>Other Changes<br/>in Symbols</th><td>-</td><td".getStyle("I", "S", $I_Other).">$IS_Link</td></tr>\n";
14126        }
14127
14128        $META_DATA .= "tool_version:$TOOL_VERSION";
14129        $Problem_Summary .= "</table>\n";
14130        # $TestInfo = getLegend().$TestInfo;
14131        return ($TestInfo.$TestResults.$Problem_Summary, $META_DATA);
14132    }
14133}
14134
14135sub getStyle($$$)
14136{
14137    my ($Subj, $Act, $Num) = @_;
14138    my %Style = (
14139        "A"=>"new",
14140        "R"=>"failed",
14141        "S"=>"passed",
14142        "L"=>"warning",
14143        "M"=>"failed",
14144        "H"=>"failed"
14145    );
14146    if($Num>0) {
14147        return " class='".$Style{$Act}."'";
14148    }
14149    return "";
14150}
14151
14152sub show_number($)
14153{
14154    if($_[0])
14155    {
14156        my $Num = cut_off_number($_[0], 2, 0);
14157        if($Num eq "0")
14158        {
14159            foreach my $P (3 .. 7)
14160            {
14161                $Num = cut_off_number($_[0], $P, 1);
14162                if($Num ne "0") {
14163                    last;
14164                }
14165            }
14166        }
14167        if($Num eq "0") {
14168            $Num = $_[0];
14169        }
14170        return $Num;
14171    }
14172    return $_[0];
14173}
14174
14175sub cut_off_number($$$)
14176{
14177    my ($num, $digs_to_cut, $z) = @_;
14178    if($num!~/\./)
14179    {
14180        $num .= ".";
14181        foreach (1 .. $digs_to_cut-1) {
14182            $num .= "0";
14183        }
14184    }
14185    elsif($num=~/\.(.+)\Z/ and length($1)<$digs_to_cut-1)
14186    {
14187        foreach (1 .. $digs_to_cut - 1 - length($1)) {
14188            $num .= "0";
14189        }
14190    }
14191    elsif($num=~/\d+\.(\d){$digs_to_cut,}/) {
14192      $num=sprintf("%.".($digs_to_cut-1)."f", $num);
14193    }
14194    $num=~s/\.[0]+\Z//g;
14195    if($z) {
14196        $num=~s/(\.[1-9]+)[0]+\Z/$1/g;
14197    }
14198    return $num;
14199}
14200
14201sub get_Report_ChangedConstants($)
14202{
14203    my $Level = $_[0];
14204    my $CHANGED_CONSTANTS = "";
14205    my %ReportMap = ();
14206    foreach my $Constant (keys(%{$ProblemsWithConstants{$Level}})) {
14207        $ReportMap{$Constants{1}{$Constant}{"Header"}}{$Constant} = 1;
14208    }
14209    my $Kind = "Changed_Constant";
14210    if(not defined $CompatRules{$Level}{$Kind}) {
14211        return "";
14212    }
14213    if($ReportFormat eq "xml")
14214    { # XML
14215        foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
14216        {
14217            $CHANGED_CONSTANTS .= "  <header name=\"$HeaderName\">\n";
14218            foreach my $Constant (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
14219            {
14220                $CHANGED_CONSTANTS .= "    <constant name=\"$Constant\">\n";
14221                my $Change = $CompatRules{$Level}{$Kind}{"Change"};
14222                my $Effect = $CompatRules{$Level}{$Kind}{"Effect"};
14223                my $Overcome = $CompatRules{$Level}{$Kind}{"Overcome"};
14224                $CHANGED_CONSTANTS .= "      <problem id=\"$Kind\">\n";
14225                $CHANGED_CONSTANTS .= "        <change".getXmlParams($Change, $ProblemsWithConstants{$Level}{$Constant}).">$Change</change>\n";
14226                $CHANGED_CONSTANTS .= "        <effect".getXmlParams($Effect, $ProblemsWithConstants{$Level}{$Constant}).">$Effect</effect>\n";
14227                $CHANGED_CONSTANTS .= "        <overcome".getXmlParams($Overcome, $ProblemsWithConstants{$Level}{$Constant}).">$Overcome</overcome>\n";
14228                $CHANGED_CONSTANTS .= "      </problem>\n";
14229                $CHANGED_CONSTANTS .= "    </constant>\n";
14230            }
14231            $CHANGED_CONSTANTS .= "    </header>\n";
14232        }
14233        $CHANGED_CONSTANTS = "<problems_with_constants severity=\"Low\">\n".$CHANGED_CONSTANTS."</problems_with_constants>\n\n";
14234    }
14235    else
14236    { # HTML
14237        my $Number = 0;
14238        foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
14239        {
14240            $CHANGED_CONSTANTS .= "<span class='h_name'>$HeaderName</span><br/>\n";
14241            foreach my $Name (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
14242            {
14243                $Number += 1;
14244                my $Change = applyMacroses($Level, $Kind, $CompatRules{$Level}{$Kind}{"Change"}, $ProblemsWithConstants{$Level}{$Name});
14245                my $Effect = $CompatRules{$Level}{$Kind}{"Effect"};
14246                my $Report = "<tr><th>1</th><td align='left' valign='top'>".$Change."</td><td align='left' valign='top'>$Effect</td></tr>\n";
14247                $Report = $ContentDivStart."<table class='ptable'><tr><th width='2%'></th><th width='47%'>Change</th><th>Effect</th></tr>".$Report."</table><br/>$ContentDivEnd\n";
14248                $Report = $ContentSpanStart."<span class='extendable'>[+]</span> ".$Name.$ContentSpanEnd."<br/>\n".$Report;
14249                $CHANGED_CONSTANTS .= insertIDs($Report);
14250            }
14251            $CHANGED_CONSTANTS .= "<br/>\n";
14252        }
14253        if($CHANGED_CONSTANTS)
14254        {
14255            my $Anchor = "<a name='Changed_Constants'></a>";
14256            if($JoinReport) {
14257                $Anchor = "<a name='".$Level."_Changed_Constants'></a>";
14258            }
14259            $CHANGED_CONSTANTS = $Anchor."<h2>Problems with Constants ($Number)</h2><hr/>\n".$CHANGED_CONSTANTS.$TOP_REF."<br/>\n";
14260        }
14261    }
14262    return $CHANGED_CONSTANTS;
14263}
14264
14265sub get_Report_Impl()
14266{
14267    my $CHANGED_IMPLEMENTATION = "";
14268    my %ReportMap = ();
14269    foreach my $Interface (sort keys(%ImplProblems))
14270    {
14271        my $HeaderName = $CompleteSignature{1}{$Interface}{"Header"};
14272        my $DyLib = $Symbol_Library{1}{$Interface};
14273        $ReportMap{$HeaderName}{$DyLib}{$Interface} = 1;
14274    }
14275    my $Changed_Number = 0;
14276    foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
14277    {
14278        foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
14279        {
14280            my $FDyLib=$DyLib.($DyLib!~/\.\w+\Z/?" (.$LIB_EXT)":"");
14281            if($HeaderName) {
14282                $CHANGED_IMPLEMENTATION .= "<span class='h_name'>$HeaderName</span>, <span class='lib_name'>$FDyLib</span><br/>\n";
14283            }
14284            else {
14285                $CHANGED_IMPLEMENTATION .= "<span class='lib_name'>$DyLib</span><br/>\n";
14286            }
14287            my %NameSpaceSymbols = ();
14288            foreach my $Interface (keys(%{$ReportMap{$HeaderName}{$DyLib}})) {
14289                $NameSpaceSymbols{get_IntNameSpace($Interface, 2)}{$Interface} = 1;
14290            }
14291            foreach my $NameSpace (sort keys(%NameSpaceSymbols))
14292            {
14293                $CHANGED_IMPLEMENTATION .= ($NameSpace)?"<span class='ns_title'>namespace</span> <span class='ns'>$NameSpace</span><br/>\n":"";
14294                my @SortedInterfaces = sort {lc(get_Signature($a, 1)) cmp lc(get_Signature($b, 1))} keys(%{$NameSpaceSymbols{$NameSpace}});
14295                foreach my $Interface (@SortedInterfaces)
14296                {
14297                    $Changed_Number += 1;
14298                    my $Signature = get_Signature($Interface, 1);
14299                    if($NameSpace) {
14300                        $Signature=~s/\b\Q$NameSpace\E::\b//g;
14301                    }
14302                    $CHANGED_IMPLEMENTATION .= insertIDs($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");
14303                }
14304            }
14305            $CHANGED_IMPLEMENTATION .= "<br/>\n";
14306        }
14307    }
14308    if($CHANGED_IMPLEMENTATION) {
14309        $CHANGED_IMPLEMENTATION = "<a name='Changed_Implementation'></a><h2>Problems with Implementation ($Changed_Number)</h2><hr/>\n".$CHANGED_IMPLEMENTATION.$TOP_REF."<br/>\n";
14310    }
14311
14312    # clean memory
14313    %ImplProblems = ();
14314
14315    return $CHANGED_IMPLEMENTATION;
14316}
14317
14318sub getTitle($$$)
14319{
14320    my ($Header, $Library, $NameSpace) = @_;
14321    my $Title = "";
14322    if($Library and $Library!~/\.\w+\Z/) {
14323        $Library .= " (.$LIB_EXT)";
14324    }
14325    if($Header and $Library)
14326    {
14327        $Title .= "<span class='h_name'>$Header</span>";
14328        $Title .= ", <span class='lib_name'>$Library</span><br/>\n";
14329    }
14330    elsif($Library) {
14331        $Title .= "<span class='lib_name'>$Library</span><br/>\n";
14332    }
14333    elsif($Header) {
14334        $Title .= "<span class='h_name'>$Header</span><br/>\n";
14335    }
14336    if($NameSpace) {
14337        $Title .= "<span class='ns_title'>namespace</span> <span class='ns'>$NameSpace</span><br/>\n";
14338    }
14339    return $Title;
14340}
14341
14342sub get_Report_Added($)
14343{
14344    my $Level = $_[0];
14345    my $ADDED_INTERFACES = "";
14346    my %ReportMap = ();
14347    foreach my $Interface (sort keys(%{$CompatProblems{$Level}}))
14348    {
14349        foreach my $Kind (sort keys(%{$CompatProblems{$Level}{$Interface}}))
14350        {
14351            if($Kind eq "Added_Symbol")
14352            {
14353                my $HeaderName = $CompleteSignature{2}{$Interface}{"Header"};
14354                my $DyLib = $Symbol_Library{2}{$Interface};
14355                if($Level eq "Source" and $ReportFormat eq "html")
14356                { # do not show library name in HTML report
14357                    $DyLib = "";
14358                }
14359                $ReportMap{$HeaderName}{$DyLib}{$Interface} = 1;
14360            }
14361        }
14362    }
14363    if($ReportFormat eq "xml")
14364    { # XML
14365        foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
14366        {
14367            $ADDED_INTERFACES .= "  <header name=\"$HeaderName\">\n";
14368            foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
14369            {
14370                $ADDED_INTERFACES .= "    <library name=\"$DyLib\">\n";
14371                foreach my $Interface (keys(%{$ReportMap{$HeaderName}{$DyLib}})) {
14372                    $ADDED_INTERFACES .= "      <name>$Interface</name>\n";
14373                }
14374                $ADDED_INTERFACES .= "    </library>\n";
14375            }
14376            $ADDED_INTERFACES .= "  </header>\n";
14377        }
14378        $ADDED_INTERFACES = "<added_symbols>\n".$ADDED_INTERFACES."</added_symbols>\n\n";
14379    }
14380    else
14381    { # HTML
14382        my $Added_Number = 0;
14383        foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
14384        {
14385            foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
14386            {
14387                my %NameSpaceSymbols = ();
14388                foreach my $Interface (keys(%{$ReportMap{$HeaderName}{$DyLib}})) {
14389                    $NameSpaceSymbols{get_IntNameSpace($Interface, 2)}{$Interface} = 1;
14390                }
14391                foreach my $NameSpace (sort keys(%NameSpaceSymbols))
14392                {
14393                    $ADDED_INTERFACES .= getTitle($HeaderName, $DyLib, $NameSpace);
14394                    my @SortedInterfaces = sort {lc(get_Signature($a, 2)) cmp lc(get_Signature($b, 2))} keys(%{$NameSpaceSymbols{$NameSpace}});
14395                    foreach my $Interface (@SortedInterfaces)
14396                    {
14397                        $Added_Number += 1;
14398                        my $Signature = get_Signature($Interface, 2);
14399                        if($NameSpace) {
14400                            $Signature=~s/\b\Q$NameSpace\E::\b//g;
14401                        }
14402                        if($Interface=~/\A(_Z|\?)/) {
14403                            if($Signature) {
14404                                $ADDED_INTERFACES .= insertIDs($ContentSpanStart.highLight_Signature_Italic_Color($Signature).$ContentSpanEnd."<br/>\n".$ContentDivStart."<span class='mangled'>[symbol: <b>$Interface</b>]</span><br/><br/>".$ContentDivEnd."\n");
14405                            }
14406                            else {
14407                                $ADDED_INTERFACES .= "<span class=\"iname\">".$Interface."</span><br/>\n";
14408                            }
14409                        }
14410                        else {
14411                            if($Signature) {
14412                                $ADDED_INTERFACES .= "<span class=\"iname\">".highLight_Signature_Italic_Color($Signature)."</span><br/>\n";
14413                            }
14414                            else {
14415                                $ADDED_INTERFACES .= "<span class=\"iname\">".$Interface."</span><br/>\n";
14416                            }
14417                        }
14418                    }
14419                    $ADDED_INTERFACES .= "<br/>\n";
14420                }
14421            }
14422        }
14423        if($ADDED_INTERFACES)
14424        {
14425            my $Anchor = "<a name='Added'></a>";
14426            if($JoinReport) {
14427                $Anchor = "<a name='".$Level."_Added'></a>";
14428            }
14429            $ADDED_INTERFACES = $Anchor."<h2>Added Symbols ($Added_Number)</h2><hr/>\n".$ADDED_INTERFACES.$TOP_REF."<br/>\n";
14430        }
14431    }
14432    return $ADDED_INTERFACES;
14433}
14434
14435sub get_Report_Removed($)
14436{
14437    my $Level = $_[0];
14438    my $REMOVED_INTERFACES = "";
14439    my %ReportMap = ();
14440    foreach my $Symbol (sort keys(%{$CompatProblems{$Level}}))
14441    {
14442        foreach my $Kind (sort keys(%{$CompatProblems{$Level}{$Symbol}}))
14443        {
14444            if($Kind eq "Removed_Symbol")
14445            {
14446                my $HeaderName = $CompleteSignature{1}{$Symbol}{"Header"};
14447                my $DyLib = $Symbol_Library{1}{$Symbol};
14448                if($Level eq "Source" and $ReportFormat eq "html")
14449                { # do not show library name in HTML report
14450                    $DyLib = "";
14451                }
14452                $ReportMap{$HeaderName}{$DyLib}{$Symbol} = 1;
14453            }
14454        }
14455    }
14456    if($ReportFormat eq "xml")
14457    { # XML
14458        foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
14459        {
14460            $REMOVED_INTERFACES .= "  <header name=\"$HeaderName\">\n";
14461            foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
14462            {
14463                $REMOVED_INTERFACES .= "    <library name=\"$DyLib\">\n";
14464                foreach my $Symbol (keys(%{$ReportMap{$HeaderName}{$DyLib}})) {
14465                    $REMOVED_INTERFACES .= "      <name>$Symbol</name>\n";
14466                }
14467                $REMOVED_INTERFACES .= "    </library>\n";
14468            }
14469            $REMOVED_INTERFACES .= "  </header>\n";
14470        }
14471        $REMOVED_INTERFACES = "<removed_symbols>\n".$REMOVED_INTERFACES."</removed_symbols>\n\n";
14472    }
14473    else
14474    { # HTML
14475        my $Removed_Number = 0;
14476        foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
14477        {
14478            foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
14479            {
14480                my %NameSpaceSymbols = ();
14481                foreach my $Interface (keys(%{$ReportMap{$HeaderName}{$DyLib}})) {
14482                    $NameSpaceSymbols{get_IntNameSpace($Interface, 1)}{$Interface} = 1;
14483                }
14484                foreach my $NameSpace (sort keys(%NameSpaceSymbols))
14485                {
14486                    $REMOVED_INTERFACES .= getTitle($HeaderName, $DyLib, $NameSpace);
14487                    my @SortedInterfaces = sort {lc(get_Signature($a, 1)) cmp lc(get_Signature($b, 1))} keys(%{$NameSpaceSymbols{$NameSpace}});
14488                    foreach my $Symbol (@SortedInterfaces)
14489                    {
14490                        $Removed_Number += 1;
14491                        my $SubReport = "";
14492                        my $Signature = get_Signature($Symbol, 1);
14493                        if($NameSpace) {
14494                            $Signature=~s/\b\Q$NameSpace\E::\b//g;
14495                        }
14496                        if($Symbol=~/\A(_Z|\?)/)
14497                        {
14498                            if($Signature) {
14499                                $REMOVED_INTERFACES .= insertIDs($ContentSpanStart.highLight_Signature_Italic_Color($Signature).$ContentSpanEnd."<br/>\n".$ContentDivStart."<span class='mangled'>[symbol: <b>$Symbol</b>]</span><br/><br/>".$ContentDivEnd."\n");
14500                            }
14501                            else {
14502                                $REMOVED_INTERFACES .= "<span class=\"iname\">".$Symbol."</span><br/>\n";
14503                            }
14504                        }
14505                        else
14506                        {
14507                            if($Signature) {
14508                                $REMOVED_INTERFACES .= "<span class=\"iname\">".highLight_Signature_Italic_Color($Signature)."</span><br/>\n";
14509                            }
14510                            else {
14511                                $REMOVED_INTERFACES .= "<span class=\"iname\">".$Symbol."</span><br/>\n";
14512                            }
14513                        }
14514                    }
14515                }
14516                $REMOVED_INTERFACES .= "<br/>\n";
14517            }
14518        }
14519        if($REMOVED_INTERFACES)
14520        {
14521            my $Anchor = "<a name='Removed'></a><a name='Withdrawn'></a>";
14522            if($JoinReport) {
14523                $Anchor = "<a name='".$Level."_Removed'></a><a name='".$Level."_Withdrawn'></a>";
14524            }
14525            $REMOVED_INTERFACES = $Anchor."<h2>Removed Symbols ($Removed_Number)</h2><hr/>\n".$REMOVED_INTERFACES.$TOP_REF."<br/>\n";
14526        }
14527    }
14528    return $REMOVED_INTERFACES;
14529}
14530
14531sub getXmlParams($$)
14532{
14533    my ($Content, $Problem) = @_;
14534    return "" if(not $Content or not $Problem);
14535    my %XMLparams = ();
14536    foreach my $Attr (sort {$b cmp $a} keys(%{$Problem}))
14537    {
14538        my $Macro = "\@".lc($Attr);
14539        if($Content=~/\Q$Macro\E/) {
14540            $XMLparams{lc($Attr)} = $Problem->{$Attr};
14541        }
14542    }
14543    my @PString = ();
14544    foreach my $P (sort {$b cmp $a} keys(%XMLparams)) {
14545        push(@PString, $P."=\"".xmlSpecChars($XMLparams{$P})."\"");
14546    }
14547    if(@PString) {
14548        return " ".join(" ", @PString);
14549    }
14550    else {
14551        return "";
14552    }
14553}
14554
14555sub addMarkup($)
14556{
14557    my $Content = $_[0];
14558    # auto-markup
14559    $Content=~s/\n[ ]*//; # spaces
14560    $Content=~s!(\@\w+\s*\(\@\w+\))!<nowrap>$1</nowrap>!g; # @old_type (@old_size)
14561    $Content=~s!(... \(\w+\))!<nowrap><b>$1</b></nowrap>!g; # ... (va_list)
14562    $Content=~s!<nowrap>(.+?)</nowrap>!<span class='nowrap'>$1</span>!g;
14563    $Content=~s!([2-9]\))!<br/>$1!g; # 1), 2), ...
14564    if($Content=~/\ANOTE:/)
14565    { # notes
14566        $Content=~s!(NOTE):!<b>$1</b>:!g;
14567    }
14568    else {
14569        $Content=~s!(NOTE):!<br/><b>$1</b>:!g;
14570    }
14571    $Content=~s! (out)-! <b>$1</b>-!g; # out-parameters
14572    my @Keywords = (
14573        "void",
14574        "const",
14575        "static",
14576        "restrict",
14577        "volatile",
14578        "register",
14579        "virtual"
14580    );
14581    my $MKeys = join("|", @Keywords);
14582    foreach (@Keywords) {
14583        $MKeys .= "|non-".$_;
14584    }
14585    $Content=~s!(added\s*|to\s*|from\s*|became\s*)($MKeys)([^\w-]|\Z)!$1<b>$2</b>$3!ig; # intrinsic types, modifiers
14586
14587    # Markdown
14588    $Content=~s!\*\*([\w\-]+)\*\*!<b>$1</b>!ig;
14589    $Content=~s!\*([\w\-]+)\*!<i>$1</i>!ig;
14590    return $Content;
14591}
14592
14593sub applyMacroses($$$$)
14594{
14595    my ($Level, $Kind, $Content, $Problem) = @_;
14596    return "" if(not $Content or not $Problem);
14597    $Problem->{"Word_Size"} = $WORD_SIZE{2};
14598    $Content = addMarkup($Content);
14599    # macros
14600    foreach my $Attr (sort {$b cmp $a} keys(%{$Problem}))
14601    {
14602        my $Macro = "\@".lc($Attr);
14603        my $Value = $Problem->{$Attr};
14604        if(not defined $Value
14605        or $Value eq "") {
14606            next;
14607        }
14608        if($Value=~/\s\(/ and $Value!~/['"]/)
14609        { # functions
14610            $Value=~s/\s*\[[\w\-]+\]//g; # remove quals
14611            $Value=~s/\s\w+(\)|,)/$1/g; # remove parameter names
14612            $Value = black_name($Value);
14613        }
14614        elsif($Value=~/\s/) {
14615            $Value = "<span class='value'>".htmlSpecChars($Value)."</span>";
14616        }
14617        elsif($Value=~/\A\d+\Z/
14618        and ($Attr eq "Old_Size" or $Attr eq "New_Size"))
14619        { # bits to bytes
14620            if($Value % $BYTE_SIZE)
14621            { # bits
14622                if($Value==1) {
14623                    $Value = "<b>".$Value."</b> bit";
14624                }
14625                else {
14626                    $Value = "<b>".$Value."</b> bits";
14627                }
14628            }
14629            else
14630            { # bytes
14631                $Value /= $BYTE_SIZE;
14632                if($Value==1) {
14633                    $Value = "<b>".$Value."</b> byte";
14634                }
14635                else {
14636                    $Value = "<b>".$Value."</b> bytes";
14637                }
14638            }
14639        }
14640        else
14641        {
14642            $Value = "<b>".htmlSpecChars($Value)."</b>";
14643        }
14644        $Content=~s/\Q$Macro\E/$Value/g;
14645    }
14646
14647    if($Content=~/(\A|[^\@\w])\@\w/)
14648    {
14649        if(not $IncompleteRules{$Level}{$Kind})
14650        { # only one warning
14651            printMsg("WARNING", "incomplete rule \"$Kind\" (\"$Level\")");
14652            $IncompleteRules{$Level}{$Kind} = 1;
14653        }
14654    }
14655    return $Content;
14656}
14657
14658sub get_Report_SymbolProblems($$)
14659{
14660    my ($TargetSeverity, $Level) = @_;
14661    my $INTERFACE_PROBLEMS = "";
14662    my (%ReportMap, %SymbolChanges) = ();
14663    foreach my $Symbol (sort keys(%{$CompatProblems{$Level}}))
14664    {
14665        my ($SN, $SS, $SV) = separate_symbol($Symbol);
14666        if($SV and defined $CompatProblems{$Level}{$SN}) {
14667            next;
14668        }
14669        foreach my $Kind (sort keys(%{$CompatProblems{$Level}{$Symbol}}))
14670        {
14671            if($CompatRules{$Level}{$Kind}{"Kind"} eq "Symbols"
14672            and $Kind ne "Added_Symbol" and $Kind ne "Removed_Symbol")
14673            {
14674                my $HeaderName = $CompleteSignature{1}{$Symbol}{"Header"};
14675                my $DyLib = $Symbol_Library{1}{$Symbol};
14676                if(not $DyLib and my $VSym = $SymVer{1}{$Symbol})
14677                { # Symbol with Version
14678                    $DyLib = $Symbol_Library{1}{$VSym};
14679                }
14680                if(not $DyLib)
14681                { # const global data
14682                    $DyLib = "";
14683                }
14684                if($Level eq "Source" and $ReportFormat eq "html")
14685                { # do not show library name in HTML report
14686                    $DyLib = "";
14687                }
14688                %{$SymbolChanges{$Symbol}{$Kind}} = %{$CompatProblems{$Level}{$Symbol}{$Kind}};
14689                foreach my $Location (sort keys(%{$SymbolChanges{$Symbol}{$Kind}}))
14690                {
14691                    my $Priority = getProblemSeverity($Level, $Kind);
14692                    if($Priority ne $TargetSeverity) {
14693                        delete($SymbolChanges{$Symbol}{$Kind}{$Location});
14694                    }
14695                }
14696                if(not keys(%{$SymbolChanges{$Symbol}{$Kind}}))
14697                {
14698                    delete($SymbolChanges{$Symbol}{$Kind});
14699                    next;
14700                }
14701                $ReportMap{$HeaderName}{$DyLib}{$Symbol} = 1;
14702            }
14703        }
14704        if(not keys(%{$SymbolChanges{$Symbol}})) {
14705            delete($SymbolChanges{$Symbol});
14706        }
14707    }
14708    if($ReportFormat eq "xml")
14709    { # XML
14710        foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
14711        {
14712            $INTERFACE_PROBLEMS .= "  <header name=\"$HeaderName\">\n";
14713            foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
14714            {
14715                $INTERFACE_PROBLEMS .= "    <library name=\"$DyLib\">\n";
14716                foreach my $Symbol (sort {lc($tr_name{$a}) cmp lc($tr_name{$b})} keys(%SymbolChanges))
14717                {
14718                    $INTERFACE_PROBLEMS .= "      <symbol name=\"$Symbol\">\n";
14719                    foreach my $Kind (keys(%{$SymbolChanges{$Symbol}}))
14720                    {
14721                        foreach my $Location (sort keys(%{$SymbolChanges{$Symbol}{$Kind}}))
14722                        {
14723                            my %Problem = %{$SymbolChanges{$Symbol}{$Kind}{$Location}};
14724                            $Problem{"Param_Pos"} = showPos($Problem{"Param_Pos"});
14725                            $INTERFACE_PROBLEMS .= "        <problem id=\"$Kind\">\n";
14726                            my $Change = $CompatRules{$Level}{$Kind}{"Change"};
14727                            $INTERFACE_PROBLEMS .= "          <change".getXmlParams($Change, \%Problem).">$Change</change>\n";
14728                            my $Effect = $CompatRules{$Level}{$Kind}{"Effect"};
14729                            $INTERFACE_PROBLEMS .= "          <effect".getXmlParams($Effect, \%Problem).">$Effect</effect>\n";
14730                            my $Overcome = $CompatRules{$Level}{$Kind}{"Overcome"};
14731                            $INTERFACE_PROBLEMS .= "          <overcome".getXmlParams($Overcome, \%Problem).">$Overcome</overcome>\n";
14732                            $INTERFACE_PROBLEMS .= "        </problem>\n";
14733                        }
14734                    }
14735                    $INTERFACE_PROBLEMS .= "      </symbol>\n";
14736                }
14737                $INTERFACE_PROBLEMS .= "    </library>\n";
14738            }
14739            $INTERFACE_PROBLEMS .= "  </header>\n";
14740        }
14741        $INTERFACE_PROBLEMS = "<problems_with_symbols severity=\"$TargetSeverity\">\n".$INTERFACE_PROBLEMS."</problems_with_symbols>\n\n";
14742    }
14743    else
14744    { # HTML
14745        my $ProblemsNum = 0;
14746        foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
14747        {
14748            foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
14749            {
14750                my (%NameSpaceSymbols, %NewSignature) = ();
14751                foreach my $Symbol (keys(%{$ReportMap{$HeaderName}{$DyLib}})) {
14752                    $NameSpaceSymbols{get_IntNameSpace($Symbol, 1)}{$Symbol} = 1;
14753                }
14754                foreach my $NameSpace (sort keys(%NameSpaceSymbols))
14755                {
14756                    $INTERFACE_PROBLEMS .= getTitle($HeaderName, $DyLib, $NameSpace);
14757                    my @SortedInterfaces = sort {lc($tr_name{$a}) cmp lc($tr_name{$b})} keys(%{$NameSpaceSymbols{$NameSpace}});
14758                    foreach my $Symbol (@SortedInterfaces)
14759                    {
14760                        my $Signature = get_Signature($Symbol, 1);
14761                        my $SYMBOL_REPORT = "";
14762                        my $ProblemNum = 1;
14763                        foreach my $Kind (keys(%{$SymbolChanges{$Symbol}}))
14764                        {
14765                            foreach my $Location (sort keys(%{$SymbolChanges{$Symbol}{$Kind}}))
14766                            {
14767                                my %Problem = %{$SymbolChanges{$Symbol}{$Kind}{$Location}};
14768                                $Problem{"Param_Pos"} = showPos($Problem{"Param_Pos"});
14769                                if($Problem{"New_Signature"}) {
14770                                    $NewSignature{$Symbol} = $Problem{"New_Signature"};
14771                                }
14772                                if(my $Change = applyMacroses($Level, $Kind, $CompatRules{$Level}{$Kind}{"Change"}, \%Problem))
14773                                {
14774                                    my $Effect = applyMacroses($Level, $Kind, $CompatRules{$Level}{$Kind}{"Effect"}, \%Problem);
14775                                    $SYMBOL_REPORT .= "<tr><th>$ProblemNum</th><td align='left' valign='top'>".$Change."</td><td align='left' valign='top'>".$Effect."</td></tr>\n";
14776                                    $ProblemNum += 1;
14777                                    $ProblemsNum += 1;
14778                                }
14779                            }
14780                        }
14781                        $ProblemNum -= 1;
14782                        if($SYMBOL_REPORT)
14783                        {
14784                            $INTERFACE_PROBLEMS .= $ContentSpanStart."<span class='extendable'>[+]</span> ";
14785                            if($Signature) {
14786                                $INTERFACE_PROBLEMS .= highLight_Signature_Italic_Color($Signature);
14787                            }
14788                            else {
14789                                $INTERFACE_PROBLEMS .= $Symbol;
14790                            }
14791                            $INTERFACE_PROBLEMS .= " ($ProblemNum)".$ContentSpanEnd."<br/>\n";
14792                            $INTERFACE_PROBLEMS .= $ContentDivStart."\n";
14793                            if($NewSignature{$Symbol})
14794                            { # argument list changed to
14795                                $INTERFACE_PROBLEMS .= "\n<span class='new_sign_lbl'>changed to:</span><br/><span class='new_sign'>".highLight_Signature_Italic_Color($NewSignature{$Symbol})."</span><br/>\n";
14796                            }
14797                            if($Symbol=~/\A(_Z|\?)/) {
14798                                $INTERFACE_PROBLEMS .= "<span class='mangled'>&#160;&#160;&#160;&#160;[symbol: <b>$Symbol</b>]</span><br/>\n";
14799                            }
14800                            $INTERFACE_PROBLEMS .= "<table class='ptable'><tr><th width='2%'></th><th width='47%'>Change</th><th>Effect</th></tr>$SYMBOL_REPORT</table><br/>\n";
14801                            $INTERFACE_PROBLEMS .= $ContentDivEnd;
14802                            if($NameSpace) {
14803                                $INTERFACE_PROBLEMS=~s/\b\Q$NameSpace\E::\b//g;
14804                            }
14805                        }
14806                    }
14807                    $INTERFACE_PROBLEMS .= "<br/>";
14808                }
14809            }
14810        }
14811        if($INTERFACE_PROBLEMS)
14812        {
14813            $INTERFACE_PROBLEMS = insertIDs($INTERFACE_PROBLEMS);
14814            my $Title = "Problems with Symbols, $TargetSeverity Severity";
14815            if($TargetSeverity eq "Safe")
14816            { # Safe Changes
14817                $Title = "Other Changes in Symbols";
14818            }
14819            $INTERFACE_PROBLEMS = "<a name=\'".get_Anchor("Symbol", $Level, $TargetSeverity)."\'></a><a name=\'".get_Anchor("Interface", $Level, $TargetSeverity)."\'></a>\n<h2>$Title ($ProblemsNum)</h2><hr/>\n".$INTERFACE_PROBLEMS.$TOP_REF."<br/>\n";
14820        }
14821    }
14822    return $INTERFACE_PROBLEMS;
14823}
14824
14825sub get_Report_TypeProblems($$)
14826{
14827    my ($TargetSeverity, $Level) = @_;
14828    my $TYPE_PROBLEMS = "";
14829    my (%ReportMap, %TypeChanges, %TypeType) = ();
14830    foreach my $Interface (sort keys(%{$CompatProblems{$Level}}))
14831    {
14832        foreach my $Kind (keys(%{$CompatProblems{$Level}{$Interface}}))
14833        {
14834            if($CompatRules{$Level}{$Kind}{"Kind"} eq "Types")
14835            {
14836                foreach my $Location (sort {cmp_locations($b, $a)} sort keys(%{$CompatProblems{$Level}{$Interface}{$Kind}}))
14837                {
14838                    my $TypeName = $CompatProblems{$Level}{$Interface}{$Kind}{$Location}{"Type_Name"};
14839                    my $TypeType = $CompatProblems{$Level}{$Interface}{$Kind}{$Location}{"Type_Type"};
14840                    my $Target = $CompatProblems{$Level}{$Interface}{$Kind}{$Location}{"Target"};
14841                    $CompatProblems{$Level}{$Interface}{$Kind}{$Location}{"Type_Type"} = lc($TypeType);
14842                    my $Severity = getProblemSeverity($Level, $Kind);
14843                    if($Severity eq "Safe"
14844                    and $TargetSeverity ne "Safe") {
14845                        next;
14846                    }
14847                    if(not $TypeType{$TypeName}
14848                    or $TypeType{$TypeName} eq "struct")
14849                    { # register type of the type, select "class" if type has "class"- and "struct"-type changes
14850                        $TypeType{$TypeName} = $CompatProblems{$Level}{$Interface}{$Kind}{$Location}{"Type_Type"};
14851                    }
14852
14853                    if(cmpSeverities($Type_MaxSeverity{$Level}{$TypeName}{$Kind}{$Target}, $Severity))
14854                    { # select a problem with the highest priority
14855                        next;
14856                    }
14857                    %{$TypeChanges{$TypeName}{$Kind}{$Location}} = %{$CompatProblems{$Level}{$Interface}{$Kind}{$Location}};
14858                }
14859            }
14860        }
14861    }
14862    my %Kinds_Locations = ();
14863    foreach my $TypeName (keys(%TypeChanges))
14864    {
14865        my %Kinds_Target = ();
14866        foreach my $Kind (sort keys(%{$TypeChanges{$TypeName}}))
14867        {
14868            foreach my $Location (sort {cmp_locations($b, $a)} sort keys(%{$TypeChanges{$TypeName}{$Kind}}))
14869            {
14870                my $Severity = getProblemSeverity($Level, $Kind);
14871                if($Severity ne $TargetSeverity)
14872                { # other priority
14873                    delete($TypeChanges{$TypeName}{$Kind}{$Location});
14874                    next;
14875                }
14876                $Kinds_Locations{$TypeName}{$Kind}{$Location} = 1;
14877                my $Target = $TypeChanges{$TypeName}{$Kind}{$Location}{"Target"};
14878                if($Kinds_Target{$Kind}{$Target})
14879                { # duplicate target
14880                    delete($TypeChanges{$TypeName}{$Kind}{$Location});
14881                    next;
14882                }
14883                $Kinds_Target{$Kind}{$Target} = 1;
14884                my $HeaderName = $TypeInfo{1}{$TName_Tid{1}{$TypeName}}{"Header"};
14885                $ReportMap{$HeaderName}{$TypeName} = 1;
14886            }
14887            if(not keys(%{$TypeChanges{$TypeName}{$Kind}})) {
14888                delete($TypeChanges{$TypeName}{$Kind});
14889            }
14890        }
14891        if(not keys(%{$TypeChanges{$TypeName}})) {
14892            delete($TypeChanges{$TypeName});
14893        }
14894    }
14895    my @Symbols = sort {lc($tr_name{$a}?$tr_name{$a}:$a) cmp lc($tr_name{$b}?$tr_name{$b}:$b)} keys(%{$CompatProblems{$Level}});
14896    if($ReportFormat eq "xml")
14897    { # XML
14898        foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
14899        {
14900            $TYPE_PROBLEMS .= "  <header name=\"$HeaderName\">\n";
14901            foreach my $TypeName (keys(%{$ReportMap{$HeaderName}}))
14902            {
14903                $TYPE_PROBLEMS .= "    <type name=\"".xmlSpecChars($TypeName)."\">\n";
14904                foreach my $Kind (sort {$b=~/Size/ <=> $a=~/Size/} sort keys(%{$TypeChanges{$TypeName}}))
14905                {
14906                    foreach my $Location (sort {cmp_locations($b, $a)} sort keys(%{$TypeChanges{$TypeName}{$Kind}}))
14907                    {
14908                        my %Problem = %{$TypeChanges{$TypeName}{$Kind}{$Location}};
14909                        $TYPE_PROBLEMS .= "      <problem id=\"$Kind\">\n";
14910                        my $Change = $CompatRules{$Level}{$Kind}{"Change"};
14911                        $TYPE_PROBLEMS .= "        <change".getXmlParams($Change, \%Problem).">$Change</change>\n";
14912                        my $Effect = $CompatRules{$Level}{$Kind}{"Effect"};
14913                        $TYPE_PROBLEMS .= "        <effect".getXmlParams($Effect, \%Problem).">$Effect</effect>\n";
14914                        my $Overcome = $CompatRules{$Level}{$Kind}{"Overcome"};
14915                        $TYPE_PROBLEMS .= "        <overcome".getXmlParams($Overcome, \%Problem).">$Overcome</overcome>\n";
14916                        $TYPE_PROBLEMS .= "      </problem>\n";
14917                    }
14918                }
14919                $TYPE_PROBLEMS .= getAffectedSymbols($Level, $TypeName, $Kinds_Locations{$TypeName}, \@Symbols);
14920                if($Level eq "Binary" and grep {$_=~/Virtual|Base_Class/} keys(%{$Kinds_Locations{$TypeName}})) {
14921                    $TYPE_PROBLEMS .= showVTables($TypeName);
14922                }
14923                $TYPE_PROBLEMS .= "    </type>\n";
14924            }
14925            $TYPE_PROBLEMS .= "  </header>\n";
14926        }
14927        $TYPE_PROBLEMS = "<problems_with_types severity=\"$TargetSeverity\">\n".$TYPE_PROBLEMS."</problems_with_types>\n\n";
14928    }
14929    else
14930    { # HTML
14931        my $ProblemsNum = 0;
14932        foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
14933        {
14934            my (%NameSpace_Type) = ();
14935            foreach my $TypeName (keys(%{$ReportMap{$HeaderName}})) {
14936                $NameSpace_Type{parse_TypeNameSpace($TypeName, 1)}{$TypeName} = 1;
14937            }
14938            foreach my $NameSpace (sort keys(%NameSpace_Type))
14939            {
14940                $TYPE_PROBLEMS .= getTitle($HeaderName, "", $NameSpace);
14941                my @SortedTypes = sort {$TypeType{$a}." ".lc($a) cmp $TypeType{$b}." ".lc($b)} keys(%{$NameSpace_Type{$NameSpace}});
14942                foreach my $TypeName (@SortedTypes)
14943                {
14944                    my $ProblemNum = 1;
14945                    my $TYPE_REPORT = "";
14946                    foreach my $Kind (sort {$b=~/Size/ <=> $a=~/Size/} sort keys(%{$TypeChanges{$TypeName}}))
14947                    {
14948                        foreach my $Location (sort {cmp_locations($b, $a)} sort keys(%{$TypeChanges{$TypeName}{$Kind}}))
14949                        {
14950                            my %Problem = %{$TypeChanges{$TypeName}{$Kind}{$Location}};
14951                            if(my $Change = applyMacroses($Level, $Kind, $CompatRules{$Level}{$Kind}{"Change"}, \%Problem))
14952                            {
14953                                my $Effect = applyMacroses($Level, $Kind, $CompatRules{$Level}{$Kind}{"Effect"}, \%Problem);
14954                                $TYPE_REPORT .= "<tr><th>$ProblemNum</th><td align='left' valign='top'>".$Change."</td><td align='left' valign='top'>$Effect</td></tr>\n";
14955                                $ProblemNum += 1;
14956                                $ProblemsNum += 1;
14957                            }
14958                        }
14959                    }
14960                    $ProblemNum -= 1;
14961                    if($TYPE_REPORT)
14962                    {
14963                        my $Affected = getAffectedSymbols($Level, $TypeName, $Kinds_Locations{$TypeName}, \@Symbols);
14964                        my $ShowVTables = "";
14965                        if($Level eq "Binary" and grep {$_=~/Virtual|Base_Class/} keys(%{$Kinds_Locations{$TypeName}})) {
14966                            $ShowVTables = showVTables($TypeName);
14967                        }
14968                        $TYPE_PROBLEMS .= $ContentSpanStart."<span class='extendable'>[+]</span> <span class='ttype'>".$TypeType{$TypeName}."</span> ".htmlSpecChars($TypeName)." ($ProblemNum)".$ContentSpanEnd;
14969                        $TYPE_PROBLEMS .= "<br/>\n".$ContentDivStart."<table class='ptable'><tr>\n";
14970                        $TYPE_PROBLEMS .= "<th width='2%'></th><th width='47%'>Change</th>\n";
14971                        $TYPE_PROBLEMS .= "<th>Effect</th></tr>".$TYPE_REPORT."</table>\n";
14972                        $TYPE_PROBLEMS .= $ShowVTables.$Affected."<br/><br/>".$ContentDivEnd."\n";
14973                        if($NameSpace) {
14974                            $TYPE_PROBLEMS=~s/\b\Q$NameSpace\E::(\w|\~)/$1/g;
14975                        }
14976                    }
14977                }
14978                $TYPE_PROBLEMS .= "<br/>";
14979            }
14980        }
14981        if($TYPE_PROBLEMS)
14982        {
14983            $TYPE_PROBLEMS = insertIDs($TYPE_PROBLEMS);
14984            my $Title = "Problems with Data Types, $TargetSeverity Severity";
14985            if($TargetSeverity eq "Safe")
14986            { # Safe Changes
14987                $Title = "Other Changes in Data Types";
14988            }
14989            $TYPE_PROBLEMS = "<a name=\'".get_Anchor("Type", $Level, $TargetSeverity)."\'></a>\n<h2>$Title ($ProblemsNum)</h2><hr/>\n".$TYPE_PROBLEMS.$TOP_REF."<br/>\n";
14990        }
14991    }
14992    return $TYPE_PROBLEMS;
14993}
14994
14995sub get_Anchor($$$)
14996{
14997    my ($Kind, $Level, $Severity) = @_;
14998    if($JoinReport)
14999    {
15000        if($Severity eq "Safe") {
15001            return "Other_".$Level."_Changes_In_".$Kind."s";
15002        }
15003        else {
15004            return $Kind."_".$Level."_Problems_".$Severity;
15005        }
15006    }
15007    else
15008    {
15009        if($Severity eq "Safe") {
15010            return "Other_Changes_In_".$Kind."s";
15011        }
15012        else {
15013            return $Kind."_Problems_".$Severity;
15014        }
15015    }
15016}
15017
15018sub showVTables($)
15019{
15020    my $TypeName = $_[0];
15021    my $TypeId1 = $TName_Tid{1}{$TypeName};
15022    my %Type1 = get_Type($TypeId1, 1);
15023    if(defined $Type1{"VTable"}
15024    and keys(%{$Type1{"VTable"}}))
15025    {
15026        my $TypeId2 = $TName_Tid{2}{$TypeName};
15027        my %Type2 = get_Type($TypeId2, 2);
15028        if(defined $Type2{"VTable"}
15029        and keys(%{$Type2{"VTable"}}))
15030        {
15031            my %Indexes = map {$_=>1} (keys(%{$Type1{"VTable"}}), keys(%{$Type2{"VTable"}}));
15032            my %Entries = ();
15033            foreach my $Index (sort {int($a)<=>int($b)} (keys(%Indexes)))
15034            {
15035                $Entries{$Index}{"E1"} = simpleVEntry($Type1{"VTable"}{$Index});
15036                $Entries{$Index}{"E2"} = simpleVEntry($Type2{"VTable"}{$Index});
15037            }
15038            my $VTABLES = "";
15039            if($ReportFormat eq "xml")
15040            { # XML
15041                $VTABLES .= "      <vtable>\n";
15042                foreach my $Index (sort {int($a)<=>int($b)} (keys(%Entries)))
15043                {
15044                    $VTABLES .= "        <entry offset=\"".$Index."\">\n";
15045                    $VTABLES .= "          <old>".xmlSpecChars($Entries{$Index}{"E1"})."</old>\n";
15046                    $VTABLES .= "          <new>".xmlSpecChars($Entries{$Index}{"E2"})."</new>\n";
15047                    $VTABLES .= "        </entry>\n";
15048                }
15049                $VTABLES .= "      </vtable>\n\n";
15050            }
15051            else
15052            { # HTML
15053                $VTABLES .= "<table class='vtable'>";
15054                $VTABLES .= "<tr><th width='2%'>Offset</th>";
15055                $VTABLES .= "<th width='45%'>Virtual Table (Old) - ".(keys(%{$Type1{"VTable"}}))." entries</th>";
15056                $VTABLES .= "<th>Virtual Table (New) - ".(keys(%{$Type2{"VTable"}}))." entries</th></tr>";
15057                foreach my $Index (sort {int($a)<=>int($b)} (keys(%Entries)))
15058                {
15059                    my ($Color1, $Color2) = ("", "");
15060                    if($Entries{$Index}{"E1"} ne $Entries{$Index}{"E2"})
15061                    {
15062                        if($Entries{$Index}{"E1"})
15063                        {
15064                            $Color1 = " class='failed'";
15065                            $Color2 = " class='failed'";
15066                        }
15067                        else {
15068                            $Color2 = " class='warning'";
15069                        }
15070                    }
15071                    $VTABLES .= "<tr><th>".$Index."</th>\n";
15072                    $VTABLES .= "<td$Color1>".htmlSpecChars($Entries{$Index}{"E1"})."</td>\n";
15073                    $VTABLES .= "<td$Color2>".htmlSpecChars($Entries{$Index}{"E2"})."</td></tr>\n";
15074                }
15075                $VTABLES .= "</table><br/>\n";
15076                $VTABLES = $ContentDivStart.$VTABLES.$ContentDivEnd;
15077                $VTABLES = $ContentSpanStart_Info."[+] show v-table (old and new)".$ContentSpanEnd."<br/>\n".$VTABLES;
15078            }
15079            return $VTABLES;
15080        }
15081    }
15082    return "";
15083}
15084
15085sub simpleVEntry($)
15086{
15087    my $VEntry = $_[0];
15088    if(not defined $VEntry
15089    or $VEntry eq "") {
15090        return "";
15091    }
15092    $VEntry=~s/\A(.+)::(_ZThn.+)\Z/$2/; # thunks
15093    $VEntry=~s/_ZTI\w+/typeinfo/g; # typeinfo
15094    if($VEntry=~/\A_ZThn.+\Z/) {
15095        $VEntry = "non-virtual thunk";
15096    }
15097    $VEntry=~s/\A\(int \(\*\)\(...\)\)([^\(\d])/$1/i;
15098    # support for old GCC versions
15099    $VEntry=~s/\A0u\Z/(int (*)(...))0/;
15100    $VEntry=~s/\A4294967268u\Z/(int (*)(...))-0x000000004/;
15101    $VEntry=~s/\A&_Z\Z/& _Z/;
15102    # templates
15103    if($VEntry=~s/ \[with (\w+) = (.+?)(, [^=]+ = .+|])\Z//g)
15104    { # std::basic_streambuf<_CharT, _Traits>::imbue [with _CharT = char, _Traits = std::char_traits<char>]
15105      # become std::basic_streambuf<char, ...>::imbue
15106        my ($Pname, $Pval) = ($1, $2);
15107        if($Pname eq "_CharT" and $VEntry=~/\Astd::/)
15108        { # stdc++ typedefs
15109            $VEntry=~s/<$Pname(, [^<>]+|)>/<$Pval>/g;
15110            # FIXME: simplify names using stdcxx typedefs (StdCxxTypedef)
15111            # The typedef info should be added to ABI dumps
15112        }
15113        else
15114        {
15115            $VEntry=~s/<$Pname>/<$Pval>/g;
15116            $VEntry=~s/<$Pname, [^<>]+>/<$Pval, ...>/g;
15117        }
15118    }
15119    $VEntry=~s/([^:]+)::\~([^:]+)\Z/~$1/; # destructors
15120    return $VEntry;
15121}
15122
15123sub getAffectedSymbols($$$$)
15124{
15125    my ($Level, $Target_TypeName, $Kinds_Locations, $Syms) = @_;
15126    my $LIMIT = 1000;
15127    if($#{$Syms}>=10000)
15128    { # reduce size of the report
15129        $LIMIT = 10;
15130    }
15131    my %SProblems = ();
15132    foreach my $Symbol (@{$Syms})
15133    {
15134        if(keys(%SProblems)>$LIMIT) {
15135            last;
15136        }
15137        if(($Symbol=~/C2E|D2E|D0E/))
15138        { # duplicated problems for C2 constructors, D2 and D0 destructors
15139            next;
15140        }
15141        my ($SN, $SS, $SV) = separate_symbol($Symbol);
15142        if($Level eq "Source")
15143        { # remove symbol version
15144            $Symbol=$SN;
15145        }
15146        my ($MinPath_Length, $ProblemLocation_Last) = (-1, "");
15147        my $Severity_Max = 0;
15148        my $Signature = get_Signature($Symbol, 1);
15149        foreach my $Kind (keys(%{$CompatProblems{$Level}{$Symbol}}))
15150        {
15151            foreach my $Location (keys(%{$CompatProblems{$Level}{$Symbol}{$Kind}}))
15152            {
15153                if(not defined $Kinds_Locations->{$Kind}
15154                or not $Kinds_Locations->{$Kind}{$Location}) {
15155                    next;
15156                }
15157                if($SV and defined $CompatProblems{$Level}{$SN}
15158                and defined $CompatProblems{$Level}{$SN}{$Kind}{$Location})
15159                { # duplicated problems for versioned symbols
15160                    next;
15161                }
15162                my $Type_Name = $CompatProblems{$Level}{$Symbol}{$Kind}{$Location}{"Type_Name"};
15163                next if($Type_Name ne $Target_TypeName);
15164
15165                my $Position = $CompatProblems{$Level}{$Symbol}{$Kind}{$Location}{"Param_Pos"};
15166                my $Param_Name = $CompatProblems{$Level}{$Symbol}{$Kind}{$Location}{"Param_Name"};
15167                my $Severity = getProblemSeverity($Level, $Kind);
15168                my $Path_Length = 0;
15169                my $ProblemLocation = $Location;
15170                if($Type_Name) {
15171                    $ProblemLocation=~s/->\Q$Type_Name\E\Z//g;
15172                }
15173                while($ProblemLocation=~/\-\>/g) {
15174                    $Path_Length += 1;
15175                }
15176                if($MinPath_Length==-1 or ($Path_Length<=$MinPath_Length and $Severity_Val{$Severity}>$Severity_Max)
15177                or (cmp_locations($ProblemLocation, $ProblemLocation_Last) and $Severity_Val{$Severity}==$Severity_Max))
15178                {
15179                    $MinPath_Length = $Path_Length;
15180                    $Severity_Max = $Severity_Val{$Severity};
15181                    $ProblemLocation_Last = $ProblemLocation;
15182                    %{$SProblems{$Symbol}} = (
15183                        "Descr"=>getAffectDescription($Level, $Symbol, $Kind, $Location),
15184                        "Severity_Max"=>$Severity_Max,
15185                        "Signature"=>$Signature,
15186                        "Position"=>$Position,
15187                        "Param_Name"=>$Param_Name,
15188                        "Location"=>$Location
15189                    );
15190                }
15191            }
15192        }
15193    }
15194    my @Symbols = keys(%SProblems);
15195    @Symbols = sort {lc($tr_name{$a}?$tr_name{$a}:$a) cmp lc($tr_name{$b}?$tr_name{$b}:$b)} @Symbols;
15196    @Symbols = sort {$SProblems{$b}{"Severity_Max"}<=>$SProblems{$a}{"Severity_Max"}} @Symbols;
15197    if($#Symbols+1>$LIMIT)
15198    { # remove last element
15199        pop(@Symbols);
15200    }
15201    my $Affected = "";
15202    if($ReportFormat eq "xml")
15203    { # XML
15204        $Affected .= "      <affected>\n";
15205        foreach my $Symbol (@Symbols)
15206        {
15207            my $Param_Name = $SProblems{$Symbol}{"Param_Name"};
15208            my $Description = $SProblems{$Symbol}{"Descr"};
15209            my $Location = $SProblems{$Symbol}{"Location"};
15210            my $Target = "";
15211            if($Param_Name) {
15212                $Target = " affected=\"param\" param_name=\"$Param_Name\"";
15213            }
15214            elsif($Location=~/\Aretval(\-|\Z)/i) {
15215                $Target = " affected=\"retval\"";
15216            }
15217            elsif($Location=~/\Athis(\-|\Z)/i) {
15218                $Target = " affected=\"this\"";
15219            }
15220            $Affected .= "        <symbol$Target name=\"$Symbol\">\n";
15221            $Affected .= "          <comment>".xmlSpecChars($Description)."</comment>\n";
15222            $Affected .= "        </symbol>\n";
15223        }
15224        $Affected .= "      </affected>\n";
15225    }
15226    else
15227    { # HTML
15228        foreach my $Symbol (@Symbols)
15229        {
15230            my $Description = $SProblems{$Symbol}{"Descr"};
15231            my $Signature = $SProblems{$Symbol}{"Signature"};
15232            my $Pos = $SProblems{$Symbol}{"Position"};
15233            $Affected .= "<span class='iname_a'>".highLight_Signature_PPos_Italic($Signature, $Pos, 1, 0, 0)."</span><br/><div class='affect'>".htmlSpecChars($Description)."</div>\n";
15234        }
15235        if(keys(%SProblems)>$LIMIT) {
15236            $Affected .= "and others ...<br/>";
15237        }
15238        $Affected = "<div class='affected'>".$Affected."</div>";
15239        if($Affected)
15240        {
15241            $Affected = $ContentDivStart.$Affected.$ContentDivEnd;
15242            $Affected = $ContentSpanStart_Affected."[+] affected symbols (".(keys(%SProblems)>$LIMIT?">".$LIMIT:keys(%SProblems)).")".$ContentSpanEnd.$Affected;
15243        }
15244    }
15245    return $Affected;
15246}
15247
15248sub cmp_locations($$)
15249{
15250    my ($L1, $L2) = @_;
15251    if($L2=~/\b(retval|this)\b/
15252    and $L1!~/\b(retval|this)\b/ and $L1!~/\-\>/) {
15253        return 1;
15254    }
15255    if($L2=~/\b(retval|this)\b/ and $L2=~/\-\>/
15256    and $L1!~/\b(retval|this)\b/ and $L1=~/\-\>/) {
15257        return 1;
15258    }
15259    return 0;
15260}
15261
15262sub getAffectDescription($$$$)
15263{
15264    my ($Level, $Symbol, $Kind, $Location) = @_;
15265    my %Problem = %{$CompatProblems{$Level}{$Symbol}{$Kind}{$Location}};
15266    my $PPos = showPos($Problem{"Param_Pos"});
15267    my @Sentence = ();
15268    $Location=~s/\A(.*)\-\>.+?\Z/$1/;
15269    if($Kind eq "Overridden_Virtual_Method"
15270    or $Kind eq "Overridden_Virtual_Method_B") {
15271        push(@Sentence, "The method '".$Problem{"New_Value"}."' will be called instead of this method.");
15272    }
15273    elsif($CompatRules{$Level}{$Kind}{"Kind"} eq "Types")
15274    {
15275        if($Location eq "this" or $Kind=~/(\A|_)Virtual(_|\Z)/)
15276        {
15277            my $METHOD_TYPE = $CompleteSignature{1}{$Symbol}{"Constructor"}?"constructor":"method";
15278            my $ClassName = $TypeInfo{1}{$CompleteSignature{1}{$Symbol}{"Class"}}{"Name"};
15279            if($ClassName eq $Problem{"Type_Name"}) {
15280                push(@Sentence, "This $METHOD_TYPE is from \'".$Problem{"Type_Name"}."\' class.");
15281            }
15282            else {
15283                push(@Sentence, "This $METHOD_TYPE is from derived class \'".$ClassName."\'.");
15284            }
15285        }
15286        else
15287        {
15288            if($Location=~/retval/)
15289            { # return value
15290                if($Location=~/\-\>/) {
15291                    push(@Sentence, "Field \'".$Location."\' in return value");
15292                }
15293                else {
15294                    push(@Sentence, "Return value");
15295                }
15296                if(my $Init = $Problem{"InitialType_Type"})
15297                {
15298                    if($Init eq "Pointer") {
15299                        push(@Sentence, "(pointer)");
15300                    }
15301                    elsif($Init eq "Ref") {
15302                        push(@Sentence, "(reference)");
15303                    }
15304                }
15305            }
15306            elsif($Location=~/this/)
15307            { # "this" pointer
15308                if($Location=~/\-\>/) {
15309                    push(@Sentence, "Field \'".$Location."\' in the object of this method");
15310                }
15311                else {
15312                    push(@Sentence, "\'this\' pointer");
15313                }
15314            }
15315            else
15316            { # parameters
15317                if($Location=~/\-\>/) {
15318                    push(@Sentence, "Field \'".$Location."\' in $PPos parameter");
15319                }
15320                else {
15321                    push(@Sentence, "$PPos parameter");
15322                }
15323                if($Problem{"Param_Name"}) {
15324                    push(@Sentence, "\'".$Problem{"Param_Name"}."\'");
15325                }
15326                if(my $Init = $Problem{"InitialType_Type"})
15327                {
15328                    if($Init eq "Pointer") {
15329                        push(@Sentence, "(pointer)");
15330                    }
15331                    elsif($Init eq "Ref") {
15332                        push(@Sentence, "(reference)");
15333                    }
15334                }
15335            }
15336            if($Location eq "this") {
15337                push(@Sentence, "has base type \'".$Problem{"Type_Name"}."\'.");
15338            }
15339            elsif(defined $Problem{"Start_Type_Name"}
15340            and $Problem{"Start_Type_Name"} eq $Problem{"Type_Name"}) {
15341                push(@Sentence, "has type \'".$Problem{"Type_Name"}."\'.");
15342            }
15343            else {
15344                push(@Sentence, "has base type \'".$Problem{"Type_Name"}."\'.");
15345            }
15346        }
15347    }
15348    if($ExtendedSymbols{$Symbol}) {
15349        push(@Sentence, " This is a symbol from an artificial external library that may use the \'$TargetLibraryName\' library and change its ABI after recompiling.");
15350    }
15351    return join(" ", @Sentence);
15352}
15353
15354sub get_XmlSign($$)
15355{
15356    my ($Symbol, $LibVersion) = @_;
15357    my $Info = $CompleteSignature{$LibVersion}{$Symbol};
15358    my $Report = "";
15359    foreach my $Pos (sort {int($a)<=>int($b)} keys(%{$Info->{"Param"}}))
15360    {
15361        my $Name = $Info->{"Param"}{$Pos}{"name"};
15362        my $Type = $Info->{"Param"}{$Pos}{"type"};
15363        my $TypeName = $TypeInfo{$LibVersion}{$Type}{"Name"};
15364        foreach my $Typedef (keys(%ChangedTypedef))
15365        {
15366            my $Base = $Typedef_BaseName{$LibVersion}{$Typedef};
15367            $TypeName=~s/\b\Q$Typedef\E\b/$Base/g;
15368        }
15369        $Report .= "    <param pos=\"$Pos\">\n";
15370        $Report .= "      <name>".$Name."</name>\n";
15371        $Report .= "      <type>".xmlSpecChars($TypeName)."</type>\n";
15372        $Report .= "    </param>\n";
15373    }
15374    if(my $Return = $Info->{"Return"})
15375    {
15376        my $RTName = $TypeInfo{$LibVersion}{$Return}{"Name"};
15377        $Report .= "    <retval>\n";
15378        $Report .= "      <type>".xmlSpecChars($RTName)."</type>\n";
15379        $Report .= "    </retval>\n";
15380    }
15381    return $Report;
15382}
15383
15384sub get_Report_SymbolsInfo($)
15385{
15386    my $Level = $_[0];
15387    my $Report = "<symbols_info>\n";
15388    foreach my $Symbol (sort keys(%{$CompatProblems{$Level}}))
15389    {
15390        my ($SN, $SS, $SV) = separate_symbol($Symbol);
15391        if($SV and defined $CompatProblems{$Level}{$SN}) {
15392            next;
15393        }
15394        $Report .= "  <symbol name=\"$Symbol\">\n";
15395        my ($S1, $P1, $S2, $P2) = ();
15396        if(not $AddedInt{$Level}{$Symbol})
15397        {
15398            if(defined $CompleteSignature{1}{$Symbol}
15399            and defined $CompleteSignature{1}{$Symbol}{"Header"})
15400            {
15401                $P1 = get_XmlSign($Symbol, 1);
15402                $S1 = get_Signature($Symbol, 1);
15403            }
15404            elsif($Symbol=~/\A(_Z|\?)/) {
15405                $S1 = $tr_name{$Symbol};
15406            }
15407        }
15408        if(not $RemovedInt{$Level}{$Symbol})
15409        {
15410            if(defined $CompleteSignature{2}{$Symbol}
15411            and defined $CompleteSignature{2}{$Symbol}{"Header"})
15412            {
15413                $P2 = get_XmlSign($Symbol, 2);
15414                $S2 = get_Signature($Symbol, 2);
15415            }
15416            elsif($Symbol=~/\A(_Z|\?)/) {
15417                $S2 = $tr_name{$Symbol};
15418            }
15419        }
15420        if($S1)
15421        {
15422            $Report .= "    <old signature=\"".xmlSpecChars($S1)."\">\n";
15423            $Report .= $P1;
15424            $Report .= "    </old>\n";
15425        }
15426        if($S2 and $S2 ne $S1)
15427        {
15428            $Report .= "    <new signature=\"".xmlSpecChars($S2)."\">\n";
15429            $Report .= $P2;
15430            $Report .= "    </new>\n";
15431        }
15432        $Report .= "  </symbol>\n";
15433    }
15434    $Report .= "</symbols_info>\n";
15435    return $Report;
15436}
15437
15438sub writeReport($$)
15439{
15440    my ($Level, $Report) = @_;
15441    if($ReportFormat eq "xml") {
15442        $Report = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n".$Report;
15443    }
15444    if($StdOut)
15445    { # --stdout option
15446        print STDOUT $Report;
15447    }
15448    else
15449    {
15450        my $RPath = getReportPath($Level);
15451        mkpath(get_dirname($RPath));
15452
15453        open(REPORT, ">", $RPath) || die ("can't open file \'$RPath\': $!\n");
15454        print REPORT $Report;
15455        close(REPORT);
15456
15457        if($Browse or $OpenReport)
15458        { # open in browser
15459            openReport($RPath);
15460            if($JoinReport or $DoubleReport)
15461            {
15462                if($Level eq "Binary")
15463                { # wait to open a browser
15464                    sleep(1);
15465                }
15466            }
15467        }
15468    }
15469}
15470
15471sub openReport($)
15472{
15473    my $Path = $_[0];
15474    my $Cmd = "";
15475    if($Browse)
15476    { # user-defined browser
15477        $Cmd = $Browse." \"$Path\"";
15478    }
15479    if(not $Cmd)
15480    { # default browser
15481        if($OSgroup eq "macos") {
15482            system("open \"$Path\"");
15483        }
15484        elsif($OSgroup eq "windows") {
15485            system("start \"$Path\"");
15486        }
15487        else
15488        { # linux, freebsd, solaris
15489            my @Browsers = (
15490                "x-www-browser",
15491                "sensible-browser",
15492                "firefox",
15493                "opera",
15494                "xdg-open",
15495                "lynx",
15496                "links"
15497            );
15498            foreach my $Br (@Browsers)
15499            {
15500                if($Br = get_CmdPath($Br))
15501                {
15502                    $Cmd = $Br." \"$Path\"";
15503                    last;
15504                }
15505            }
15506        }
15507    }
15508    if($Cmd)
15509    {
15510        if($Debug) {
15511            printMsg("INFO", "running $Cmd");
15512        }
15513        if($Cmd!~/lynx|links/) {
15514            $Cmd .= "  >\"$TMP_DIR/null\" 2>&1 &";
15515        }
15516        system($Cmd);
15517    }
15518    else {
15519        printMsg("ERROR", "cannot open report in browser");
15520    }
15521}
15522
15523sub getReport($)
15524{
15525    my $Level = $_[0];
15526    if($ReportFormat eq "xml")
15527    { # XML
15528
15529        if($Level eq "Join")
15530        {
15531            my $Report = "<reports>\n";
15532            $Report .= getReport("Binary");
15533            $Report .= getReport("Source");
15534            $Report .= "</reports>\n";
15535            return $Report;
15536        }
15537        else
15538        {
15539            my $Report = "<report kind=\"".lc($Level)."\" version=\"$XML_REPORT_VERSION\">\n\n";
15540            my ($Summary, $MetaData) = get_Summary($Level);
15541            $Report .= $Summary."\n";
15542            $Report .= get_Report_Added($Level).get_Report_Removed($Level);
15543            $Report .= get_Report_Problems("High", $Level).get_Report_Problems("Medium", $Level).get_Report_Problems("Low", $Level).get_Report_Problems("Safe", $Level);
15544            $Report .= get_Report_SymbolsInfo($Level);
15545            $Report .= "</report>\n";
15546            return $Report;
15547        }
15548    }
15549    else
15550    { # HTML
15551        my $CssStyles = readModule("Styles", "Report.css");
15552        my $JScripts = readModule("Scripts", "Sections.js");
15553        if($Level eq "Join")
15554        {
15555            $CssStyles .= "\n".readModule("Styles", "Tabs.css");
15556            $JScripts .= "\n".readModule("Scripts", "Tabs.js");
15557            my $Title = $TargetLibraryFName.": ".$Descriptor{1}{"Version"}." to ".$Descriptor{2}{"Version"}." compatibility report";
15558            my $Keywords = $TargetLibraryFName.", compatibility, API, report";
15559            my $Description = "Compatibility report for the $TargetLibraryFName $TargetComponent between ".$Descriptor{1}{"Version"}." and ".$Descriptor{2}{"Version"}." versions";
15560            my ($BSummary, $BMetaData) = get_Summary("Binary");
15561            my ($SSummary, $SMetaData) = get_Summary("Source");
15562            my $Report = "<!-\- $BMetaData -\->\n<!-\- $SMetaData -\->\n".composeHTML_Head($Title, $Keywords, $Description, $CssStyles, $JScripts)."<body><a name='Source'></a><a name='Binary'></a><a name='Top'></a>";
15563            $Report .= get_Report_Header("Join")."
15564            <br/><div class='tabset'>
15565            <a id='BinaryID' href='#BinaryTab' class='tab active'>Binary<br/>Compatibility</a>
15566            <a id='SourceID' href='#SourceTab' style='margin-left:3px' class='tab disabled'>Source<br/>Compatibility</a>
15567            </div>";
15568            $Report .= "<div id='BinaryTab' class='tab'>\n$BSummary\n".get_Report_Added("Binary").get_Report_Removed("Binary").get_Report_Problems("High", "Binary").get_Report_Problems("Medium", "Binary").get_Report_Problems("Low", "Binary").get_Report_Problems("Safe", "Binary").get_SourceInfo()."<br/><br/><br/></div>";
15569            $Report .= "<div id='SourceTab' class='tab'>\n$SSummary\n".get_Report_Added("Source").get_Report_Removed("Source").get_Report_Problems("High", "Source").get_Report_Problems("Medium", "Source").get_Report_Problems("Low", "Source").get_Report_Problems("Safe", "Source").get_SourceInfo()."<br/><br/><br/></div>";
15570            $Report .= getReportFooter($TargetLibraryFName);
15571            $Report .= "\n<div style='height:999px;'></div>\n</body></html>";
15572            return $Report;
15573        }
15574        else
15575        {
15576            my ($Summary, $MetaData) = get_Summary($Level);
15577            my $Title = $TargetLibraryFName.": ".$Descriptor{1}{"Version"}." to ".$Descriptor{2}{"Version"}." ".lc($Level)." compatibility report";
15578            my $Keywords = $TargetLibraryFName.", ".lc($Level)." compatibility, API, report";
15579            my $Description = "$Level compatibility report for the ".$TargetLibraryFName." ".$TargetComponent." between ".$Descriptor{1}{"Version"}." and ".$Descriptor{2}{"Version"}." versions";
15580            if($Level eq "Binary")
15581            {
15582                if(getArch(1) eq getArch(2)
15583                and getArch(1) ne "unknown") {
15584                    $Description .= " on ".showArch(getArch(1));
15585                }
15586            }
15587            my $Report = "<!-\- $MetaData -\->\n".composeHTML_Head($Title, $Keywords, $Description, $CssStyles, $JScripts)."\n<body>\n<div><a name='Top'></a>\n";
15588            $Report .= get_Report_Header($Level)."\n".$Summary."\n";
15589            $Report .= get_Report_Added($Level).get_Report_Removed($Level);
15590            $Report .= get_Report_Problems("High", $Level).get_Report_Problems("Medium", $Level).get_Report_Problems("Low", $Level).get_Report_Problems("Safe", $Level);
15591            $Report .= get_SourceInfo();
15592            $Report .= "</div>\n<br/><br/><br/><hr/>\n";
15593            $Report .= getReportFooter($TargetLibraryFName);
15594            $Report .= "\n<div style='height:999px;'></div>\n</body></html>";
15595            return $Report;
15596        }
15597    }
15598}
15599
15600sub getLegend()
15601{
15602    return "<br/>
15603<table class='summary'>
15604<tr>
15605    <td class='new'>added</td>
15606    <td class='passed'>compatible</td>
15607</tr>
15608<tr>
15609    <td class='warning'>warning</td>
15610    <td class='failed'>incompatible</td>
15611</tr></table>\n";
15612}
15613
15614sub createReport()
15615{
15616    if($JoinReport)
15617    { # --stdout
15618        writeReport("Join", getReport("Join"));
15619    }
15620    elsif($DoubleReport)
15621    { # default
15622        writeReport("Binary", getReport("Binary"));
15623        writeReport("Source", getReport("Source"));
15624    }
15625    elsif($BinaryOnly)
15626    { # --binary
15627        writeReport("Binary", getReport("Binary"));
15628    }
15629    elsif($SourceOnly)
15630    { # --source
15631        writeReport("Source", getReport("Source"));
15632    }
15633}
15634
15635sub getReportFooter($)
15636{
15637    my $LibName = $_[0];
15638    my $FooterStyle = (not $JoinReport)?"width:99%":"width:97%;padding-top:3px";
15639    my $Footer = "<div style='$FooterStyle;font-size:11px;' align='right'><i>Generated on ".(localtime time); # report date
15640    $Footer .= " for <span style='font-weight:bold'>$LibName</span>"; # tested library/system name
15641    $Footer .= " by <a href='".$HomePage{"Wiki"}."'>ABI Compliance Checker</a>"; # tool name
15642    my $ToolSummary = "<br/>A tool for checking backward compatibility of a C/C++ library API&#160;&#160;";
15643    $Footer .= " $TOOL_VERSION &#160;$ToolSummary</i></div>"; # tool version
15644    return $Footer;
15645}
15646
15647sub get_Report_Problems($$)
15648{
15649    my ($Priority, $Level) = @_;
15650    my $Report = get_Report_TypeProblems($Priority, $Level);
15651    if(my $SProblems = get_Report_SymbolProblems($Priority, $Level)) {
15652        $Report .= $SProblems;
15653    }
15654    if($Priority eq "Low")
15655    {
15656        $Report .= get_Report_ChangedConstants($Level);
15657        if($ReportFormat eq "html") {
15658            if($CheckImpl and $Level eq "Binary") {
15659                $Report .= get_Report_Impl();
15660            }
15661        }
15662    }
15663    if($ReportFormat eq "html")
15664    {
15665        if($Report)
15666        { # add anchor
15667            if($JoinReport)
15668            {
15669                if($Priority eq "Safe") {
15670                    $Report = "<a name=\'Other_".$Level."_Changes\'></a>".$Report;
15671                }
15672                else {
15673                    $Report = "<a name=\'".$Priority."_Risk_".$Level."_Problems\'></a>".$Report;
15674                }
15675            }
15676            else
15677            {
15678                if($Priority eq "Safe") {
15679                    $Report = "<a name=\'Other_Changes\'></a>".$Report;
15680                }
15681                else {
15682                    $Report = "<a name=\'".$Priority."_Risk_Problems\'></a>".$Report;
15683                }
15684            }
15685        }
15686    }
15687    return $Report;
15688}
15689
15690sub composeHTML_Head($$$$$)
15691{
15692    my ($Title, $Keywords, $Description, $Styles, $Scripts) = @_;
15693    return "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">
15694    <html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">
15695    <head>
15696    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />
15697    <meta name=\"keywords\" content=\"$Keywords\" />
15698    <meta name=\"description\" content=\"$Description\" />
15699    <title>
15700        $Title
15701    </title>
15702    <style type=\"text/css\">
15703    $Styles
15704    </style>
15705    <script type=\"text/javascript\" language=\"JavaScript\">
15706    <!--
15707    $Scripts
15708    -->
15709    </script>
15710    </head>";
15711}
15712
15713sub insertIDs($)
15714{
15715    my $Text = $_[0];
15716    while($Text=~/CONTENT_ID/)
15717    {
15718        if(int($Content_Counter)%2) {
15719            $ContentID -= 1;
15720        }
15721        $Text=~s/CONTENT_ID/c_$ContentID/;
15722        $ContentID += 1;
15723        $Content_Counter += 1;
15724    }
15725    return $Text;
15726}
15727
15728sub checkPreprocessedUnit($)
15729{
15730    my $Path = $_[0];
15731    my ($CurHeader, $CurHeaderName) = ("", "");
15732    open(PREPROC, $Path) || die ("can't open file \'$Path\': $!\n");
15733    while(my $Line = <PREPROC>)
15734    { # detecting public and private constants
15735
15736        if(substr($Line, 0, 1) eq "#")
15737        {
15738            chomp($Line);
15739            if($Line=~/\A\#\s+\d+\s+\"(.+)\"/)
15740            {
15741                $CurHeader = path_format($1, $OSgroup);
15742                $CurHeaderName = get_filename($CurHeader);
15743            }
15744            if(not $Include_Neighbors{$Version}{$CurHeaderName}
15745            and not $Registered_Headers{$Version}{$CurHeader})
15746            { # not a target
15747                next;
15748            }
15749            if(not is_target_header($CurHeaderName, 1)
15750            and not is_target_header($CurHeaderName, 2))
15751            { # user-defined header
15752                next;
15753            }
15754            if($Line=~/\A\#\s*define\s+([_A-Z0-9]+)\s+(.+)\s*\Z/)
15755            {
15756                my ($Name, $Value) = ($1, $2);
15757                if(not $Constants{$Version}{$Name}{"Access"})
15758                {
15759                    $Constants{$Version}{$Name}{"Access"} = "public";
15760                    $Constants{$Version}{$Name}{"Value"} = $Value;
15761                    $Constants{$Version}{$Name}{"Header"} = $CurHeaderName;
15762                }
15763            }
15764            elsif($Line=~/\A\#[ \t]*undef[ \t]+([_A-Z]+)[ \t]*/) {
15765                $Constants{$Version}{$1}{"Access"} = "private";
15766            }
15767        }
15768    }
15769    close(PREPROC);
15770    foreach my $Constant (keys(%{$Constants{$Version}}))
15771    {
15772        if($Constants{$Version}{$Constant}{"Access"} eq "private"
15773        or $Constant=~/_h\Z/i
15774        or isBuiltIn($Constants{$Version}{$Constant}{"Header"}))
15775        { # skip private constants
15776            delete($Constants{$Version}{$Constant});
15777        }
15778        else {
15779            delete($Constants{$Version}{$Constant}{"Access"});
15780        }
15781    }
15782    if($Debug)
15783    {
15784        mkpath($DEBUG_PATH{$Version});
15785        copy($Path, $DEBUG_PATH{$Version}."/preprocessor.txt");
15786    }
15787}
15788
15789sub uncoverConstant($$)
15790{
15791    my ($LibVersion, $Constant) = @_;
15792    return "" if(not $LibVersion or not $Constant);
15793    return $Constant if(isCyclical(\@RecurConstant, $Constant));
15794    if(defined $Cache{"uncoverConstant"}{$LibVersion}{$Constant}) {
15795        return $Cache{"uncoverConstant"}{$LibVersion}{$Constant};
15796    }
15797    my $Value = $Constants{$LibVersion}{$Constant}{"Value"};
15798    if(defined $Value)
15799    {
15800        if($Value=~/\A[A-Z0-9_]+\Z/ and $Value=~/[A-Z]/)
15801        {
15802            push(@RecurConstant, $Constant);
15803            my $Uncovered = uncoverConstant($LibVersion, $Value);
15804            if($Uncovered ne "") {
15805                $Value = $Uncovered;
15806            }
15807            pop(@RecurConstant);
15808        }
15809        # FIXME: uncover $Value using all the enum constants
15810        # USECASE: change of define NC_LONG from NC_INT (enum value) to NC_INT (define)
15811        return ($Cache{"uncoverConstant"}{$LibVersion}{$Constant} = $Value);
15812    }
15813    return ($Cache{"uncoverConstant"}{$LibVersion}{$Constant} = "");
15814}
15815
15816my %IgnoreConstant=(
15817    "VERSION"=>1,
15818    "VERSIONCODE"=>1,
15819    "VERNUM"=>1,
15820    "VERS_INFO"=>1,
15821    "PATCHLEVEL"=>1,
15822    "INSTALLPREFIX"=>1,
15823    "VBUILD"=>1,
15824    "VPATCH"=>1,
15825    "VMINOR"=>1,
15826    "BUILD_STRING"=>1,
15827    "BUILD_TIME"=>1,
15828    "PACKAGE_STRING"=>1,
15829    "PRODUCTION"=>1,
15830    "CONFIGURE_COMMAND"=>1,
15831    "INSTALLDIR"=>1,
15832    "BINDIR"=>1,
15833    "CONFIG_FILE_PATH"=>1,
15834    "DATADIR"=>1,
15835    "EXTENSION_DIR"=>1,
15836    "INCLUDE_PATH"=>1,
15837    "LIBDIR"=>1,
15838    "LOCALSTATEDIR"=>1,
15839    "SBINDIR"=>1,
15840    "SYSCONFDIR"=>1,
15841    "RELEASE"=>1,
15842    "SOURCE_ID"=>1,
15843    "SUBMINOR"=>1,
15844    "MINOR"=>1,
15845    "MINNOR"=>1,
15846    "MINORVERSION"=>1,
15847    "MAJOR"=>1,
15848    "MAJORVERSION"=>1,
15849    "MICRO"=>1,
15850    "MICROVERSION"=>1,
15851    "BINARY_AGE"=>1,
15852    "INTERFACE_AGE"=>1,
15853    "CORE_ABI"=>1,
15854    "PATCH"=>1,
15855    "COPYRIGHT"=>1,
15856    "TIMESTAMP"=>1,
15857    "REVISION"=>1,
15858    "PACKAGE_TAG"=>1,
15859    "PACKAGEDATE"=>1,
15860    "NUMVERSION"=>1
15861);
15862
15863sub mergeConstants($)
15864{
15865    my $Level = $_[0];
15866    foreach my $Constant (keys(%{$Constants{1}}))
15867    {
15868        if($SkipConstants{1}{$Constant})
15869        { # skipped by the user
15870            next;
15871        }
15872        if(not defined $Constants{2}{$Constant}{"Value"}
15873        or $Constants{2}{$Constant}{"Value"} eq "")
15874        { # empty value
15875            next;
15876        }
15877        my $Header = $Constants{1}{$Constant}{"Header"};
15878        if(not is_target_header($Header, 1)
15879        and not is_target_header($Header, 2))
15880        { # user-defined header
15881            next;
15882        }
15883        my ($Old_Value, $New_Value, $Old_Value_Pure, $New_Value_Pure);
15884        $Old_Value = $Old_Value_Pure = uncoverConstant(1, $Constant);
15885        $New_Value = $New_Value_Pure = uncoverConstant(2, $Constant);
15886        $Old_Value_Pure=~s/(\W)\s+/$1/g;
15887        $Old_Value_Pure=~s/\s+(\W)/$1/g;
15888        $New_Value_Pure=~s/(\W)\s+/$1/g;
15889        $New_Value_Pure=~s/\s+(\W)/$1/g;
15890        next if($New_Value_Pure eq "" or $Old_Value_Pure eq "");
15891        if($New_Value_Pure ne $Old_Value_Pure)
15892        { # different values
15893            if($Level eq "Binary")
15894            {
15895                if(grep {$Constant=~/(\A|_)$_(_|\Z)/} keys(%IgnoreConstant))
15896                { # ignore library version
15897                    next;
15898                }
15899                if($Constant=~/(\A|_)(lib|open|)$TargetLibraryShortName(_|)(VERSION|VER|DATE|API|PREFIX)(_|\Z)/i)
15900                { # ignore library version
15901                    next;
15902                }
15903                if($Old_Value=~/\A('|"|)[\/\\]\w+([\/\\]|:|('|"|)\Z)/ or $Old_Value=~/[\/\\]\w+[\/\\]\w+/)
15904                { # ignoring path defines:
15905                  #  /lib64:/usr/lib64:/lib:/usr/lib:/usr/X11R6/lib/Xaw3d ...
15906                    next;
15907                }
15908                if($Old_Value=~/\A\(*[a-z_]+(\s+|\|)/i)
15909                { # ignore source defines:
15910                  #  static int gcry_pth_init ( void) { return ...
15911                  #  (RE_BACKSLASH_ESCAPE_IN_LISTS | RE...
15912                    next;
15913                }
15914                if($Old_Value=~/\(/i and $Old_Value!~/[\"\']/i)
15915                { # ignore source defines:
15916                  #  foo(p)
15917                    next;
15918                }
15919            }
15920            if(convert_integer($Old_Value) eq convert_integer($New_Value))
15921            { # 0x0001 and 0x1, 0x1 and 1 equal constants
15922                next;
15923            }
15924            if($Old_Value eq "0" and $New_Value eq "NULL")
15925            { # 0 => NULL
15926                next;
15927            }
15928            if($Old_Value eq "NULL" and $New_Value eq "0")
15929            { # NULL => 0
15930                next;
15931            }
15932            %{$ProblemsWithConstants{$Level}{$Constant}} = (
15933                "Target"=>$Constant,
15934                "Old_Value"=>$Old_Value,
15935                "New_Value"=>$New_Value  );
15936        }
15937    }
15938}
15939
15940sub convert_integer($)
15941{
15942    my $Value = $_[0];
15943    if($Value=~/\A0x[a-f0-9]+\Z/)
15944    { # hexadecimal
15945        return hex($Value);
15946    }
15947    elsif($Value=~/\A0[0-7]+\Z/)
15948    { # octal
15949        return oct($Value);
15950    }
15951    elsif($Value=~/\A0b[0-1]+\Z/)
15952    { # binary
15953        return oct($Value);
15954    }
15955    else {
15956        return $Value;
15957    }
15958}
15959
15960sub readSymbols($)
15961{
15962    my $LibVersion = $_[0];
15963    my @LibPaths = getSOPaths($LibVersion);
15964    if($#LibPaths==-1 and not $CheckHeadersOnly)
15965    {
15966        if($LibVersion==1)
15967        {
15968            printMsg("WARNING", "checking headers only");
15969            $CheckHeadersOnly = 1;
15970        }
15971        else {
15972            exitStatus("Error", "$SLIB_TYPE libraries are not found in ".$Descriptor{$LibVersion}{"Version"});
15973        }
15974    }
15975    my %GroupNames = map {parse_libname(get_filename($_), "name+ext", $OStarget)=>1} @LibPaths;
15976    foreach my $LibPath (sort {length($a)<=>length($b)} @LibPaths) {
15977        readSymbols_Lib($LibVersion, $LibPath, 0, \%GroupNames, "+Weak");
15978    }
15979    if(not $CheckHeadersOnly)
15980    {
15981        if($#LibPaths!=-1)
15982        {
15983            if(not keys(%{$Symbol_Library{$LibVersion}}))
15984            {
15985                printMsg("WARNING", "the set of public symbols in library(ies) is empty ($LibVersion)");
15986                printMsg("WARNING", "checking headers only");
15987                $CheckHeadersOnly = 1;
15988            }
15989        }
15990    }
15991
15992    # clean memory
15993   %SystemObjects = ();
15994}
15995
15996sub getSymbolSize($$)
15997{ # size from the shared library
15998    my ($Symbol, $LibVersion) = @_;
15999    return 0 if(not $Symbol);
16000    if(defined $Symbol_Library{$LibVersion}{$Symbol}
16001    and my $LibName = $Symbol_Library{$LibVersion}{$Symbol})
16002    {
16003        if(defined $Library_Symbol{$LibVersion}{$LibName}{$Symbol}
16004        and my $Size = $Library_Symbol{$LibVersion}{$LibName}{$Symbol})
16005        {
16006            if($Size<0) {
16007                return -$Size;
16008            }
16009        }
16010    }
16011    return 0;
16012}
16013
16014sub canonifyName($)
16015{ # make TIFFStreamOpen(char const*, std::basic_ostream<char, std::char_traits<char> >*)
16016  # to be TIFFStreamOpen(char const*, std::basic_ostream<char>*)
16017    my $Name = $_[0];
16018    my $Rem = "std::(allocator|less|char_traits|regex_traits)";
16019    while($Name=~/([^<>,]+),\s*$Rem<([^<>,]+)>\s*/ and $1 eq $3)
16020    {
16021        my $P = $1;
16022        $Name=~s/\Q$P\E,\s*$Rem<\Q$P\E>\s*/$P/g;
16023    }
16024    return $Name;
16025}
16026
16027sub translateSymbols(@)
16028{
16029    my $LibVersion = pop(@_);
16030    my (@MnglNames1, @MnglNames2, @UnmangledNames) = ();
16031    foreach my $Interface (sort @_)
16032    {
16033        if($Interface=~/\A_Z/)
16034        {
16035            next if($tr_name{$Interface});
16036            $Interface=~s/[\@\$]+(.*)\Z//;
16037            push(@MnglNames1, $Interface);
16038        }
16039        elsif($Interface=~/\A\?/) {
16040            push(@MnglNames2, $Interface);
16041        }
16042        else
16043        { # not mangled
16044            $tr_name{$Interface} = $Interface;
16045            $mangled_name_gcc{$Interface} = $Interface;
16046            $mangled_name{$LibVersion}{$Interface} = $Interface;
16047        }
16048    }
16049    if($#MnglNames1 > -1)
16050    { # GCC names
16051        @UnmangledNames = reverse(unmangleArray(@MnglNames1));
16052        foreach my $MnglName (@MnglNames1)
16053        {
16054            if(my $Unmangled = pop(@UnmangledNames))
16055            {
16056                $tr_name{$MnglName} = formatName(canonifyName($Unmangled));
16057                if(not $mangled_name_gcc{$tr_name{$MnglName}}) {
16058                    $mangled_name_gcc{$tr_name{$MnglName}} = $MnglName;
16059                }
16060                if($MnglName=~/\A_ZTV/
16061                and $tr_name{$MnglName}=~/vtable for (.+)/)
16062                { # bind class name and v-table symbol
16063                    my $ClassName = $1;
16064                    $ClassVTable{$ClassName} = $MnglName;
16065                    $VTableClass{$MnglName} = $ClassName;
16066                }
16067            }
16068        }
16069    }
16070    if($#MnglNames2 > -1)
16071    { # MSVC names
16072        @UnmangledNames = reverse(unmangleArray(@MnglNames2));
16073        foreach my $MnglName (@MnglNames2)
16074        {
16075            if(my $Unmangled = pop(@UnmangledNames))
16076            {
16077                $tr_name{$MnglName} = formatName($Unmangled);
16078                $mangled_name{$LibVersion}{$tr_name{$MnglName}} = $MnglName;
16079            }
16080        }
16081    }
16082    return \%tr_name;
16083}
16084
16085sub link_symbol($$$)
16086{
16087    my ($Symbol, $RunWith, $Deps) = @_;
16088    if(link_symbol_internal($Symbol, $RunWith, \%Symbol_Library)) {
16089        return 1;
16090    }
16091    if($Deps eq "+Deps")
16092    { # check the dependencies
16093        if(link_symbol_internal($Symbol, $RunWith, \%DepSymbol_Library)) {
16094            return 1;
16095        }
16096    }
16097    return 0;
16098}
16099
16100sub link_symbol_internal($$$)
16101{
16102    my ($Symbol, $RunWith, $Where) = @_;
16103    return 0 if(not $Where or not $Symbol);
16104    if($Where->{$RunWith}{$Symbol})
16105    { # the exact match by symbol name
16106        return 1;
16107    }
16108    if(my $VSym = $SymVer{$RunWith}{$Symbol})
16109    { # indirect symbol version, i.e.
16110      # foo_old and its symlink foo@v (or foo@@v)
16111      # foo_old may be in .symtab table
16112        if($Where->{$RunWith}{$VSym}) {
16113            return 1;
16114        }
16115    }
16116    my ($Sym, $Spec, $Ver) = separate_symbol($Symbol);
16117    if($Sym and $Ver)
16118    { # search for the symbol with the same version
16119      # or without version
16120        if($Where->{$RunWith}{$Sym})
16121        { # old: foo@v|foo@@v
16122          # new: foo
16123            return 1;
16124        }
16125        if($Where->{$RunWith}{$Sym."\@".$Ver})
16126        { # old: foo|foo@@v
16127          # new: foo@v
16128            return 1;
16129        }
16130        if($Where->{$RunWith}{$Sym."\@\@".$Ver})
16131        { # old: foo|foo@v
16132          # new: foo@@v
16133            return 1;
16134        }
16135    }
16136    return 0;
16137}
16138
16139sub readSymbols_App($)
16140{
16141    my $Path = $_[0];
16142    return () if(not $Path or not -f $Path);
16143    my @Imported = ();
16144    if($OSgroup eq "macos")
16145    {
16146        my $OtoolCmd = get_CmdPath("otool");
16147        if(not $OtoolCmd) {
16148            exitStatus("Not_Found", "can't find \"otool\"");
16149        }
16150        open(APP, "$OtoolCmd -IV \"$Path\" 2>\"$TMP_DIR/null\" |");
16151        while(<APP>) {
16152            if(/[^_]+\s+_?([\w\$]+)\s*\Z/) {
16153                push(@Imported, $1);
16154            }
16155        }
16156        close(APP);
16157    }
16158    elsif($OSgroup eq "windows")
16159    {
16160        my $DumpBinCmd = get_CmdPath("dumpbin");
16161        if(not $DumpBinCmd) {
16162            exitStatus("Not_Found", "can't find \"dumpbin.exe\"");
16163        }
16164        open(APP, "$DumpBinCmd /IMPORTS \"$Path\" 2>\"$TMP_DIR/null\" |");
16165        while(<APP>) {
16166            if(/\s*\w+\s+\w+\s+\w+\s+([\w\?\@]+)\s*/) {
16167                push(@Imported, $1);
16168            }
16169        }
16170        close(APP);
16171    }
16172    else
16173    {
16174        my $ReadelfCmd = get_CmdPath("readelf");
16175        if(not $ReadelfCmd) {
16176            exitStatus("Not_Found", "can't find \"readelf\"");
16177        }
16178        open(APP, "$ReadelfCmd -WhlSsdA \"$Path\" 2>\"$TMP_DIR/null\" |");
16179        my $symtab=0; # indicates that we are processing 'symtab' section of 'readelf' output
16180        while(<APP>)
16181        {
16182            if( /'.dynsym'/ ) {
16183                $symtab=0;
16184            }
16185            elsif($symtab == 1) {
16186                # do nothing with symtab (but there are some plans for the future)
16187                next;
16188            }
16189            elsif( /'.symtab'/ ) {
16190                $symtab=1;
16191            }
16192            elsif(my ($fullname, $idx, $Ndx, $type, $size, $bind) = readline_ELF($_))
16193            {
16194                if( $Ndx eq "UND" ) {
16195                    #only imported symbols
16196                    push(@Imported, $fullname);
16197                }
16198            }
16199        }
16200        close(APP);
16201    }
16202    return @Imported;
16203}
16204
16205sub readline_ELF($)
16206{
16207    if($_[0]=~/\s*\d+:\s+(\w*)\s+(\w+)\s+(\w+)\s+(\w+)\s+(\w+)\s+(\w+)\s([^\s]+)/)
16208    { # the line of 'readelf' output corresponding to the interface
16209      # symbian-style: _ZN12CCTTokenType4NewLE4TUid3RFs@@ctfinder{000a0000}[102020e5].dll
16210        my ($value, $size, $type, $bind,
16211        $vis, $Ndx, $fullname)=($1, $2, $3, $4, $5, $6, $7);
16212        if($bind!~/\A(WEAK|GLOBAL)\Z/) {
16213            return ();
16214        }
16215        if($type!~/\A(FUNC|IFUNC|OBJECT|COMMON)\Z/) {
16216            return ();
16217        }
16218        if($vis!~/\A(DEFAULT|PROTECTED)\Z/) {
16219            return ();
16220        }
16221        if($Ndx eq "ABS" and $value!~/\D|1|2|3|4|5|6|7|8|9/) {
16222            return ();
16223        }
16224        if($OStarget eq "symbian")
16225        {
16226            if($fullname=~/_\._\.absent_export_\d+/)
16227            { # "_._.absent_export_111"@@libstdcpp{00010001}[10282872].dll
16228                return ();
16229            }
16230            my @Elems = separate_symbol($fullname);
16231            $fullname = $Elems[0]; # remove internal version, {00020001}[10011235].dll
16232        }
16233        if(index($size, "0x")!=-1)
16234        { # 0x3d158
16235            $size = hex($size);
16236        }
16237        return ($fullname, $value, $Ndx, $type, $size, $bind);
16238    }
16239    return ();
16240}
16241
16242sub read_symlink($)
16243{
16244    my $Path = $_[0];
16245    return "" if(not $Path);
16246    return "" if(not -f $Path and not -l $Path);
16247    if(defined $Cache{"read_symlink"}{$Path}) {
16248        return $Cache{"read_symlink"}{$Path};
16249    }
16250    if(my $Res = readlink($Path)) {
16251        return ($Cache{"read_symlink"}{$Path} = $Res);
16252    }
16253    elsif(my $ReadlinkCmd = get_CmdPath("readlink")) {
16254        return ($Cache{"read_symlink"}{$Path} = `$ReadlinkCmd -n \"$Path\"`);
16255    }
16256    elsif(my $FileCmd = get_CmdPath("file"))
16257    {
16258        my $Info = `$FileCmd \"$Path\"`;
16259        if($Info=~/symbolic\s+link\s+to\s+['`"]*([\w\d\.\-\/\\]+)['`"]*/i) {
16260            return ($Cache{"read_symlink"}{$Path} = $1);
16261        }
16262    }
16263    return ($Cache{"read_symlink"}{$Path} = "");
16264}
16265
16266sub resolve_symlink($)
16267{
16268    my $Path = $_[0];
16269    return "" if(not $Path);
16270    return "" if(not -f $Path and not -l $Path);
16271    if(defined $Cache{"resolve_symlink"}{$Path}) {
16272        return $Cache{"resolve_symlink"}{$Path};
16273    }
16274    return $Path if(isCyclical(\@RecurSymlink, $Path));
16275    push(@RecurSymlink, $Path);
16276    if(-l $Path and my $Redirect=read_symlink($Path))
16277    {
16278        if(is_abs($Redirect))
16279        { # absolute path
16280            if($SystemRoot and $SystemRoot ne "/"
16281            and $Path=~/\A\Q$SystemRoot\E\//
16282            and (-f $SystemRoot.$Redirect or -l $SystemRoot.$Redirect))
16283            { # symbolic links from the sysroot
16284              # should be corrected to point to
16285              # the files inside sysroot
16286                $Redirect = $SystemRoot.$Redirect;
16287            }
16288            my $Res = resolve_symlink($Redirect);
16289            pop(@RecurSymlink);
16290            return ($Cache{"resolve_symlink"}{$Path} = $Res);
16291        }
16292        elsif($Redirect=~/\.\.[\/\\]/)
16293        { # relative path
16294            $Redirect = joinPath(get_dirname($Path), $Redirect);
16295            while($Redirect=~s&(/|\\)[^\/\\]+(\/|\\)\.\.(\/|\\)&$1&){};
16296            my $Res = resolve_symlink($Redirect);
16297            pop(@RecurSymlink);
16298            return ($Cache{"resolve_symlink"}{$Path} = $Res);
16299        }
16300        elsif(-f get_dirname($Path)."/".$Redirect)
16301        { # file name in the same directory
16302            my $Res = resolve_symlink(joinPath(get_dirname($Path), $Redirect));
16303            pop(@RecurSymlink);
16304            return ($Cache{"resolve_symlink"}{$Path} = $Res);
16305        }
16306        else
16307        { # broken link
16308            pop(@RecurSymlink);
16309            return ($Cache{"resolve_symlink"}{$Path} = "");
16310        }
16311    }
16312    pop(@RecurSymlink);
16313    return ($Cache{"resolve_symlink"}{$Path} = $Path);
16314}
16315
16316sub find_lib_path($$)
16317{
16318    my ($LibVersion, $DyLib) = @_;
16319    return "" if(not $DyLib or not $LibVersion);
16320    return $DyLib if(is_abs($DyLib));
16321    if(defined $Cache{"find_lib_path"}{$LibVersion}{$DyLib}) {
16322        return $Cache{"find_lib_path"}{$LibVersion}{$DyLib};
16323    }
16324    if(my @Paths = sort keys(%{$InputObject_Paths{$LibVersion}{$DyLib}})) {
16325        return ($Cache{"find_lib_path"}{$LibVersion}{$DyLib} = $Paths[0]);
16326    }
16327    elsif(my $DefaultPath = $DyLib_DefaultPath{$DyLib}) {
16328        return ($Cache{"find_lib_path"}{$LibVersion}{$DyLib} = $DefaultPath);
16329    }
16330    else
16331    {
16332        foreach my $Dir (sort keys(%DefaultLibPaths), sort keys(%{$SystemPaths{"lib"}}))
16333        { # search in default linker paths and then in all system paths
16334            if(-f $Dir."/".$DyLib) {
16335                return ($Cache{"find_lib_path"}{$LibVersion}{$DyLib} = joinPath($Dir,$DyLib));
16336            }
16337        }
16338        detectSystemObjects() if(not keys(%SystemObjects));
16339        if(my @AllObjects = keys(%{$SystemObjects{$DyLib}})) {
16340            return ($Cache{"find_lib_path"}{$LibVersion}{$DyLib} = $AllObjects[0]);
16341        }
16342        my $ShortName = parse_libname($DyLib, "name+ext", $OStarget);
16343        if($ShortName ne $DyLib
16344        and my $Path = find_lib_path($ShortName))
16345        { # FIXME: check this case
16346            return ($Cache{"find_lib_path"}{$LibVersion}{$DyLib} = $Path);
16347        }
16348        return ($Cache{"find_lib_path"}{$LibVersion}{$DyLib} = "");
16349    }
16350}
16351
16352sub readSymbols_Lib($$$$$)
16353{
16354    my ($LibVersion, $Lib_Path, $IsNeededLib, $GroupNames, $Weak) = @_;
16355    return if(not $Lib_Path or not -f $Lib_Path);
16356    my ($Lib_Dir, $Lib_Name) = separate_path(resolve_symlink($Lib_Path));
16357    return if($CheckedDyLib{$LibVersion}{$Lib_Name} and $IsNeededLib);
16358    return if(isCyclical(\@RecurLib, $Lib_Name) or $#RecurLib>=1);
16359    $CheckedDyLib{$LibVersion}{$Lib_Name} = 1;
16360    my $Lib_SName = parse_libname($Lib_Name, "name+ext", $OStarget);
16361
16362    if($CheckImpl and not $IsNeededLib) {
16363        getImplementations($LibVersion, $Lib_Path);
16364    }
16365
16366    push(@RecurLib, $Lib_Name);
16367    my (%Value_Interface, %Interface_Value, %NeededLib) = ();
16368    if(not $IsNeededLib)
16369    { # libstdc++ and libc are always used by other libs
16370      # if you test one of these libs then you not need
16371      # to find them in the system for reusing
16372        if(parse_libname($Lib_Name, "short", $OStarget) eq "libstdc++")
16373        { # libstdc++.so.6
16374            $STDCXX_TESTING = 1;
16375        }
16376        if(parse_libname($Lib_Name, "short", $OStarget) eq "libc")
16377        { # libc-2.11.3.so
16378            $GLIBC_TESTING = 1;
16379        }
16380    }
16381    my $DebugPath = "";
16382    if($Debug and not $DumpSystem)
16383    { # debug mode
16384        $DebugPath = $DEBUG_PATH{$LibVersion}."/libs/".get_filename($Lib_Path).".txt";
16385        mkpath(get_dirname($DebugPath));
16386    }
16387    if($OStarget eq "macos")
16388    { # Mac OS X: *.dylib, *.a
16389        my $OtoolCmd = get_CmdPath("otool");
16390        if(not $OtoolCmd) {
16391            exitStatus("Not_Found", "can't find \"otool\"");
16392        }
16393        $OtoolCmd .= " -TV \"$Lib_Path\" 2>\"$TMP_DIR/null\"";
16394        if($DebugPath)
16395        { # debug mode
16396          # write to file
16397            system($OtoolCmd." >\"$DebugPath\"");
16398            open(LIB, $DebugPath);
16399        }
16400        else
16401        { # write to pipe
16402            open(LIB, $OtoolCmd." |");
16403        }
16404        while(<LIB>)
16405        {
16406            if(/[^_]+\s+_([\w\$]+)\s*\Z/)
16407            {
16408                my $realname = $1;
16409                if($IsNeededLib)
16410                {
16411                    if(not $GroupNames->{$Lib_SName})
16412                    {
16413                        $DepSymbol_Library{$LibVersion}{$realname} = $Lib_Name;
16414                        $DepLibrary_Symbol{$LibVersion}{$Lib_Name}{$realname} = 1;
16415                    }
16416                }
16417                else
16418                {
16419                    $Symbol_Library{$LibVersion}{$realname} = $Lib_Name;
16420                    $Library_Symbol{$LibVersion}{$Lib_Name}{$realname} = 1;
16421                    if($COMMON_LANGUAGE{$LibVersion} ne "C++"
16422                    and $realname=~/\A(_Z|\?)/) {
16423                        setLanguage($LibVersion, "C++");
16424                    }
16425                    if($CheckObjectsOnly
16426                    and $LibVersion==1) {
16427                        $CheckedSymbols{"Binary"}{$realname} = 1;
16428                    }
16429                }
16430            }
16431        }
16432        close(LIB);
16433        if($LIB_TYPE eq "dynamic")
16434        { # dependencies
16435            open(LIB, "$OtoolCmd -L \"$Lib_Path\" 2>\"$TMP_DIR/null\" |");
16436            while(<LIB>)
16437            {
16438                if(/\s*([\/\\].+\.$LIB_EXT)\s*/
16439                and $1 ne $Lib_Path) {
16440                    $NeededLib{$1} = 1;
16441                }
16442            }
16443            close(LIB);
16444        }
16445    }
16446    elsif($OStarget eq "windows")
16447    { # Windows *.dll, *.lib
16448        my $DumpBinCmd = get_CmdPath("dumpbin");
16449        if(not $DumpBinCmd) {
16450            exitStatus("Not_Found", "can't find \"dumpbin\"");
16451        }
16452        $DumpBinCmd .= " /EXPORTS \"".$Lib_Path."\" 2>$TMP_DIR/null";
16453        if($DebugPath)
16454        { # debug mode
16455          # write to file
16456            system($DumpBinCmd." >\"$DebugPath\"");
16457            open(LIB, $DebugPath);
16458        }
16459        else
16460        { # write to pipe
16461            open(LIB, $DumpBinCmd." |");
16462        }
16463        while(<LIB>)
16464        { # 1197 4AC 0000A620 SetThreadStackGuarantee
16465          # 1198 4AD          SetThreadToken (forwarded to ...)
16466          # 3368 _o2i_ECPublicKey
16467            if(/\A\s*\d+\s+[a-f\d]+\s+[a-f\d]+\s+([\w\?\@]+)\s*\Z/i
16468            or /\A\s*\d+\s+[a-f\d]+\s+([\w\?\@]+)\s*\(\s*forwarded\s+/
16469            or /\A\s*\d+\s+_([\w\?\@]+)\s*\Z/)
16470            { # dynamic, static and forwarded symbols
16471                my $realname = $1;
16472                if($IsNeededLib)
16473                {
16474                    if(not $GroupNames->{$Lib_SName})
16475                    {
16476                        $DepSymbol_Library{$LibVersion}{$realname} = $Lib_Name;
16477                        $DepLibrary_Symbol{$LibVersion}{$Lib_Name}{$realname} = 1;
16478                    }
16479                }
16480                else
16481                {
16482                    $Symbol_Library{$LibVersion}{$realname} = $Lib_Name;
16483                    $Library_Symbol{$LibVersion}{$Lib_Name}{$realname} = 1;
16484                    if($COMMON_LANGUAGE{$LibVersion} ne "C++"
16485                    and $realname=~/\A(_Z|\?)/) {
16486                        setLanguage($LibVersion, "C++");
16487                    }
16488                    if($CheckObjectsOnly
16489                    and $LibVersion==1) {
16490                        $CheckedSymbols{"Binary"}{$realname} = 1;
16491                    }
16492                }
16493            }
16494        }
16495        close(LIB);
16496        if($LIB_TYPE eq "dynamic")
16497        { # dependencies
16498            open(LIB, "$DumpBinCmd /DEPENDENTS \"$Lib_Path\" 2>\"$TMP_DIR/null\" |");
16499            while(<LIB>)
16500            {
16501                if(/\s*([^\s]+?\.$LIB_EXT)\s*/i
16502                and $1 ne $Lib_Path) {
16503                    $NeededLib{path_format($1, $OSgroup)} = 1;
16504                }
16505            }
16506            close(LIB);
16507        }
16508    }
16509    else
16510    { # Unix; *.so, *.a
16511      # Symbian: *.dso, *.lib
16512        my $ReadelfCmd = get_CmdPath("readelf");
16513        if(not $ReadelfCmd) {
16514            exitStatus("Not_Found", "can't find \"readelf\"");
16515        }
16516        $ReadelfCmd .= " -WhlSsdA \"$Lib_Path\" 2>\"$TMP_DIR/null\"";
16517        if($DebugPath)
16518        { # debug mode
16519          # write to file
16520            system($ReadelfCmd." >\"$DebugPath\"");
16521            open(LIB, $DebugPath);
16522        }
16523        else
16524        { # write to pipe
16525            open(LIB, $ReadelfCmd." |");
16526        }
16527        my $symtab=0; # indicates that we are processing 'symtab' section of 'readelf' output
16528        while(<LIB>)
16529        {
16530            if($LIB_TYPE eq "dynamic")
16531            { # dynamic library specifics
16532                if($symtab==1)
16533                {
16534                    if(/'\.dynsym'/)
16535                    { # dynamic table
16536                        $symtab=0;
16537                        next;
16538                    }
16539                    else
16540                    { # do nothing with symtab
16541                        next;
16542                    }
16543                }
16544                elsif(/'\.symtab'/)
16545                { # symbol table
16546                    $symtab=1;
16547                    next;
16548                }
16549            }
16550            if(my ($fullname, $idx, $Ndx, $type, $size, $bind) = readline_ELF($_))
16551            { # read ELF entry
16552                if( $Ndx eq "UND" )
16553                { # ignore interfaces that are imported from somewhere else
16554                    next;
16555                }
16556                if($bind eq "WEAK"
16557                and $Weak eq "-Weak")
16558                { # skip WEAK symbols
16559                    next;
16560                }
16561                my ($realname, $version_spec, $version) = separate_symbol($fullname);
16562                if($type eq "OBJECT")
16563                { # global data
16564                    $GlobalDataObject{$LibVersion}{$fullname} = 1;
16565                    $GlobalDataObject{$LibVersion}{$realname} = 1;
16566                }
16567                if($IsNeededLib)
16568                {
16569                    if(not $GroupNames->{$Lib_SName})
16570                    {
16571                        $DepSymbol_Library{$LibVersion}{$fullname} = $Lib_Name;
16572                        $DepLibrary_Symbol{$LibVersion}{$Lib_Name}{$fullname} = ($type eq "OBJECT")?-$size:1;
16573                    }
16574                }
16575                else
16576                {
16577                    $Symbol_Library{$LibVersion}{$fullname} = $Lib_Name;
16578                    $Library_Symbol{$LibVersion}{$Lib_Name}{$fullname} = ($type eq "OBJECT")?-$size:1;
16579                    if($LIB_EXT eq "so")
16580                    { # value
16581                        $Interface_Value{$LibVersion}{$fullname} = $idx;
16582                        $Value_Interface{$LibVersion}{$idx}{$fullname} = 1;
16583                    }
16584                    if($COMMON_LANGUAGE{$LibVersion} ne "C++"
16585                    and $realname=~/\A(_Z|\?)/) {
16586                        setLanguage($LibVersion, "C++");
16587                    }
16588                    if($CheckObjectsOnly
16589                    and $LibVersion==1) {
16590                        $CheckedSymbols{"Binary"}{$fullname} = 1;
16591                    }
16592                }
16593            }
16594            elsif($LIB_TYPE eq "dynamic")
16595            { # dynamic library specifics
16596                if(/NEEDED.+\[([^\[\]]+)\]/)
16597                { # dependencies:
16598                  # 0x00000001 (NEEDED) Shared library: [libc.so.6]
16599                    $NeededLib{$1} = 1;
16600                }
16601            }
16602        }
16603        close(LIB);
16604    }
16605    if(not $IsNeededLib and $LIB_EXT eq "so")
16606    { # get symbol versions
16607        foreach my $Symbol (keys(%{$Symbol_Library{$LibVersion}}))
16608        {
16609            next if(index($Symbol,"\@")==-1);
16610            if(my $Value = $Interface_Value{$LibVersion}{$Symbol})
16611            {
16612                my $Interface_SymName = "";
16613                foreach my $Symbol_SameValue (keys(%{$Value_Interface{$LibVersion}{$Value}}))
16614                {
16615                    if($Symbol_SameValue ne $Symbol
16616                    and index($Symbol_SameValue,"\@")==-1)
16617                    {
16618                        $SymVer{$LibVersion}{$Symbol_SameValue} = $Symbol;
16619                        $Interface_SymName = $Symbol_SameValue;
16620                        last;
16621                    }
16622                }
16623                if(not $Interface_SymName)
16624                {
16625                    if($Symbol=~/\A([^\@\$\?]*)[\@\$]+([^\@\$]*)\Z/
16626                    and not $SymVer{$LibVersion}{$1}) {
16627                        $SymVer{$LibVersion}{$1} = $Symbol;
16628                    }
16629                }
16630            }
16631        }
16632    }
16633    foreach my $DyLib (sort keys(%NeededLib))
16634    {
16635        my $DepPath = find_lib_path($LibVersion, $DyLib);
16636        if($DepPath and -f $DepPath) {
16637            readSymbols_Lib($LibVersion, $DepPath, 1, $GroupNames, "+Weak");
16638        }
16639    }
16640    pop(@RecurLib);
16641    return $Library_Symbol{$LibVersion};
16642}
16643
16644sub get_path_prefixes($)
16645{
16646    my $Path = $_[0];
16647    my ($Dir, $Name) = separate_path($Path);
16648    my %Prefixes = ();
16649    foreach my $Prefix (reverse(split(/[\/\\]+/, $Dir)))
16650    {
16651        $Prefixes{$Name} = 1;
16652        $Name = joinPath($Prefix, $Name);
16653        last if(keys(%Prefixes)>5 or $Prefix eq "include");
16654    }
16655    return keys(%Prefixes);
16656}
16657
16658sub detectSystemHeaders()
16659{
16660    my @SysHeaders = ();
16661    foreach my $DevelPath (keys(%{$SystemPaths{"include"}}))
16662    {
16663        next if(not -d $DevelPath);
16664        # search for all header files in the /usr/include
16665        # with or without extension (ncurses.h, QtCore, ...)
16666        @SysHeaders = (@SysHeaders, cmd_find($DevelPath,"f","",""));
16667        foreach my $Link (cmd_find($DevelPath,"l","",""))
16668        { # add symbolic links
16669            if(-f $Link) {
16670                push(@SysHeaders, $Link);
16671            }
16672        }
16673    }
16674    foreach my $DevelPath (keys(%{$SystemPaths{"lib"}}))
16675    {
16676        next if(not -d $DevelPath);
16677        # search for config headers in the /usr/lib
16678        @SysHeaders = (@SysHeaders, cmd_find($DevelPath,"f","*.h",""));
16679        foreach my $Dir (cmd_find($DevelPath,"d","include",""))
16680        { # search for all include directories
16681          # this is for headers that are installed to /usr/lib
16682          # Example: Qt4 headers in Mandriva (/usr/lib/qt4/include/)
16683            if($Dir=~/\/(gcc|jvm|syslinux|kdb)\//) {
16684                next;
16685            }
16686            @SysHeaders = (@SysHeaders, cmd_find($Dir,"f","",""));
16687        }
16688    }
16689    foreach my $Path (@SysHeaders)
16690    {
16691        foreach my $Part (get_path_prefixes($Path)) {
16692            $SystemHeaders{$Part}{$Path}=1;
16693        }
16694    }
16695}
16696
16697sub detectSystemObjects()
16698{
16699    foreach my $DevelPath (keys(%{$SystemPaths{"lib"}}))
16700    {
16701        next if(not -d $DevelPath);
16702        foreach my $Path (find_libs($DevelPath,"",""))
16703        { # search for shared libraries in the /usr/lib (including symbolic links)
16704            $SystemObjects{parse_libname(get_filename($Path), "name+ext", $OStarget)}{$Path}=1;
16705        }
16706    }
16707}
16708
16709sub getSOPaths($)
16710{
16711    my $LibVersion = $_[0];
16712    my @SoPaths = ();
16713    foreach my $Dest (split(/\s*\n\s*/, $Descriptor{$LibVersion}{"Libs"}))
16714    {
16715        if(not -e $Dest) {
16716            exitStatus("Access_Error", "can't access \'$Dest\'");
16717        }
16718        my @SoPaths_Dest = getSOPaths_Dest($Dest, $LibVersion);
16719        foreach (@SoPaths_Dest) {
16720            push(@SoPaths, $_);
16721        }
16722    }
16723    return sort @SoPaths;
16724}
16725
16726sub skip_lib($$)
16727{
16728    my ($Path, $LibVersion) = @_;
16729    return 1 if(not $Path or not $LibVersion);
16730    my $Name = get_filename($Path);
16731    if($SkipLibs{$LibVersion}{"Name"}{$Name}) {
16732        return 1;
16733    }
16734    my $ShortName = parse_libname($Name, "name+ext", $OStarget);
16735    if($SkipLibs{$LibVersion}{"Name"}{$ShortName}) {
16736        return 1;
16737    }
16738    foreach my $Dir (keys(%{$SkipLibs{$LibVersion}{"Path"}}))
16739    {
16740        if($Path=~/\Q$Dir\E([\/\\]|\Z)/) {
16741            return 1;
16742        }
16743    }
16744    foreach my $P (keys(%{$SkipLibs{$LibVersion}{"Pattern"}}))
16745    {
16746        if($Name=~/$P/) {
16747            return 1;
16748        }
16749        if($P=~/[\/\\]/ and $Path=~/$P/) {
16750            return 1;
16751        }
16752    }
16753    return 0;
16754}
16755
16756sub skipHeader($$)
16757{
16758    my ($Path, $LibVersion) = @_;
16759    return 1 if(not $Path or not $LibVersion);
16760    if(not keys(%{$SkipHeaders{$LibVersion}})) {
16761        return 0;
16762    }
16763    if(defined $Cache{"skipHeader"}{$Path}) {
16764        return $Cache{"skipHeader"}{$Path};
16765    }
16766    return ($Cache{"skipHeader"}{$Path} = skipHeader_I(@_));
16767}
16768
16769sub skipHeader_I($$)
16770{ # returns:
16771  #  1 - if header should NOT be included and checked
16772  #  2 - if header should NOT be included, but should be checked
16773    my ($Path, $LibVersion) = @_;
16774    my $Name = get_filename($Path);
16775    if(my $Kind = $SkipHeaders{$LibVersion}{"Name"}{$Name}) {
16776        return $Kind;
16777    }
16778    foreach my $D (keys(%{$SkipHeaders{$LibVersion}{"Path"}}))
16779    {
16780        if($Path=~/\Q$D\E([\/\\]|\Z)/) {
16781            return $SkipHeaders{$LibVersion}{"Path"}{$D};
16782        }
16783    }
16784    foreach my $P (keys(%{$SkipHeaders{$LibVersion}{"Pattern"}}))
16785    {
16786        if(my $Kind = $SkipHeaders{$LibVersion}{"Pattern"}{$P})
16787        {
16788            if($Name=~/$P/) {
16789                return $Kind;
16790            }
16791            if($P=~/[\/\\]/ and $Path=~/$P/) {
16792                return $Kind;
16793            }
16794        }
16795    }
16796    return 0;
16797}
16798
16799sub register_objects($$)
16800{
16801    my ($Dir, $LibVersion) = @_;
16802    if($SystemPaths{"lib"}{$Dir})
16803    { # system directory
16804        return;
16805    }
16806    if($RegisteredObjDirs{$LibVersion}{$Dir})
16807    { # already registered
16808        return;
16809    }
16810    foreach my $Path (find_libs($Dir,"",1))
16811    {
16812        next if(ignore_path($Path));
16813        next if(skip_lib($Path, $LibVersion));
16814        $InputObject_Paths{$LibVersion}{get_filename($Path)}{$Path} = 1;
16815    }
16816    $RegisteredObjDirs{$LibVersion}{$Dir} = 1;
16817}
16818
16819sub getSOPaths_Dest($$)
16820{
16821    my ($Dest, $LibVersion) = @_;
16822    if(skip_lib($Dest, $LibVersion)) {
16823        return ();
16824    }
16825    if(-f $Dest)
16826    {
16827        if(not parse_libname($Dest, "name", $OStarget)) {
16828            exitStatus("Error", "incorrect format of library (should be *.$LIB_EXT): \'$Dest\'");
16829        }
16830        $InputObject_Paths{$LibVersion}{get_filename($Dest)}{$Dest} = 1;
16831        register_objects(get_dirname($Dest), $LibVersion);
16832        return ($Dest);
16833    }
16834    elsif(-d $Dest)
16835    {
16836        $Dest=~s/[\/\\]+\Z//g;
16837        my %Libs = ();
16838        if($SystemPaths{"lib"}{$Dest})
16839        { # you have specified /usr/lib as the search directory (<libs>) in the XML descriptor
16840          # and the real name of the library by -l option (bz2, stdc++, Xaw, ...)
16841            foreach my $Path (cmd_find($Dest,"","*".esc($TargetLibraryName)."*\.$LIB_EXT*",2))
16842            { # all files and symlinks that match the name of a library
16843                if(get_filename($Path)=~/\A(|lib)\Q$TargetLibraryName\E[\d\-]*\.$LIB_EXT[\d\.]*\Z/i)
16844                {
16845                    $InputObject_Paths{$LibVersion}{get_filename($Path)}{$Path} = 1;
16846                    $Libs{resolve_symlink($Path)}=1;
16847                }
16848            }
16849        }
16850        else
16851        { # search for all files and symlinks
16852            foreach my $Path (find_libs($Dest,"",""))
16853            {
16854                next if(ignore_path($Path));
16855                next if(skip_lib($Path, $LibVersion));
16856                $InputObject_Paths{$LibVersion}{get_filename($Path)}{$Path} = 1;
16857                $Libs{resolve_symlink($Path)}=1;
16858            }
16859            if($OSgroup eq "macos")
16860            { # shared libraries on MacOS X may have no extension
16861                foreach my $Path (cmd_find($Dest,"f","",""))
16862                {
16863                    next if(ignore_path($Path));
16864                    next if(skip_lib($Path, $LibVersion));
16865                    if(get_filename($Path)!~/\./
16866                    and cmd_file($Path)=~/(shared|dynamic)\s+library/i)
16867                    {
16868                        $InputObject_Paths{$LibVersion}{get_filename($Path)}{$Path} = 1;
16869                        $Libs{resolve_symlink($Path)}=1;
16870                    }
16871                }
16872            }
16873        }
16874        return keys(%Libs);
16875    }
16876    else {
16877        return ();
16878    }
16879}
16880
16881sub isCyclical($$)
16882{
16883    my ($Stack, $Value) = @_;
16884    return (grep {$_ eq $Value} @{$Stack});
16885}
16886
16887sub generateTemplate()
16888{
16889    writeFile("VERSION.xml", $DescriptorTemplate."\n");
16890    printMsg("INFO", "XML-descriptor template ./VERSION.xml has been generated");
16891}
16892
16893sub detectWordSize()
16894{
16895    return "" if(not $GCC_PATH);
16896    if($Cache{"detectWordSize"}) {
16897        return $Cache{"detectWordSize"};
16898    }
16899    writeFile("$TMP_DIR/empty.h", "");
16900    my $Defines = `$GCC_PATH -E -dD \"$TMP_DIR/empty.h\"`;
16901    unlink("$TMP_DIR/empty.h");
16902    my $WSize = 0;
16903    if($Defines=~/ __SIZEOF_POINTER__\s+(\d+)/)
16904    { # GCC 4
16905        $WSize = $1;
16906    }
16907    elsif($Defines=~/ __PTRDIFF_TYPE__\s+(\w+)/)
16908    { # GCC 3
16909        my $PTRDIFF = $1;
16910        if($PTRDIFF=~/long/) {
16911            $WSize = "8";
16912        }
16913        else {
16914            $WSize = "4";
16915        }
16916    }
16917    if(not int($WSize)) {
16918        exitStatus("Error", "can't check WORD size");
16919    }
16920    return ($Cache{"detectWordSize"} = $WSize);
16921}
16922
16923sub majorVersion($)
16924{
16925    my $V = $_[0];
16926    return 0 if(not $V);
16927    my @VParts = split(/\./, $V);
16928    return $VParts[0];
16929}
16930
16931sub cmpVersions($$)
16932{ # compare two versions in dotted-numeric format
16933    my ($V1, $V2) = @_;
16934    return 0 if($V1 eq $V2);
16935    my @V1Parts = split(/\./, $V1);
16936    my @V2Parts = split(/\./, $V2);
16937    for (my $i = 0; $i <= $#V1Parts && $i <= $#V2Parts; $i++) {
16938        return -1 if(int($V1Parts[$i]) < int($V2Parts[$i]));
16939        return 1 if(int($V1Parts[$i]) > int($V2Parts[$i]));
16940    }
16941    return -1 if($#V1Parts < $#V2Parts);
16942    return 1 if($#V1Parts > $#V2Parts);
16943    return 0;
16944}
16945
16946sub read_ABI_Dump($$)
16947{
16948    my ($LibVersion, $Path) = @_;
16949    return if(not $LibVersion or not -e $Path);
16950    my $FilePath = "";
16951    if($Path=~/\.abi\Z/)
16952    { # input *.abi
16953        $FilePath = $Path;
16954    }
16955    else
16956    { # input *.abi.tar.gz
16957        $FilePath = unpackDump($Path);
16958    }
16959    if($FilePath!~/\.abi\Z/) {
16960        exitStatus("Invalid_Dump", "specified ABI dump \'$Path\' is not valid, try to recreate it");
16961    }
16962
16963    my $Line = readLineNum($FilePath, 1);
16964    if($Line=~/xml/) {
16965        exitStatus("Invalid_Dump", "reading of XML-format ABI dumps is not implemented yet");
16966    }
16967
16968    open(DUMP, $FilePath);
16969    local $/ = undef;
16970    my $Content = <DUMP>;
16971    close(DUMP);
16972
16973    if(get_dirname($FilePath) eq $TMP_DIR."/unpack")
16974    { # remove temp file
16975        unlink($FilePath);
16976    }
16977    if($Content!~/};\s*\Z/) {
16978        exitStatus("Invalid_Dump", "specified ABI dump \'$Path\' is not valid, try to recreate it");
16979    }
16980    my $LibraryABI = eval($Content);
16981    if(not $LibraryABI) {
16982        exitStatus("Error", "internal error - eval() procedure seem to not working correctly, try to remove 'use strict' and try again");
16983    }
16984    # new dumps (>=1.22) have a personal versioning
16985    my $DumpVersion = $LibraryABI->{"ABI_DUMP_VERSION"};
16986    my $ToolVersion = $LibraryABI->{"ABI_COMPLIANCE_CHECKER_VERSION"};
16987    if(not $DumpVersion)
16988    { # old dumps (<=1.21.6) have been marked by the tool version
16989        $DumpVersion = $ToolVersion;
16990    }
16991    $UsedDump{$LibVersion}{"V"} = $DumpVersion;
16992    if(majorVersion($DumpVersion) ne majorVersion($ABI_DUMP_VERSION))
16993    { # should be compatible with dumps of the same major version
16994        if(cmpVersions($DumpVersion, $ABI_DUMP_VERSION)>0)
16995        { # Don't know how to parse future dump formats
16996            exitStatus("Dump_Version", "incompatible version $DumpVersion of specified ABI dump (newer than $ABI_DUMP_VERSION)");
16997        }
16998        elsif(cmpVersions($DumpVersion, $TOOL_VERSION)>0 and not $LibraryABI->{"ABI_DUMP_VERSION"})
16999        { # Don't know how to parse future dump formats
17000            exitStatus("Dump_Version", "incompatible version $DumpVersion of specified ABI dump (newer than $TOOL_VERSION)");
17001        }
17002        if($UseOldDumps)
17003        {
17004            if(cmpVersions($DumpVersion, $OLDEST_SUPPORTED_VERSION)<0) {
17005                exitStatus("Dump_Version", "incompatible version $DumpVersion of specified ABI dump (older than $OLDEST_SUPPORTED_VERSION)");
17006            }
17007        }
17008        else
17009        {
17010            my $Msg = "incompatible version $DumpVersion of specified ABI dump (allowed only ".majorVersion($ABI_DUMP_VERSION).".0<=V<=$ABI_DUMP_VERSION)";
17011            if(cmpVersions($DumpVersion, $OLDEST_SUPPORTED_VERSION)>=0) {
17012                $Msg .= "\nUse -old-dumps option to use old-version dumps ($OLDEST_SUPPORTED_VERSION<=V<".majorVersion($ABI_DUMP_VERSION).".0)";
17013            }
17014            exitStatus("Dump_Version", $Msg);
17015        }
17016    }
17017    if(not checkDump($LibVersion, "2.11"))
17018    { # old ABI dumps
17019        $UsedDump{$LibVersion}{"BinOnly"} = 1;
17020    }
17021    elsif($LibraryABI->{"BinOnly"})
17022    { # ABI dump created with --binary option
17023        $UsedDump{$LibVersion}{"BinOnly"} = 1;
17024    }
17025    else
17026    { # default
17027        $UsedDump{$LibVersion}{"SrcBin"} = 1;
17028    }
17029    if(defined $LibraryABI->{"Mode"}
17030    and $LibraryABI->{"Mode"} eq "Extended")
17031    { # --ext option
17032        $ExtendedCheck = 1;
17033    }
17034    if(my $Lang = $LibraryABI->{"Language"})
17035    {
17036        $UsedDump{$LibVersion}{"L"} = $Lang;
17037        setLanguage($LibVersion, $Lang);
17038    }
17039    if(checkDump($LibVersion, "2.15")) {
17040        $TypeInfo{$LibVersion} = $LibraryABI->{"TypeInfo"};
17041    }
17042    else
17043    { # support for old ABI dumps
17044        my $TInfo = $LibraryABI->{"TypeInfo"};
17045        if(not $TInfo)
17046        { # support for older ABI dumps
17047            $TInfo = $LibraryABI->{"TypeDescr"};
17048        }
17049        my %Tid_TDid = ();
17050        foreach my $TDid (keys(%{$TInfo}))
17051        {
17052            foreach my $Tid (keys(%{$TInfo->{$TDid}}))
17053            {
17054                $MAX_ID = $Tid if($Tid>$MAX_ID);
17055                $MAX_ID = $TDid if($TDid and $TDid>$MAX_ID);
17056                $Tid_TDid{$Tid}{$TDid}=1;
17057            }
17058        }
17059        my %NewID = ();
17060        foreach my $Tid (keys(%Tid_TDid))
17061        {
17062            my @TDids = keys(%{$Tid_TDid{$Tid}});
17063            if($#TDids>=1)
17064            {
17065                foreach my $TDid (@TDids)
17066                {
17067                    if($TDid) {
17068                        %{$TypeInfo{$LibVersion}{$Tid}} = %{$TInfo->{$TDid}{$Tid}};
17069                    }
17070                    else
17071                    {
17072                        if(my $ID = ++$MAX_ID)
17073                        {
17074                            $NewID{$TDid}{$Tid} = $ID;
17075                            %{$TypeInfo{$LibVersion}{$ID}} = %{$TInfo->{$TDid}{$Tid}};
17076                            $TypeInfo{$LibVersion}{$ID}{"Tid"} = $ID;
17077                        }
17078                    }
17079                }
17080            }
17081            else
17082            {
17083                my $TDid = $TDids[0];
17084                %{$TypeInfo{$LibVersion}{$Tid}} = %{$TInfo->{$TDid}{$Tid}};
17085            }
17086        }
17087        foreach my $Tid (keys(%{$TypeInfo{$LibVersion}}))
17088        {
17089            my %Info = %{$TypeInfo{$LibVersion}{$Tid}};
17090            if(defined $Info{"BaseType"})
17091            {
17092                my $Bid = $Info{"BaseType"}{"Tid"};
17093                my $BDid = $Info{"BaseType"}{"TDid"};
17094                $BDid="" if(not defined $BDid);
17095                if(defined $NewID{$BDid} and my $ID = $NewID{$BDid}{$Bid}) {
17096                    $TypeInfo{$LibVersion}{$Tid}{"BaseType"}{"Tid"} = $ID;
17097                }
17098                delete($TypeInfo{$LibVersion}{$Tid}{"BaseType"}{"TDid"});
17099            }
17100            delete($TypeInfo{$LibVersion}{$Tid}{"TDid"});
17101        }
17102    }
17103    read_Machine_DumpInfo($LibraryABI, $LibVersion);
17104    $SymbolInfo{$LibVersion} = $LibraryABI->{"SymbolInfo"};
17105    if(not $SymbolInfo{$LibVersion})
17106    { # support for old dumps
17107        $SymbolInfo{$LibVersion} = $LibraryABI->{"FuncDescr"};
17108    }
17109    if(not keys(%{$SymbolInfo{$LibVersion}}))
17110    { # validation of old-version dumps
17111        if(not $ExtendedCheck) {
17112            exitStatus("Invalid_Dump", "the input dump d$LibVersion is invalid");
17113        }
17114    }
17115    $Library_Symbol{$LibVersion} = $LibraryABI->{"Symbols"};
17116    if(not $Library_Symbol{$LibVersion})
17117    { # support for old dumps
17118        $Library_Symbol{$LibVersion} = $LibraryABI->{"Interfaces"};
17119    }
17120    if(checkDump($LibVersion, "2.15")) {
17121        $DepLibrary_Symbol{$LibVersion} = $LibraryABI->{"DepSymbols"};
17122    }
17123    else
17124    { # support for old ABI dumps
17125        my $DepSymbols = $LibraryABI->{"DepSymbols"};
17126        if(not $DepSymbols) {
17127            $DepSymbols = $LibraryABI->{"DepInterfaces"};
17128        }
17129        if(not $DepSymbols)
17130        { # Cannot reconstruct DepSymbols. This may result in false
17131          # positives if the old dump is for library 2. Not a problem if
17132          # old dumps are only from old libraries.
17133            $DepSymbols = {};
17134        }
17135        foreach my $Symbol (keys(%{$DepSymbols})) {
17136            $DepSymbol_Library{$LibVersion}{$Symbol} = 1;
17137        }
17138    }
17139    $SymVer{$LibVersion} = $LibraryABI->{"SymbolVersion"};
17140    $Descriptor{$LibVersion}{"Version"} = $LibraryABI->{"LibraryVersion"};
17141    $SkipTypes{$LibVersion} = $LibraryABI->{"SkipTypes"};
17142    if(not $SkipTypes{$LibVersion})
17143    { # support for old dumps
17144        $SkipTypes{$LibVersion} = $LibraryABI->{"OpaqueTypes"};
17145    }
17146    $SkipSymbols{$LibVersion} = $LibraryABI->{"SkipSymbols"};
17147    if(not $SkipSymbols{$LibVersion})
17148    { # support for old dumps
17149        $SkipSymbols{$LibVersion} = $LibraryABI->{"SkipInterfaces"};
17150    }
17151    if(not $SkipSymbols{$LibVersion})
17152    { # support for old dumps
17153        $SkipSymbols{$LibVersion} = $LibraryABI->{"InternalInterfaces"};
17154    }
17155    $SkipNameSpaces{$LibVersion} = $LibraryABI->{"SkipNameSpaces"};
17156    $TargetHeaders{$LibVersion} = $LibraryABI->{"TargetHeaders"};
17157    foreach my $Path (keys(%{$LibraryABI->{"SkipHeaders"}}))
17158    {
17159        $SkipHeadersList{$LibVersion}{$Path} = $LibraryABI->{"SkipHeaders"}{$Path};
17160        my ($CPath, $Type) = classifyPath($Path);
17161        $SkipHeaders{$LibVersion}{$Type}{$CPath} = $LibraryABI->{"SkipHeaders"}{$Path};
17162    }
17163    read_Headers_DumpInfo($LibraryABI, $LibVersion);
17164    read_Libs_DumpInfo($LibraryABI, $LibVersion);
17165    if(not checkDump($LibVersion, "2.10.1")
17166    or not $TargetHeaders{$LibVersion})
17167    { # support for old ABI dumps: added target headers
17168        foreach (keys(%{$Registered_Headers{$LibVersion}})) {
17169            $TargetHeaders{$LibVersion}{get_filename($_)}=1;
17170        }
17171    }
17172    $Constants{$LibVersion} = $LibraryABI->{"Constants"};
17173    $NestedNameSpaces{$LibVersion} = $LibraryABI->{"NameSpaces"};
17174    if(not $NestedNameSpaces{$LibVersion})
17175    { # support for old dumps
17176      # Cannot reconstruct NameSpaces. This may affect design
17177      # of the compatibility report.
17178        $NestedNameSpaces{$LibVersion} = {};
17179    }
17180    # target system type
17181    # needed to adopt HTML report
17182    if(not $DumpSystem)
17183    { # to use in createSymbolsList(...)
17184        $OStarget = $LibraryABI->{"Target"};
17185    }
17186    # recreate environment
17187    foreach my $Lib_Name (keys(%{$Library_Symbol{$LibVersion}}))
17188    {
17189        foreach my $Symbol (keys(%{$Library_Symbol{$LibVersion}{$Lib_Name}}))
17190        {
17191            $Symbol_Library{$LibVersion}{$Symbol} = $Lib_Name;
17192            if($Library_Symbol{$LibVersion}{$Lib_Name}{$Symbol}<=-1)
17193            { # data marked as -size in the dump
17194                $GlobalDataObject{$LibVersion}{$Symbol}=1;
17195            }
17196            if($COMMON_LANGUAGE{$LibVersion} ne "C++"
17197            and $Symbol=~/\A(_Z|\?)/) {
17198                setLanguage($LibVersion, "C++");
17199            }
17200        }
17201    }
17202    foreach my $Lib_Name (keys(%{$DepLibrary_Symbol{$LibVersion}}))
17203    {
17204        foreach my $Symbol (keys(%{$DepLibrary_Symbol{$LibVersion}{$Lib_Name}})) {
17205            $DepSymbol_Library{$LibVersion}{$Symbol} = $Lib_Name;
17206        }
17207    }
17208
17209    my @VFunc = ();
17210    foreach my $InfoId (keys(%{$SymbolInfo{$LibVersion}}))
17211    {
17212        my $MnglName = $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"};
17213        if($MnglName)
17214        {
17215            if(not $Symbol_Library{$LibVersion}{$MnglName}
17216            and not $DepSymbol_Library{$LibVersion}{$MnglName}) {
17217                push(@VFunc, $MnglName);
17218            }
17219        }
17220    }
17221    translateSymbols(@VFunc, $LibVersion);
17222    translateSymbols(keys(%{$Symbol_Library{$LibVersion}}), $LibVersion);
17223    translateSymbols(keys(%{$DepSymbol_Library{$LibVersion}}), $LibVersion);
17224
17225    foreach my $TypeId (sort {int($a)<=>int($b)} keys(%{$TypeInfo{$LibVersion}}))
17226    {
17227        if(defined $TypeInfo{$LibVersion}{$TypeId}{"BaseClass"})
17228        { # support for old ABI dumps < 2.0 (ACC 1.22)
17229            foreach my $BId (keys(%{$TypeInfo{$LibVersion}{$TypeId}{"BaseClass"}}))
17230            {
17231                if(my $Access = $TypeInfo{$LibVersion}{$TypeId}{"BaseClass"}{$BId})
17232                {
17233                    if($Access ne "public") {
17234                        $TypeInfo{$LibVersion}{$TypeId}{"Base"}{$BId}{"access"} = $Access;
17235                    }
17236                }
17237                $TypeInfo{$LibVersion}{$TypeId}{"Base"}{$BId} = {};
17238            }
17239            delete($TypeInfo{$LibVersion}{$TypeId}{"BaseClass"});
17240        }
17241        my %TInfo = %{$TypeInfo{$LibVersion}{$TypeId}};
17242        if(defined $TInfo{"Base"})
17243        {
17244            foreach (keys(%{$TInfo{"Base"}})) {
17245                $Class_SubClasses{$LibVersion}{$_}{$TypeId}=1;
17246            }
17247        }
17248        if($TInfo{"Type"} eq "Typedef" and defined $TInfo{"BaseType"})
17249        {
17250            if(my $BTid = $TInfo{"BaseType"}{"Tid"})
17251            {
17252                my $BName = $TypeInfo{$LibVersion}{$BTid}{"Name"};
17253                if(not $BName)
17254                { # broken type
17255                    next;
17256                }
17257                if($TInfo{"Name"} eq $BName)
17258                { # typedef to "class Class"
17259                    # should not be registered in TName_Tid
17260                    next;
17261                }
17262                if(not $Typedef_BaseName{$LibVersion}{$TInfo{"Name"}}) {
17263                    $Typedef_BaseName{$LibVersion}{$TInfo{"Name"}} = $BName;
17264                }
17265            }
17266        }
17267        if(not $TName_Tid{$LibVersion}{$TInfo{"Name"}})
17268        { # classes: class (id1), typedef (artificial, id2 > id1)
17269            $TName_Tid{$LibVersion}{$TInfo{"Name"}} = $TypeId;
17270        }
17271    }
17272
17273    if(not checkDump($LibVersion, "2.15"))
17274    { # support for old ABI dumps
17275        my %Dups = ();
17276        foreach my $InfoId (keys(%{$SymbolInfo{$LibVersion}}))
17277        {
17278            if(my $ClassId = $SymbolInfo{$LibVersion}{$InfoId}{"Class"})
17279            {
17280                if(not defined $TypeInfo{$LibVersion}{$ClassId})
17281                { # remove template decls
17282                    delete($SymbolInfo{$LibVersion}{$InfoId});
17283                    next;
17284                }
17285            }
17286            my $MName = $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"};
17287            if(not $MName and $SymbolInfo{$LibVersion}{$InfoId}{"Class"})
17288            { # templates
17289                delete($SymbolInfo{$LibVersion}{$InfoId});
17290            }
17291        }
17292    }
17293
17294    $Descriptor{$LibVersion}{"Dump"} = 1;
17295}
17296
17297sub read_Machine_DumpInfo($$)
17298{
17299    my ($LibraryABI, $LibVersion) = @_;
17300    if($LibraryABI->{"Arch"}) {
17301        $CPU_ARCH{$LibVersion} = $LibraryABI->{"Arch"};
17302    }
17303    if($LibraryABI->{"WordSize"}) {
17304        $WORD_SIZE{$LibVersion} = $LibraryABI->{"WordSize"};
17305    }
17306    else
17307    { # support for old dumps
17308        $WORD_SIZE{$LibVersion} = $LibraryABI->{"SizeOfPointer"};
17309    }
17310    if(not $WORD_SIZE{$LibVersion})
17311    { # support for old dumps (<1.23)
17312        if(my $Tid = getTypeIdByName("char*", $LibVersion))
17313        { # size of char*
17314            $WORD_SIZE{$LibVersion} = $TypeInfo{$LibVersion}{$Tid}{"Size"};
17315        }
17316        else
17317        {
17318            my $PSize = 0;
17319            foreach my $Tid (keys(%{$TypeInfo{$LibVersion}}))
17320            {
17321                if($TypeInfo{$LibVersion}{$Tid}{"Type"} eq "Pointer")
17322                { # any "pointer"-type
17323                    $PSize = $TypeInfo{$LibVersion}{$Tid}{"Size"};
17324                    last;
17325                }
17326            }
17327            if($PSize)
17328            { # a pointer type size
17329                $WORD_SIZE{$LibVersion} = $PSize;
17330            }
17331            else {
17332                printMsg("WARNING", "cannot identify a WORD size in the ABI dump (too old format)");
17333            }
17334        }
17335    }
17336    if($LibraryABI->{"GccVersion"}) {
17337        $GCC_VERSION{$LibVersion} = $LibraryABI->{"GccVersion"};
17338    }
17339}
17340
17341sub read_Libs_DumpInfo($$)
17342{
17343    my ($LibraryABI, $LibVersion) = @_;
17344    if(keys(%{$Library_Symbol{$LibVersion}})
17345    and not $DumpAPI) {
17346        $Descriptor{$LibVersion}{"Libs"} = "OK";
17347    }
17348}
17349
17350sub read_Headers_DumpInfo($$)
17351{
17352    my ($LibraryABI, $LibVersion) = @_;
17353    if(keys(%{$LibraryABI->{"Headers"}})
17354    and not $DumpAPI) {
17355        $Descriptor{$LibVersion}{"Headers"} = "OK";
17356    }
17357    foreach my $Identity (keys(%{$LibraryABI->{"Headers"}}))
17358    { # headers info is stored in the old dumps in the different way
17359        if($UseOldDumps
17360        and my $Name = $LibraryABI->{"Headers"}{$Identity}{"Name"})
17361        { # support for old dumps: headers info corrected in 1.22
17362            $Identity = $Name;
17363        }
17364        $Registered_Headers{$LibVersion}{$Identity}{"Identity"} = $Identity;
17365    }
17366}
17367
17368sub find_libs($$$)
17369{
17370    my ($Path, $Type, $MaxDepth) = @_;
17371    # FIXME: correct the search pattern
17372    return cmd_find($Path, $Type, ".*\\.$LIB_EXT\[0-9.]*", $MaxDepth);
17373}
17374
17375sub createDescriptor($$)
17376{
17377    my ($LibVersion, $Path) = @_;
17378    if(not $LibVersion or not $Path
17379    or not -e $Path) {
17380        return "";
17381    }
17382    if(-d $Path)
17383    { # directory with headers files and shared objects
17384        return "
17385            <version>
17386                ".$TargetVersion{$LibVersion}."
17387            </version>
17388
17389            <headers>
17390                $Path
17391            </headers>
17392
17393            <libs>
17394                $Path
17395            </libs>";
17396    }
17397    else
17398    { # files
17399        if($Path=~/\.xml\Z/i)
17400        { # standard XML-descriptor
17401            return readFile($Path);
17402        }
17403        elsif(is_header($Path, 2, $LibVersion))
17404        { # header file
17405            return "
17406                <version>
17407                    ".$TargetVersion{$LibVersion}."
17408                </version>
17409
17410                <headers>
17411                    $Path
17412                </headers>
17413
17414                <libs>
17415                    none
17416                </libs>";
17417        }
17418        elsif(parse_libname($Path, "name", $OStarget))
17419        { # shared object
17420            return "
17421                <version>
17422                    ".$TargetVersion{$LibVersion}."
17423                </version>
17424
17425                <headers>
17426                    none
17427                </headers>
17428
17429                <libs>
17430                    $Path
17431                </libs>";
17432        }
17433        else
17434        { # standard XML-descriptor
17435            return readFile($Path);
17436        }
17437    }
17438}
17439
17440sub detect_lib_default_paths()
17441{
17442    my %LPaths = ();
17443    if($OSgroup eq "bsd")
17444    {
17445        if(my $LdConfig = get_CmdPath("ldconfig"))
17446        {
17447            foreach my $Line (split(/\n/, `$LdConfig -r 2>\"$TMP_DIR/null\"`))
17448            {
17449                if($Line=~/\A[ \t]*\d+:\-l(.+) \=\> (.+)\Z/) {
17450                    $LPaths{"lib".$1} = $2;
17451                }
17452            }
17453        }
17454        else {
17455            printMsg("WARNING", "can't find ldconfig");
17456        }
17457    }
17458    else
17459    {
17460        if(my $LdConfig = get_CmdPath("ldconfig"))
17461        {
17462            if($SystemRoot and $OSgroup eq "linux")
17463            { # use host (x86) ldconfig with the target (arm) ld.so.conf
17464                if(-e $SystemRoot."/etc/ld.so.conf") {
17465                    $LdConfig .= " -f ".$SystemRoot."/etc/ld.so.conf";
17466                }
17467            }
17468            foreach my $Line (split(/\n/, `$LdConfig -p 2>\"$TMP_DIR/null\"`))
17469            {
17470                if($Line=~/\A[ \t]*([^ \t]+) .* \=\> (.+)\Z/)
17471                {
17472                    my ($Name, $Path) = ($1, $2);
17473                    $Path=~s/[\/]{2,}/\//;
17474                    $LPaths{$Name} = $Path;
17475                }
17476            }
17477        }
17478        elsif($OSgroup=~/linux/i) {
17479            printMsg("WARNING", "can't find ldconfig");
17480        }
17481    }
17482    return \%LPaths;
17483}
17484
17485sub detect_bin_default_paths()
17486{
17487    my $EnvPaths = $ENV{"PATH"};
17488    if($OSgroup eq "beos") {
17489        $EnvPaths.=":".$ENV{"BETOOLS"};
17490    }
17491    my $Sep = ($OSgroup eq "windows")?";":":|;";
17492    foreach my $Path (sort {length($a)<=>length($b)} split(/$Sep/, $EnvPaths))
17493    {
17494        $Path = path_format($Path, $OSgroup);
17495        $Path=~s/[\/\\]+\Z//g;
17496        next if(not $Path);
17497        if($SystemRoot
17498        and $Path=~/\A\Q$SystemRoot\E\//)
17499        { # do NOT use binaries from target system
17500            next;
17501        }
17502        $DefaultBinPaths{$Path} = 1;
17503    }
17504}
17505
17506sub detect_inc_default_paths()
17507{
17508    return () if(not $GCC_PATH);
17509    my %DPaths = ("Cpp"=>{},"Gcc"=>{},"Inc"=>{});
17510    writeFile("$TMP_DIR/empty.h", "");
17511    foreach my $Line (split(/\n/, `$GCC_PATH -v -x c++ -E \"$TMP_DIR/empty.h\" 2>&1`))
17512    { # detecting GCC default include paths
17513        if($Line=~/\A[ \t]*((\/|\w+:\\).+)[ \t]*\Z/)
17514        {
17515            my $Path = simplify_path($1);
17516            $Path=~s/[\/\\]+\Z//g;
17517            $Path = path_format($Path, $OSgroup);
17518            if($Path=~/c\+\+|\/g\+\+\//)
17519            {
17520                $DPaths{"Cpp"}{$Path}=1;
17521                if(not defined $MAIN_CPP_DIR
17522                or get_depth($MAIN_CPP_DIR)>get_depth($Path)) {
17523                    $MAIN_CPP_DIR = $Path;
17524                }
17525            }
17526            elsif($Path=~/gcc/) {
17527                $DPaths{"Gcc"}{$Path}=1;
17528            }
17529            else
17530            {
17531                next if($Path=~/local[\/\\]+include/);
17532                if($SystemRoot
17533                and $Path!~/\A\Q$SystemRoot\E(\/|\Z)/)
17534                { # The GCC include path for user headers is not a part of the system root
17535                  # The reason: you are not specified the --cross-gcc option or selected a wrong compiler
17536                  # or it is the internal cross-GCC path like arm-linux-gnueabi/include
17537                    next;
17538                }
17539                $DPaths{"Inc"}{$Path}=1;
17540            }
17541        }
17542    }
17543    unlink("$TMP_DIR/empty.h");
17544    return %DPaths;
17545}
17546
17547sub detect_default_paths($)
17548{
17549    my ($HSearch, $LSearch, $BSearch, $GSearch) = (1, 1, 1, 1);
17550    my $Search = $_[0];
17551    if($Search!~/inc/) {
17552        $HSearch = 0;
17553    }
17554    if($Search!~/lib/) {
17555        $LSearch = 0;
17556    }
17557    if($Search!~/bin/) {
17558        $BSearch = 0;
17559    }
17560    if($Search!~/gcc/) {
17561        $GSearch = 0;
17562    }
17563    if(keys(%{$SystemPaths{"include"}}))
17564    { # <search_headers> section of the XML descriptor
17565      # do NOT search for systems headers
17566        $HSearch = 0;
17567    }
17568    if(keys(%{$SystemPaths{"lib"}}))
17569    { # <search_headers> section of the XML descriptor
17570      # do NOT search for systems headers
17571        $LSearch = 0;
17572    }
17573    foreach my $Type (keys(%{$OS_AddPath{$OSgroup}}))
17574    { # additional search paths
17575        next if($Type eq "include" and not $HSearch);
17576        next if($Type eq "lib" and not $LSearch);
17577        next if($Type eq "bin" and not $BSearch);
17578        foreach my $Path (keys(%{$OS_AddPath{$OSgroup}{$Type}}))
17579        {
17580            next if(not -d $Path);
17581            $SystemPaths{$Type}{$Path} = $OS_AddPath{$OSgroup}{$Type}{$Path};
17582        }
17583    }
17584    if($OSgroup ne "windows")
17585    { # unix-like
17586        foreach my $Type ("include", "lib", "bin")
17587        { # automatic detection of system "devel" directories
17588            next if($Type eq "include" and not $HSearch);
17589            next if($Type eq "lib" and not $LSearch);
17590            next if($Type eq "bin" and not $BSearch);
17591            my ($UsrDir, $RootDir) = ("/usr", "/");
17592            if($SystemRoot and $Type ne "bin")
17593            { # 1. search for target headers and libraries
17594              # 2. use host commands: ldconfig, readelf, etc.
17595                ($UsrDir, $RootDir) = ("$SystemRoot/usr", $SystemRoot);
17596            }
17597            foreach my $Path (cmd_find($RootDir,"d","*$Type*",1)) {
17598                $SystemPaths{$Type}{$Path} = 1;
17599            }
17600            if(-d $RootDir."/".$Type)
17601            { # if "/lib" is symbolic link
17602                if($RootDir eq "/") {
17603                    $SystemPaths{$Type}{"/".$Type} = 1;
17604                }
17605                else {
17606                    $SystemPaths{$Type}{$RootDir."/".$Type} = 1;
17607                }
17608            }
17609            if(-d $UsrDir) {
17610                foreach my $Path (cmd_find($UsrDir,"d","*$Type*",1)) {
17611                    $SystemPaths{$Type}{$Path} = 1;
17612                }
17613                if(-d $UsrDir."/".$Type)
17614                { # if "/usr/lib" is symbolic link
17615                    $SystemPaths{$Type}{$UsrDir."/".$Type} = 1;
17616                }
17617            }
17618        }
17619    }
17620    if($BSearch)
17621    {
17622        detect_bin_default_paths();
17623        foreach my $Path (keys(%DefaultBinPaths)) {
17624            $SystemPaths{"bin"}{$Path} = $DefaultBinPaths{$Path};
17625        }
17626    }
17627    # check environment variables
17628    if($OSgroup eq "beos")
17629    {
17630        foreach (keys(%{$SystemPaths{"bin"}}))
17631        {
17632            if($_ eq ".") {
17633                next;
17634            }
17635            foreach my $Path (cmd_find($_, "d", "bin", ""))
17636            { # search for /boot/develop/abi/x86/gcc4/tools/gcc-4.4.4-haiku-101111/bin/
17637                $SystemPaths{"bin"}{$Path} = 1;
17638            }
17639        }
17640        if($HSearch)
17641        {
17642            foreach my $Path (split(/:|;/, $ENV{"BEINCLUDES"}))
17643            {
17644                if(is_abs($Path)) {
17645                    $DefaultIncPaths{$Path} = 1;
17646                }
17647            }
17648        }
17649        if($LSearch)
17650        {
17651            foreach my $Path (split(/:|;/, $ENV{"BELIBRARIES"}), split(/:|;/, $ENV{"LIBRARY_PATH"}))
17652            {
17653                if(is_abs($Path)) {
17654                    $DefaultLibPaths{$Path} = 1;
17655                }
17656            }
17657        }
17658    }
17659    if($LSearch)
17660    { # using linker to get system paths
17661        if(my $LPaths = detect_lib_default_paths())
17662        { # unix-like
17663            foreach my $Name (keys(%{$LPaths}))
17664            {
17665                if($SystemRoot
17666                and $LPaths->{$Name}!~/\A\Q$SystemRoot\E\//)
17667                { # wrong ldconfig configuration
17668                  # check your <sysroot>/etc/ld.so.conf
17669                    next;
17670                }
17671                $DyLib_DefaultPath{$Name} = $LPaths->{$Name};
17672                $DefaultLibPaths{get_dirname($LPaths->{$Name})} = 1;
17673            }
17674        }
17675        foreach my $Path (keys(%DefaultLibPaths)) {
17676            $SystemPaths{"lib"}{$Path} = $DefaultLibPaths{$Path};
17677        }
17678    }
17679    if($BSearch)
17680    {
17681        if($CrossGcc)
17682        { # --cross-gcc=arm-linux-gcc
17683            if(-e $CrossGcc)
17684            { # absolute or relative path
17685                $GCC_PATH = get_abs_path($CrossGcc);
17686            }
17687            elsif($CrossGcc!~/\// and get_CmdPath($CrossGcc))
17688            { # command name
17689                $GCC_PATH = $CrossGcc;
17690            }
17691            else {
17692                exitStatus("Access_Error", "can't access \'$CrossGcc\'");
17693            }
17694            if($GCC_PATH=~/\s/) {
17695                $GCC_PATH = "\"".$GCC_PATH."\"";
17696            }
17697        }
17698    }
17699    if($GSearch)
17700    { # GCC path and default include dirs
17701        if(not $CrossGcc) {
17702            $GCC_PATH = get_CmdPath("gcc");
17703        }
17704        if(not $GCC_PATH) {
17705            exitStatus("Not_Found", "can't find GCC>=3.0 in PATH");
17706        }
17707        if(not $CheckObjectsOnly_Opt)
17708        {
17709            if(my $GCC_Ver = get_dumpversion($GCC_PATH))
17710            {
17711                my $GccTarget = get_dumpmachine($GCC_PATH);
17712                printMsg("INFO", "Using GCC $GCC_Ver ($GccTarget)");
17713                if($GccTarget=~/symbian/)
17714                {
17715                    $OStarget = "symbian";
17716                    $LIB_EXT = $OS_LibExt{$LIB_TYPE}{$OStarget};
17717                }
17718            }
17719            else {
17720                exitStatus("Error", "something is going wrong with the GCC compiler");
17721            }
17722        }
17723        if(not $NoStdInc)
17724        { # do NOT search in GCC standard paths
17725            my %DPaths = detect_inc_default_paths();
17726            %DefaultCppPaths = %{$DPaths{"Cpp"}};
17727            %DefaultGccPaths = %{$DPaths{"Gcc"}};
17728            %DefaultIncPaths = %{$DPaths{"Inc"}};
17729            foreach my $Path (keys(%DefaultIncPaths)) {
17730                $SystemPaths{"include"}{$Path} = $DefaultIncPaths{$Path};
17731            }
17732        }
17733    }
17734    if($HSearch)
17735    { # user include paths
17736        my $IncPath = "/usr/include";
17737        if($SystemRoot) {
17738            $IncPath = $SystemRoot.$IncPath;
17739        }
17740        if(-d $IncPath) {
17741            $UserIncPath{$IncPath}=1;
17742        }
17743    }
17744}
17745
17746sub getLIB_EXT($)
17747{
17748    my $Target = $_[0];
17749    if(my $Ext = $OS_LibExt{$LIB_TYPE}{$Target}) {
17750        return $Ext;
17751    }
17752    return $OS_LibExt{$LIB_TYPE}{"default"};
17753}
17754
17755sub getAR_EXT($)
17756{
17757    my $Target = $_[0];
17758    if(my $Ext = $OS_Archive{$Target}) {
17759        return $Ext;
17760    }
17761    return $OS_Archive{"default"};
17762}
17763
17764sub get_dumpversion($)
17765{
17766    my $Cmd = $_[0];
17767    return "" if(not $Cmd);
17768    if($Cache{"get_dumpversion"}{$Cmd}) {
17769        return $Cache{"get_dumpversion"}{$Cmd};
17770    }
17771    my $V = `$Cmd -dumpversion 2>\"$TMP_DIR/null\"`;
17772    chomp($V);
17773    return ($Cache{"get_dumpversion"}{$Cmd} = $V);
17774}
17775
17776sub get_dumpmachine($)
17777{
17778    my $Cmd = $_[0];
17779    return "" if(not $Cmd);
17780    if($Cache{"get_dumpmachine"}{$Cmd}) {
17781        return $Cache{"get_dumpmachine"}{$Cmd};
17782    }
17783    my $Machine = `$Cmd -dumpmachine 2>\"$TMP_DIR/null\"`;
17784    chomp($Machine);
17785    return ($Cache{"get_dumpmachine"}{$Cmd} = $Machine);
17786}
17787
17788sub check_command($)
17789{
17790    my $Cmd = $_[0];
17791    return "" if(not $Cmd);
17792    my @Options = (
17793        "--version",
17794        "-help"
17795    );
17796    foreach my $Opt (@Options)
17797    {
17798        my $Info = `$Cmd $Opt 2>\"$TMP_DIR/null\"`;
17799        if($Info) {
17800            return 1;
17801        }
17802    }
17803    return 0;
17804}
17805
17806sub check_gcc($$)
17807{
17808    my ($Cmd, $ReqVer) = @_;
17809    return 0 if(not $Cmd or not $ReqVer);
17810    if(defined $Cache{"check_gcc"}{$Cmd}{$ReqVer}) {
17811        return $Cache{"check_gcc"}{$Cmd}{$ReqVer};
17812    }
17813    if(my $GccVer = get_dumpversion($Cmd))
17814    {
17815        $GccVer=~s/(-|_)[a-z_]+.*\Z//; # remove suffix (like "-haiku-100818")
17816        if(cmpVersions($GccVer, $ReqVer)>=0) {
17817            return ($Cache{"check_gcc"}{$Cmd}{$ReqVer} = $Cmd);
17818        }
17819    }
17820    return ($Cache{"check_gcc"}{$Cmd}{$ReqVer} = "");
17821}
17822
17823sub get_depth($)
17824{
17825    if(defined $Cache{"get_depth"}{$_[0]}) {
17826        return $Cache{"get_depth"}{$_[0]}
17827    }
17828    return ($Cache{"get_depth"}{$_[0]} = ($_[0]=~tr![\/\\]|\:\:!!));
17829}
17830
17831sub find_gcc_cxx_headers($)
17832{
17833    my $LibVersion = $_[0];
17834    return if($Cache{"find_gcc_cxx_headers"});# this function should be called once
17835    # detecting system header paths
17836    foreach my $Path (sort {get_depth($b) <=> get_depth($a)} keys(%DefaultGccPaths))
17837    {
17838        foreach my $HeaderPath (sort {get_depth($a) <=> get_depth($b)} cmd_find($Path,"f","",""))
17839        {
17840            my $FileName = get_filename($HeaderPath);
17841            next if($DefaultGccHeader{$FileName});
17842            $DefaultGccHeader{$FileName} = $HeaderPath;
17843        }
17844    }
17845    if($COMMON_LANGUAGE{$LibVersion} eq "C++" and not $STDCXX_TESTING)
17846    {
17847        foreach my $CppDir (sort {get_depth($b)<=>get_depth($a)} keys(%DefaultCppPaths))
17848        {
17849            my @AllCppHeaders = cmd_find($CppDir,"f","","");
17850            foreach my $Path (sort {get_depth($a)<=>get_depth($b)} @AllCppHeaders)
17851            {
17852                my $FileName = get_filename($Path);
17853                next if($DefaultCppHeader{$FileName});
17854                $DefaultCppHeader{$FileName} = $Path;
17855            }
17856        }
17857    }
17858    $Cache{"find_gcc_cxx_headers"} = 1;
17859}
17860
17861sub parse_libname($$$)
17862{
17863    my ($Name, $Type, $Target) = @_;
17864    if(not $Name) {
17865        return "";
17866    }
17867    if($Target eq "symbian") {
17868        return parse_libname_symbian($Name, $Type);
17869    }
17870    elsif($Target eq "windows") {
17871        return parse_libname_windows($Name, $Type);
17872    }
17873    my $Ext = getLIB_EXT($Target);
17874    if($Name=~/((((lib|).+?)([\-\_][\d\-\.\_]+.*?|))\.$Ext)(\.(.+)|)\Z/)
17875    { # libSDL-1.2.so.0.7.1
17876      # libwbxml2.so.0.0.18
17877      # libopcodes-2.21.53-system.20110810.so
17878        if($Type eq "name")
17879        { # libSDL-1.2
17880          # libwbxml2
17881            return $2;
17882        }
17883        elsif($Type eq "name+ext")
17884        { # libSDL-1.2.so
17885          # libwbxml2.so
17886            return $1;
17887        }
17888        elsif($Type eq "version")
17889        {
17890            if(defined $7
17891            and $7 ne "")
17892            { # 0.7.1
17893                return $7;
17894            }
17895            else
17896            { # libc-2.5.so (=>2.5 version)
17897                my $MV = $5;
17898                $MV=~s/\A[\-\_]+//g;
17899                return $MV;
17900            }
17901        }
17902        elsif($Type eq "short")
17903        { # libSDL
17904          # libwbxml2
17905            return $3;
17906        }
17907        elsif($Type eq "shortest")
17908        { # SDL
17909          # wbxml
17910            return shortest_name($3);
17911        }
17912    }
17913    return "";# error
17914}
17915
17916sub parse_libname_symbian($$)
17917{
17918    my ($Name, $Type) = @_;
17919    my $Ext = getLIB_EXT("symbian");
17920    if($Name=~/(((.+?)(\{.+\}|))\.$Ext)\Z/)
17921    { # libpthread{00010001}.dso
17922        if($Type eq "name")
17923        { # libpthread{00010001}
17924            return $2;
17925        }
17926        elsif($Type eq "name+ext")
17927        { # libpthread{00010001}.dso
17928            return $1;
17929        }
17930        elsif($Type eq "version")
17931        { # 00010001
17932            my $V = $4;
17933            $V=~s/\{(.+)\}/$1/;
17934            return $V;
17935        }
17936        elsif($Type eq "short")
17937        { # libpthread
17938            return $3;
17939        }
17940        elsif($Type eq "shortest")
17941        { # pthread
17942            return shortest_name($3);
17943        }
17944    }
17945    return "";# error
17946}
17947
17948sub parse_libname_windows($$)
17949{
17950    my ($Name, $Type) = @_;
17951    my $Ext = getLIB_EXT("windows");
17952    if($Name=~/((.+?)\.$Ext)\Z/)
17953    { # netapi32.dll
17954        if($Type eq "name")
17955        { # netapi32
17956            return $2;
17957        }
17958        elsif($Type eq "name+ext")
17959        { # netapi32.dll
17960            return $1;
17961        }
17962        elsif($Type eq "version")
17963        { # DLL version embedded
17964          # at binary-level
17965            return "";
17966        }
17967        elsif($Type eq "short")
17968        { # netapi32
17969            return $2;
17970        }
17971        elsif($Type eq "shortest")
17972        { # netapi
17973            return shortest_name($2);
17974        }
17975    }
17976    return "";# error
17977}
17978
17979sub shortest_name($)
17980{
17981    my $Name = $_[0];
17982    # remove prefix
17983    $Name=~s/\A(lib|open)//;
17984    # remove suffix
17985    $Name=~s/[\W\d_]+\Z//i;
17986    $Name=~s/([a-z]{2,})(lib)\Z/$1/i;
17987    return $Name;
17988}
17989
17990sub getPrefix($)
17991{
17992    my $Str = $_[0];
17993    if($Str=~/\A(Get|get|Set|set)([A-Z]|_)/)
17994    { # GetError
17995        return "";
17996    }
17997    if($Str=~/\A([_]*[A-Z][a-z]{1,5})[A-Z]/)
17998    { # XmuValidArea: Xmu
17999        return $1;
18000    }
18001    elsif($Str=~/\A([_]*[a-z]+)[A-Z]/)
18002    { # snfReadFont: snf
18003        return $1;
18004    }
18005    elsif($Str=~/\A([_]*[A-Z]{2,})[A-Z][a-z]+([A-Z][a-z]+|\Z)/)
18006    { # XRRTimes: XRR
18007        return $1;
18008    }
18009    elsif($Str=~/\A([_]*[a-z0-9]{2,}_)[a-z]+/i)
18010    { # alarm_event_add: alarm_
18011        return $1;
18012    }
18013    elsif($Str=~/\A(([a-z])\2{1,})/i)
18014    { # ffopen
18015        return $1;
18016    }
18017    else {
18018        return "";
18019    }
18020}
18021
18022sub problem_title($)
18023{
18024    if($_[0]==1)  {
18025        return "1 problem";
18026    }
18027    else  {
18028        return $_[0]." problems";
18029    }
18030}
18031
18032sub warning_title($)
18033{
18034    if($_[0]==1)  {
18035        return "1 warning";
18036    }
18037    else  {
18038        return $_[0]." warnings";
18039    }
18040}
18041
18042sub createSymbolsList($$$$$)
18043{
18044    my ($DPath, $SaveTo, $LName, $LVersion, $ArchName) = @_;
18045    read_ABI_Dump(1, $DPath);
18046    if(not $CheckObjectsOnly) {
18047        prepareSymbols(1);
18048    }
18049    my %SymbolHeaderLib = ();
18050    my $Total = 0;
18051    # Get List
18052    foreach my $Symbol (sort keys(%{$CompleteSignature{1}}))
18053    {
18054        if(not link_symbol($Symbol, 1, "-Deps"))
18055        { # skip src only and all external functions
18056            next;
18057        }
18058        if(not symbolFilter($Symbol, 1, "Public", "Binary"))
18059        { # skip other symbols
18060            next;
18061        }
18062        my $HeaderName = $CompleteSignature{1}{$Symbol}{"Header"};
18063        if(not $HeaderName)
18064        { # skip src only and all external functions
18065            next;
18066        }
18067        my $DyLib = $Symbol_Library{1}{$Symbol};
18068        if(not $DyLib)
18069        { # skip src only and all external functions
18070            next;
18071        }
18072        $SymbolHeaderLib{$HeaderName}{$DyLib}{$Symbol} = 1;
18073        $Total+=1;
18074    }
18075    # Draw List
18076    my $SYMBOLS_LIST = "<h1>Public symbols in <span style='color:Blue;'>$LName</span> (<span style='color:Red;'>$LVersion</span>)";
18077    $SYMBOLS_LIST .= " on <span style='color:Blue;'>".showArch($ArchName)."</span><br/>Total: $Total</h1><br/>";
18078    foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%SymbolHeaderLib))
18079    {
18080        foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$SymbolHeaderLib{$HeaderName}}))
18081        {
18082            my %NS_Symbol = ();
18083            foreach my $Symbol (keys(%{$SymbolHeaderLib{$HeaderName}{$DyLib}})) {
18084                $NS_Symbol{get_IntNameSpace($Symbol, 1)}{$Symbol} = 1;
18085            }
18086            foreach my $NameSpace (sort keys(%NS_Symbol))
18087            {
18088                $SYMBOLS_LIST .= getTitle($HeaderName, $DyLib, $NameSpace);
18089                my @SortedInterfaces = sort {lc(get_Signature($a, 1)) cmp lc(get_Signature($b, 1))} keys(%{$NS_Symbol{$NameSpace}});
18090                foreach my $Symbol (@SortedInterfaces)
18091                {
18092                    my $SubReport = "";
18093                    my $Signature = get_Signature($Symbol, 1);
18094                    if($NameSpace) {
18095                        $Signature=~s/\b\Q$NameSpace\E::\b//g;
18096                    }
18097                    if($Symbol=~/\A(_Z|\?)/)
18098                    {
18099                        if($Signature) {
18100                            $SubReport = insertIDs($ContentSpanStart.highLight_Signature_Italic_Color($Signature).$ContentSpanEnd."<br/>\n".$ContentDivStart."<span class='mangled'>[symbol: <b>$Symbol</b>]</span><br/><br/>".$ContentDivEnd."\n");
18101                        }# report_added
18102                        else {
18103                            $SubReport = "<span class='iname'>".$Symbol."</span><br/>\n";
18104                        }
18105                    }
18106                    else
18107                    {
18108                        if($Signature) {
18109                            $SubReport = "<span class='iname'>".highLight_Signature_Italic_Color($Signature)."</span><br/>\n";
18110                        }
18111                        else {
18112                            $SubReport = "<span class='iname'>".$Symbol."</span><br/>\n";
18113                        }
18114                    }
18115                    $SYMBOLS_LIST .= $SubReport;
18116                }
18117            }
18118            $SYMBOLS_LIST .= "<br/>\n";
18119        }
18120    }
18121    # clear info
18122    (%TypeInfo, %SymbolInfo, %Library_Symbol, %DepSymbol_Library,
18123    %DepLibrary_Symbol, %SymVer, %SkipTypes, %SkipSymbols,
18124    %NestedNameSpaces, %ClassMethods, %AllocableClass, %ClassNames,
18125    %CompleteSignature, %SkipNameSpaces, %Symbol_Library, %Library_Symbol) = ();
18126    ($Content_Counter, $ContentID) = (0, 0);
18127    # print report
18128    my $CssStyles = readModule("Styles", "SymbolsList.css");
18129    my $JScripts = readModule("Scripts", "Sections.js");
18130    $SYMBOLS_LIST = "<a name='Top'></a>".$SYMBOLS_LIST.$TOP_REF."<br/>\n";
18131    my $Title = "$LName: public symbols";
18132    my $Keywords = "$LName, API, symbols";
18133    my $Description = "List of symbols in $LName ($LVersion) on ".showArch($ArchName);
18134    $SYMBOLS_LIST = composeHTML_Head($Title, $Keywords, $Description, $CssStyles, $JScripts)."
18135    <body><div>\n$SYMBOLS_LIST</div>
18136    <br/><br/><hr/>\n".getReportFooter($LName)."
18137    <div style='height:999px;'></div></body></html>";
18138    writeFile($SaveTo, $SYMBOLS_LIST);
18139}
18140
18141sub readModule($$)
18142{
18143    my ($Module, $Name) = @_;
18144    my $Path = $MODULES_DIR."/Internals/$Module/".$Name;
18145    if(not -f $Path) {
18146        exitStatus("Module_Error", "can't access \'$Path\'");
18147    }
18148    return readFile($Path);
18149}
18150
18151sub is_target_lib($)
18152{
18153    my $LName = $_[0];
18154    if(not $LName) {
18155        return 0;
18156    }
18157    if($TargetLibraryName
18158    and $LName!~/\Q$TargetLibraryName\E/) {
18159        return 0;
18160    }
18161    if(keys(%TargetLibs)
18162    and not $TargetLibs{$LName}
18163    and not $TargetLibs{parse_libname($LName, "name+ext", $OStarget)}) {
18164        return 0;
18165    }
18166    return 1;
18167}
18168
18169sub is_target_header($$)
18170{ # --header, --headers-list
18171    my ($H, $V) = @_;
18172    if(keys(%{$TargetHeaders{$V}}))
18173    {
18174        if($TargetHeaders{$V}{$H}) {
18175            return 1;
18176        }
18177    }
18178    return 0;
18179}
18180
18181sub checkVersionNum($$)
18182{
18183    my ($LibVersion, $Path) = @_;
18184    if(my $VerNum = $TargetVersion{$LibVersion}) {
18185        return $VerNum;
18186    }
18187    my $UsedAltDescr = 0;
18188    foreach my $Part (split(/\s*,\s*/, $Path))
18189    { # try to get version string from file path
18190        next if($Part=~/\.xml\Z/i);
18191        next if(isDump($Part));
18192        my $VerNum = "";
18193        if(parse_libname($Part, "name", $OStarget))
18194        {
18195            $UsedAltDescr = 1;
18196            $VerNum = parse_libname($Part, "version", $OStarget);
18197            if(not $VerNum) {
18198                $VerNum = readStringVersion($Part);
18199            }
18200        }
18201        elsif(is_header($Part, 2, $LibVersion) or -d $Part)
18202        {
18203            $UsedAltDescr = 1;
18204            $VerNum = readStringVersion($Part);
18205        }
18206        if($VerNum ne "")
18207        {
18208            $TargetVersion{$LibVersion} = $VerNum;
18209            if($DumpAPI) {
18210                printMsg("WARNING", "setting version number to $VerNum (use -vnum <num> option to change it)");
18211            }
18212            else {
18213                printMsg("WARNING", "setting ".($LibVersion==1?"1st":"2nd")." version number to \"$VerNum\" (use -v$LibVersion <num> option to change it)");
18214            }
18215            return $TargetVersion{$LibVersion};
18216        }
18217    }
18218    if($UsedAltDescr)
18219    {
18220        if($DumpAPI) {
18221            exitStatus("Error", "version number is not set (use -vnum <num> option)");
18222        }
18223        else {
18224            exitStatus("Error", ($LibVersion==1?"1st":"2nd")." version number is not set (use -v$LibVersion <num> option)");
18225        }
18226    }
18227}
18228
18229sub readStringVersion($)
18230{
18231    my $Str = $_[0];
18232    return "" if(not $Str);
18233    $Str=~s/\Q$TargetLibraryName\E//g;
18234    if($Str=~/(\/|\\|\w|\A)[\-\_]*(\d+[\d\.\-]+\d+|\d+)/)
18235    { # .../libssh-0.4.0/...
18236        return $2;
18237    }
18238    elsif(my $V = parse_libname($Str, "version", $OStarget)) {
18239        return $V;
18240    }
18241    return "";
18242}
18243
18244sub readLibs($)
18245{
18246    my $LibVersion = $_[0];
18247    if($OStarget eq "windows")
18248    { # dumpbin.exe will crash
18249        # without VS Environment
18250        check_win32_env();
18251    }
18252    readSymbols($LibVersion);
18253    translateSymbols(keys(%{$Symbol_Library{$LibVersion}}), $LibVersion);
18254    translateSymbols(keys(%{$DepSymbol_Library{$LibVersion}}), $LibVersion);
18255}
18256
18257sub dump_sorting($)
18258{
18259    my $Hash = $_[0];
18260    return [] if(not $Hash);
18261    my @Keys = keys(%{$Hash});
18262    return [] if($#Keys<0);
18263    if($Keys[0]=~/\A\d+\Z/)
18264    { # numbers
18265        return [sort {int($a)<=>int($b)} @Keys];
18266    }
18267    else
18268    { # strings
18269        return [sort {$a cmp $b} @Keys];
18270    }
18271}
18272
18273sub printMsg($$)
18274{
18275    my ($Type, $Msg) = @_;
18276    if($Type!~/\AINFO/) {
18277        $Msg = $Type.": ".$Msg;
18278    }
18279    if($Type!~/_C\Z/) {
18280        $Msg .= "\n";
18281    }
18282    if($Quiet)
18283    { # --quiet option
18284        appendFile($COMMON_LOG_PATH, $Msg);
18285    }
18286    else
18287    {
18288        if($Type eq "ERROR") {
18289            print STDERR $Msg;
18290        }
18291        else {
18292            print $Msg;
18293        }
18294    }
18295}
18296
18297sub exitStatus($$)
18298{
18299    my ($Code, $Msg) = @_;
18300    printMsg("ERROR", $Msg);
18301    exit($ERROR_CODE{$Code});
18302}
18303
18304sub exitReport()
18305{ # the tool has run without any errors
18306    printReport();
18307    if($COMPILE_ERRORS)
18308    { # errors in headers may add false positives/negatives
18309        exit($ERROR_CODE{"Compile_Error"});
18310    }
18311    if($BinaryOnly and $RESULT{"Binary"}{"Problems"})
18312    { # --binary
18313        exit($ERROR_CODE{"Incompatible"});
18314    }
18315    elsif($SourceOnly and $RESULT{"Source"}{"Problems"})
18316    { # --source
18317        exit($ERROR_CODE{"Incompatible"});
18318    }
18319    elsif($RESULT{"Source"}{"Problems"}
18320    or $RESULT{"Binary"}{"Problems"})
18321    { # default
18322        exit($ERROR_CODE{"Incompatible"});
18323    }
18324    else {
18325        exit($ERROR_CODE{"Compatible"});
18326    }
18327}
18328
18329sub readRules($)
18330{
18331    my $Kind = $_[0];
18332    if(not -f $RULES_PATH{$Kind}) {
18333        exitStatus("Module_Error", "can't access \'".$RULES_PATH{$Kind}."\'");
18334    }
18335    my $Content = readFile($RULES_PATH{$Kind});
18336    while(my $Rule = parseTag(\$Content, "rule"))
18337    {
18338        my $RId = parseTag(\$Rule, "id");
18339        my @Properties = ("Severity", "Change", "Effect", "Overcome", "Kind");
18340        foreach my $Prop (@Properties) {
18341            if(my $Value = parseTag(\$Rule, lc($Prop)))
18342            {
18343                $Value=~s/\n[ ]*//;
18344                $CompatRules{$Kind}{$RId}{$Prop} = $Value;
18345            }
18346        }
18347        if($CompatRules{$Kind}{$RId}{"Kind"}=~/\A(Symbols|Parameters)\Z/) {
18348            $CompatRules{$Kind}{$RId}{"Kind"} = "Symbols";
18349        }
18350        else {
18351            $CompatRules{$Kind}{$RId}{"Kind"} = "Types";
18352        }
18353    }
18354}
18355
18356sub getReportPath($)
18357{
18358    my $Level = $_[0];
18359    my $Dir = "compat_reports/$TargetLibraryName/".$Descriptor{1}{"Version"}."_to_".$Descriptor{2}{"Version"};
18360    if($Level eq "Binary")
18361    {
18362        if($BinaryReportPath)
18363        { # --bin-report-path
18364            return $BinaryReportPath;
18365        }
18366        elsif($OutputReportPath)
18367        { # --report-path
18368            return $OutputReportPath;
18369        }
18370        else
18371        { # default
18372            return $Dir."/abi_compat_report.$ReportFormat";
18373        }
18374    }
18375    elsif($Level eq "Source")
18376    {
18377        if($SourceReportPath)
18378        { # --src-report-path
18379            return $SourceReportPath;
18380        }
18381        elsif($OutputReportPath)
18382        { # --report-path
18383            return $OutputReportPath;
18384        }
18385        else
18386        { # default
18387            return $Dir."/src_compat_report.$ReportFormat";
18388        }
18389    }
18390    else
18391    {
18392        if($OutputReportPath)
18393        { # --report-path
18394            return $OutputReportPath;
18395        }
18396        else
18397        { # default
18398            return $Dir."/compat_report.$ReportFormat";
18399        }
18400    }
18401}
18402
18403sub printStatMsg($)
18404{
18405    my $Level = $_[0];
18406    printMsg("INFO", "total \"$Level\" compatibility problems: ".$RESULT{$Level}{"Problems"}.", warnings: ".$RESULT{$Level}{"Warnings"});
18407}
18408
18409sub listAffected($)
18410{
18411    my $Level = $_[0];
18412    my $List = "";
18413    foreach (keys(%{$TotalAffected{$Level}}))
18414    {
18415        if($StrictCompat and $TotalAffected{$Level}{$_} eq "Low")
18416        { # skip "Low"-severity problems
18417            next;
18418        }
18419        $List .= "$_\n";
18420    }
18421    my $Dir = get_dirname(getReportPath($Level));
18422    if($Level eq "Binary") {
18423        writeFile($Dir."/abi_affected.txt", $List);
18424    }
18425    elsif($Level eq "Source") {
18426        writeFile($Dir."/src_affected.txt", $List);
18427    }
18428}
18429
18430sub printReport()
18431{
18432    printMsg("INFO", "creating compatibility report ...");
18433    createReport();
18434    if($JoinReport or $DoubleReport)
18435    {
18436        if($RESULT{"Binary"}{"Problems"}
18437        or $RESULT{"Source"}{"Problems"}) {
18438            printMsg("INFO", "result: INCOMPATIBLE (Binary: ".$RESULT{"Binary"}{"Affected"}."\%, Source: ".$RESULT{"Source"}{"Affected"}."\%)");
18439        }
18440        else {
18441            printMsg("INFO", "result: COMPATIBLE");
18442        }
18443        printStatMsg("Binary");
18444        printStatMsg("Source");
18445        if($ListAffected)
18446        { # --list-affected
18447            listAffected("Binary");
18448            listAffected("Source");
18449        }
18450    }
18451    elsif($BinaryOnly)
18452    {
18453        if($RESULT{"Binary"}{"Problems"}) {
18454            printMsg("INFO", "result: INCOMPATIBLE (".$RESULT{"Binary"}{"Affected"}."\%)");
18455        }
18456        else {
18457            printMsg("INFO", "result: COMPATIBLE");
18458        }
18459        printStatMsg("Binary");
18460        if($ListAffected)
18461        { # --list-affected
18462            listAffected("Binary");
18463        }
18464    }
18465    elsif($SourceOnly)
18466    {
18467        if($RESULT{"Source"}{"Problems"}) {
18468            printMsg("INFO", "result: INCOMPATIBLE (".$RESULT{"Source"}{"Affected"}."\%)");
18469        }
18470        else {
18471            printMsg("INFO", "result: COMPATIBLE");
18472        }
18473        printStatMsg("Source");
18474        if($ListAffected)
18475        { # --list-affected
18476            listAffected("Source");
18477        }
18478    }
18479    if($StdOut)
18480    {
18481        if($JoinReport or not $DoubleReport)
18482        { # --binary or --source
18483            printMsg("INFO", "compatibility report has been generated to stdout");
18484        }
18485        else
18486        { # default
18487            printMsg("INFO", "compatibility reports have been generated to stdout");
18488        }
18489    }
18490    else
18491    {
18492        if($JoinReport)
18493        {
18494            printMsg("INFO", "see detailed report:\n  ".getReportPath("Join"));
18495        }
18496        elsif($DoubleReport)
18497        { # default
18498            printMsg("INFO", "see detailed reports:\n  ".getReportPath("Binary")."\n  ".getReportPath("Source"));
18499        }
18500        elsif($BinaryOnly)
18501        { # --binary
18502            printMsg("INFO", "see detailed report:\n  ".getReportPath("Binary"));
18503        }
18504        elsif($SourceOnly)
18505        { # --source
18506            printMsg("INFO", "see detailed report:\n  ".getReportPath("Source"));
18507        }
18508    }
18509}
18510
18511sub check_win32_env()
18512{
18513    if(not $ENV{"DevEnvDir"}
18514    or not $ENV{"LIB"}) {
18515        exitStatus("Error", "can't start without VS environment (vsvars32.bat)");
18516    }
18517}
18518
18519sub diffSets($$)
18520{
18521    my ($S1, $S2) = @_;
18522    my @SK1 = keys(%{$S1});
18523    my @SK2 = keys(%{$S2});
18524    if($#SK1!=$#SK2) {
18525        return 1;
18526    }
18527    foreach my $K1 (@SK1)
18528    {
18529        if(not defined $S2->{$K1}) {
18530            return 1;
18531        }
18532    }
18533    return 0;
18534}
18535
18536sub create_ABI_Dump()
18537{
18538    if(not -e $DumpAPI) {
18539        exitStatus("Access_Error", "can't access \'$DumpAPI\'");
18540    }
18541    # check the archive utilities
18542    if($OSgroup eq "windows")
18543    { # using zip
18544        my $ZipCmd = get_CmdPath("zip");
18545        if(not $ZipCmd) {
18546            exitStatus("Not_Found", "can't find \"zip\"");
18547        }
18548    }
18549    else
18550    { # using tar and gzip
18551        my $TarCmd = get_CmdPath("tar");
18552        if(not $TarCmd) {
18553            exitStatus("Not_Found", "can't find \"tar\"");
18554        }
18555        my $GzipCmd = get_CmdPath("gzip");
18556        if(not $GzipCmd) {
18557            exitStatus("Not_Found", "can't find \"gzip\"");
18558        }
18559    }
18560    my @DParts = split(/\s*,\s*/, $DumpAPI);
18561    foreach my $Part (@DParts)
18562    {
18563        if(not -e $Part) {
18564            exitStatus("Access_Error", "can't access \'$Part\'");
18565        }
18566    }
18567    checkVersionNum(1, $DumpAPI);
18568    foreach my $Part (@DParts)
18569    {
18570        if(isDump($Part)) {
18571            read_ABI_Dump(1, $Part);
18572        }
18573        else {
18574            readDescriptor(1, createDescriptor(1, $Part));
18575        }
18576    }
18577    initLogging(1);
18578    detect_default_paths("inc|lib|bin|gcc"); # complete analysis
18579    if(not $CheckHeadersOnly) {
18580        readLibs(1);
18581    }
18582    if($CheckHeadersOnly) {
18583        setLanguage(1, "C++");
18584    }
18585    if(not $CheckObjectsOnly) {
18586        searchForHeaders(1);
18587    }
18588    $WORD_SIZE{1} = detectWordSize();
18589    if($Descriptor{1}{"Headers"}
18590    and not $Descriptor{1}{"Dump"}) {
18591        readHeaders(1);
18592    }
18593    cleanDump(1);
18594    if(not keys(%{$SymbolInfo{1}}))
18595    { # check if created dump is valid
18596        if(not $ExtendedCheck and not $CheckObjectsOnly)
18597        {
18598            if($CheckHeadersOnly) {
18599                exitStatus("Empty_Set", "the set of public symbols is empty");
18600            }
18601            else {
18602                exitStatus("Empty_Intersection", "the sets of public symbols in headers and libraries have empty intersection");
18603            }
18604        }
18605    }
18606    my %HeadersInfo = ();
18607    foreach my $HPath (keys(%{$Registered_Headers{1}}))
18608    { # headers info stored without paths in the dump
18609        $HeadersInfo{$Registered_Headers{1}{$HPath}{"Identity"}} = $Registered_Headers{1}{$HPath}{"Pos"};
18610    }
18611    printMsg("INFO", "creating library ABI dump ...");
18612    my %LibraryABI = (
18613        "TypeInfo" => $TypeInfo{1},
18614        "SymbolInfo" => $SymbolInfo{1},
18615        "Symbols" => $Library_Symbol{1},
18616        "DepSymbols" => $DepLibrary_Symbol{1},
18617        "SymbolVersion" => $SymVer{1},
18618        "LibraryVersion" => $Descriptor{1}{"Version"},
18619        "LibraryName" => $TargetLibraryName,
18620        "Language" => $COMMON_LANGUAGE{1},
18621        "SkipTypes" => $SkipTypes{1},
18622        "SkipSymbols" => $SkipSymbols{1},
18623        "SkipNameSpaces" => $SkipNameSpaces{1},
18624        "SkipHeaders" => $SkipHeadersList{1},
18625        "Headers" => \%HeadersInfo,
18626        "Constants" => $Constants{1},
18627        "NameSpaces" => $NestedNameSpaces{1},
18628        "Target" => $OStarget,
18629        "Arch" => getArch(1),
18630        "WordSize" => $WORD_SIZE{1},
18631        "GccVersion" => get_dumpversion($GCC_PATH),
18632        "ABI_DUMP_VERSION" => $ABI_DUMP_VERSION,
18633        "ABI_COMPLIANCE_CHECKER_VERSION" => $TOOL_VERSION
18634    );
18635    if(diffSets($TargetHeaders{1}, \%HeadersInfo)) {
18636        $LibraryABI{"TargetHeaders"} = $TargetHeaders{1};
18637    }
18638    if($UseXML) {
18639        $LibraryABI{"XML_ABI_DUMP_VERSION"} = $XML_ABI_DUMP_VERSION;
18640    }
18641    if($ExtendedCheck)
18642    { # --ext option
18643        $LibraryABI{"Mode"} = "Extended";
18644    }
18645    if($BinaryOnly)
18646    { # --binary
18647        $LibraryABI{"BinOnly"} = 1;
18648    }
18649
18650    my $ABI_DUMP = "";
18651    if($UseXML)
18652    {
18653        loadModule("XmlDump");
18654        $ABI_DUMP = createXmlDump(\%LibraryABI);
18655    }
18656    else
18657    { # default
18658        $ABI_DUMP = Dumper(\%LibraryABI);
18659    }
18660    if($StdOut)
18661    { # --stdout option
18662        print STDOUT $ABI_DUMP;
18663        printMsg("INFO", "ABI dump has been generated to stdout");
18664        return;
18665    }
18666    else
18667    { # write to gzipped file
18668        my $DumpPath = "abi_dumps/$TargetLibraryName/".$TargetLibraryName."_".$Descriptor{1}{"Version"}.".abi";
18669        $DumpPath .= ".".$AR_EXT; # gzipped by default
18670        if($OutputDumpPath)
18671        { # user defined path
18672            $DumpPath = $OutputDumpPath;
18673        }
18674        my $Archive = ($DumpPath=~s/\Q.$AR_EXT\E\Z//g);
18675        my ($DDir, $DName) = separate_path($DumpPath);
18676        my $DPath = $TMP_DIR."/".$DName;
18677        if(not $Archive) {
18678            $DPath = $DumpPath;
18679        }
18680
18681        mkpath($DDir);
18682
18683        open(DUMP, ">", $DPath) || die ("can't open file \'$DPath\': $!\n");
18684        print DUMP $ABI_DUMP;
18685        close(DUMP);
18686
18687        if(not -s $DPath) {
18688            exitStatus("Error", "can't create ABI dump because something is going wrong with the Data::Dumper module");
18689        }
18690        if($Archive)
18691        {
18692            my $PkgPath = createArchive($DPath, $DDir);
18693            printMsg("INFO", "library ABI has been dumped to:\n  $PkgPath");
18694        }
18695        else {
18696            printMsg("INFO", "library ABI has been dumped to:\n  $DumpPath");
18697        }
18698
18699        printMsg("INFO", "you can transfer this dump everywhere and use instead of the ".$Descriptor{1}{"Version"}." version descriptor");
18700    }
18701}
18702
18703sub quickEmptyReports()
18704{ # Quick "empty" reports
18705  # 4 times faster than merging equal dumps
18706  # NOTE: the dump contains the "LibraryVersion" attribute
18707  # if you change the version, then your dump will be different
18708  # OVERCOME: use -v1 and v2 options for comparing dumps
18709  # and don't change version in the XML descriptor (and dumps)
18710  # OVERCOME 2: separate meta info from the dumps in ACC 2.0
18711    if(-s $Descriptor{1}{"Path"} == -s $Descriptor{2}{"Path"})
18712    {
18713        my $FilePath1 = unpackDump($Descriptor{1}{"Path"});
18714        my $FilePath2 = unpackDump($Descriptor{2}{"Path"});
18715        if($FilePath1 and $FilePath2)
18716        {
18717            local $/ = undef;
18718
18719            open(DUMP1, $FilePath1);
18720            my $Content1 = <DUMP1>;
18721            close(DUMP1);
18722
18723            open(DUMP2, $FilePath2);
18724            my $Content2 = <DUMP2>;
18725            close(DUMP2);
18726
18727            if($Content1 eq $Content2)
18728            {
18729                # clean memory
18730                undef $Content2;
18731
18732                # read a number of headers, libs, symbols and types
18733                my $ABIdump = eval($Content1);
18734
18735                # clean memory
18736                undef $Content1;
18737
18738                if(not $ABIdump) {
18739                    exitStatus("Error", "internal error");
18740                }
18741                if(not $ABIdump->{"TypeInfo"})
18742                { # support for old dumps
18743                    $ABIdump->{"TypeInfo"} = $ABIdump->{"TypeDescr"};
18744                }
18745                if(not $ABIdump->{"SymbolInfo"})
18746                { # support for old dumps
18747                    $ABIdump->{"SymbolInfo"} = $ABIdump->{"FuncDescr"};
18748                }
18749                read_Headers_DumpInfo($ABIdump, 1);
18750                read_Libs_DumpInfo($ABIdump, 1);
18751                read_Machine_DumpInfo($ABIdump, 1);
18752                read_Machine_DumpInfo($ABIdump, 2);
18753
18754                %{$CheckedTypes{"Binary"}} = %{$ABIdump->{"TypeInfo"}};
18755                %{$CheckedTypes{"Source"}} = %{$ABIdump->{"TypeInfo"}};
18756
18757                %{$CheckedSymbols{"Binary"}} = %{$ABIdump->{"SymbolInfo"}};
18758                %{$CheckedSymbols{"Source"}} = %{$ABIdump->{"SymbolInfo"}};
18759
18760                $Descriptor{1}{"Version"} = $TargetVersion{1}?$TargetVersion{1}:$ABIdump->{"LibraryVersion"};
18761                $Descriptor{2}{"Version"} = $TargetVersion{2}?$TargetVersion{2}:$ABIdump->{"LibraryVersion"};
18762                exitReport();
18763            }
18764        }
18765    }
18766}
18767
18768sub initLogging($)
18769{
18770    my $LibVersion = $_[0];
18771    # create log directory
18772    my ($LOG_DIR, $LOG_FILE) = ("logs/$TargetLibraryName/".$Descriptor{$LibVersion}{"Version"}, "log.txt");
18773    if($OutputLogPath{$LibVersion})
18774    { # user-defined by -log-path option
18775        ($LOG_DIR, $LOG_FILE) = separate_path($OutputLogPath{$LibVersion});
18776    }
18777    if($LogMode ne "n") {
18778        mkpath($LOG_DIR);
18779    }
18780    $LOG_PATH{$LibVersion} = get_abs_path($LOG_DIR)."/".$LOG_FILE;
18781    if($Debug)
18782    { # debug directory
18783        $DEBUG_PATH{$LibVersion} = "debug/$TargetLibraryName/".$Descriptor{$LibVersion}{"Version"};
18784    }
18785    resetLogging($LibVersion);
18786}
18787
18788sub writeLog($$)
18789{
18790    my ($LibVersion, $Msg) = @_;
18791    if($LogMode ne "n") {
18792        appendFile($LOG_PATH{$LibVersion}, $Msg);
18793    }
18794}
18795
18796sub resetLogging($)
18797{
18798    my $LibVersion = $_[0];
18799    if($LogMode!~/a|n/)
18800    { # remove old log
18801        unlink($LOG_PATH{$LibVersion});
18802        if($Debug) {
18803            rmtree($DEBUG_PATH{$LibVersion});
18804        }
18805    }
18806}
18807
18808sub printErrorLog($)
18809{
18810    my $LibVersion = $_[0];
18811    if($LogMode ne "n") {
18812        printMsg("ERROR", "see log for details:\n  ".$LOG_PATH{$LibVersion}."\n");
18813    }
18814}
18815
18816sub isDump($)
18817{
18818    if(get_filename($_[0])=~/\A(.+)\.abi(\Q.tar.gz\E|\Q.zip\E|)\Z/)
18819    { # returns a name of package
18820        return $1;
18821    }
18822    return 0;
18823}
18824
18825sub compareInit()
18826{
18827    # read input XML descriptors or ABI dumps
18828    if(not $Descriptor{1}{"Path"}) {
18829        exitStatus("Error", "-old option is not specified");
18830    }
18831    my @DParts1 = split(/\s*,\s*/, $Descriptor{1}{"Path"});
18832    foreach my $Part (@DParts1)
18833    {
18834        if(not -e $Part) {
18835            exitStatus("Access_Error", "can't access \'$Part\'");
18836        }
18837    }
18838    if(not $Descriptor{2}{"Path"}) {
18839        exitStatus("Error", "-new option is not specified");
18840    }
18841    my @DParts2 = split(/\s*,\s*/, $Descriptor{2}{"Path"});
18842    foreach my $Part (@DParts2)
18843    {
18844        if(not -e $Part) {
18845            exitStatus("Access_Error", "can't access \'$Part\'");
18846        }
18847    }
18848    detect_default_paths("bin"); # to extract dumps
18849    if($#DParts1==0 and $#DParts2==0
18850    and isDump($Descriptor{1}{"Path"})
18851    and isDump($Descriptor{2}{"Path"}))
18852    { # optimization: equal ABI dumps
18853        quickEmptyReports();
18854    }
18855    checkVersionNum(1, $Descriptor{1}{"Path"});
18856    checkVersionNum(2, $Descriptor{2}{"Path"});
18857    printMsg("INFO", "preparation, please wait ...");
18858    foreach my $Part (@DParts1)
18859    {
18860        if(isDump($Part)) {
18861            read_ABI_Dump(1, $Part);
18862        }
18863        else {
18864            readDescriptor(1, createDescriptor(1, $Part));
18865        }
18866    }
18867    foreach my $Part (@DParts2)
18868    {
18869        if(isDump($Part)) {
18870            read_ABI_Dump(2, $Part);
18871        }
18872        else {
18873            readDescriptor(2, createDescriptor(2, $Part));
18874        }
18875    }
18876    initLogging(1);
18877    initLogging(2);
18878    # check consistency
18879    if(not $Descriptor{1}{"Headers"}
18880    and not $Descriptor{1}{"Libs"}) {
18881        exitStatus("Error", "descriptor d1 does not contain both header files and libraries info");
18882    }
18883    if(not $Descriptor{2}{"Headers"}
18884    and not $Descriptor{2}{"Libs"}) {
18885        exitStatus("Error", "descriptor d2 does not contain both header files and libraries info");
18886    }
18887    if($Descriptor{1}{"Headers"} and not $Descriptor{1}{"Libs"}
18888    and not $Descriptor{2}{"Headers"} and $Descriptor{2}{"Libs"}) {
18889        exitStatus("Error", "can't compare headers with $SLIB_TYPE libraries");
18890    }
18891    elsif(not $Descriptor{1}{"Headers"} and $Descriptor{1}{"Libs"}
18892    and $Descriptor{2}{"Headers"} and not $Descriptor{2}{"Libs"}) {
18893        exitStatus("Error", "can't compare $SLIB_TYPE libraries with headers");
18894    }
18895    if(not $Descriptor{1}{"Headers"}) {
18896        if($CheckHeadersOnly_Opt) {
18897            exitStatus("Error", "can't find header files info in descriptor d1");
18898        }
18899    }
18900    if(not $Descriptor{2}{"Headers"}) {
18901        if($CheckHeadersOnly_Opt) {
18902            exitStatus("Error", "can't find header files info in descriptor d2");
18903        }
18904    }
18905    if(not $Descriptor{1}{"Headers"}
18906    or not $Descriptor{2}{"Headers"}) {
18907        if(not $CheckObjectsOnly_Opt) {
18908            printMsg("WARNING", "comparing $SLIB_TYPE libraries only");
18909            $CheckObjectsOnly = 1;
18910        }
18911    }
18912    if(not $Descriptor{1}{"Libs"}) {
18913        if($CheckObjectsOnly_Opt) {
18914            exitStatus("Error", "can't find $SLIB_TYPE libraries info in descriptor d1");
18915        }
18916    }
18917    if(not $Descriptor{2}{"Libs"}) {
18918        if($CheckObjectsOnly_Opt) {
18919            exitStatus("Error", "can't find $SLIB_TYPE libraries info in descriptor d2");
18920        }
18921    }
18922    if(not $Descriptor{1}{"Libs"}
18923    or not $Descriptor{2}{"Libs"})
18924    { # comparing standalone header files
18925      # comparing ABI dumps created with --headers-only
18926        if(not $CheckHeadersOnly_Opt)
18927        {
18928            printMsg("WARNING", "checking headers only");
18929            $CheckHeadersOnly = 1;
18930        }
18931    }
18932    if($UseDumps)
18933    { # --use-dumps
18934      # parallel processing
18935        my $pid = fork();
18936        if($pid)
18937        { # dump on two CPU cores
18938            my @PARAMS = ("-dump", $Descriptor{1}{"Path"}, "-l", $TargetLibraryName);
18939            if($RelativeDirectory{1}) {
18940                @PARAMS = (@PARAMS, "-relpath", $RelativeDirectory{1});
18941            }
18942            if($OutputLogPath{1}) {
18943                @PARAMS = (@PARAMS, "-log-path", $OutputLogPath{1});
18944            }
18945            if($CrossGcc) {
18946                @PARAMS = (@PARAMS, "-cross-gcc", $CrossGcc);
18947            }
18948            if($Quiet)
18949            {
18950                @PARAMS = (@PARAMS, "-quiet");
18951                @PARAMS = (@PARAMS, "-logging-mode", "a");
18952            }
18953            elsif($LogMode and $LogMode ne "w")
18954            { # "w" is default
18955                @PARAMS = (@PARAMS, "-logging-mode", $LogMode);
18956            }
18957            if($ExtendedCheck) {
18958                @PARAMS = (@PARAMS, "-extended");
18959            }
18960            if($UserLang) {
18961                @PARAMS = (@PARAMS, "-lang", $UserLang);
18962            }
18963            if($TargetVersion{1}) {
18964                @PARAMS = (@PARAMS, "-vnum", $TargetVersion{1});
18965            }
18966            if($BinaryOnly) {
18967                @PARAMS = (@PARAMS, "-binary");
18968            }
18969            if($SourceOnly) {
18970                @PARAMS = (@PARAMS, "-source");
18971            }
18972            if($SortDump) {
18973                @PARAMS = (@PARAMS, "-sort");
18974            }
18975            if($Debug)
18976            {
18977                @PARAMS = (@PARAMS, "-debug");
18978                printMsg("INFO", "running perl $0 @PARAMS");
18979            }
18980            system("perl", $0, @PARAMS);
18981            if($?) {
18982                exit(1);
18983            }
18984        }
18985        else
18986        { # child
18987            my @PARAMS = ("-dump", $Descriptor{2}{"Path"}, "-l", $TargetLibraryName);
18988            if($RelativeDirectory{2}) {
18989                @PARAMS = (@PARAMS, "-relpath", $RelativeDirectory{2});
18990            }
18991            if($OutputLogPath{2}) {
18992                @PARAMS = (@PARAMS, "-log-path", $OutputLogPath{2});
18993            }
18994            if($CrossGcc) {
18995                @PARAMS = (@PARAMS, "-cross-gcc", $CrossGcc);
18996            }
18997            if($Quiet)
18998            {
18999                @PARAMS = (@PARAMS, "-quiet");
19000                @PARAMS = (@PARAMS, "-logging-mode", "a");
19001            }
19002            elsif($LogMode and $LogMode ne "w")
19003            { # "w" is default
19004                @PARAMS = (@PARAMS, "-logging-mode", $LogMode);
19005            }
19006            if($ExtendedCheck) {
19007                @PARAMS = (@PARAMS, "-extended");
19008            }
19009            if($UserLang) {
19010                @PARAMS = (@PARAMS, "-lang", $UserLang);
19011            }
19012            if($TargetVersion{2}) {
19013                @PARAMS = (@PARAMS, "-vnum", $TargetVersion{2});
19014            }
19015            if($BinaryOnly) {
19016                @PARAMS = (@PARAMS, "-binary");
19017            }
19018            if($SourceOnly) {
19019                @PARAMS = (@PARAMS, "-source");
19020            }
19021            if($SortDump) {
19022                @PARAMS = (@PARAMS, "-sort");
19023            }
19024            if($Debug)
19025            {
19026                @PARAMS = (@PARAMS, "-debug");
19027                printMsg("INFO", "running perl $0 @PARAMS");
19028            }
19029            system("perl", $0, @PARAMS);
19030            if($?) {
19031                exit(1);
19032            }
19033            else {
19034                exit(0);
19035            }
19036        }
19037        waitpid($pid, 0);
19038        my @CMP_PARAMS = ("-l", $TargetLibraryName);
19039        @CMP_PARAMS = (@CMP_PARAMS, "-d1", "abi_dumps/$TargetLibraryName/".$TargetLibraryName."_".$Descriptor{1}{"Version"}.".abi.$AR_EXT");
19040        @CMP_PARAMS = (@CMP_PARAMS, "-d2", "abi_dumps/$TargetLibraryName/".$TargetLibraryName."_".$Descriptor{2}{"Version"}.".abi.$AR_EXT");
19041        if($TargetLibraryFName ne $TargetLibraryName) {
19042            @CMP_PARAMS = (@CMP_PARAMS, "-l-full", $TargetLibraryFName);
19043        }
19044        if($ShowRetVal) {
19045            @CMP_PARAMS = (@CMP_PARAMS, "-show-retval");
19046        }
19047        if($CrossGcc) {
19048            @CMP_PARAMS = (@CMP_PARAMS, "-cross-gcc", $CrossGcc);
19049        }
19050        @CMP_PARAMS = (@CMP_PARAMS, "-logging-mode", "a");
19051        if($Quiet) {
19052            @CMP_PARAMS = (@CMP_PARAMS, "-quiet");
19053        }
19054        if($ReportFormat and $ReportFormat ne "html")
19055        { # HTML is default format
19056            @CMP_PARAMS = (@CMP_PARAMS, "-report-format", $ReportFormat);
19057        }
19058        if($OutputReportPath) {
19059            @CMP_PARAMS = (@CMP_PARAMS, "-report-path", $OutputReportPath);
19060        }
19061        if($BinaryReportPath) {
19062            @CMP_PARAMS = (@CMP_PARAMS, "-bin-report-path", $BinaryReportPath);
19063        }
19064        if($SourceReportPath) {
19065            @CMP_PARAMS = (@CMP_PARAMS, "-src-report-path", $SourceReportPath);
19066        }
19067        if($LoggingPath) {
19068            @CMP_PARAMS = (@CMP_PARAMS, "-log-path", $LoggingPath);
19069        }
19070        if($Browse) {
19071            @CMP_PARAMS = (@CMP_PARAMS, "-browse", $Browse);
19072        }
19073        if($OpenReport) {
19074            @CMP_PARAMS = (@CMP_PARAMS, "-open");
19075        }
19076        if($Debug)
19077        {
19078            @CMP_PARAMS = (@CMP_PARAMS, "-debug");
19079            printMsg("INFO", "running perl $0 @CMP_PARAMS");
19080        }
19081        system("perl", $0, @CMP_PARAMS);
19082        exit($?>>8);
19083    }
19084    if(not $Descriptor{1}{"Dump"}
19085    or not $Descriptor{2}{"Dump"})
19086    { # need GCC toolchain to analyze
19087      # header files and libraries
19088        detect_default_paths("inc|lib|gcc");
19089    }
19090    if(not $Descriptor{1}{"Dump"})
19091    {
19092        if(not $CheckHeadersOnly) {
19093            readLibs(1);
19094        }
19095        if($CheckHeadersOnly) {
19096            setLanguage(1, "C++");
19097        }
19098        if(not $CheckObjectsOnly) {
19099            searchForHeaders(1);
19100        }
19101        $WORD_SIZE{1} = detectWordSize();
19102    }
19103    if(not $Descriptor{2}{"Dump"})
19104    {
19105        if(not $CheckHeadersOnly) {
19106            readLibs(2);
19107        }
19108        if($CheckHeadersOnly) {
19109            setLanguage(2, "C++");
19110        }
19111        if(not $CheckObjectsOnly) {
19112            searchForHeaders(2);
19113        }
19114        $WORD_SIZE{2} = detectWordSize();
19115    }
19116    if($WORD_SIZE{1} ne $WORD_SIZE{2})
19117    { # support for old ABI dumps
19118      # try to synch different WORD sizes
19119        if(not checkDump(1, "2.1"))
19120        {
19121            $WORD_SIZE{1} = $WORD_SIZE{2};
19122            printMsg("WARNING", "set WORD size to ".$WORD_SIZE{2}." bytes");
19123        }
19124        elsif(not checkDump(2, "2.1"))
19125        {
19126            $WORD_SIZE{2} = $WORD_SIZE{1};
19127            printMsg("WARNING", "set WORD size to ".$WORD_SIZE{1}." bytes");
19128        }
19129    }
19130    elsif(not $WORD_SIZE{1}
19131    and not $WORD_SIZE{2})
19132    { # support for old ABI dumps
19133        $WORD_SIZE{1} = "4";
19134        $WORD_SIZE{2} = "4";
19135    }
19136    if($Descriptor{1}{"Dump"})
19137    { # support for old ABI dumps
19138        prepareTypes(1);
19139    }
19140    if($Descriptor{2}{"Dump"})
19141    { # support for old ABI dumps
19142        prepareTypes(2);
19143    }
19144    if($AppPath and not keys(%{$Symbol_Library{1}})) {
19145        printMsg("WARNING", "the application ".get_filename($AppPath)." has no symbols imported from the $SLIB_TYPE libraries");
19146    }
19147    # started to process input data
19148    if(not $CheckObjectsOnly)
19149    {
19150        if($Descriptor{1}{"Headers"}
19151        and not $Descriptor{1}{"Dump"}) {
19152            readHeaders(1);
19153        }
19154        if($Descriptor{2}{"Headers"}
19155        and not $Descriptor{2}{"Dump"}) {
19156            readHeaders(2);
19157        }
19158    }
19159
19160    # clean memory
19161    %SystemHeaders = ();
19162    %mangled_name_gcc = ();
19163
19164    prepareSymbols(1);
19165    prepareSymbols(2);
19166
19167    # clean memory
19168    %SymbolInfo = ();
19169
19170    # Virtual Tables
19171    registerVTable(1);
19172    registerVTable(2);
19173
19174    if(not checkDump(1, "1.22")
19175    and checkDump(2, "1.22"))
19176    { # support for old ABI dumps
19177        foreach my $ClassName (keys(%{$VirtualTable{2}}))
19178        {
19179            if($ClassName=~/</)
19180            { # templates
19181                if(not defined $VirtualTable{1}{$ClassName})
19182                { # synchronize
19183                    delete($VirtualTable{2}{$ClassName});
19184                }
19185            }
19186        }
19187    }
19188
19189    registerOverriding(1);
19190    registerOverriding(2);
19191
19192    setVirtFuncPositions(1);
19193    setVirtFuncPositions(2);
19194
19195    # Other
19196    addParamNames(1);
19197    addParamNames(2);
19198
19199    detectChangedTypedefs();
19200}
19201
19202sub compareAPIs($)
19203{
19204    my $Level = $_[0];
19205    readRules($Level);
19206    if($Level eq "Binary") {
19207        printMsg("INFO", "comparing ABIs ...");
19208    }
19209    else {
19210        printMsg("INFO", "comparing APIs ...");
19211    }
19212    if($CheckHeadersOnly
19213    or $Level eq "Source")
19214    { # added/removed in headers
19215        detectAdded_H($Level);
19216        detectRemoved_H($Level);
19217    }
19218    else
19219    { # added/removed in libs
19220        detectAdded($Level);
19221        detectRemoved($Level);
19222    }
19223    if(not $CheckObjectsOnly)
19224    {
19225        mergeSignatures($Level);
19226        if(keys(%{$CheckedSymbols{$Level}})) {
19227            mergeConstants($Level);
19228        }
19229    }
19230    if($CheckHeadersOnly
19231    or $Level eq "Source")
19232    { # added/removed in headers
19233        mergeHeaders($Level);
19234    }
19235    else
19236    { # added/removed in libs
19237        mergeLibs($Level);
19238        if($CheckImpl
19239        and $Level eq "Binary") {
19240            mergeImpl();
19241        }
19242    }
19243}
19244
19245sub writeOpts()
19246{
19247    my %Opts = (
19248    "OStarget"=>$OStarget,
19249    "Debug"=>$Debug,
19250    "Quiet"=>$Quiet,
19251    "LogMode"=>$LogMode,
19252    "CheckHeadersOnly"=>$CheckHeadersOnly,
19253
19254    "SystemRoot"=>$SystemRoot,
19255    "MODULES_DIR"=>$MODULES_DIR,
19256    "GCC_PATH"=>$GCC_PATH,
19257    "TargetSysInfo"=>$TargetSysInfo,
19258    "CrossPrefix"=>$CrossPrefix,
19259    "TargetLibraryName"=>$TargetLibraryName,
19260    "CrossGcc"=>$CrossGcc,
19261    "UseStaticLibs"=>$UseStaticLibs,
19262    "NoStdInc"=>$NoStdInc
19263    );
19264    return \%Opts;
19265}
19266
19267sub get_CoreError($)
19268{
19269    my %CODE_ERROR = reverse(%ERROR_CODE);
19270    return $CODE_ERROR{$_[0]};
19271}
19272
19273sub scenario()
19274{
19275    if($StdOut)
19276    { # enable quiet mode
19277        $Quiet = 1;
19278        $JoinReport = 1;
19279    }
19280    if(not $LogMode)
19281    { # default
19282        $LogMode = "w";
19283    }
19284    if($UserLang)
19285    { # --lang=C++
19286        $UserLang = uc($UserLang);
19287        $COMMON_LANGUAGE{1}=$UserLang;
19288        $COMMON_LANGUAGE{2}=$UserLang;
19289    }
19290    if($LoggingPath)
19291    {
19292        $OutputLogPath{1} = $LoggingPath;
19293        $OutputLogPath{2} = $LoggingPath;
19294        if($Quiet) {
19295            $COMMON_LOG_PATH = $LoggingPath;
19296        }
19297    }
19298    if($OutputDumpPath)
19299    { # validate
19300        if($OutputDumpPath!~/\.abi(\.\Q$AR_EXT\E|)\Z/) {
19301            exitStatus("Error", "the dump path should be a path to *.abi.$AR_EXT or *.abi file");
19302        }
19303    }
19304    if($BinaryOnly and $SourceOnly)
19305    { # both --binary and --source
19306      # is the default mode
19307        $DoubleReport = 1;
19308        $JoinReport = 0;
19309        $BinaryOnly = 0;
19310        $SourceOnly = 0;
19311        if($OutputReportPath)
19312        { # --report-path
19313            $DoubleReport = 0;
19314            $JoinReport = 1;
19315        }
19316    }
19317    elsif($BinaryOnly or $SourceOnly)
19318    { # --binary or --source
19319        $DoubleReport = 0;
19320        $JoinReport = 0;
19321    }
19322    if($UseXML)
19323    { # --xml option
19324        $ReportFormat = "xml";
19325        $DumpFormat = "xml";
19326    }
19327    if($ReportFormat)
19328    { # validate
19329        $ReportFormat = lc($ReportFormat);
19330        if($ReportFormat!~/\A(xml|html|htm)\Z/) {
19331            exitStatus("Error", "unknown report format \'$ReportFormat\'");
19332        }
19333        if($ReportFormat eq "htm")
19334        { # HTM == HTML
19335            $ReportFormat = "html";
19336        }
19337        elsif($ReportFormat eq "xml")
19338        { # --report-format=XML equal to --xml
19339            $UseXML = 1;
19340        }
19341    }
19342    else
19343    { # default: HTML
19344        $ReportFormat = "html";
19345    }
19346    if($DumpFormat)
19347    { # validate
19348        $DumpFormat = lc($DumpFormat);
19349        if($DumpFormat!~/\A(xml|perl)\Z/) {
19350            exitStatus("Error", "unknown ABI dump format \'$DumpFormat\'");
19351        }
19352        if($DumpFormat eq "xml")
19353        { # --dump-format=XML equal to --xml
19354            $UseXML = 1;
19355        }
19356    }
19357    else
19358    { # default: HTML
19359        $DumpFormat = "perl";
19360    }
19361    if($Quiet and $LogMode!~/a|n/)
19362    { # --quiet log
19363        if(-f $COMMON_LOG_PATH) {
19364            unlink($COMMON_LOG_PATH);
19365        }
19366    }
19367    if($TestTool and $UseDumps)
19368    { # --test && --use-dumps == --test-dump
19369        $TestDump = 1;
19370    }
19371    if($Help) {
19372        HELP_MESSAGE();
19373        exit(0);
19374    }
19375    if($InfoMsg) {
19376        INFO_MESSAGE();
19377        exit(0);
19378    }
19379    if($ShowVersion) {
19380        printMsg("INFO", "ABI Compliance Checker (ACC) $TOOL_VERSION\nCopyright (C) 2012 ROSA Laboratory\nLicense: LGPL or GPL <http://www.gnu.org/licenses/>\nThis program is free software: you can redistribute it and/or modify it.\n\nWritten by Andrey Ponomarenko.");
19381        exit(0);
19382    }
19383    if($DumpVersion) {
19384        printMsg("INFO", $TOOL_VERSION);
19385        exit(0);
19386    }
19387    if($ExtendedCheck) {
19388        $CheckHeadersOnly = 1;
19389    }
19390    if($SystemRoot_Opt)
19391    { # user defined root
19392        if(not -e $SystemRoot_Opt) {
19393            exitStatus("Access_Error", "can't access \'$SystemRoot\'");
19394        }
19395        $SystemRoot = $SystemRoot_Opt;
19396        $SystemRoot=~s/[\/]+\Z//g;
19397        if($SystemRoot) {
19398            $SystemRoot = get_abs_path($SystemRoot);
19399        }
19400    }
19401    $Data::Dumper::Sortkeys = 1;
19402
19403    if($SortDump)
19404    {
19405        $Data::Dumper::Useperl = 1;
19406        $Data::Dumper::Sortkeys = \&dump_sorting;
19407    }
19408
19409    if($TargetLibsPath)
19410    {
19411        if(not -f $TargetLibsPath) {
19412            exitStatus("Access_Error", "can't access file \'$TargetLibsPath\'");
19413        }
19414        foreach my $Lib (split(/\s*\n\s*/, readFile($TargetLibsPath))) {
19415            $TargetLibs{$Lib} = 1;
19416        }
19417    }
19418    if($TargetHeadersPath)
19419    { # --headers-list
19420        if(not -f $TargetHeadersPath) {
19421            exitStatus("Access_Error", "can't access file \'$TargetHeadersPath\'");
19422        }
19423        foreach my $Header (split(/\s*\n\s*/, readFile($TargetHeadersPath)))
19424        {
19425            $TargetHeaders{1}{$Header} = 1;
19426            $TargetHeaders{2}{$Header} = 1;
19427        }
19428    }
19429    if($TargetHeader)
19430    { # --header
19431        $TargetHeaders{1}{$TargetHeader} = 1;
19432        $TargetHeaders{2}{$TargetHeader} = 1;
19433    }
19434    if($TestTool
19435    or $TestDump)
19436    { # --test, --test-dump
19437        detect_default_paths("bin|gcc"); # to compile libs
19438        loadModule("RegTests");
19439        testTool($TestDump, $Debug, $Quiet, $ExtendedCheck, $LogMode,
19440        $ReportFormat, $LIB_EXT, $GCC_PATH, $Browse, $OpenReport, $SortDump);
19441        exit(0);
19442    }
19443    if($DumpSystem)
19444    { # --dump-system
19445        loadModule("SysCheck");
19446        if($DumpSystem=~/\.xml\Z/)
19447        { # system XML descriptor
19448            if(not -f $DumpSystem) {
19449                exitStatus("Access_Error", "can't access file \'$DumpSystem\'");
19450            }
19451            my $Ret = readSystemDescriptor(readFile($DumpSystem));
19452            foreach (@{$Ret->{"Tools"}}) {
19453                $SystemPaths{"bin"}{$_} = 1;
19454                $TargetTools{$_}=1;
19455            }
19456            if($Ret->{"CrossPrefix"}) {
19457                $CrossPrefix = $Ret->{"CrossPrefix"};
19458            }
19459        }
19460        elsif($SystemRoot_Opt)
19461        { # -sysroot "/" option
19462          # default target: /usr/lib, /usr/include
19463          # search libs: /usr/lib and /lib
19464            if(not -e $SystemRoot."/usr/lib") {
19465                exitStatus("Access_Error", "can't access '".$SystemRoot."/usr/lib'");
19466            }
19467            if(not -e $SystemRoot."/lib") {
19468                exitStatus("Access_Error", "can't access '".$SystemRoot."/lib'");
19469            }
19470            if(not -e $SystemRoot."/usr/include") {
19471                exitStatus("Access_Error", "can't access '".$SystemRoot."/usr/include'");
19472            }
19473            readSystemDescriptor("
19474                <name>
19475                    $DumpSystem
19476                </name>
19477                <headers>
19478                    $SystemRoot/usr/include
19479                </headers>
19480                <libs>
19481                    $SystemRoot/usr/lib
19482                </libs>
19483                <search_libs>
19484                    $SystemRoot/lib
19485                </search_libs>");
19486        }
19487        else {
19488            exitStatus("Error", "-sysroot <dirpath> option should be specified, usually it's \"/\"");
19489        }
19490        detect_default_paths("bin|gcc"); # to check symbols
19491        if($OStarget eq "windows")
19492        { # to run dumpbin.exe
19493          # and undname.exe
19494            check_win32_env();
19495        }
19496        dumpSystem(writeOpts());
19497        exit(0);
19498    }
19499    if($CmpSystems)
19500    { # --cmp-systems
19501        detect_default_paths("bin"); # to extract dumps
19502        loadModule("SysCheck");
19503        cmpSystems($Descriptor{1}{"Path"}, $Descriptor{2}{"Path"}, writeOpts());
19504        exit(0);
19505    }
19506    if($GenerateTemplate) {
19507        generateTemplate();
19508        exit(0);
19509    }
19510    if(not $TargetLibraryName) {
19511        exitStatus("Error", "library name is not selected (option -l <name>)");
19512    }
19513    else
19514    { # validate library name
19515        if($TargetLibraryName=~/[\*\/\\]/) {
19516            exitStatus("Error", "\"\\\", \"\/\" and \"*\" symbols are not allowed in the library name");
19517        }
19518    }
19519    if(not $TargetLibraryFName) {
19520        $TargetLibraryFName = $TargetLibraryName;
19521    }
19522    if($CheckHeadersOnly_Opt and $CheckObjectsOnly_Opt) {
19523        exitStatus("Error", "you can't specify both -headers-only and -objects-only options at the same time");
19524    }
19525    if($SymbolsListPath)
19526    {
19527        if(not -f $SymbolsListPath) {
19528            exitStatus("Access_Error", "can't access file \'$SymbolsListPath\'");
19529        }
19530        foreach my $Interface (split(/\s*\n\s*/, readFile($SymbolsListPath))) {
19531            $SymbolsList{$Interface} = 1;
19532        }
19533    }
19534    if($SkipHeadersPath)
19535    {
19536        if(not -f $SkipHeadersPath) {
19537            exitStatus("Access_Error", "can't access file \'$SkipHeadersPath\'");
19538        }
19539        foreach my $Path (split(/\s*\n\s*/, readFile($SkipHeadersPath)))
19540        { # register for both versions
19541            $SkipHeadersList{1}{$Path} = 1;
19542            $SkipHeadersList{2}{$Path} = 1;
19543            my ($CPath, $Type) = classifyPath($Path);
19544            $SkipHeaders{1}{$Type}{$CPath} = 1;
19545            $SkipHeaders{2}{$Type}{$CPath} = 1;
19546        }
19547    }
19548    if($ParamNamesPath)
19549    {
19550        if(not -f $ParamNamesPath) {
19551            exitStatus("Access_Error", "can't access file \'$ParamNamesPath\'");
19552        }
19553        foreach my $Line (split(/\n/, readFile($ParamNamesPath)))
19554        {
19555            if($Line=~s/\A(\w+)\;//)
19556            {
19557                my $Interface = $1;
19558                if($Line=~/;(\d+);/)
19559                {
19560                    while($Line=~s/(\d+);(\w+)//) {
19561                        $AddIntParams{$Interface}{$1}=$2;
19562                    }
19563                }
19564                else
19565                {
19566                    my $Num = 0;
19567                    foreach my $Name (split(/;/, $Line)) {
19568                        $AddIntParams{$Interface}{$Num++}=$Name;
19569                    }
19570                }
19571            }
19572        }
19573    }
19574    if($AppPath)
19575    {
19576        if(not -f $AppPath) {
19577            exitStatus("Access_Error", "can't access file \'$AppPath\'");
19578        }
19579        foreach my $Interface (readSymbols_App($AppPath)) {
19580            $SymbolsList_App{$Interface} = 1;
19581        }
19582    }
19583    if($DumpAPI)
19584    { # --dump-abi
19585      # make an API dump
19586        create_ABI_Dump();
19587        exit($COMPILE_ERRORS);
19588    }
19589    # default: compare APIs
19590    #  -d1 <path>
19591    #  -d2 <path>
19592    compareInit();
19593    if($JoinReport or $DoubleReport)
19594    {
19595        compareAPIs("Binary");
19596        compareAPIs("Source");
19597    }
19598    elsif($BinaryOnly) {
19599        compareAPIs("Binary");
19600    }
19601    elsif($SourceOnly) {
19602        compareAPIs("Source");
19603    }
19604    exitReport();
19605}
19606
19607scenario();
19608