diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 18:45:59 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 18:45:59 +0000 |
commit | 19fcec84d8d7d21e796c7624e521b60d28ee21ed (patch) | |
tree | 42d26aa27d1e3f7c0b8bd3fd14e7d7082f5008dc /src/boost/tools/inspect | |
parent | Initial commit. (diff) | |
download | ceph-19fcec84d8d7d21e796c7624e521b60d28ee21ed.tar.xz ceph-19fcec84d8d7d21e796c7624e521b60d28ee21ed.zip |
Adding upstream version 16.2.11+ds.upstream/16.2.11+dsupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
36 files changed, 3548 insertions, 0 deletions
diff --git a/src/boost/tools/inspect/apple_macro_check.cpp b/src/boost/tools/inspect/apple_macro_check.cpp new file mode 100644 index 000000000..7afb8f9fd --- /dev/null +++ b/src/boost/tools/inspect/apple_macro_check.cpp @@ -0,0 +1,105 @@ +// apple_macro_check implementation ------------------------------------------------// + +// Copyright Marshall Clow 2007. +// Based on the tab-check checker by Beman Dawes +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include "apple_macro_check.hpp" +#include <functional> +#include "boost/regex.hpp" +#include "boost/lexical_cast.hpp" +#include "boost/filesystem/operations.hpp" + +namespace fs = boost::filesystem; + +namespace +{ + boost::regex apple_macro_regex( + "(" + "^\\s*#\\s*undef\\s*" // # undef + "\\b(check|verify|require|check_error)\\b" // followed by apple macro name, whole word + ")" + "|" // or (ignored) + "(" + "//[^\\n]*" // single line comments (//) + "|" + "/\\*.*?\\*/" // multi line comments (/**/) + "|" + "\"(?:\\\\\\\\|\\\\\"|[^\"])*\"" // string literals + ")" + "|" // or + "(" + "\\b(check|verify|require|check_error)\\b" // apple macro name, whole word + "\\s*\\(" // followed by 0 or more spaces and an opening paren + ")" + , boost::regex::normal); + +} // unnamed namespace + + +namespace boost +{ + namespace inspect + { + apple_macro_check::apple_macro_check() : m_files_with_errors(0) + { + register_signature( ".c" ); + register_signature( ".cpp" ); + register_signature( ".cxx" ); + register_signature( ".h" ); + register_signature( ".hpp" ); + register_signature( ".hxx" ); + register_signature( ".ipp" ); + } + + void apple_macro_check::inspect( + const string & library_name, + const path & full_path, // example: c:/foo/boost/filesystem/path.hpp + const string & contents ) // contents of file to be inspected + { + if (contents.find( "boostinspect:" "naapple_macros" ) != string::npos) return; + + // Only check files in the boost directory, as we can avoid including the + // apple test headers elsewhere. + path relative( relative_to( full_path, search_root_path() ) ); + if ( relative.empty() || *relative.begin() != "boost") return; + + boost::sregex_iterator cur(contents.begin(), contents.end(), apple_macro_regex), end; + + long errors = 0; + + for( ; cur != end; ++cur /*, ++m_files_with_errors*/ ) + { + + if(!(*cur)[3].matched) + { + string::const_iterator it = contents.begin(); + string::const_iterator match_it = (*cur)[0].first; + + string::const_iterator line_start = it; + + string::size_type line_number = 1; + for ( ; it != match_it; ++it) { + if (string::traits_type::eq(*it, '\n')) { + ++line_number; + line_start = it + 1; // could be end() + } + } + + ++errors; + error( library_name, full_path, + "Apple macro clash: " + std::string((*cur)[0].first, (*cur)[0].second-1), + line_number ); + } + } + if(errors > 0) { + ++m_files_with_errors; + } + } + } // namespace inspect +} // namespace boost + + diff --git a/src/boost/tools/inspect/apple_macro_check.hpp b/src/boost/tools/inspect/apple_macro_check.hpp new file mode 100644 index 000000000..5acdcf70c --- /dev/null +++ b/src/boost/tools/inspect/apple_macro_check.hpp @@ -0,0 +1,39 @@ +// apple_macro_check header --------------------------------------------------------// + +// Copyright Marshall Clow 2007. +// Based on the tab-check checker by Beman Dawes +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_APPLE_MACRO_CHECK_HPP +#define BOOST_APPLE_MACRO_CHECK_HPP + +#include "inspector.hpp" + + +namespace boost +{ + namespace inspect + { + class apple_macro_check : public inspector + { + long m_files_with_errors; + public: + + apple_macro_check(); + virtual const char * name() const { return "*APPLE-MACROS*"; } + virtual const char * desc() const { return "calls to Apple's debugging macros in file"; } + + virtual void inspect( + const std::string & library_name, + const path & full_path, + const std::string & contents ); + + virtual ~apple_macro_check() + { std::cout << " " << m_files_with_errors << " files with Apple macros" << line_break(); } + }; + } +} + +#endif // BOOST_APPLE_MACRO_CHECK_HPP diff --git a/src/boost/tools/inspect/ascii_check.cpp b/src/boost/tools/inspect/ascii_check.cpp new file mode 100644 index 000000000..da2aa4020 --- /dev/null +++ b/src/boost/tools/inspect/ascii_check.cpp @@ -0,0 +1,102 @@ +// ascii_check implementation ------------------------------------------------// + +// Copyright Marshall Clow 2007. +// Based on the tab-check checker by Beman Dawes +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// √ -- this is a test. + +#include "ascii_check.hpp" +#include <functional> + +namespace boost +{ + namespace inspect + { + + static const string gPunct ( "$_{}[]#()<>%:;.?*+-/ˆ&|~!=,\\\"'@^`" ); + + // Legal characters for a source file are defined in section 2.2 of the standard + // I have added '@', '^', and '`' to the "legal" chars because they are commonly + // used in comments, and they are strictly ASCII. + struct non_ascii : public std::unary_function<char, bool> { + public: + non_ascii () {} + ~non_ascii () {} + bool operator () ( char c ) const + { + if ( c == ' ' ) return false; + if ( c >= 'a' && c <= 'z' ) return false; + if ( c >= 'A' && c <= 'Z' ) return false; + if ( c >= '0' && c <= '9' ) return false; + // Horizontal/Vertical tab, newline, and form feed + if ( c == '\t' || c == '\n' || c == '\r' || c == '\v' || c == '\f' ) return false; + return gPunct.find ( c ) == string::npos; + } + }; + + struct is_CRLF : public std::unary_function<char, bool> { + public: + is_CRLF () {} + ~is_CRLF () {} + bool operator () ( char c ) const + { + return c == '\015' || c == '\012'; + } + }; + + const char *kCRLF = "\012\015"; + +// Given a position in the file, extract and return the line + std::string find_line ( const std::string &contents, std::string::const_iterator iter_pos ) + { + std::size_t pos = iter_pos - contents.begin (); + + // Search backwards for a CR or LR + std::size_t start_pos = contents.find_last_of ( kCRLF, pos ); + std::string::const_iterator line_start = contents.begin () + ( start_pos == std::string::npos ? 0 : start_pos + 1 ); + + + // Search forwards for a CR or LF + std::size_t end_pos = contents.find_first_of ( kCRLF, pos + 1 ); + std::string::const_iterator line_end; + if ( end_pos == std::string::npos ) + line_end = contents.end (); + else + line_end = contents.begin () + end_pos - 1; + + return std::string ( line_start, line_end ); + } + + ascii_check::ascii_check() : m_files_with_errors(0) + { + register_signature( ".c" ); + register_signature( ".cpp" ); + register_signature( ".cxx" ); + register_signature( ".h" ); + register_signature( ".hpp" ); + register_signature( ".hxx" ); + register_signature( ".ipp" ); + } + + void ascii_check::inspect( + const string & library_name, + const path & full_path, // example: c:/foo/boost/filesystem/path.hpp + const string & contents ) // contents of file to be inspected + { + if (contents.find( "boostinspect:" "noascii" ) != string::npos) return; + string::const_iterator bad_char = std::find_if ( contents.begin (), contents.end (), non_ascii ()); + if ( bad_char != contents.end ()) + { + ++m_files_with_errors; + int ln = std::count( contents.begin(), bad_char, '\n' ) + 1; + string the_line = find_line ( contents, bad_char ); + error( library_name, full_path, "Non-ASCII: " + the_line, ln ); + } + } + } // namespace inspect +} // namespace boost + + diff --git a/src/boost/tools/inspect/ascii_check.hpp b/src/boost/tools/inspect/ascii_check.hpp new file mode 100644 index 000000000..6094ce856 --- /dev/null +++ b/src/boost/tools/inspect/ascii_check.hpp @@ -0,0 +1,38 @@ +// ascii_check header --------------------------------------------------------// + +// Copyright Marshall Clow 2007. +// Based on the tab-check checker by Beman Dawes +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_ASCII_CHECK_HPP +#define BOOST_ASCII_CHECK_HPP + +#include "inspector.hpp" + +namespace boost +{ + namespace inspect + { + class ascii_check : public inspector + { + long m_files_with_errors; + public: + + ascii_check(); + virtual const char * name() const { return "*ASCII*"; } + virtual const char * desc() const { return "non-ASCII chars in file"; } + + virtual void inspect( + const std::string & library_name, + const path & full_path, + const std::string & contents ); + + virtual ~ascii_check() + { std::cout << " " << m_files_with_errors << " files with non-ASCII chars" << line_break(); } + }; + } +} + +#endif // BOOST_ASCII_CHECK_HPP diff --git a/src/boost/tools/inspect/assert_macro_check.cpp b/src/boost/tools/inspect/assert_macro_check.cpp new file mode 100644 index 000000000..340a9f5ba --- /dev/null +++ b/src/boost/tools/inspect/assert_macro_check.cpp @@ -0,0 +1,110 @@ +// assert_macro_check implementation ------------------------------------------------// + +// Copyright Eric Niebler 2010. +// Based on the assert_macro_check checker by Marshall Clow +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include "assert_macro_check.hpp" +#include <functional> +#include "boost/regex.hpp" +#include "boost/lexical_cast.hpp" +#include "boost/filesystem/operations.hpp" + +namespace fs = boost::filesystem; + +namespace +{ + boost::regex assert_macro_regex( + "(" + "^\\s*#\\s*undef\\s*" // # undef + "\\b(assert)\\b" // followed by assert macro, whole word + ")" + "|" // or (ignored) + "(" + "//[^\\n]*" // single line comments (//) + "|" + "/\\*.*?\\*/" // multi line comments (/**/) + "|" + "\"(?:\\\\\\\\|\\\\\"|[^\"])*\"" // string literals + ")" + "|" // or + "(" + "\\b(assert)\\b" // assert macro, whole word + "\\s*\\(" // followed by 0 or more spaces and an opening paren + ")" + , boost::regex::normal); + +} // unnamed namespace + + +namespace boost +{ + namespace inspect + { + assert_macro_check::assert_macro_check() + : m_files_with_errors(0) + , m_from_boost_root( + fs::exists(search_root_path() / "boost") && + fs::exists(search_root_path() / "libs")) + { + register_signature( ".c" ); + register_signature( ".cpp" ); + register_signature( ".cxx" ); + register_signature( ".h" ); + register_signature( ".hpp" ); + register_signature( ".hxx" ); + register_signature( ".ipp" ); + } + + void assert_macro_check::inspect( + const string & library_name, + const path & full_path, // example: c:/foo/boost/filesystem/path.hpp + const string & contents ) // contents of file to be inspected + { + if (contents.find( "boostinspect:" "naassert_macro" ) != string::npos) + return; + + // Check files iff (a) they are in the boost directory, or (b) they + // are in the src directory under libs. + if (m_from_boost_root) { + path relative( relative_to( full_path, search_root_path() ) ); + path::const_iterator pbeg = relative.begin(), pend = relative.end(); + if (pbeg != std::find(pbeg, pend, "boost") && + !(pbeg == std::find(pbeg, pend, "libs") && pend != std::find(pbeg, pend, "src"))) + return; + } + + long errors = 0; + boost::sregex_iterator cur(contents.begin(), contents.end(), assert_macro_regex), end; + for( ; cur != end; ++cur ) + { + if(!(*cur)[3].matched) + { + string::const_iterator it = contents.begin(); + string::const_iterator match_it = (*cur)[0].first; + + string::const_iterator line_start = it; + + string::size_type line_number = 1; + for ( ; it != match_it; ++it) { + if (string::traits_type::eq(*it, '\n')) { + ++line_number; + line_start = it + 1; // could be end() + } + } + + ++errors; + error( library_name, full_path, "C-style assert macro on line " + + boost::lexical_cast<string>( line_number ) ); + } + } + if(errors > 0) + ++m_files_with_errors; + } + } // namespace inspect +} // namespace boost + + diff --git a/src/boost/tools/inspect/assert_macro_check.hpp b/src/boost/tools/inspect/assert_macro_check.hpp new file mode 100644 index 000000000..c28a377f3 --- /dev/null +++ b/src/boost/tools/inspect/assert_macro_check.hpp @@ -0,0 +1,40 @@ +// assert_macro_check header --------------------------------------------------------// + +// Copyright Eric Niebler 2010. +// Based on the apple_macro_check checker by Marshall Clow +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_ASSERT_MACRO_CHECK_HPP +#define BOOST_ASSERT_MACRO_CHECK_HPP + +#include "inspector.hpp" + + +namespace boost +{ + namespace inspect + { + class assert_macro_check : public inspector + { + long m_files_with_errors; + bool m_from_boost_root; + public: + + assert_macro_check(); + virtual const char * name() const { return "*ASSERT-MACROS*"; } + virtual const char * desc() const { return "presence of C-style assert macro in file (use BOOST_ASSERT instead)"; } + + virtual void inspect( + const std::string & library_name, + const path & full_path, + const std::string & contents ); + + virtual ~assert_macro_check() + { std::cout << " " << m_files_with_errors << " files with a C-style assert macro" << line_break(); } + }; + } +} + +#endif // BOOST_ASSERT_MACRO_CHECK_HPP diff --git a/src/boost/tools/inspect/build/Jamfile.v2 b/src/boost/tools/inspect/build/Jamfile.v2 new file mode 100644 index 000000000..e3a53a03d --- /dev/null +++ b/src/boost/tools/inspect/build/Jamfile.v2 @@ -0,0 +1,56 @@ +# Inspect Jamfile + +# Copyright Vladimir Prus + +# Distributed under the Boost Software License, Version 1.0. +# See http://www.boost.org/LICENSE_1_0.txt + +project + : + requirements + : + source-location .. + ; + +exe inspect + : + apple_macro_check.cpp + ascii_check.cpp + assert_macro_check.cpp + copyright_check.cpp + crlf_check.cpp + deprecated_macro_check.cpp + end_check.cpp + inspect.cpp + license_check.cpp + link_check.cpp + minmax_check.cpp + path_name_check.cpp + tab_check.cpp + unnamed_namespace_check.cpp + /boost//filesystem/<link>static + /boost//regex/<link>static + : + : + release + ; + +install dist-bin + : + inspect + : + <install-type>EXE + <location>../../../dist/bin + : + release + ; + +install dist-lib + : + inspect + : + <install-type>LIB + <location>../../../dist/lib + : + release + ; diff --git a/src/boost/tools/inspect/build/msvc/boost_inspect.sln b/src/boost/tools/inspect/build/msvc/boost_inspect.sln new file mode 100644 index 000000000..a4a1a40ab --- /dev/null +++ b/src/boost/tools/inspect/build/msvc/boost_inspect.sln @@ -0,0 +1,20 @@ + +Microsoft Visual Studio Solution File, Format Version 11.00 +# Visual C++ Express 2010 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "inspect", "boost_inspect.vcxproj", "{0EC8AC1C-6D1F-47FC-A06A-9CC3F924BD82}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {0EC8AC1C-6D1F-47FC-A06A-9CC3F924BD82}.Debug|Win32.ActiveCfg = Debug|Win32 + {0EC8AC1C-6D1F-47FC-A06A-9CC3F924BD82}.Debug|Win32.Build.0 = Debug|Win32 + {0EC8AC1C-6D1F-47FC-A06A-9CC3F924BD82}.Release|Win32.ActiveCfg = Release|Win32 + {0EC8AC1C-6D1F-47FC-A06A-9CC3F924BD82}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/src/boost/tools/inspect/build/msvc/boost_inspect.vcxproj b/src/boost/tools/inspect/build/msvc/boost_inspect.vcxproj new file mode 100644 index 000000000..3c35c22b8 --- /dev/null +++ b/src/boost/tools/inspect/build/msvc/boost_inspect.vcxproj @@ -0,0 +1,117 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup Label="ProjectConfigurations"> + <ProjectConfiguration Include="Debug|Win32"> + <Configuration>Debug</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|Win32"> + <Configuration>Release</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + </ItemGroup> + <PropertyGroup Label="Globals"> + <ProjectName>inspect</ProjectName> + <ProjectGuid>{0EC8AC1C-6D1F-47FC-A06A-9CC3F924BD82}</ProjectGuid> + <RootNamespace>boost_inspect</RootNamespace> + <Keyword>Win32Proj</Keyword> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> + <ConfigurationType>Application</ConfigurationType> + <CharacterSet>Unicode</CharacterSet> + <WholeProgramOptimization>true</WholeProgramOptimization> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration"> + <ConfigurationType>Application</ConfigurationType> + <CharacterSet>Unicode</CharacterSet> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> + <ImportGroup Label="ExtensionSettings"> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <PropertyGroup Label="UserMacros" /> + <PropertyGroup> + <_ProjectFileVersion>10.0.40219.1</_ProjectFileVersion> + <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(SolutionDir)$(Configuration)\</OutDir> + <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(Configuration)\</IntDir> + <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</LinkIncremental> + <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(SolutionDir)$(Configuration)\</OutDir> + <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(Configuration)\</IntDir> + <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</LinkIncremental> + </PropertyGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <ClCompile> + <Optimization>Disabled</Optimization> + <AdditionalIncludeDirectories>..\..\..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <MinimalRebuild>true</MinimalRebuild> + <ExceptionHandling>Async</ExceptionHandling> + <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks> + <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary> + <PrecompiledHeader> + </PrecompiledHeader> + <WarningLevel>Level3</WarningLevel> + <DebugInformationFormat>EditAndContinue</DebugInformationFormat> + </ClCompile> + <Link> + <AdditionalLibraryDirectories>..\..\..\..\stage\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories> + <GenerateDebugInformation>true</GenerateDebugInformation> + <SubSystem>Console</SubSystem> + <TargetMachine>MachineX86</TargetMachine> + </Link> + <PostBuildEvent> + <Command>"$(TargetDir)\$(TargetName).exe" ../.. -text -brief</Command> + </PostBuildEvent> + <PostBuildEvent> + <Message>Executing test $(TargetName).exe...</Message> + </PostBuildEvent> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <ClCompile> + <Optimization>MaxSpeed</Optimization> + <IntrinsicFunctions>true</IntrinsicFunctions> + <AdditionalIncludeDirectories>..\..\..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <ExceptionHandling>Async</ExceptionHandling> + <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary> + <FunctionLevelLinking>true</FunctionLevelLinking> + <PrecompiledHeader> + </PrecompiledHeader> + <WarningLevel>Level3</WarningLevel> + <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> + </ClCompile> + <Link> + <AdditionalLibraryDirectories>..\..\..\..\stage\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories> + <GenerateDebugInformation>true</GenerateDebugInformation> + <SubSystem>Console</SubSystem> + <OptimizeReferences>true</OptimizeReferences> + <EnableCOMDATFolding>true</EnableCOMDATFolding> + <TargetMachine>MachineX86</TargetMachine> + </Link> + </ItemDefinitionGroup> + <ItemGroup> + <ClCompile Include="..\..\apple_macro_check.cpp" /> + <ClCompile Include="..\..\ascii_check.cpp" /> + <ClCompile Include="..\..\assert_macro_check.cpp" /> + <ClCompile Include="..\..\copyright_check.cpp" /> + <ClCompile Include="..\..\crlf_check.cpp" /> + <ClCompile Include="..\..\deprecated_macro_check.cpp" /> + <ClCompile Include="..\..\end_check.cpp" /> + <ClCompile Include="..\..\inspect.cpp" /> + <ClCompile Include="..\..\license_check.cpp" /> + <ClCompile Include="..\..\link_check.cpp" /> + <ClCompile Include="..\..\minmax_check.cpp" /> + <ClCompile Include="..\..\path_name_check.cpp" /> + <ClCompile Include="..\..\tab_check.cpp" /> + <ClCompile Include="..\..\unnamed_namespace_check.cpp" /> + </ItemGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> + <ImportGroup Label="ExtensionTargets"> + </ImportGroup> +</Project>
\ No newline at end of file diff --git a/src/boost/tools/inspect/build/msvc/readme.txt b/src/boost/tools/inspect/build/msvc/readme.txt new file mode 100644 index 000000000..a549811ad --- /dev/null +++ b/src/boost/tools/inspect/build/msvc/readme.txt @@ -0,0 +1,8 @@ +The provided Microsoft VC++ 10 solution assumes the following commands have been run +in the root directory: + + b2 --toolset=msvc-10.0express --build-type=complete --with-filesystem stage + b2 --toolset=msvc-10.0express --build-type=complete --with-regex stage + +boost-no-inspect + diff --git a/src/boost/tools/inspect/copyright_check.cpp b/src/boost/tools/inspect/copyright_check.cpp new file mode 100644 index 000000000..f56bbc955 --- /dev/null +++ b/src/boost/tools/inspect/copyright_check.cpp @@ -0,0 +1,35 @@ +// copyright_check implementation ------------------------------------------------// + +// Copyright Beman Dawes 2002. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include "copyright_check.hpp" + +namespace boost +{ + namespace inspect + { + copyright_check::copyright_check() : m_files_with_errors(0) + { + } + + void copyright_check::inspect( + const string & library_name, + const path & full_path, // example: c:/foo/boost/filesystem/path.hpp + const string & contents ) // contents of file to be inspected + { + if (contents.find( "boostinspect:" "nocopyright" ) != string::npos) return; + + if ( contents.find( "Copyright" ) == string::npos + && contents.find( "copyright" ) == string::npos ) + { + ++m_files_with_errors; + error( library_name, full_path, name() ); + } + } + } // namespace inspect +} // namespace boost + + diff --git a/src/boost/tools/inspect/copyright_check.hpp b/src/boost/tools/inspect/copyright_check.hpp new file mode 100644 index 000000000..278596e3e --- /dev/null +++ b/src/boost/tools/inspect/copyright_check.hpp @@ -0,0 +1,39 @@ +// copyright_check header --------------------------------------------------// + +// Copyright Beman Dawes 2002, 2003. +// Copyright Rene Rivera 2004. +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_COPYRIGHT_CHECK_HPP +#define BOOST_COPYRIGHT_CHECK_HPP + +#include "inspector.hpp" + +namespace boost +{ + namespace inspect + { + class copyright_check : public source_inspector + { + long m_files_with_errors; + public: + + copyright_check(); + virtual const char * name() const { return "*C*"; } + virtual const char * desc() const { return "missing copyright notice"; } + + virtual void inspect( + const std::string & library_name, + const path & full_path, + const std::string & contents ); + + virtual ~copyright_check() + { std::cout << " " << m_files_with_errors << " files " << desc() << line_break(); } + }; + } +} + +#endif // BOOST_COPYRIGHT_CHECK_HPP diff --git a/src/boost/tools/inspect/crlf_check.cpp b/src/boost/tools/inspect/crlf_check.cpp new file mode 100644 index 000000000..c38271140 --- /dev/null +++ b/src/boost/tools/inspect/crlf_check.cpp @@ -0,0 +1,97 @@ +// crlf_check implementation ------------------------------------------------// + +// Copyright Beman Dawes 2002. +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// Contributed by Joerg Walter + +#include "crlf_check.hpp" + +namespace boost +{ + namespace inspect + { + crlf_check::crlf_check() : m_files_with_errors(0) + { + } + + void crlf_check::inspect( + const string & library_name, + const path & full_path, // example: c:/foo/boost/filesystem/path.hpp + const string & contents ) // contents of file to be inspected + { + if (contents.find( "boostinspect:" "nocrlf" ) != string::npos) return; + + // this file deliberately contains errors + const char test_file_name[] = "wrong_line_ends_test.cpp"; + + bool failed = false; + // The understanding on line endings, as I remember it, was that + // either "\n" or "\r\n" is OK, and they can be mixed, but "\r" alone + // is not acceptable. Mixed line endings are allowed because Boost files + // are commonly edited in both Windows and UNIX environments, and editors + // in those environments generally accept either ending. Even Mac people + // agreed with this policy. --Beman + + // Joerg's original implementation is saved below, + // in case we change our minds! + + for ( std::string::const_iterator itr ( contents.begin() ); + itr != contents.end(); ++itr ) + { + if ( *itr == '\r' && ((itr+1) == contents.end() || *(itr+1) != '\n') ) + { + failed = true; + break; + } + } + + if (failed && full_path.leaf() != test_file_name) + { + ++m_files_with_errors; + error( library_name, full_path, name() ); + } + + if (!failed && full_path.leaf() == test_file_name) + { + ++m_files_with_errors; + error( library_name, full_path, string(name()) + " should have cr-only line endings" ); + } + +/* + size_t cr_count = 0; + size_t lf_count = 0; + size_t crlf_count = 0; + bool had_cr = false; + for ( size_t i = 0; i < contents.length(); ++i ) + { + switch ( contents[i] ) + { + case '\r': + had_cr = true; + ++cr_count; + break; + case '\n': + ++lf_count; + if ( had_cr ) + ++crlf_count; + // fallthrough + default: + had_cr = false; + break; + } + } + if ( cr_count > 0 && lf_count != crlf_count ) + { + ++m_files_with_errors; + error( library_name, full_path, desc() ); + } +*/ + } + } // namespace inspect +} // namespace boost + + diff --git a/src/boost/tools/inspect/crlf_check.hpp b/src/boost/tools/inspect/crlf_check.hpp new file mode 100644 index 000000000..c6627ceee --- /dev/null +++ b/src/boost/tools/inspect/crlf_check.hpp @@ -0,0 +1,40 @@ +// crfl_check header --------------------------------------------------------// + +// Copyright Beman Dawes 2002. +// Copyright Rene Rivera 2004. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// Contributed by Joerg Walter + +#ifndef BOOST_CRLF_CHECK_HPP +#define BOOST_CRLF_CHECK_HPP + +#include "inspector.hpp" + +namespace boost +{ + namespace inspect + { + class crlf_check : public source_inspector + { + long m_files_with_errors; + public: + + crlf_check(); + virtual const char * name() const { return "*EOL*"; } + virtual const char * desc() const { return "invalid (cr only) line-ending"; } + + virtual void inspect( + const std::string & library_name, + const path & full_path, + const std::string & contents ); + + virtual ~crlf_check() + { std::cout << " " << m_files_with_errors << " files with invalid line endings" << line_break(); } + }; + } +} + +#endif // BOOST_CRLF_CHECK_HPP diff --git a/src/boost/tools/inspect/deprecated_macro_check.cpp b/src/boost/tools/inspect/deprecated_macro_check.cpp new file mode 100644 index 000000000..7eeeda00c --- /dev/null +++ b/src/boost/tools/inspect/deprecated_macro_check.cpp @@ -0,0 +1,146 @@ +// deprecated macro check implementation ---------------------------------------------// +// Protect against ourself: boostinspect:ndprecated_macros + +// Copyright Eric Niebler 2010. +// Based on the assert_macro_check checker by Marshall Clow +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include "deprecated_macro_check.hpp" +#include <functional> +#include "boost/regex.hpp" +#include "boost/lexical_cast.hpp" +#include "boost/filesystem/operations.hpp" + +namespace fs = boost::filesystem; + +namespace +{ + const char * boost150macros [] = { + "BOOST_NO_0X_HDR_ARRAY", + "BOOST_NO_0X_HDR_CHRONO", + "BOOST_NO_0X_HDR_CODECVT", + "BOOST_NO_0X_HDR_CONDITION_VARIABLE", + "BOOST_NO_0X_HDR_FORWARD_LIST", + "BOOST_NO_0X_HDR_FUTURE", + "BOOST_NO_0X_HDR_INITIALIZER_LIST", + "BOOST_NO_INITIALIZER_LISTS", + "BOOST_NO_0X_HDR_MUTEX", + "BOOST_NO_0X_HDR_RANDOM", + "BOOST_NO_0X_HDR_RATIO", + "BOOST_NO_0X_HDR_REGEX", + "BOOST_NO_0X_HDR_SYSTEM_ERROR", + "BOOST_NO_0X_HDR_THREAD", + "BOOST_NO_0X_HDR_TUPLE", + "BOOST_NO_0X_HDR_TYPE_TRAITS", + "BOOST_NO_0X_HDR_TYPEINDEX", + "BOOST_NO_0X_HDR_UNORDERED_SET", + "BOOST_NO_0X_HDR_UNORDERED_MAP", + "BOOST_NO_STD_UNORDERED", + NULL + }; + + const char * boost151macros [] = { + "BOOST_NO_AUTO_DECLARATIONS", + "BOOST_NO_AUTO_MULTIDECLARATIONS", + "BOOST_NO_CHAR16_T", + "BOOST_NO_CHAR32_T", + "BOOST_NO_TEMPLATE_ALIASES", + "BOOST_NO_CONSTEXPR", + "BOOST_NO_DECLTYPE", + "BOOST_NO_DECLTYPE_N3276", + "BOOST_NO_DEFAULTED_FUNCTIONS", + "BOOST_NO_DELETED_FUNCTIONS", + "BOOST_NO_EXPLICIT_CONVERSION_OPERATORS", + "BOOST_NO_EXTERN_TEMPLATE", + "BOOST_NO_FUNCTION_TEMPLATE_DEFAULT_ARGS", + "BOOST_NO_LAMBDAS", + "BOOST_NO_LOCAL_CLASS_TEMPLATE_PARAMETERS", + "BOOST_NO_NOEXCEPT", + "BOOST_NO_NULLPTR", + "BOOST_NO_RAW_LITERALS", + "BOOST_NO_RVALUE_REFERENCES", + "BOOST_NO_SCOPED_ENUMS", + "BOOST_NO_STATIC_ASSERT", + "BOOST_NO_STD_UNORDERED", + "BOOST_NO_UNICODE_LITERALS", + "BOOST_NO_UNIFIED_INITIALIZATION_SYNTAX", + "BOOST_NO_VARIADIC_TEMPLATES", + "BOOST_NO_VARIADIC_MACROS", + "BOOST_NO_NUMERIC_LIMITS_LOWEST", + NULL + }; + + const char * boost153macros [] = { + "BOOST_HAS_STATIC_ASSERT", + "BOOST_HAS_RVALUE_REFS", + "BOOST_HAS_VARIADIC_TMPL", + "BOOST_HAS_CHAR16_T", + "BOOST_HAS_CHAR32_T", + NULL + }; +} // unnamed namespace + + +namespace boost +{ + namespace inspect + { + deprecated_macro_check::deprecated_macro_check() + : m_files_with_errors(0) + , m_from_boost_root( + fs::exists(search_root_path() / "boost") && + fs::exists(search_root_path() / "libs")) + { + register_signature( ".c" ); + register_signature( ".cpp" ); + register_signature( ".cxx" ); + register_signature( ".h" ); + register_signature( ".hpp" ); + register_signature( ".hxx" ); + register_signature( ".ipp" ); + } + + void deprecated_macro_check::inspect( + const string & library_name, + const path & full_path, // example: c:/foo/boost/filesystem/path.hpp + const string & contents ) // contents of file to be inspected + { + if (contents.find( "boostinspect:" "ndprecated_macros" ) != string::npos) + return; + + const char **ptr; + long errors = 0; + for ( ptr = boost150macros; *ptr != NULL; ++ptr ) + { + if ( contents.find( *ptr ) != string::npos ) { + ++errors; + error( library_name, full_path, string ( "Boost macro deprecated in 1.50: " ) + *ptr ); + } + } + + for ( ptr = boost151macros; *ptr != NULL; ++ptr ) + { + if ( contents.find( *ptr ) != string::npos ) { + ++errors; + error( library_name, full_path, string ( "Boost macro deprecated in 1.51: " ) + *ptr ); + } + } + + for ( ptr = boost153macros; *ptr != NULL; ++ptr ) + { + if ( contents.find( *ptr ) != string::npos ) { + ++errors; + error( library_name, full_path, string ( "Boost macro deprecated in 1.53: " ) + *ptr ); + } + } + + if(errors > 0) + ++m_files_with_errors; + } + } // namespace inspect +} // namespace boost + + diff --git a/src/boost/tools/inspect/deprecated_macro_check.hpp b/src/boost/tools/inspect/deprecated_macro_check.hpp new file mode 100644 index 000000000..c9093907d --- /dev/null +++ b/src/boost/tools/inspect/deprecated_macro_check.hpp @@ -0,0 +1,40 @@ +// deprecated_macro_check header --------------------------------------------------------// + +// Copyright Eric Niebler 2010. +// Based on the apple_macro_check checker by Marshall Clow +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_DEPRECATED_MACRO_CHECK_HPP +#define BOOST_DEPRECATED_MACRO_CHECK_HPP + +#include "inspector.hpp" + + +namespace boost +{ + namespace inspect + { + class deprecated_macro_check : public inspector + { + long m_files_with_errors; + bool m_from_boost_root; + public: + + deprecated_macro_check(); + virtual const char * name() const { return "*DEPRECATED-MACROS*"; } + virtual const char * desc() const { return "presence of deprecated BOOST macro in file (see docs for replacements)"; } + + virtual void inspect( + const std::string & library_name, + const path & full_path, + const std::string & contents ); + + virtual ~deprecated_macro_check() + { std::cout << " " << m_files_with_errors << " files with a deprecated BOOST macro" << line_break(); } + }; + } +} + +#endif // BOOST_DEPRECATED_MACRO_CHECK_HPP diff --git a/src/boost/tools/inspect/end_check.cpp b/src/boost/tools/inspect/end_check.cpp new file mode 100644 index 000000000..9c1e438af --- /dev/null +++ b/src/boost/tools/inspect/end_check.cpp @@ -0,0 +1,58 @@ +// end_check implementation -------------------------------------------------// + +// Copyright Beman Dawes 2002. +// Copyright Daniel James 2009. +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include "end_check.hpp" +#include <boost/next_prior.hpp> + +namespace boost +{ + namespace inspect + { + end_check::end_check() : m_files_with_errors(0) + { + register_signature( ".c" ); + register_signature( ".cpp" ); + register_signature( ".cxx" ); + register_signature( ".h" ); + register_signature( ".hpp" ); + register_signature( ".hxx" ); + register_signature( ".ipp" ); + } + + void end_check::inspect( + const string & library_name, + const path & full_path, // example: c:/foo/boost/filesystem/path.hpp + const string & contents ) // contents of file to be inspected + { + if (contents.find( "boostinspect:" "noend" ) != string::npos) return; + + // this file deliberately contains errors + const char test_file_name[] = "wrong_line_ends_test.cpp"; + + char final_char = contents.begin() == contents.end() ? '\0' + : *(boost::prior(contents.end())); + + bool failed = final_char != '\n' && final_char != '\r'; + + if (failed && full_path.leaf() != test_file_name) + { + ++m_files_with_errors; + error( library_name, full_path, string(name()) + ' ' + desc() ); + } + + if (!failed && full_path.leaf() == test_file_name) + { + ++m_files_with_errors; + error( library_name, full_path, string(name()) + " should not end with a newline" ); + } + } + } // namespace inspect +} // namespace boost + + diff --git a/src/boost/tools/inspect/end_check.hpp b/src/boost/tools/inspect/end_check.hpp new file mode 100644 index 000000000..41e5041ce --- /dev/null +++ b/src/boost/tools/inspect/end_check.hpp @@ -0,0 +1,40 @@ +// end_check header ---------------------------------------------------------// + +// Copyright Beman Dawes 2002. +// Copyright Rene Rivera 2004. +// Copyright Daniel James 2009. +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_END_CHECK_HPP +#define BOOST_END_CHECK_HPP + +#include "inspector.hpp" + +namespace boost +{ + namespace inspect + { + class end_check : public inspector + { + long m_files_with_errors; + public: + + end_check(); + virtual const char * name() const { return "*END*"; } + virtual const char * desc() const { return "file doesn't end with a newline"; } + + virtual void inspect( + const std::string & library_name, + const path & full_path, + const std::string & contents ); + + virtual ~end_check() + { std::cout << " " << m_files_with_errors << " files that don't end with a newline" << line_break(); } + }; + } +} + +#endif // BOOST_END_CHECK_HPP diff --git a/src/boost/tools/inspect/index.html b/src/boost/tools/inspect/index.html new file mode 100644 index 000000000..c8abdf337 --- /dev/null +++ b/src/boost/tools/inspect/index.html @@ -0,0 +1,55 @@ +<html> + +<head> +<meta http-equiv="Content-Language" content="en-us"> +<meta name="GENERATOR" content="Microsoft FrontPage 5.0"> +<meta name="ProgId" content="FrontPage.Editor.Document"> +<meta http-equiv="Content-Type" content="text/html; charset=windows-1252"> +<title>Inspect Tool</title> +</head> + +<body bgcolor="#FFFFFF"> + +<h1> +<img src="../../boost.png" alt="boost.png (6897 bytes)" align="center" width="277" height="86">Inspect +Tool</h1> +<p>It is not uncommon for various common errors or +<a href="http://www.boost.org/more/lib_guide.htm">guideline violations</a> to creep into the +Boost libraries. The <i>inspect</i> program detects and reports several common +problems. It can be used to scan a proposed Boost submission to identify various +failures.</p> +<p>The <i>inspect</i> program is written in C++ to limit tool chain +dependencies, and should be portable to any system.</p> +<p>The program is run in the directory to be scanned for errors. Sub-directories +are also included in the scan.</p> +<p>If the first program argument is <code>-help</code>, a usage message is +displayed, showing all available program options.</p> +<p>The program sources include:</p> +<ul> + <li><a href="inspector.hpp">inspect.hpp</a> and <a href="inspect.cpp"> + inspect.cpp</a></li> + <li><a href="link_check.hpp">link_check.hpp</a> and <a href="link_check.cpp"> + link_check.cpp</a></li> + <li><a href="path_name_check.hpp">path_name_check.hpp</a> and + <a href="path_name_check.cpp">path_name_check.cpp</a></li> + <li><a href="tab_check.hpp">tab_check.hpp</a> and <a href="tab_check.cpp"> + tab_check.cpp</a></li> +</ul> +<p>A <a href="build/Jamfile.v2">Jamfile</a> is provided to build the program +using Boost.Build.</p> +<p>A Microsoft Visual Studio solution file is provided to aid maintenance. See +<a href="build/msvc/readme.txt">readme.txt</a> +before using it.</p> +<hr> +<p>Revised +<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->29 June, 2008<!--webbot bot="Timestamp" endspan i-checksum="19976" --></p> + +<p>© Copyright Beman Dawes, 2003</p> +<p> Distributed under the Boost Software +License, Version 1.0. (See accompanying file <a href="../../LICENSE_1_0.txt"> +LICENSE_1_0.txt</a> or copy at <a href="http://www.boost.org/LICENSE_1_0.txt"> +www.boost.org/LICENSE_1_0.txt</a>)</p> + +</body> + +</html> diff --git a/src/boost/tools/inspect/inspect.cpp b/src/boost/tools/inspect/inspect.cpp new file mode 100644 index 000000000..eb759fb3e --- /dev/null +++ b/src/boost/tools/inspect/inspect.cpp @@ -0,0 +1,1041 @@ +// inspect program -------------------------------------------------------------------// + +// Copyright Beman Dawes 2002. +// Copyright Rene Rivera 2004-2006. +// Copyright Gennaro Prota 2006. + +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// This program recurses through sub-directories looking for various problems. +// It contains some Boost specific features, like ignoring "bin", +// and the code that identifies library names assumes the Boost directory +// structure. + +// See http://www.boost.org/tools/inspect/ for more information. + +const char* boost_no_inspect = "boost-" "no-inspect"; + +// Directories with a file name of the boost_no_inspect value are not inspected. +// Files that contain the boost_no_inspect value are not inspected. + + +#include <vector> +#include <list> +#include <algorithm> +#include <cstring> + +#include "boost/shared_ptr.hpp" +#include "boost/lexical_cast.hpp" +#include "boost/filesystem/operations.hpp" +#include "boost/filesystem/fstream.hpp" + +#include <stdio.h> // for popen, pclose +#if defined(_MSC_VER) +# define POPEN _popen +# define PCLOSE _pclose +#else +# define POPEN popen +# define PCLOSE pclose +#endif + +#include "time_string.hpp" + +#include "inspector.hpp" + +// the inspectors +#include "copyright_check.hpp" +#include "crlf_check.hpp" +#include "end_check.hpp" +#include "license_check.hpp" +#include "link_check.hpp" +#include "path_name_check.hpp" +#include "tab_check.hpp" +#include "ascii_check.hpp" +#include "apple_macro_check.hpp" +#include "assert_macro_check.hpp" +#include "deprecated_macro_check.hpp" +#include "minmax_check.hpp" +#include "unnamed_namespace_check.hpp" + +#if !defined(INSPECT_USE_BOOST_TEST) +#define INSPECT_USE_BOOST_TEST 0 +#endif + +#if INSPECT_USE_BOOST_TEST +#include "boost/test/included/prg_exec_monitor.hpp" +#endif + +namespace fs = boost::filesystem; + +using namespace boost::inspect; + +namespace +{ + fs::path search_root = fs::initial_path(); + + class inspector_element + { + typedef boost::shared_ptr< boost::inspect::inspector > inspector_ptr; + + public: + inspector_ptr inspector; + explicit + inspector_element( boost::inspect::inspector * p ) : inspector(p) {} + }; + + typedef std::list< inspector_element > inspector_list; + + long file_count = 0; + long directory_count = 0; + long error_count = 0; + const int max_offenders = 5; // maximum "worst offenders" to display + + boost::inspect::string_set content_signatures; + + struct error_msg + { + string library; + string rel_path; + string msg; + int line_number; + + bool operator<( const error_msg & rhs ) const + { + if ( library < rhs.library ) return true; + if ( library > rhs.library ) return false; + if ( rel_path < rhs.rel_path ) return true; + if ( rel_path > rhs.rel_path ) return false; + if ( line_number < rhs.line_number ) return true; + if ( line_number > rhs.line_number ) return false; + return msg < rhs.msg; + } + }; + + typedef std::vector< error_msg > error_msg_vector; + error_msg_vector msgs; + + struct lib_error_count + { + int error_count; + string library; + + bool operator<( const lib_error_count & rhs ) const + { + return error_count > rhs.error_count; + } + }; + + typedef std::vector< lib_error_count > lib_error_count_vector; + lib_error_count_vector libs; + +// visit_predicate (determines which directories are visited) --------------// + + typedef bool(*pred_type)(const path&); + + bool visit_predicate( const path & pth ) + { + string local( boost::inspect::relative_to( pth, search_root_path() ) ); + string leaf( pth.leaf().string() ); + if (leaf[0] == '.') // ignore hidden by convention directories such as + return false; // .htaccess, .git, .svn, .bzr, .DS_Store, etc. + + return + // don't look at binaries + leaf != "bin" + && leaf != "bin.v2" + // no point in checking doxygen xml output + && local.find("doc/xml") != 0 + && local.find("doc\\xml") != 0 + // ignore if tag file present + && !boost::filesystem::exists(pth / boost_no_inspect) + ; + } + +// library_from_content ----------------------------------------------------// + + string library_from_content( const string & content ) + { + const string unknown_library ( "unknown" ); + const string lib_root ( "www.boost.org/libs/" ); + string::size_type pos( content.find( lib_root ) ); + + string lib = unknown_library; + + if ( pos != string::npos ) { + + pos += lib_root.length(); + + const char delims[] = " " // space and... + "/\n\r\t"; + + string::size_type n = content.find_first_of( string(delims), pos ); + if (n != string::npos) + lib = string(content, pos, n - pos); + + } + + return lib; + } + +// find_signature ----------------------------------------------------------// + + bool find_signature( const path & file_path, + const boost::inspect::string_set & signatures ) + { + string name( file_path.leaf().string() ); + if ( signatures.find( name ) == signatures.end() ) + { + string::size_type pos( name.rfind( '.' ) ); + if ( pos == string::npos + || signatures.find( name.substr( pos ) ) + == signatures.end() ) return false; + } + return true; + } + +// load_content ------------------------------------------------------------// + + void load_content( const path & file_path, string & target ) + { + target = ""; + + if ( !find_signature( file_path, content_signatures ) ) return; + + fs::ifstream fin( file_path, std::ios_base::in|std::ios_base::binary ); + if ( !fin ) + throw string( "could not open input file: " ) + file_path.string(); + std::getline( fin, target, '\0' ); // read the whole file + } + +// check -------------------------------------------------------------------// + + void check( const string & lib, + const path & pth, const string & content, const inspector_list & insp_list ) + { + // invoke each inspector + for ( inspector_list::const_iterator itr = insp_list.begin(); + itr != insp_list.end(); ++itr ) + { + itr->inspector->inspect( lib, pth ); // always call two-argument form + if ( find_signature( pth, itr->inspector->signatures() ) ) + { + itr->inspector->inspect( lib, pth, content ); + } + } + } + +// visit_all ---------------------------------------------------------------// + + template< class DirectoryIterator > + void visit_all( const string & lib, + const path & dir_path, const inspector_list & insps ) + { + static DirectoryIterator end_itr; + ++directory_count; + + for ( DirectoryIterator itr( dir_path ); itr != end_itr; ++itr ) + { + if ( fs::is_directory( *itr ) ) + { + if ( visit_predicate( *itr ) ) + { + string cur_lib( boost::inspect::impute_library( *itr ) ); + check( cur_lib, *itr, "", insps ); + visit_all<DirectoryIterator>( cur_lib, *itr, insps ); + } + } + else if (itr->path().leaf().string()[0] != '.') // ignore if hidden + { + ++file_count; + string content; + load_content( *itr, content ); + if (content.find(boost_no_inspect) == string::npos) + check( lib.empty() ? library_from_content( content ) : lib, + *itr, content, insps ); + } + } + } + +// display -----------------------------------------------------------------// + + enum display_format_type + { + display_html, display_text + } + display_format = display_html; + + enum display_mode_type + { + display_full, display_brief + } + display_mode = display_full; + +// display_summary_helper --------------------------------------------------// + + void display_summary_helper( const string & current_library, int err_count ) + { + if (display_format == display_text) + { + std::cout << " " << current_library << " (" << err_count << ")\n"; + } + else + { + std::cout + << " <a href=\"#" + << current_library // what about malformed for URI refs? [gps] + << "\">" << current_library + << "</a> (" + << err_count << ")<br>\n"; + } + } + +// display_summary ---------------------------------------------------------// + + void display_summary() + { + if (display_format == display_text) + { + std::cout << "Summary:\n"; + } + else + { + std::cout << + "<h2>Summary</h2>\n" + "<blockquote>\n" + ; + } + + string current_library( msgs.begin()->library ); + int err_count = 0; + for ( error_msg_vector::iterator itr ( msgs.begin() ); + itr != msgs.end(); ++itr ) + { + if ( current_library != itr->library ) + { + display_summary_helper( current_library, err_count ); + current_library = itr->library; + err_count = 0; + } + ++err_count; + } + display_summary_helper( current_library, err_count ); + + if (display_format == display_text) + std::cout << "\n"; + else + std::cout << "</blockquote>\n"; + } + +// html_encode -------------------------------------------------------------// + + std::string html_encode(std::string const& text) + { + std::string result; + + for(std::string::const_iterator it = text.begin(), + end = text.end(); it != end; ++it) + { + switch(*it) { + case '<': + result += "<"; + break; + case '>': + result += ">"; + break; + case '&': + result += "&"; + break; + default: + result += *it; + } + } + + return result; + } + +// display_details ---------------------------------------------------------// + + void display_details() + { + if (display_format == display_text) + { + // display error messages with group indication + error_msg current; + string sep; + for ( error_msg_vector::iterator itr ( msgs.begin() ); + itr != msgs.end(); ++itr ) + { + if ( current.library != itr->library ) + { + if ( display_full == display_mode ) + std::cout << "\n|" << itr->library << "|\n"; + else + std::cout << "\n\n|" << itr->library << '|'; + } + + if ( current.library != itr->library + || current.rel_path != itr->rel_path ) + { + if ( display_full == display_mode ) + { + std::cout << " " << itr->rel_path << ":\n"; + } + else + { + path current_rel_path(current.rel_path); + path this_rel_path(itr->rel_path); + if (current_rel_path.branch_path() != this_rel_path.branch_path()) + { + std::cout << "\n " << this_rel_path.branch_path().string() << '/'; + } + std::cout << "\n " << this_rel_path.leaf() << ':'; + } + } + if ( current.library != itr->library + || current.rel_path != itr->rel_path + || current.msg != itr->msg ) + { + const string m = itr->msg; + + if ( display_full == display_mode ) + std::cout << " " << m << '\n'; + else + std::cout << ' ' << m; + } + current.library = itr->library; + current.rel_path = itr->rel_path; + current.msg = itr->msg; + } + std::cout << "\n"; + } + else // html + { + // display error messages with group indication + error_msg current; + bool first_sep = true; + bool first = true; + for ( error_msg_vector::iterator itr ( msgs.begin() ); + itr != msgs.end(); ++itr ) + { + if ( current.library != itr->library ) + { + if ( !first ) std::cout << "</pre>\n"; + std::cout << "\n<h3><a name=\"" << itr->library + << "\">" << itr->library << "</a></h3>\n<pre>"; + } + if ( current.library != itr->library + || current.rel_path != itr->rel_path ) + { + std::cout << "\n"; + std::cout << itr->rel_path; + first_sep = true; + } + if ( current.library != itr->library + || current.rel_path != itr->rel_path + || current.msg != itr->msg ) + { + std::string sep; + if (first_sep) + if (itr->line_number) sep = ":<br> "; + else sep = ": "; + else + if (itr->line_number) sep = "<br> "; + else sep = ", "; + + // print the message + if (itr->line_number) + std::cout << sep << "(line " << itr->line_number << ") " << html_encode(itr->msg); + else std::cout << sep << html_encode(itr->msg); + + first_sep = false; + } + current.library = itr->library; + current.rel_path = itr->rel_path; + current.msg = itr->msg; + first = false; + } + std::cout << "</pre>\n"; + } + } + + +// worst_offenders_count_helper --------------------------------------------------// + + void worst_offenders_count_helper( const string & current_library, int err_count ) + { + lib_error_count lec; + lec.library = current_library; + lec.error_count = err_count; + libs.push_back( lec ); + } +// worst_offenders_count -----------------------------------------------------// + + void worst_offenders_count() + { + if ( msgs.empty() ) + { + return; + } + string current_library( msgs.begin()->library ); + int err_count = 0; + for ( error_msg_vector::iterator itr ( msgs.begin() ); + itr != msgs.end(); ++itr ) + { + if ( current_library != itr->library ) + { + worst_offenders_count_helper( current_library, err_count ); + current_library = itr->library; + err_count = 0; + } + ++err_count; + } + worst_offenders_count_helper( current_library, err_count ); + } + +// display_worst_offenders -------------------------------------------------// + + void display_worst_offenders() + { + if (display_mode == display_brief) + return; + if (display_format == display_text) + { + std::cout << "Worst Offenders:\n"; + } + else + { + std::cout << + "<h2>Worst Offenders</h2>\n" + "<blockquote>\n" + ; + } + + int display_count = 0; + int last_error_count = 0; + for ( lib_error_count_vector::iterator itr ( libs.begin() ); + itr != libs.end() + && (display_count < max_offenders + || itr->error_count == last_error_count); + ++itr, ++display_count ) + { + if (display_format == display_text) + { + std::cout << itr->library << " " << itr->error_count << "\n"; + } + else + { + std::cout + << " <a href=\"#" + << itr->library + << "\">" << itr->library + << "</a> (" + << itr->error_count << ")<br>\n"; + } + last_error_count = itr->error_count; + } + + if (display_format == display_text) + std::cout << "\n"; + else + std::cout << "</blockquote>\n"; + } + + + const char * options() + { + return + " Output Options:\n\n" + " -brief\n" + " -text\n" + " -version-string <version message>\n" + "\n" + " Checks:\n\n" + " -license\n" + " -copyright\n" + " -crlf\n" + " -end\n" + " -link\n" + " -path_name\n" + " -tab\n" + " -ascii\n" + " -apple_macro\n" + " -assert_macro\n" + " -deprecated_macro\n" + " -minmax\n" + " -unnamed\n" + " -version-string <version message>\n" + " default is all checks on; otherwise options specify desired checks" + "\n"; + } + + const char * doctype_declaration() + { + return + "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n" + "\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">" + ; + } + + std::string validator_link(const std::string & text) + { + return + // with link to validation service + "<a href=\"http://validator.w3.org/check?uri=referer\">" + + text + + "</a>" + ; + } + +} // unnamed namespace + +namespace boost +{ + namespace inspect + { + +// line_break --------------------------------------------------------------// + + const char * line_break() + { + return display_format ? "\n" : "<br>\n"; + } + +// search_root_path --------------------------------------------------------// + + path search_root_path() + { + return search_root; + } + +// register_signature ------------------------------------------------------// + + void inspector::register_signature( const string & signature ) + { + m_signatures.insert( signature ); + content_signatures.insert( signature ); + } + +// error -------------------------------------------------------------------// + + void inspector::error( const string & library_name, + const path & full_path, const string & msg, int line_number ) + { + ++error_count; + error_msg err_msg; + err_msg.library = library_name; + err_msg.rel_path = relative_to( full_path, search_root_path() ); + err_msg.msg = msg; + err_msg.line_number = line_number; + msgs.push_back( err_msg ); + +// std::cout << library_name << ": " +// << full_path.string() << ": " +// << msg << '\n'; + + } + + source_inspector::source_inspector() + { + // C/C++ source code... + register_signature( ".c" ); + register_signature( ".cpp" ); + register_signature( ".css" ); + register_signature( ".cxx" ); + register_signature( ".h" ); + register_signature( ".hpp" ); + register_signature( ".hxx" ); + register_signature( ".inc" ); + register_signature( ".ipp" ); + + // Boost.Build BJam source code... + register_signature( "Jamfile" ); + register_signature( ".jam" ); + register_signature( ".v2" ); + + // Other scripts; Python, shell, autoconfig, etc. + register_signature( "configure.in" ); + register_signature( "GNUmakefile" ); + register_signature( "Makefile" ); + register_signature( ".bat" ); + register_signature( ".mak" ); + register_signature( ".pl" ); + register_signature( ".py" ); + register_signature( ".sh" ); + + // Hypertext, Boost.Book, and other text... + register_signature( "news" ); + register_signature( "readme" ); + register_signature( "todo" ); + register_signature( "NEWS" ); + register_signature( "README" ); + register_signature( "TODO" ); + register_signature( ".boostbook" ); + register_signature( ".htm" ); + register_signature( ".html" ); + register_signature( ".rst" ); + register_signature( ".sgml" ); + register_signature( ".shtml" ); + register_signature( ".txt" ); + register_signature( ".xml" ); + register_signature( ".xsd" ); + register_signature( ".xsl" ); + register_signature( ".qbk" ); + } + + hypertext_inspector::hypertext_inspector() + { + register_signature( ".htm" ); + register_signature( ".html" ); + register_signature( ".shtml" ); + } + +// impute_library ----------------------------------------------------------// + + // may return an empty string [gps] + string impute_library( const path & full_dir_path ) + { + path relative( relative_to( full_dir_path, search_root_path() ) ); + if ( relative.empty() ) return "boost-root"; + string first( (*relative.begin()).string() ); + string second = // borland 5.61 requires op= + ++relative.begin() == relative.end() + ? string() : (*++relative.begin()).string(); + + if ( first == "boost" ) + return second; + + return (( first == "libs" || first == "tools" ) && !second.empty()) + ? second : first; + } + + } // namespace inspect +} // namespace boost + +// cpp_main() --------------------------------------------------------------// + +#if !INSPECT_USE_BOOST_TEST +int main( int argc_param, char * argv_param[] ) +#else +int cpp_main( int argc_param, char * argv_param[] ) +#endif +{ + // <hack> for the moment, let's be on the safe side + // and ensure we don't modify anything being pointed to; + // then we'll do some cleanup here + int argc = argc_param; + const char* const * argv = &argv_param[0]; + + if ( argc > 1 && (std::strcmp( argv[1], "-help" ) == 0 + || std::strcmp( argv[1], "--help" ) == 0 ) ) + { + std::clog << "Usage: inspect [search-root] [options...]\n\n" + " search-root default is the current directory (i.e. '.')\n\n" + << options() << '\n'; + return 0; + } + + bool options_not_set = true; + bool license_ck = false; + bool copyright_ck = false; + bool crlf_ck = false; + bool end_ck = false; + bool link_ck = false; + bool path_name_ck = false; + bool tab_ck = false; + bool ascii_ck = false; + bool apple_ck = false; + bool assert_ck = false; + bool deprecated_ck = false; + bool minmax_ck = false; + bool unnamed_ck = false; + const char* version_string = 0; + + if ( argc > 1 && *argv[1] != '-' ) + { + search_root = fs::canonical(fs::absolute(argv[1], fs::initial_path())); + --argc; ++argv; + } + + bool invalid_options = false; + for(; argc > 1; --argc, ++argv ) + { + if ( std::strcmp( argv[1], "-license" ) == 0 ) { + options_not_set = false; + license_ck = true; + } + else if ( std::strcmp( argv[1], "-copyright" ) == 0 ) { + options_not_set = false; + copyright_ck = true; + } + else if ( std::strcmp( argv[1], "-crlf" ) == 0 ) { + options_not_set = false; + crlf_ck = true; + } + else if ( std::strcmp( argv[1], "-end" ) == 0 ) { + options_not_set = false; + end_ck = true; + } + else if ( std::strcmp( argv[1], "-link" ) == 0 ) { + options_not_set = false; + link_ck = true; + } + else if ( std::strcmp( argv[1], "-path_name" ) == 0 ) { + options_not_set = false; + path_name_ck = true; + } + else if ( std::strcmp( argv[1], "-tab" ) == 0 ) { + options_not_set = false; + tab_ck = true; + } + else if ( std::strcmp( argv[1], "-ascii" ) == 0 ) { + options_not_set = false; + ascii_ck = true; + } + else if ( std::strcmp( argv[1], "-apple_macro" ) == 0 ) { + options_not_set = false; + apple_ck = true; + } + else if ( std::strcmp( argv[1], "-assert_macro" ) == 0 ) { + options_not_set = false; + assert_ck = true; + } + else if ( std::strcmp( argv[1], "-deprecated_macro" ) == 0 ) { + options_not_set = false; + deprecated_ck = true; + } + else if ( std::strcmp( argv[1], "-minmax" ) == 0 ) { + options_not_set = false; + minmax_ck = true; + } + else if ( std::strcmp( argv[1], "-unnamed" ) == 0 ) { + options_not_set = false; + unnamed_ck = true; + } + else if ( argc > 1 && std::strcmp( argv[1], "-text" ) == 0 ) + { + display_format = display_text; + } + else if ( argc > 1 && std::strcmp( argv[1], "-brief" ) == 0 ) + { + display_mode = display_brief; + } + else if ( std::strcmp( argv[1], "-version-string" ) == 0 ) { + if (argc == 2 || argv[2][0] == '-') { + std::cerr << "Missing value for -version-string.\n"; + invalid_options = true; + } + else { + --argc, ++argv; + version_string = argv[1]; + } + } + else + { + std::cerr << "unknown option: " << argv[1] << '\n'; + invalid_options = true; + } + } + if ( invalid_options ) { + std::cerr << "\nvalid options are:\n" + << options(); + return 1; + } + + if (options_not_set) { + license_ck = true; + copyright_ck = true; + crlf_ck = true; + end_ck = true; + link_ck = true; + path_name_ck = true; + tab_ck = true; + ascii_ck = true; + apple_ck = true; + assert_ck = true; + deprecated_ck = true; + minmax_ck = true; + unnamed_ck = true; + } + + string inspector_keys; + + { // begin reporting block + + // since this is in its own block; reporting will happen + // automatically, from each registered inspector, when + // leaving, due to destruction of the inspector_list object + inspector_list inspectors; + + if ( license_ck ) + inspectors.push_back( inspector_element( new boost::inspect::license_check ) ); + if ( copyright_ck ) + inspectors.push_back( inspector_element( new boost::inspect::copyright_check ) ); + if ( crlf_ck ) + inspectors.push_back( inspector_element( new boost::inspect::crlf_check ) ); + if ( end_ck ) + inspectors.push_back( inspector_element( new boost::inspect::end_check ) ); + if ( link_ck ) + inspectors.push_back( inspector_element( new boost::inspect::link_check ) ); + if ( path_name_ck ) + inspectors.push_back( inspector_element( new boost::inspect::file_name_check ) ); + if ( tab_ck ) + inspectors.push_back( inspector_element( new boost::inspect::tab_check ) ); + if ( ascii_ck ) + inspectors.push_back( inspector_element( new boost::inspect::ascii_check ) ); + if ( apple_ck ) + inspectors.push_back( inspector_element( new boost::inspect::apple_macro_check ) ); + if ( assert_ck ) + inspectors.push_back( inspector_element( new boost::inspect::assert_macro_check ) ); + if ( deprecated_ck ) + inspectors.push_back( inspector_element( new boost::inspect::deprecated_macro_check ) ); + if ( minmax_ck ) + inspectors.push_back( inspector_element( new boost::inspect::minmax_check ) ); + if ( unnamed_ck ) + inspectors.push_back( inspector_element( new boost::inspect::unnamed_namespace_check ) ); + + visit_all<fs::directory_iterator>( search_root.leaf().string(), + search_root, inspectors ); + + // close + for ( inspector_list::iterator itr = inspectors.begin(); + itr != inspectors.end(); ++itr ) + { + itr->inspector->close(); + } + + string run_date ( "n/a" ); + boost::time_string( run_date ); + + if (display_format == display_text) + { + std::cout + << + "Boost Inspection Report\n" + "Run Date: " << run_date << "\n" + "\n" + ; + + if (version_string) { + std::cout + << "The files checked were from " + << version_string + << ".\n\n"; + } + + std::cout + << "Totals:\n" + << " " << file_count << " files scanned\n" + << " " << directory_count << " directories scanned (including root)\n" + << " " << error_count << " problems reported\n" + << '\n' + ; + } + else + { + // + std::cout << doctype_declaration() << '\n'; + + std::cout + << "<html>\n" + "<head>\n" + "<style> body { font-family: sans-serif; } </style>\n" + "<title>Boost Inspection Report</title>\n" + "</head>\n" + + "<body>\n" + // we should not use a table, of course [gps] + "<table>\n" + "<tr>\n" + "<td><img src=\"http://www.boost.org/boost.png\" alt=\"Boost logo\" />" + "</td>\n" + "<td>\n" + "<h1>Boost Inspection Report</h1>\n" + "<b>Run Date:</b> " << run_date << "\n" + //" / " << validator_link( "validate me" ) << " /\n" + "</td>\n" + "</tr>\n" + "</table>\n" + + "<p>This report is generated by an <a href=\"http://www.boost.org/tools/inspect/index.html\">inspection\n" + "program</a> that checks files for the problems noted below.</p>\n" + ; + if (version_string) { + std::cout + << "<p>The files checked were from " + << html_encode(version_string) + << ".</p>\n"; + } + + + std::cout + << "<h2>Totals</h2>\n" + << file_count << " files scanned<br>\n" + << directory_count << " directories scanned (including root)<br>\n" + << error_count << " problems reported\n<p>"; + } + + for ( inspector_list::iterator itr = inspectors.begin(); + itr != inspectors.end(); ++itr ) + { + + inspector_keys += static_cast<string>(" ") + + itr->inspector->name() + + ' ' + itr->inspector->desc() + + line_break() + ; + } + + if (display_format == display_text) + std::cout << "\nProblem counts:\n"; + else + std::cout << "\n<h2>Problem counts</h2>\n<blockquote><p>\n" ; + + } // end of block: starts reporting + + if (display_format == display_text) + std::cout << "\n" ; + else + std::cout << "</blockquote>\n"; + + std::sort( msgs.begin(), msgs.end() ); + + worst_offenders_count(); + std::stable_sort( libs.begin(), libs.end() ); + + if ( !libs.empty() && display_mode != display_brief) + display_worst_offenders(); + + if ( !msgs.empty() ) + { + display_summary(); + + if (display_format == display_text) + { + std::cout << "Details:\n" << inspector_keys; + std::cout << "\nDirectories with a file named \"" << boost_no_inspect << "\" will not be inspected.\n" + "Files containing \"" << boost_no_inspect << "\" will not be inspected.\n"; + } + else + { + std::cout << "<h2>Details</h2>\n" << inspector_keys; + std::cout << "\n<p>Directories with a file named \"" << boost_no_inspect << "\" will not be inspected.<br>\n" + "Files containing \"" << boost_no_inspect << "\" will not be inspected.</p>\n"; + } + display_details(); + } + + if (display_format == display_text) + { + std::cout << "\n\n" ; + } + else + { + std::cout + << "</body>\n" + "</html>\n"; + } + + return error_count ? 1 : 0; +} diff --git a/src/boost/tools/inspect/inspector.hpp b/src/boost/tools/inspect/inspector.hpp new file mode 100644 index 000000000..408a4f868 --- /dev/null +++ b/src/boost/tools/inspect/inspector.hpp @@ -0,0 +1,108 @@ +// inspector header --------------------------------------------------------// + +// Copyright Beman Dawes 2002. +// Copyright Rene Rivera 2004. +// Copyright Gennaro Prota 2006. +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_INSPECTOR_HPP +#define BOOST_INSPECTOR_HPP + +#include <set> +#include <iostream> +#include <ostream> +#include <string> +#include "boost/filesystem/path.hpp" + +using std::string; +using boost::filesystem::path; + +namespace boost +{ + namespace inspect + { + typedef std::set< string > string_set; + + const char * line_break(); + + path search_root_path(); + + class inspector + { + protected: + inspector() {} + + public: + virtual ~inspector() {} + + virtual const char * name() const = 0; // example: "tab-check" + virtual const char * desc() const = 0; // example: "verify no tabs" + + // always called: + virtual void inspect( + const string & /*library_name*/, // "filesystem" + const path & /*full_path*/ ) {} // "c:/foo/boost/filesystem/path.hpp" + + // called only for registered leaf() signatures: + virtual void inspect( + const string & library_name, // "filesystem" + const path & full_path, // "c:/foo/boost/filesystem/path.hpp" + const string & contents ) // contents of file + = 0 + ; + + // called after all paths visited, but still in time to call error(): + virtual void close() {} + + // callback used by constructor to register leaf() signature. + // Signature can be a full file name (Jamfile) or partial (.cpp) + void register_signature( const string & signature ); + const string_set & signatures() const { return m_signatures; } + + // report error callback (from inspect(), close() ): + void error( + const string & library_name, + const path & full_path, + const string & msg, + int line_number =0 ); // 0 if not available or not applicable + + private: + string_set m_signatures; + }; + + // for inspection of source code of one form or other + class source_inspector : public inspector + { + public: + // registers the basic set of known source signatures + source_inspector(); + }; + + // for inspection of hypertext, specifically html + class hypertext_inspector : public inspector + { + public: + // registers the set of known html source signatures + hypertext_inspector(); + }; + + inline string relative_to( const path & src_arg, const path & base_arg ) + { + path base( base_arg ); + base.normalize(); + string::size_type pos( base.string().size() ); + path src( src_arg.string().substr(pos) ); + src.normalize(); + return src.string().substr(1); + } + + string impute_library( const path & full_dir_path ); + + } +} + +#endif // BOOST_INSPECTOR_HPP + diff --git a/src/boost/tools/inspect/license_check.cpp b/src/boost/tools/inspect/license_check.cpp new file mode 100644 index 000000000..86d1d20e7 --- /dev/null +++ b/src/boost/tools/inspect/license_check.cpp @@ -0,0 +1,48 @@ +// license_check implementation --------------------------------------------// + +// Copyright Beman Dawes 2002-2003. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include "boost/regex.hpp" +#include "license_check.hpp" + +namespace +{ + boost::regex license_regex( + //~ The next two lines change the regex so that it detects when the license + //~ doesn't follow the prefered statement. Disabled because it currently + //~ generates a large number of issues. + //~ "Distributed[\\s\\W]+" + //~ "under[\\s\\W]+the[\\s\\W]+" + "boost[\\s\\W]+software[\\s\\W]+license", + boost::regbase::normal | boost::regbase::icase); + +} // unnamed namespace + +namespace boost +{ + namespace inspect + { + license_check::license_check() : m_files_with_errors(0) + { + } + + void license_check::inspect( + const string & library_name, + const path & full_path, // example: c:/foo/boost/filesystem/path.hpp + const string & contents ) // contents of file to be inspected + { + if (contents.find( "boostinspect:" "nolicense" ) != string::npos) return; + + if ( !boost::regex_search( contents, license_regex ) ) + { + ++m_files_with_errors; + error( library_name, full_path, name() ); + } + } + } // namespace inspect +} // namespace boost + + diff --git a/src/boost/tools/inspect/license_check.hpp b/src/boost/tools/inspect/license_check.hpp new file mode 100644 index 000000000..831202363 --- /dev/null +++ b/src/boost/tools/inspect/license_check.hpp @@ -0,0 +1,40 @@ +// license_check header ----------------------------------------------------// + +// Copyright Beman Dawes 2002, 2003. +// Copyright Rene Rivera 2004. +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_LICENSE_CHECK_HPP +#define BOOST_LICENSE_CHECK_HPP + +#include "inspector.hpp" + +namespace boost +{ + namespace inspect + { + class license_check : public source_inspector + { + long m_files_with_errors; + public: + + license_check(); + virtual const char * name() const { return "*Lic*"; } + virtual const char * desc() const { return "missing Boost license info, or wrong reference text"; } + + virtual void inspect( + const std::string & library_name, + const path & full_path, + const std::string & contents ); + + virtual ~license_check() + { std::cout << " " + << m_files_with_errors << " files missing Boost license info or having wrong reference text" << line_break(); } + }; + } +} + +#endif // BOOST_LICENSE_CHECK_HPP diff --git a/src/boost/tools/inspect/link_check.cpp b/src/boost/tools/inspect/link_check.cpp new file mode 100644 index 000000000..182af3bf7 --- /dev/null +++ b/src/boost/tools/inspect/link_check.cpp @@ -0,0 +1,487 @@ +// link_check implementation -----------------------------------------------// + +// Copyright Beman Dawes 2002. +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include "link_check.hpp" +#include "boost/regex.hpp" +#include "boost/filesystem/operations.hpp" +#include <boost/algorithm/string/case_conv.hpp> +#include <cstdlib> +#include <set> + +// #include <iostream> + +namespace fs = boost::filesystem; + +namespace +{ + boost::regex html_bookmark_regex( + "<([^\\s<>]*)\\s*[^<>]*\\s+(NAME|ID)\\s*=\\s*(['\"])(.*?)\\3" + "|<!--.*?-->", + boost::regbase::normal | boost::regbase::icase); + boost::regex html_url_regex( + "<([^\\s<>]*)\\s*[^<>]*\\s+(?:HREF|SRC)" // HREF or SRC + "\\s*=\\s*(['\"])\\s*(.*?)\\s*\\2" + "|<!--.*?-->", + boost::regbase::normal | boost::regbase::icase); + boost::regex css_url_regex( + "(\\@import\\s*[\"']|url\\s*\\(\\s*[\"']?)([^\"')]*)" + "|/\\*.*?\\*/", + boost::regbase::normal | boost::regbase::icase); + + // Regular expression for parsing URLS from: + // http://tools.ietf.org/html/rfc3986#appendix-B + boost::regex url_decompose_regex( + "^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\\?([^#]*))?(#(.*))?$", + boost::regbase::normal); + + typedef std::set<std::string> bookmark_set; + bookmark_set bookmarks; + bookmark_set bookmarks_lowercase; // duplicate check needs case insensitive + + // Decode html escapsed ampersands, returns an empty string if there's an error. + std::string decode_ampersands(std::string const& url_path) { + std::string::size_type pos = 0, next; + std::string result; + result.reserve(url_path.length()); + + while((next = url_path.find('&', pos)) != std::string::npos) { + result.append(url_path, pos, next - pos); + pos = next; + if(url_path.substr(pos, 5) == "&") { + result += '&'; pos += 5; + } + else { + result += '&'; pos += 1; + } + break; + } + + result.append(url_path, pos, url_path.length()); + + return result; + } + + // Decode percent encoded characters, returns an empty string if there's an error. + std::string decode_percents(std::string const& url_path) { + std::string::size_type pos = 0, next; + std::string result; + result.reserve(url_path.length()); + + while((next = url_path.find('%', pos)) != std::string::npos) { + result.append(url_path, pos, next - pos); + pos = next; + switch(url_path[pos]) { + case '%': { + if(url_path.length() - next < 3) return ""; + char hex[3] = { url_path[next + 1], url_path[next + 2], '\0' }; + char* end_ptr; + result += (char) std::strtol(hex, &end_ptr, 16); + if(*end_ptr) return ""; + pos = next + 3; + break; + } + } + } + + result.append(url_path, pos, url_path.length()); + + return result; + } + + bool is_css(const path & p) { + return p.extension() == ".css"; + } + +} // unnamed namespace + +namespace boost +{ + namespace inspect + { + +// link_check constructor --------------------------------------------------// + + link_check::link_check() + : m_broken_errors(0), m_unlinked_errors(0), m_invalid_errors(0), + m_bookmark_errors(0), m_duplicate_bookmark_errors(0) + { + // HTML signatures are already registered by the base class, + // 'hypertext_inspector' + register_signature(".css"); + } + +// inspect (all) -----------------------------------------------------------// + + void link_check::inspect( + const string & /*library_name*/, + const path & full_path ) + { + // keep track of paths already encountered to reduce disk activity + if ( !fs::is_directory( full_path ) ) + m_paths[ relative_to( full_path, search_root_path() ) ] |= m_present; + } + +// inspect ( .htm, .html, .shtml, .css ) -----------------------------------// + + void link_check::inspect( + const string & library_name, + const path & full_path, // example: c:/foo/boost/filesystem/path.hpp + const string & contents ) // contents of file to be inspected + { + if (contents.find( "boostinspect:" "nounlinked" ) != string::npos) + m_paths[ relative_to( full_path, search_root_path() ) ] |= m_nounlinked_errors; + + bool no_link_errors = + (contents.find( "boostinspect:" "nolink" ) != string::npos); + + // build bookmarks databases + bookmarks.clear(); + bookmarks_lowercase.clear(); + string::const_iterator a_start( contents.begin() ); + string::const_iterator a_end( contents.end() ); + boost::match_results< string::const_iterator > a_what; + boost::match_flag_type a_flags = boost::match_default; + + if(!is_css(full_path)) + { + string previous_id; + + while( boost::regex_search( a_start, a_end, a_what, html_bookmark_regex, a_flags) ) + { + // a_what[0] contains the whole string iterators. + // a_what[1] contains the tag iterators. + // a_what[2] contains the attribute name. + // a_what[4] contains the bookmark iterators. + + if (a_what[4].matched) + { + string tag( a_what[1].first, a_what[1].second ); + boost::algorithm::to_lower(tag); + string attribute( a_what[2].first, a_what[2].second ); + boost::algorithm::to_lower(attribute); + string bookmark( a_what[4].first, a_what[4].second ); + + bool name_following_id = ( attribute == "name" && previous_id == bookmark ); + if ( tag != "meta" && attribute == "id" ) previous_id = bookmark; + else previous_id.clear(); + + if ( tag != "meta" && !name_following_id ) + { + bookmarks.insert( bookmark ); +// std::cout << "******************* " << bookmark << '\n'; + + // w3.org recommends case-insensitive checking for duplicate bookmarks + // since some browsers do a case-insensitive match. + string bookmark_lowercase( bookmark ); + boost::algorithm::to_lower(bookmark_lowercase); + + std::pair<bookmark_set::iterator, bool> result + = bookmarks_lowercase.insert( bookmark_lowercase ); + if (!result.second) + { + ++m_duplicate_bookmark_errors; + int ln = std::count( contents.begin(), a_what[3].first, '\n' ) + 1; + error( library_name, full_path, "Duplicate bookmark: " + bookmark, ln ); + } + } + } + + a_start = a_what[0].second; // update search position + a_flags |= boost::match_prev_avail; // update flags + a_flags |= boost::match_not_bob; + } + } + + // process urls + string::const_iterator start( contents.begin() ); + string::const_iterator end( contents.end() ); + boost::match_results< string::const_iterator > what; + boost::match_flag_type flags = boost::match_default; + + if(!is_css(full_path)) + { + while( boost::regex_search( start, end, what, html_url_regex, flags) ) + { + // what[0] contains the whole string iterators. + // what[1] contains the element type iterators. + // what[3] contains the URL iterators. + + if(what[3].matched) + { + string type( what[1].first, what[1].second ); + boost::algorithm::to_lower(type); + + // TODO: Complain if 'link' tags use external stylesheets. + do_url( string( what[3].first, what[3].second ), + library_name, full_path, no_link_errors, + type == "a" || type == "link", contents.begin(), what[3].first ); + } + + start = what[0].second; // update search position + flags |= boost::match_prev_avail; // update flags + flags |= boost::match_not_bob; + } + } + + while( boost::regex_search( start, end, what, css_url_regex, flags) ) + { + // what[0] contains the whole string iterators. + // what[2] contains the URL iterators. + + if(what[2].matched) + { + do_url( string( what[2].first, what[2].second ), + library_name, full_path, no_link_errors, false, + contents.begin(), what[3].first ); + } + + start = what[0].second; // update search position + flags |= boost::match_prev_avail; // update flags + flags |= boost::match_not_bob; + } + } + +// do_url ------------------------------------------------------------------// + + void link_check::do_url( const string & url, const string & library_name, + const path & source_path, bool no_link_errors, bool allow_external_content, + std::string::const_iterator contents_begin, std::string::const_iterator url_start ) + // precondition: source_path.is_complete() + { + if(!no_link_errors && url.empty()) { + ++m_invalid_errors; + int ln = std::count( contents_begin, url_start, '\n' ) + 1; + error( library_name, source_path, "Empty URL.", ln ); + return; + } + + // Decode ampersand encoded characters. + string decoded_url = is_css(source_path) ? url : decode_ampersands(url); + if(decoded_url.empty()) { + if(!no_link_errors) { + ++m_invalid_errors; + int ln = std::count( contents_begin, url_start, '\n' ) + 1; + error( library_name, source_path, + "Invalid URL (invalid ampersand encodings): " + url, ln ); + } + return; + } + + boost::smatch m; + if(!boost::regex_match(decoded_url, m, url_decompose_regex)) { + if(!no_link_errors) { + ++m_invalid_errors; + int ln = std::count( contents_begin, url_start, '\n' ) + 1; + error( library_name, source_path, "Invalid URL: " + decoded_url, ln ); + } + return; + } + + bool scheme_matched = m[2].matched, + authority_matched = m[4].matched, + //query_matched = m[7].matched, + fragment_matched = m[9].matched; + + std::string scheme(m[2]), + authority(m[4]), + url_path(m[5]), + //query(m[7]), + fragment(m[9]); + + // Check for external content + if(!allow_external_content && (authority_matched || scheme_matched)) { + if(!no_link_errors) { + ++m_invalid_errors; + int ln = std::count( contents_begin, url_start, '\n' ) + 1; + error( library_name, source_path, "External content: " + decoded_url, ln ); + } + } + + // Protocol checks + if(scheme_matched) { + if(scheme == "http" || scheme == "https") { + // All http links should have a hostname. Generally if they don't + // it's by mistake. If they shouldn't, then a protocol isn't + // required. + if(!authority_matched) { + if(!no_link_errors) { + ++m_invalid_errors; + int ln = std::count( contents_begin, url_start, '\n' ) + 1; + error( library_name, source_path, "No hostname: " + decoded_url, ln ); + } + } + + return; + } + else if(scheme == "file") { + if(!no_link_errors) { + ++m_invalid_errors; + int ln = std::count( contents_begin, url_start, '\n' ) + 1; + error( library_name, source_path, + "Invalid URL (hardwired file): " + decoded_url, ln ); + } + } + else if(scheme == "mailto" || scheme == "ftp" || scheme == "news" || scheme == "javascript") { + if ( !no_link_errors && is_css(source_path) ) { + ++m_invalid_errors; + int ln = std::count( contents_begin, url_start, '\n' ) + 1; + error( library_name, source_path, + "Invalid protocol for css: " + decoded_url, ln ); + } + } + else { + if(!no_link_errors) { + ++m_invalid_errors; + int ln = std::count( contents_begin, url_start, '\n' ) + 1; + error( library_name, source_path, "Unknown protocol: '" + scheme + "' in url: " + decoded_url, ln ); + } + } + + return; + } + + // Hostname without protocol. + if(authority_matched) { + if(!no_link_errors) { + ++m_invalid_errors; + int ln = std::count( contents_begin, url_start, '\n' ) + 1; + error( library_name, source_path, + "Invalid URL (hostname without protocol): " + decoded_url, ln ); + } + } + + // Check the fragment identifier + if ( fragment_matched ) { + if ( is_css(source_path) ) { + if ( !no_link_errors ) { + ++m_invalid_errors; + int ln = std::count( contents_begin, url_start, '\n' ) + 1; + error( library_name, source_path, + "Fragment link in CSS: " + decoded_url, ln ); + } + } + else { + if ( !no_link_errors && fragment.find( '#' ) != string::npos ) + { + ++m_bookmark_errors; + int ln = std::count( contents_begin, url_start, '\n' ) + 1; + error( library_name, source_path, "Invalid bookmark: " + decoded_url, ln ); + } + else if ( !no_link_errors && url_path.empty() && !fragment.empty() + // w3.org recommends case-sensitive broken bookmark checking + // since some browsers do a case-sensitive match. + && bookmarks.find(decode_percents(fragment)) == bookmarks.end() ) + { + ++m_broken_errors; + int ln = std::count( contents_begin, url_start, '\n' ) + 1; + error( library_name, source_path, "Unknown bookmark: " + decoded_url, ln ); + } + } + + // No more to do if it's just a fragment identifier + if(url_path.empty()) return; + } + + // Detect characters banned by RFC2396: + if ( !no_link_errors && decoded_url.find_first_of( " <>\"{}|\\^[]'" ) != string::npos ) + { + ++m_invalid_errors; + int ln = std::count( contents_begin, url_start, '\n' ) + 1; + error( library_name, source_path, + "Invalid character in URL: " + decoded_url, ln ); + } + + // Check that we actually have a path. + if(url_path.empty()) { + if(!no_link_errors) { + ++m_invalid_errors; + int ln = std::count( contents_begin, url_start, '\n' ) + 1; + error( library_name, source_path, + "Invalid URL (empty path in relative url): " + decoded_url, ln ); + } + } + + // Decode percent encoded characters. + string decoded_path = decode_percents(url_path); + if(decoded_path.empty()) { + if(!no_link_errors) { + ++m_invalid_errors; + int ln = std::count( contents_begin, url_start, '\n' ) + 1; + error( library_name, source_path, + "Invalid URL (invalid character encodings): " + decoded_url, ln ); + } + return; + } + + // strip url of references to current dir + if ( decoded_path[0]=='.' && decoded_path[1]=='/' ) decoded_path.erase( 0, 2 ); + + // url is relative source_path.branch() + // convert to target_path, which is_complete() + path target_path; + try { target_path = source_path.branch_path() /= path( decoded_path ); } + catch ( const fs::filesystem_error & ) + { + if(!no_link_errors) { + int ln = std::count( contents_begin, url_start, '\n' ) + 1; + ++m_invalid_errors; + error( library_name, source_path, + "Invalid URL (error resolving path): " + decoded_url, ln ); + } + return; + } + + // create a m_paths entry if necessary + std::pair< const string, int > entry( + relative_to( target_path, search_root_path() ), 0 ); + m_path_map::iterator itr( m_paths.find( entry.first ) ); + if ( itr == m_paths.end() ) + { + if ( fs::exists( target_path ) ) entry.second = m_present; + itr = m_paths.insert( entry ).first; + } + + // itr now points to the m_paths entry + itr->second |= m_linked_to; + + // if target isn't present, the link is broken + if ( !no_link_errors && (itr->second & m_present) == 0 ) + { + ++m_broken_errors; + int ln = std::count( contents_begin, url_start, '\n' ) + 1; + error( library_name, source_path, "Broken link: " + decoded_url, ln ); + } + } + +// close -------------------------------------------------------------------// + + void link_check::close() + { + for ( m_path_map::const_iterator itr = m_paths.begin(); + itr != m_paths.end(); ++itr ) + { +// std::clog << itr->first << " " << itr->second << "\n"; + if ( (itr->second & m_linked_to) != m_linked_to + && (itr->second & m_nounlinked_errors) != m_nounlinked_errors + && (itr->first.rfind( ".html" ) == itr->first.size()-5 + || itr->first.rfind( ".htm" ) == itr->first.size()-4 + || itr->first.rfind( ".css" ) == itr->first.size()-4) + // because they may be redirectors, it is OK if these are unlinked: + && itr->first.rfind( "index.html" ) == string::npos + && itr->first.rfind( "index.htm" ) == string::npos ) + { + ++m_unlinked_errors; + path full_path( search_root_path() / path(itr->first) ); + error( impute_library( full_path ), full_path, "Unlinked file" ); + } + } + } + + } // namespace inspect +} // namespace boost + diff --git a/src/boost/tools/inspect/link_check.hpp b/src/boost/tools/inspect/link_check.hpp new file mode 100644 index 000000000..726cd91f4 --- /dev/null +++ b/src/boost/tools/inspect/link_check.hpp @@ -0,0 +1,72 @@ +// link_check header -------------------------------------------------------// + +// Copyright Beman Dawes 2002 +// Copyright Rene Rivera 2004. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_LINK_CHECK_HPP +#define BOOST_LINK_CHECK_HPP + +#include <map> + +#include "inspector.hpp" + +namespace boost +{ + namespace inspect + { + const int m_linked_to = 1; + const int m_present = 2; + const int m_nounlinked_errors = 4; + + class link_check : public hypertext_inspector + { + long m_broken_errors; + long m_unlinked_errors; + long m_invalid_errors; + long m_bookmark_errors; + long m_duplicate_bookmark_errors; + + typedef std::map< string, int > m_path_map; + m_path_map m_paths; // first() is relative to search_root_path() + + void do_url( const string & url, const string & library_name, + const path & full_source_path, bool no_link_errors, + bool allow_external_links, + std::string::const_iterator contents_begin, std::string::const_iterator url_start); + public: + + link_check(); + virtual const char * name() const { return "*LINK*"; } + virtual const char * desc() const + { return "invalid bookmarks, duplicate bookmarks," + " invalid urls, broken links, unlinked files"; } + + virtual void inspect( + const std::string & library_name, + const path & full_path ); + + virtual void inspect( + const std::string & library_name, + const path & full_path, + const std::string & contents ); + + virtual void close(); + + virtual ~link_check() + { + std::cout << " " << m_bookmark_errors + << " bookmarks with invalid characters" << line_break(); + std::cout << " " << m_duplicate_bookmark_errors + << " duplicate bookmarks" << line_break(); + std::cout << " " << m_invalid_errors << " invalid urls" << line_break(); + std::cout << " " << m_broken_errors << " broken links" << line_break(); + std::cout << " " << m_unlinked_errors << " unlinked files" << line_break(); + } + }; + } +} + +#endif // BOOST_LINK_CHECK_HPP diff --git a/src/boost/tools/inspect/link_check_test.html b/src/boost/tools/inspect/link_check_test.html new file mode 100644 index 000000000..2d1e9845e --- /dev/null +++ b/src/boost/tools/inspect/link_check_test.html @@ -0,0 +1,24 @@ +<html> + +<head> +<meta http-equiv="Content-Language" content="en-us"> +<meta name="GENERATOR" content="Microsoft FrontPage 5.0"> +<meta name="ProgId" content="FrontPage.Editor.Document"> +<meta http-equiv="Content-Type" content="text/html; charset=windows-1252"> +<title>valid link</title> +</head> + +<body> + +<p><a href="#link-target">valid bookmark link</a></p> +<p><a href="link_check_test.html">valid relative link</a></p> +<p><a href="foo.html#bar">broken relative link with bookmark</a></p> +<p><a href="#broken">broken bookmark link</a></p> +<p><a name="link-target">bookmark</a></p> +<p><a name="second-target">second bookmark</a></p> +<p><a name="SECOND-TARGET">duplicate second bookmark</a></p> +<p> </p> + +</body> + +</html>
\ No newline at end of file diff --git a/src/boost/tools/inspect/minmax_check.cpp b/src/boost/tools/inspect/minmax_check.cpp new file mode 100644 index 000000000..00cc44bca --- /dev/null +++ b/src/boost/tools/inspect/minmax_check.cpp @@ -0,0 +1,102 @@ +// minmax_check implementation --------------------------------------------// + +// Copyright Beman Dawes 2002. +// Copyright Gennaro Prota 2006. +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + + +#include <algorithm> + +#include "minmax_check.hpp" +#include "boost/regex.hpp" +#include "boost/lexical_cast.hpp" + +namespace +{ + boost::regex minmax_regex( + "(" + "^\\s*#\\s*undef\\s*" // # undef + "\\b(min|max)\\b" // followed by min or max, whole word + ")" + "|" // or (ignored) + "(" + "//[^\\n]*" // single line comments (//) + "|" + "/\\*.*?\\*/" // multi line comments (/**/) + "|" + "\"(?:\\\\\\\\|\\\\\"|[^\"])*\"" // string literals + ")" + "|" // or + "(" + "\\b(min|max)\\b" // min or max, whole word + "\\s*\\(" // followed by 0 or more spaces and an opening paren + ")" + , boost::regex::normal); + +} // unnamed namespace + +namespace boost +{ + namespace inspect + { + + // minmax_check constructor -------------------------------------------// + + minmax_check::minmax_check() + : m_errors(0) + { + // C/C++ source code... + register_signature( ".c" ); + register_signature( ".cpp" ); + register_signature( ".cxx" ); + register_signature( ".h" ); + register_signature( ".hpp" ); + register_signature( ".hxx" ); + register_signature( ".inc" ); + register_signature( ".ipp" ); + } + + // inspect ( C++ source files ) ---------------------------------------// + + void minmax_check::inspect( + const string & library_name, + const path & full_path, // example: c:/foo/boost/filesystem/path.hpp + const string & contents) // contents of file to be inspected + { + if (contents.find( "boostinspect:" "nominmax" ) != string::npos) return; + + boost::sregex_iterator cur(contents.begin(), contents.end(), minmax_regex), end; + + for( ; cur != end; ++cur /*, ++m_errors*/ ) + { + + if(!(*cur)[3].matched) + { + string::const_iterator it = contents.begin(); + string::const_iterator match_it = (*cur)[0].first; + + string::const_iterator line_start = it; + + string::size_type line_number = 1; + for ( ; it != match_it; ++it) { + if (string::traits_type::eq(*it, '\n')) { + ++line_number; + line_start = it + 1; // could be end() + } + } + + ++m_errors; + error( library_name, full_path, string(name()) + + " violation of Boost min/max guidelines on line " + + boost::lexical_cast<string>( line_number ) ); + } + + } + } + + } // namespace inspect +} // namespace boost + diff --git a/src/boost/tools/inspect/minmax_check.hpp b/src/boost/tools/inspect/minmax_check.hpp new file mode 100644 index 000000000..03ff923ea --- /dev/null +++ b/src/boost/tools/inspect/minmax_check.hpp @@ -0,0 +1,45 @@ +// minmax_check header -------------------------------------------------------// + +// Copyright Beman Dawes 2002 +// Copyright Rene Rivera 2004. +// Copyright Gennaro Prota 2006. +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_MINMAX_CHECK_HPP +#define BOOST_MINMAX_CHECK_HPP + +#include "inspector.hpp" + +namespace boost +{ + namespace inspect + { + class minmax_check : public inspector + { + long m_errors; + + public: + + minmax_check(); + virtual const char * name() const { return "*M*"; } + virtual const char * desc() const { return "uses of min or max that" + " have not been protected from the min/max macros," + " or unallowed #undef-s"; } + + virtual void inspect( + const std::string & library_name, + const path & full_path, + const std::string & contents); + + virtual ~minmax_check() + { + std::cout << " " << m_errors << " violations of the Boost min/max guidelines" << line_break(); + } + }; + } +} + +#endif // BOOST_MINMAX_CHECK_HPP diff --git a/src/boost/tools/inspect/path_name_check.cpp b/src/boost/tools/inspect/path_name_check.cpp new file mode 100644 index 000000000..0714e20c0 --- /dev/null +++ b/src/boost/tools/inspect/path_name_check.cpp @@ -0,0 +1,110 @@ +// path_name_check implementation ------------------------------------------// + +// Copyright Beman Dawes 2002. +// Copyright Gennaro Prota 2006. +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include "path_name_check.hpp" + +#include "boost/filesystem/operations.hpp" +#include "boost/lexical_cast.hpp" + +#include <string> +#include <algorithm> +#include <cctype> +#include <cstring> + +using std::string; + +namespace +{ + const char allowable[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_-."; + const char initial_char[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_"; +} + +namespace boost +{ + namespace inspect + { + + + file_name_check::file_name_check() : m_name_errors(0) {} + + void file_name_check::inspect( + const string & library_name, + const path & full_path ) + { + string::size_type pos; + + // called for each file and directory, so only the leaf need be tested + string const leaf( full_path.leaf().string() ); + + // includes only allowable characters + if ( (pos = leaf.find_first_not_of( allowable )) != string::npos ) + { + ++m_name_errors; + error( library_name, full_path, string(name()) + + " file or directory name contains unacceptable character '" + + leaf[pos] + "'" ); + } + + // allowable initial character + if ( std::strchr( initial_char, leaf[0] ) == 0 ) + { + ++m_name_errors; + error( library_name, full_path, string(name()) + + " file or directory name begins with an unacceptable character" ); + } + + // rules for dot characters differ slightly for directories and files + if ( filesystem::is_directory( full_path ) ) + { + if ( std::strchr( leaf.c_str(), '.' ) ) + { + ++m_name_errors; + error( library_name, full_path, string(name()) + + " directory name contains a dot character ('.')" ); + } + } + //else // not a directory + //{ + // // includes at most one dot character + // const char * first_dot = std::strchr( leaf.c_str(), '.' ); + // if ( first_dot && std::strchr( first_dot+1, '.' ) ) + // { + // ++m_name_errors; + // error( library_name, full_path, string(name()) + // + " file name with more than one dot character ('.')" ); + // } + //} + + // the path, including a presumed root, does not exceed the maximum size + path const relative_path( relative_to( full_path, search_root_path() ) ); + const unsigned max_relative_path = 207; // ISO 9660:1999 sets this limit + const string generic_root( "boost_X_XX_X/" ); + if ( relative_path.string().size() > + ( max_relative_path - generic_root.size() ) ) + { + ++m_name_errors; + error( library_name, full_path, + string(name()) + + " path will exceed " + + boost::lexical_cast<string>(max_relative_path) + + " characters in a directory tree with a root in the form " + + generic_root + ", and this exceeds ISO 9660:1999 limit of 207" ) + ; + } + + } + + file_name_check::~file_name_check() + { + std::cout << " " << m_name_errors << " " << desc() << line_break(); + } + + + } // namespace inspect +} // namespace boost diff --git a/src/boost/tools/inspect/path_name_check.hpp b/src/boost/tools/inspect/path_name_check.hpp new file mode 100644 index 000000000..ec1218ace --- /dev/null +++ b/src/boost/tools/inspect/path_name_check.hpp @@ -0,0 +1,48 @@ +// long_name_check header --------------------------------------------------// +// (main class renamed to: file_name_check) - gps + +// Copyright Beman Dawes 2002. +// Copyright Gennaro Prota 2006. +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_FILE_NAME_CHECK_HPP +#define BOOST_FILE_NAME_CHECK_HPP + +#include "inspector.hpp" + +namespace boost +{ + namespace inspect + { + class file_name_check : public inspector + { + long m_name_errors; + + public: + + file_name_check(); + virtual ~file_name_check(); + + virtual const char * name() const { return "*N*"; } + virtual const char * desc() const { return "file and directory name issues"; } + + virtual void inspect( + const string & library_name, + const path & full_path ); + + virtual void inspect( + const string &, // "filesystem" + const path &, // "c:/foo/boost/filesystem/path.hpp" + const string &) + { /* empty */ } + + + + }; + } +} + +#endif // BOOST_FILE_NAME_CHECK_HPP diff --git a/src/boost/tools/inspect/tab_check.cpp b/src/boost/tools/inspect/tab_check.cpp new file mode 100644 index 000000000..e84d088da --- /dev/null +++ b/src/boost/tools/inspect/tab_check.cpp @@ -0,0 +1,44 @@ +// tab_check implementation ------------------------------------------------// + +// Copyright Beman Dawes 2002. +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include "tab_check.hpp" + +namespace boost +{ + namespace inspect + { + tab_check::tab_check() : m_files_with_errors(0) + { + register_signature( ".c" ); + register_signature( ".cpp" ); + register_signature( ".cxx" ); + register_signature( ".h" ); + register_signature( ".hpp" ); + register_signature( ".hxx" ); + register_signature( ".ipp" ); + register_signature( "Jamfile" ); + register_signature( ".py" ); + } + + void tab_check::inspect( + const string & library_name, + const path & full_path, // example: c:/foo/boost/filesystem/path.hpp + const string & contents ) // contents of file to be inspected + { + if (contents.find( "boostinspect:" "notab" ) != string::npos) return; + + if ( contents.find( '\t' ) != string::npos ) + { + ++m_files_with_errors; + error( library_name, full_path, name() ); + } + } + } // namespace inspect +} // namespace boost + + diff --git a/src/boost/tools/inspect/tab_check.hpp b/src/boost/tools/inspect/tab_check.hpp new file mode 100644 index 000000000..fb7f617ba --- /dev/null +++ b/src/boost/tools/inspect/tab_check.hpp @@ -0,0 +1,37 @@ +// tab_check header --------------------------------------------------------// + +// Copyright Beman Dawes 2002. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_TAB_CHECK_HPP +#define BOOST_TAB_CHECK_HPP + +#include "inspector.hpp" + +namespace boost +{ + namespace inspect + { + class tab_check : public inspector + { + long m_files_with_errors; + public: + + tab_check(); + virtual const char * name() const { return "*Tabs*"; } + virtual const char * desc() const { return "tabs in file"; } + + virtual void inspect( + const std::string & library_name, + const path & full_path, + const std::string & contents ); + + virtual ~tab_check() + { std::cout << " " << m_files_with_errors << " files with tabs" << line_break(); } + }; + } +} + +#endif // BOOST_TAB_CHECK_HPP diff --git a/src/boost/tools/inspect/time_string.hpp b/src/boost/tools/inspect/time_string.hpp new file mode 100644 index 000000000..72ca43968 --- /dev/null +++ b/src/boost/tools/inspect/time_string.hpp @@ -0,0 +1,55 @@ +// ---- time_string: thin wrapper around std::strftime -------- // +// +// Copyright Gennaro Prota 2006 +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// ------------------------------------------------------------------ +// +// $Id$ + +#ifndef BOOST_TIME_STRING_HPP_GP_20060731 +#define BOOST_TIME_STRING_HPP_GP_20060731 + +#include <string> +#include <ctime> + +#include <boost/config/warning_disable.hpp> + +namespace boost { + +// Many of the boost tools just need a quick way to obtain +// a formatted "run date" string or similar. This is one. +// +// In case of failure false is returned and result is +// unchanged. +// +inline +bool time_string(std::string & result + , const std::string & format = "%X UTC, %A %d %B %Y") +{ + // give up qualifying names and using std::size_t, + // to avoid including "config.hpp" + using namespace std; + + const int sz = 256; + char buffer [ sz ] = { 0 }; + const time_t no_cal_time ( -1 ); + time_t tod; + + const bool ok = + time ( &tod ) != no_cal_time + && strftime( buffer, sz, format.c_str(), gmtime( &tod ) ) != 0 + ; + + if (ok) + result = buffer; + + return ok; +} + +} + +#endif // include guard diff --git a/src/boost/tools/inspect/unnamed_namespace_check.cpp b/src/boost/tools/inspect/unnamed_namespace_check.cpp new file mode 100644 index 000000000..92431a171 --- /dev/null +++ b/src/boost/tools/inspect/unnamed_namespace_check.cpp @@ -0,0 +1,62 @@ +// unnamed_namespace_check -----------------------------------------// + +// Copyright Gennaro Prota 2006. +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include "boost/regex.hpp" +#include "boost/lexical_cast.hpp" +#include "unnamed_namespace_check.hpp" + + +namespace +{ + + boost::regex unnamed_namespace_regex( + "\\<namespace\\s*(\\?\\?<|\\{)" // trigraph ??< or { + ); + +} // unnamed namespace (ironical? :-) + + + +namespace boost +{ + namespace inspect + { + unnamed_namespace_check::unnamed_namespace_check() : m_errors(0) + { + register_signature( ".h" ); + register_signature( ".hh" ); // just in case + register_signature( ".hpp" ); + register_signature( ".hxx" ); // just in case + register_signature( ".inc" ); + register_signature( ".ipp" ); + register_signature( ".inl" ); + } + + void unnamed_namespace_check::inspect( + const string & library_name, + const path & full_path, // example: c:/foo/boost/filesystem/path.hpp + const string & contents ) // contents of file to be inspected + { + if (contents.find( "boostinspect:" "nounnamed" ) != string::npos) return; + + + boost::sregex_iterator cur(contents.begin(), contents.end(), unnamed_namespace_regex), end; + for( ; cur != end; ++cur, ++m_errors ) + { + const string::size_type + ln = std::count( contents.begin(), (*cur)[0].first, '\n' ) + 1; + + error( library_name, full_path, "Unnamed namespace", ln ); + } + + + } + } // namespace inspect +} // namespace boost + + diff --git a/src/boost/tools/inspect/unnamed_namespace_check.hpp b/src/boost/tools/inspect/unnamed_namespace_check.hpp new file mode 100644 index 000000000..87f36b717 --- /dev/null +++ b/src/boost/tools/inspect/unnamed_namespace_check.hpp @@ -0,0 +1,39 @@ +// unnamed_namespace_check -----------------------------------------// + +// Copyright Gennaro Prota 2006. + +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_UNNAMED_NAMESPACE_CHECK_HPP_GP_20060718 +#define BOOST_UNNAMED_NAMESPACE_CHECK_HPP_GP_20060718 + +#include "inspector.hpp" + +namespace boost +{ + namespace inspect + { + class unnamed_namespace_check : public inspector + { + long m_errors; + public: + + unnamed_namespace_check(); + virtual const char * name() const { return "*U*"; } + virtual const char * desc() const { return "unnamed namespace in header"; } + + virtual void inspect( + const std::string & library_name, + const path & full_path, + const std::string & contents ); + + virtual ~unnamed_namespace_check() + { std::cout << " " << m_errors << " usages of unnamed namespaces in headers (including .ipp files)" << line_break(); } + }; + } +} + + +#endif // include guard diff --git a/src/boost/tools/inspect/wrong_line_ends_test.cpp b/src/boost/tools/inspect/wrong_line_ends_test.cpp new file mode 100644 index 000000000..05d1a1b42 --- /dev/null +++ b/src/boost/tools/inspect/wrong_line_ends_test.cpp @@ -0,0 +1 @@ +// this is a test file; it isn't supposed to have correct line endings
// Copyright Beman Dawes, 2003.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
line ending with cr
line ending without any cr or nl
\ No newline at end of file |