summaryrefslogtreecommitdiff
path: root/tools/inspect
diff options
context:
space:
mode:
Diffstat (limited to 'tools/inspect')
-rw-r--r--tools/inspect/apple_macro_check.cpp105
-rw-r--r--tools/inspect/apple_macro_check.hpp39
-rw-r--r--tools/inspect/ascii_check.cpp102
-rw-r--r--tools/inspect/ascii_check.hpp38
-rw-r--r--tools/inspect/assert_macro_check.cpp110
-rw-r--r--tools/inspect/assert_macro_check.hpp40
-rw-r--r--tools/inspect/build/Jamfile.v255
-rw-r--r--tools/inspect/build/msvc/boost_inspect.sln20
-rw-r--r--tools/inspect/build/msvc/boost_inspect.vcproj247
-rw-r--r--tools/inspect/build/msvc/readme.txt4
-rw-r--r--tools/inspect/copyright_check.cpp35
-rw-r--r--tools/inspect/copyright_check.hpp39
-rw-r--r--tools/inspect/crlf_check.cpp97
-rw-r--r--tools/inspect/crlf_check.hpp40
-rw-r--r--tools/inspect/cvs_iterator.hpp81
-rw-r--r--tools/inspect/doc/build.jam21
-rw-r--r--tools/inspect/doc/inspect.qbk128
-rw-r--r--tools/inspect/end_check.cpp58
-rw-r--r--tools/inspect/end_check.hpp40
-rw-r--r--tools/inspect/index.html58
-rw-r--r--tools/inspect/inspect.cpp1000
-rw-r--r--tools/inspect/inspector.hpp106
-rw-r--r--tools/inspect/license_check.cpp48
-rw-r--r--tools/inspect/license_check.hpp40
-rw-r--r--tools/inspect/link_check.cpp487
-rw-r--r--tools/inspect/link_check.hpp72
-rw-r--r--tools/inspect/link_check_test.html24
-rw-r--r--tools/inspect/minmax_check.cpp102
-rw-r--r--tools/inspect/minmax_check.hpp45
-rw-r--r--tools/inspect/path_name_check.cpp110
-rw-r--r--tools/inspect/path_name_check.hpp48
-rw-r--r--tools/inspect/tab_check.cpp44
-rw-r--r--tools/inspect/tab_check.hpp37
-rw-r--r--tools/inspect/time_string.hpp55
-rw-r--r--tools/inspect/unnamed_namespace_check.cpp62
-rw-r--r--tools/inspect/unnamed_namespace_check.hpp39
-rw-r--r--tools/inspect/wrong_line_ends_test.cpp1
37 files changed, 3677 insertions, 0 deletions
diff --git a/tools/inspect/apple_macro_check.cpp b/tools/inspect/apple_macro_check.cpp
new file mode 100644
index 0000000000..ce917e0d8a
--- /dev/null
+++ b/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, fs::initial_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/tools/inspect/apple_macro_check.hpp b/tools/inspect/apple_macro_check.hpp
new file mode 100644
index 0000000000..5acdcf70c1
--- /dev/null
+++ b/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/tools/inspect/ascii_check.cpp b/tools/inspect/ascii_check.cpp
new file mode 100644
index 0000000000..da2aa40201
--- /dev/null
+++ b/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/tools/inspect/ascii_check.hpp b/tools/inspect/ascii_check.hpp
new file mode 100644
index 0000000000..878909e31c
--- /dev/null
+++ b/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_TAB_CHECK_HPP
diff --git a/tools/inspect/assert_macro_check.cpp b/tools/inspect/assert_macro_check.cpp
new file mode 100644
index 0000000000..a91cb8a9f8
--- /dev/null
+++ b/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(fs::initial_path() / "boost") &&
+ fs::exists(fs::initial_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, fs::initial_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/tools/inspect/assert_macro_check.hpp b/tools/inspect/assert_macro_check.hpp
new file mode 100644
index 0000000000..c28a377f34
--- /dev/null
+++ b/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/tools/inspect/build/Jamfile.v2 b/tools/inspect/build/Jamfile.v2
new file mode 100644
index 0000000000..f9355baa32
--- /dev/null
+++ b/tools/inspect/build/Jamfile.v2
@@ -0,0 +1,55 @@
+# 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
+ 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/tools/inspect/build/msvc/boost_inspect.sln b/tools/inspect/build/msvc/boost_inspect.sln
new file mode 100644
index 0000000000..c01f5e330c
--- /dev/null
+++ b/tools/inspect/build/msvc/boost_inspect.sln
@@ -0,0 +1,20 @@
+
+Microsoft Visual Studio Solution File, Format Version 10.00
+# Visual C++ Express 2008
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "boost_inspect", "boost_inspect.vcproj", "{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/tools/inspect/build/msvc/boost_inspect.vcproj b/tools/inspect/build/msvc/boost_inspect.vcproj
new file mode 100644
index 0000000000..372c14b06f
--- /dev/null
+++ b/tools/inspect/build/msvc/boost_inspect.vcproj
@@ -0,0 +1,247 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="9.00"
+ Name="inspect"
+ ProjectGUID="{0EC8AC1C-6D1F-47FC-A06A-9CC3F924BD82}"
+ RootNamespace="boost_inspect"
+ Keyword="Win32Proj"
+ TargetFrameworkVersion="196613"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="..\..\..\.."
+ PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
+ MinimalRebuild="true"
+ ExceptionHandling="2"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ DebugInformationFormat="4"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ LinkIncremental="2"
+ AdditionalLibraryDirectories="..\..\..\..\stage\lib"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="1"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ EnableIntrinsicFunctions="true"
+ AdditionalIncludeDirectories="..\..\..\.."
+ PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
+ ExceptionHandling="2"
+ RuntimeLibrary="2"
+ EnableFunctionLevelLinking="true"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ LinkIncremental="1"
+ AdditionalLibraryDirectories="..\..\..\..\stage\lib"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+ >
+ <File
+ RelativePath="..\..\apple_macro_check.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\ascii_check.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\assert_macro_check.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\copyright_check.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\crlf_check.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\end_check.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\inspect.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\license_check.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\link_check.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\minmax_check.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\path_name_check.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\tab_check.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\unnamed_namespace_check.cpp"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+ >
+ </Filter>
+ <Filter
+ Name="Resource Files"
+ Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
+ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
+ >
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/tools/inspect/build/msvc/readme.txt b/tools/inspect/build/msvc/readme.txt
new file mode 100644
index 0000000000..1f8de0cb28
--- /dev/null
+++ b/tools/inspect/build/msvc/readme.txt
@@ -0,0 +1,4 @@
+The provided Microsoft VC++ solution assumes the following commands have been run in the root directory:
+
+ bjam --toolset=msvc-9.0express --build-type=complete --with-filesystem stage
+ bjam --toolset=msvc-9.0express --build-type=complete --with-regex stage
diff --git a/tools/inspect/copyright_check.cpp b/tools/inspect/copyright_check.cpp
new file mode 100644
index 0000000000..f56bbc9550
--- /dev/null
+++ b/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/tools/inspect/copyright_check.hpp b/tools/inspect/copyright_check.hpp
new file mode 100644
index 0000000000..278596e3eb
--- /dev/null
+++ b/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/tools/inspect/crlf_check.cpp b/tools/inspect/crlf_check.cpp
new file mode 100644
index 0000000000..c382711403
--- /dev/null
+++ b/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/tools/inspect/crlf_check.hpp b/tools/inspect/crlf_check.hpp
new file mode 100644
index 0000000000..c6627ceeeb
--- /dev/null
+++ b/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/tools/inspect/cvs_iterator.hpp b/tools/inspect/cvs_iterator.hpp
new file mode 100644
index 0000000000..538534074f
--- /dev/null
+++ b/tools/inspect/cvs_iterator.hpp
@@ -0,0 +1,81 @@
+// cvs_iterator ------------------------------------------------------------//
+
+// 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)
+
+// WARNING: This is just a quick hack. It doesn't conform to C++ Standard
+// Library iterator requirements.
+
+#ifndef BOOST_CVS_ITERATOR_HPP
+#define BOOST_CVS_ITERATOR_HPP
+
+#include <string>
+#include <assert.h>
+
+#include "boost/filesystem/path.hpp"
+#include "boost/filesystem/operations.hpp"
+#include "boost/filesystem/fstream.hpp"
+#include "boost/noncopyable.hpp"
+
+namespace hack
+{
+ class cvs_iterator : boost::noncopyable
+ {
+ boost::filesystem::ifstream entries_file;
+ boost::filesystem::path dir_path;
+ boost::filesystem::path value_path;
+ public:
+
+ cvs_iterator(){} // end iterator
+
+ ~cvs_iterator() { if ( !!entries_file ) entries_file.close(); }
+
+ cvs_iterator( const boost::filesystem::path & dir_path ) : dir_path(dir_path)
+ {
+ boost::filesystem::path entries_file_path( dir_path / "CVS/Entries" );
+ entries_file.open( entries_file_path );
+ if ( !entries_file )
+ throw std::string( "could not open: " ) + entries_file_path.string();
+ ++*this;
+ }
+
+ const boost::filesystem::path & operator*() const { return value_path; }
+
+ cvs_iterator & operator++()
+ {
+ assert( !!entries_file );
+ std::string contents;
+ do
+ {
+ do
+ {
+ std::getline( entries_file, contents );
+ if ( entries_file.eof() )
+ {
+ entries_file.close();
+ value_path = "";
+ return *this;
+ }
+ } while ( contents == "D" );
+ if ( contents[0] == 'D' ) contents.erase( 0, 1 );
+ value_path = dir_path
+ / boost::filesystem::path( contents.substr( 1, contents.find( '/', 1 ) ) );
+
+ // in case entries file is mistaken, do until value_path actually found
+ } while ( !boost::filesystem::exists( value_path ) );
+ return *this;
+ }
+
+ bool operator==( const cvs_iterator & rhs )
+ { return value_path.string() == rhs.value_path.string(); }
+
+ bool operator!=( const cvs_iterator & rhs )
+ { return value_path.string() != rhs.value_path.string(); }
+
+ };
+}
+
+#endif // include guard
diff --git a/tools/inspect/doc/build.jam b/tools/inspect/doc/build.jam
new file mode 100644
index 0000000000..498c959556
--- /dev/null
+++ b/tools/inspect/doc/build.jam
@@ -0,0 +1,21 @@
+project tools/inspect/doc ;
+
+import path ;
+
+using quickbook ;
+
+xml inspect
+ :
+ inspect.qbk
+ ;
+
+boostbook standalone
+ :
+ inspect
+ :
+ <xsl:param>boost.root=../../../..
+ ;
+
+#~ Copyright Rene Rivera 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)
diff --git a/tools/inspect/doc/inspect.qbk b/tools/inspect/doc/inspect.qbk
new file mode 100644
index 0000000000..87f95e69ac
--- /dev/null
+++ b/tools/inspect/doc/inspect.qbk
@@ -0,0 +1,128 @@
+[article Inspect
+ [quickbook 1.3]
+ [authors [Dawes, Beman], [Prota, Gennaro], [Rivera, Rene]]
+ [copyright 2003 2006 Beman Dawes, Rene Rivera]
+ [category tool-build]
+ [id inspect]
+ [dirname inspect]
+ [purpose
+ The inspect program detects and reports several common errors and
+ Boost guideline violations.
+ ]
+ [license
+ 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])
+ ]
+]
+
+[/ QuickBook Document version 1.3 ]
+
+[/ Shortcuts ]
+
+[def :version: 3.1.14]
+
+[/ Images ]
+
+[def :NOTE: [$images/note.png]]
+[def :ALERT: [$images/caution.png]]
+[def :DETAIL: [$images/note.png]]
+[def :TIP: [$images/tip.png]]
+
+[/ Links ]
+
+[def :Boost: [@http://www.boost.org Boost]]
+
+[section:intro Introduction]
+
+It is not uncommon for various common errors or [@http://www.boost.org/more/lib_guide.htm guideline violations] to creep into the Boost libraries. The inspect program detects and reports several common problems. It can be used to scan a proposed Boost submission to identify various failures.
+
+The inspect program is written in C++ to limit tool chain dependencies, and should be portable to any system.
+
+[endsect]
+
+[section:usage Using Inspect]
+
+The program is run in the directory to be scanned for errors. Sub-directories are also included in the scan. For best results in the generated reports one should run inspect from the Boost root directory. The program generates, by default, an HTML report with summaries and per library details of the infractions.
+
+If the first program argument is -help, a usage message is displayed, showing all available program options:
+
+[pre
+Usage: inspect \[-cvs\] \[-text\] \[-brief\] \[options...\]
+
+ Options:
+ -license
+ -copyright
+ -crlf
+ -end
+ -link
+ -path_name
+ -tab
+ -ascii
+ -apple_macro
+ -assert_macro
+ -minmax
+ -unnamed
+ default is all checks on; otherwise options specify desired checks
+]
+
+[section:options Options]
+
+There are two types of options allowed, ones that control general operation and kind of output produced, and the ones that indicate the checks to perform.
+
+[variablelist
+
+ [ [[^-cvs]]
+ [Only files and directories in the CVS tree of the current directory are scanned. Otherwise all files and sub-directories are included in the scan.] ]
+
+ [ [[^-text]]
+ [Generate plain text report instead of the default HTML.] ]
+
+ [ [[^-brief]]
+ [The default report style can be rather verobse. This generates a more condesed report, for example suitable to send as an email.] ]
+
+ [ [[^-license]]
+ [Checks for presense of approved license text.] ]
+
+ [ [[^-copyright]]
+ [Checks that files are copyright assigned to someone.] ]
+
+ [ [[^-crlf]]
+ [Checks that files use consistent EOL chanracters.] ]
+
+ [ [[^-end]]
+ [Checks that files end with a newline character.] ]
+
+ [ [[^-link]]
+ [Checks the validity of URIs in HTML files.] ]
+
+ [ [[^-path_name]]
+ [Checks for long names, and a variety of other file name problems that inhibit portability of files.] ]
+
+ [ [[^-tab]]
+ [Checks for files with tab characters.] ]
+
+ [ [[^-ascii]]
+ [Checks for files with non-ASCII characters.] ]
+
+ [ [[^-apple_macro]]
+ [Checks for conflicts with to Apple's unfortunately named debugging macros.] ]
+
+ [ [[^-assert_macro]]
+ [Checks for presence of C-style assert macros (instead of BOOST_ASSERT).] ]
+
+ [ [[^-minmax]]
+ [Checks for violations of the Boost min/max quidelines.] ]
+
+ [ [[^-unnamed]]
+ [Checks for unnamed namespace in C++ header files.] ]
+
+]
+
+[endsect]
+
+[endsect]
+
+[section:checks Checks]
+
+[endsect]
diff --git a/tools/inspect/end_check.cpp b/tools/inspect/end_check.cpp
new file mode 100644
index 0000000000..9c1e438afd
--- /dev/null
+++ b/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/tools/inspect/end_check.hpp b/tools/inspect/end_check.hpp
new file mode 100644
index 0000000000..41e5041ced
--- /dev/null
+++ b/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/tools/inspect/index.html b/tools/inspect/index.html
new file mode 100644
index 0000000000..bfecc45f06
--- /dev/null
+++ b/tools/inspect/index.html
@@ -0,0 +1,58 @@
+<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>-cvs</code>, only files and
+directories in the CVS tree of the current directory are scanned. Otherwise all
+files and sub-directories are 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/tools/inspect/inspect.cpp b/tools/inspect/inspect.cpp
new file mode 100644
index 0000000000..00e72f9935
--- /dev/null
+++ b/tools/inspect/inspect.cpp
@@ -0,0 +1,1000 @@
+// 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 "CVS" and "bin",
+// and the code that identifies library names assumes the Boost directory
+// structure.
+
+// See http://www.boost.org/tools/inspect/ for more information.
+
+
+#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 "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 "minmax_check.hpp"
+#include "unnamed_namespace_check.hpp"
+
+#include "cvs_iterator.hpp"
+
+#include "boost/test/included/prg_exec_monitor.hpp"
+
+namespace fs = boost::filesystem;
+
+using namespace boost::inspect;
+
+namespace
+{
+ 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;
+
+// get info (as a string) if inspect_root is svn working copy --------------//
+
+ void extract_info( fs::ifstream & entries_file, string & rev, string & repos )
+ {
+ std::getline( entries_file, rev );
+ std::getline( entries_file, rev );
+ std::getline( entries_file, rev );
+ std::getline( entries_file, rev ); // revision number as a string
+ std::getline( entries_file, repos ); // repository as a string
+ }
+
+ string info( const fs::path & inspect_root )
+ {
+ string rev( "?" );
+ string repos( "unknown" );
+ fs::path entries( inspect_root / ".svn" / "entries" );
+ fs::ifstream entries_file( entries );
+ if ( entries_file )
+ extract_info( entries_file, rev, repos );
+ else
+ {
+ entries = inspect_root / ".." / "svn_info" / ".svn" / "entries";
+ fs::ifstream entries_file( entries );
+ if ( entries_file )
+ extract_info( entries_file, rev, repos );
+ }
+ return repos + " at revision " + rev;
+ }
+
+// 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, fs::initial_path() ) );
+ string leaf( pth.leaf().string() );
+ return
+ // so we can inspect a checkout
+ leaf != "CVS"
+ // 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 some web files
+ && leaf != ".htaccess"
+ // ignore svn files:
+ && leaf != ".svn"
+ // ignore other version control files
+ && leaf != ".git"
+ && leaf != ".bzr"
+ // ignore OS X directory info files:
+ && leaf != ".DS_Store"
+ // 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
+ {
+ ++file_count;
+ string content;
+ load_content( *itr, content );
+ 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_text == display_format)
+ {
+ 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_text == display_format)
+ {
+ 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_text == display_format)
+ 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 += "&lt;";
+ break;
+ case '>':
+ result += "&gt;";
+ break;
+ case '&':
+ result += "&amp;";
+ break;
+ default:
+ result += *it;
+ }
+ }
+
+ return result;
+ }
+
+// display_details ---------------------------------------------------------//
+
+ void display_details()
+ {
+ // gps - review this
+
+ if (display_text == display_format)
+ {
+ // 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>&nbsp;&nbsp;&nbsp; ";
+ else sep = ": ";
+ else
+ if (itr->line_number) sep = "<br>&nbsp;&nbsp;&nbsp; ";
+ 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_text == display_format)
+ {
+ 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_text == display_format)
+ {
+ 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_text == display_format)
+ std::cout << "\n";
+ else
+ std::cout << "</blockquote>\n";
+ }
+
+
+ const char * options()
+ {
+ return
+ " -license\n"
+ " -copyright\n"
+ " -crlf\n"
+ " -end\n"
+ " -link\n"
+ " -path_name\n"
+ " -tab\n"
+ " -ascii\n"
+ " -apple_macro\n"
+ " -assert_macro\n"
+ " -minmax\n"
+ " -unnamed\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";
+ }
+
+
+// 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, fs::initial_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, fs::initial_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() --------------------------------------------------------------//
+
+int cpp_main( int argc_param, char * argv_param[] )
+{
+ // <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 [-cvs] [-text] [-brief] [options...]\n\n"
+ " Options:\n"
+ << options() << '\n';
+ return 0;
+ }
+
+ bool license_ck = true;
+ bool copyright_ck = true;
+ bool crlf_ck = true;
+ bool end_ck = true;
+ bool link_ck = true;
+ bool path_name_ck = true;
+ bool tab_ck = true;
+ bool ascii_ck = true;
+ bool apple_ok = true;
+ bool assert_ok = true;
+ bool minmax_ck = true;
+ bool unnamed_ck = true;
+ bool cvs = false;
+
+ if ( argc > 1 && std::strcmp( argv[1], "-cvs" ) == 0 )
+ {
+ cvs = true;
+ --argc; ++argv;
+ }
+
+ if ( argc > 1 && std::strcmp( argv[1], "-text" ) == 0 )
+ {
+ display_format = display_text;
+ --argc; ++argv;
+ }
+
+ if ( argc > 1 && std::strcmp( argv[1], "-brief" ) == 0 )
+ {
+ display_mode = display_brief;
+ --argc; ++argv;
+ }
+
+ if ( argc > 1 && *argv[1] == '-' )
+ {
+ license_ck = false;
+ copyright_ck = false;
+ crlf_ck = false;
+ end_ck = false;
+ link_ck = false;
+ path_name_ck = false;
+ tab_ck = false;
+ ascii_ck = false;
+ apple_ok = false;
+ assert_ok = false;
+ minmax_ck = false;
+ unnamed_ck = false;
+ }
+
+ bool invalid_options = false;
+ for(; argc > 1; --argc, ++argv )
+ {
+ if ( std::strcmp( argv[1], "-license" ) == 0 )
+ license_ck = true;
+ else if ( std::strcmp( argv[1], "-copyright" ) == 0 )
+ copyright_ck = true;
+ else if ( std::strcmp( argv[1], "-crlf" ) == 0 )
+ crlf_ck = true;
+ else if ( std::strcmp( argv[1], "-end" ) == 0 )
+ end_ck = true;
+ else if ( std::strcmp( argv[1], "-link" ) == 0 )
+ link_ck = true;
+ else if ( std::strcmp( argv[1], "-path_name" ) == 0 )
+ path_name_ck = true;
+ else if ( std::strcmp( argv[1], "-tab" ) == 0 )
+ tab_ck = true;
+ else if ( std::strcmp( argv[1], "-ascii" ) == 0 )
+ ascii_ck = true;
+ else if ( std::strcmp( argv[1], "-apple_macro" ) == 0 )
+ apple_ok = true;
+ else if ( std::strcmp( argv[1], "-assert_macro" ) == 0 )
+ assert_ok = true;
+ else if ( std::strcmp( argv[1], "-minmax" ) == 0 )
+ minmax_ck = true;
+ else if ( std::strcmp( argv[1], "-unnamed" ) == 0 )
+ unnamed_ck = true;
+ else
+ {
+ std::cerr << "unknown option: " << argv[1] << '\n';
+ invalid_options = true;
+ }
+ }
+ if ( invalid_options ) {
+ std::cerr << "\nvalid options are:\n"
+ << options();
+ return 1;
+ }
+
+ string inspector_keys;
+ fs::initial_path();
+
+
+ { // 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_ok )
+ inspectors.push_back( inspector_element( new boost::inspect::apple_macro_check ) );
+ if ( assert_ok )
+ inspectors.push_back( inspector_element( new boost::inspect::assert_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 ) );
+
+ // perform the actual inspection, using the requested type of iteration
+ if ( cvs )
+ visit_all<hack::cvs_iterator>( "boost-root",
+ fs::initial_path(), inspectors );
+ else
+ visit_all<fs::directory_iterator>( "boost-root",
+ fs::initial_path(), 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_text == display_format)
+ {
+ std::cout
+ <<
+ "Boost Inspection Report\n"
+ "Run Date: " << run_date << "\n"
+ "\n"
+ "An inspection program <http://www.boost.org/tools/inspect/index.html>\n"
+ "checks each file in the current Boost CVS for various problems,\n"
+ "generating an HTML page as output.\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"
+ //"&nbsp;&nbsp;/ " << 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"
+ ;
+ std::cout
+ << "<p>The files checked were from "
+ << info( fs::initial_path() )
+ << ".</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_text == display_format)
+ std::cout << "\nProblem counts:\n";
+ else
+ std::cout << "\n<h2>Problem counts</h2>\n<blockquote><p>\n" ;
+
+ } // end of block: starts reporting
+
+ if (display_text == display_format)
+ 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_worst_offenders();
+
+ if ( !msgs.empty() )
+ {
+ display_summary();
+
+ if (display_text == display_format)
+ {
+ std::cout << "Details:\n" << inspector_keys;
+ }
+ else
+ {
+ std::cout << "<h2>Details</h2>\n" << inspector_keys;
+ }
+ display_details();
+ }
+
+ if (display_text == display_format)
+ {
+ std::cout << "\n\n" ;
+ }
+ else
+ {
+ std::cout
+ << "</body>\n"
+ "</html>\n";
+ }
+
+ return 0;
+}
diff --git a/tools/inspect/inspector.hpp b/tools/inspect/inspector.hpp
new file mode 100644
index 0000000000..ad9fdd01f9
--- /dev/null
+++ b/tools/inspect/inspector.hpp
@@ -0,0 +1,106 @@
+// 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();
+
+ 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/tools/inspect/license_check.cpp b/tools/inspect/license_check.cpp
new file mode 100644
index 0000000000..86d1d20e70
--- /dev/null
+++ b/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/tools/inspect/license_check.hpp b/tools/inspect/license_check.hpp
new file mode 100644
index 0000000000..8312023632
--- /dev/null
+++ b/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/tools/inspect/link_check.cpp b/tools/inspect/link_check.cpp
new file mode 100644
index 0000000000..ca692bdfb2
--- /dev/null
+++ b/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) == "&amp;") {
+ 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, fs::initial_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, fs::initial_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, fs::initial_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( fs::initial_path() / path(itr->first) );
+ error( impute_library( full_path ), full_path, "Unlinked file" );
+ }
+ }
+ }
+
+ } // namespace inspect
+} // namespace boost
+
diff --git a/tools/inspect/link_check.hpp b/tools/inspect/link_check.hpp
new file mode 100644
index 0000000000..2878c4db02
--- /dev/null
+++ b/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 initial_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/tools/inspect/link_check_test.html b/tools/inspect/link_check_test.html
new file mode 100644
index 0000000000..2d1e9845e4
--- /dev/null
+++ b/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>&nbsp;</p>
+
+</body>
+
+</html> \ No newline at end of file
diff --git a/tools/inspect/minmax_check.cpp b/tools/inspect/minmax_check.cpp
new file mode 100644
index 0000000000..00cc44bca2
--- /dev/null
+++ b/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/tools/inspect/minmax_check.hpp b/tools/inspect/minmax_check.hpp
new file mode 100644
index 0000000000..03ff923eaf
--- /dev/null
+++ b/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/tools/inspect/path_name_check.cpp b/tools/inspect/path_name_check.cpp
new file mode 100644
index 0000000000..87bc6842c9
--- /dev/null
+++ b/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, filesystem::initial_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/tools/inspect/path_name_check.hpp b/tools/inspect/path_name_check.hpp
new file mode 100644
index 0000000000..ec1218ace1
--- /dev/null
+++ b/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/tools/inspect/tab_check.cpp b/tools/inspect/tab_check.cpp
new file mode 100644
index 0000000000..e84d088da3
--- /dev/null
+++ b/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/tools/inspect/tab_check.hpp b/tools/inspect/tab_check.hpp
new file mode 100644
index 0000000000..9cc4cc3f9e
--- /dev/null
+++ b/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 "*Tab*"; }
+ 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/tools/inspect/time_string.hpp b/tools/inspect/time_string.hpp
new file mode 100644
index 0000000000..fc005dddde
--- /dev/null
+++ b/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: time_string.hpp 47222 2008-07-08 14:29:03Z bemandawes $
+
+#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/tools/inspect/unnamed_namespace_check.cpp b/tools/inspect/unnamed_namespace_check.cpp
new file mode 100644
index 0000000000..3850e3af6c
--- /dev/null
+++ b/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/tools/inspect/unnamed_namespace_check.hpp b/tools/inspect/unnamed_namespace_check.hpp
new file mode 100644
index 0000000000..87f36b7170
--- /dev/null
+++ b/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/tools/inspect/wrong_line_ends_test.cpp b/tools/inspect/wrong_line_ends_test.cpp
new file mode 100644
index 0000000000..05d1a1b42e
--- /dev/null
+++ b/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