//  apple_macro_check implementation  ------------------------------------------------//

//  Copyright Marshall Clow 2007.
//  Based on the tab-check checker by Beman Dawes
//
//  Distributed under the Boost Software License, Version 1.0.
//  (See accompanying file LICENSE_1_0.txt or copy at
//  http://www.boost.org/LICENSE_1_0.txt)

#include "apple_macro_check.hpp"
#include <functional>
#include "boost/regex.hpp"
#include "boost/lexical_cast.hpp"
#include "boost/filesystem/operations.hpp"

namespace fs = boost::filesystem;

namespace
{
  boost::regex apple_macro_regex(
    "("
    "^\\s*#\\s*undef\\s*" // # undef
    "\\b(check|verify|require|check_error)\\b"     // followed by apple macro name, whole word
    ")"
    "|"                   // or (ignored)
    "("
    "//[^\\n]*"           // single line comments (//)
    "|"
    "/\\*.*?\\*/"         // multi line comments (/**/)
    "|"
    "\"(?:\\\\\\\\|\\\\\"|[^\"])*\"" // string literals
    ")"
    "|"                   // or
    "("
    "\\b(check|verify|require|check_error)\\b" // apple macro name, whole word
    "\\s*\\("         // followed by 0 or more spaces and an opening paren
    ")"
    , boost::regex::normal);

} // unnamed namespace


namespace boost
{
  namespace inspect
  {
   apple_macro_check::apple_macro_check() : m_files_with_errors(0)
   {
     register_signature( ".c" );
     register_signature( ".cpp" );
     register_signature( ".cxx" );
     register_signature( ".h" );
     register_signature( ".hpp" );
     register_signature( ".hxx" );
     register_signature( ".ipp" );
   }

   void apple_macro_check::inspect(
      const string & library_name,
      const path & full_path,   // example: c:/foo/boost/filesystem/path.hpp
      const string & contents )     // contents of file to be inspected
    {
      if (contents.find( "boostinspect:" "naapple_macros" ) != string::npos) return;

      // Only check files in the boost directory, as we can avoid including the
      // apple test headers elsewhere.
      path relative( relative_to( full_path, search_root_path() ) );
      if ( relative.empty() || *relative.begin() != "boost") return;

      boost::sregex_iterator cur(contents.begin(), contents.end(), apple_macro_regex), end;

      long errors = 0;

      for( ; cur != end; ++cur /*, ++m_files_with_errors*/ )
      {

        if(!(*cur)[3].matched)
        {
          string::const_iterator it = contents.begin();
          string::const_iterator match_it = (*cur)[0].first;

          string::const_iterator line_start = it;

          string::size_type line_number = 1;
          for ( ; it != match_it; ++it) {
              if (string::traits_type::eq(*it, '\n')) {
                  ++line_number;
                  line_start = it + 1; // could be end()
              }
          }

          ++errors;
          error( library_name, full_path, 
            "Apple macro clash: " + std::string((*cur)[0].first, (*cur)[0].second-1),
            line_number );
        }
      }
      if(errors > 0) {
        ++m_files_with_errors;
      }
    }
  } // namespace inspect
} // namespace boost


