| /* |
| * |
| * Copyright (c) 2009 Dr John Maddock |
| * Use, modification and distribution is subject to 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 file implements the following: |
| * void bcp_implementation::add_path(const fs::path& p) |
| * void bcp_implementation::add_directory(const fs::path& p) |
| * void bcp_implementation::add_file(const fs::path& p) |
| * void bcp_implementation::add_dependent_lib(const std::string& libname, const fs::path& p, const fileview& view) |
| */ |
| |
| #include "bcp_imp.hpp" |
| #include "fileview.hpp" |
| #include <boost/regex.hpp> |
| #include <boost/filesystem/operations.hpp> |
| #include <boost/filesystem/exception.hpp> |
| #include <iostream> |
| |
| // |
| // This file contains the code required to work out whether the source/header file being scanned |
| // is actually dependent upon some library's source code or not. |
| // |
| |
| static std::map<std::string, boost::regex> scanner; |
| |
| static std::map<std::string, std::set<std::string> > free_function_names; |
| static std::map<std::string, std::set<std::string> > class_names; |
| static std::map<std::string, std::set<std::string> > variable_names; |
| |
| static void init_library_scanner(const fs::path& p, bool cvs_mode, const std::string& libname, bool recurse = false) |
| { |
| /* |
| if(free_function_names.count(libname) == 0) |
| { |
| free_function_names[libname] = "[\\x0]"; |
| class_names[libname] = "[\\x0]"; |
| variable_names[libname] = "[\\x0]"; |
| } |
| */ |
| // |
| // Don't add files created by build system: |
| // |
| if((p.leaf() == "bin") || (p.leaf() == "bin-stage")) |
| return; |
| // |
| // Don't add version control directories: |
| // |
| if((p.leaf() == "CVS") || (p.leaf() == ".svn")) |
| return; |
| // |
| // don't add directories not under version control: |
| // |
| if(cvs_mode && !fs::exists(p / "CVS/Entries")) |
| return; |
| if(cvs_mode && !fs::exists(p / ".svn/entries")) |
| return; |
| // |
| // Enumerate files and directories: |
| // |
| fs::directory_iterator i(p); |
| fs::directory_iterator j; |
| while(i != j) |
| { |
| if(fs::is_directory(*i)) |
| init_library_scanner(*i, cvs_mode, libname, true); |
| if(bcp_implementation::is_source_file(*i)) |
| { |
| static boost::regex function_scanner( |
| "(?|" // Branch reset group |
| "(?:\\<\\w+\\>[^>;{},:]*)" // Return type |
| "(?:" |
| "(\\<\\w+\\>)" // Maybe class name |
| "\\s*" |
| "(?:<[^>;{]*>)?" // Maybe template specialisation |
| "::\\s*)?" |
| "(\\<(?!throw|if|while|for|catch)\\w+\\>)" // function name |
| "\\s*" |
| "\\(" |
| "[^\\(\\);{}]*" // argument list |
| "\\)" |
| "\\s*" |
| "\\{" // start of definition |
| "|" |
| "(\\<\\w+\\>)" // Maybe class name |
| "\\s*" |
| "(?:<[^>;{]*>)?" // Maybe template specialisation |
| "::\\s*" |
| "~?\\1" // function name, same as class name |
| "\\s*" |
| "\\(" |
| "[^\\(\\);{}]*" // argument list |
| "\\)" |
| "\\s*" |
| "\\{" // start of definition |
| ")" // end branch reset |
| ); |
| fileview view(*i); |
| boost::regex_iterator<const char*> a(view.begin(), view.end(), function_scanner); |
| boost::regex_iterator<const char*> b; |
| while(a != b) |
| { |
| if((*a)[1].matched) |
| { |
| std::string n = a->str(1); |
| class_names[libname].insert(n); |
| } |
| else |
| { |
| std::string n = a->str(2); |
| free_function_names[libname].insert(n); |
| } |
| ++a; |
| } |
| } |
| ++i; |
| } |
| |
| if(recurse == false) |
| { |
| // |
| // Build the regular expressions: |
| // |
| const char* e1 = |
| "^(?>[[:blank:]]*)(?!#)[^;{}\\r\\n]*" |
| "(?|" |
| "(?:class|struct)[^:;{}#]*" |
| "("; |
| // list of class names goes here... |
| const char* e2 = |
| ")\\s*(?:<[^;{>]*>\\s*)?(?::[^;{]*)?\\{" |
| "|" |
| "\\<(?!return)\\w+\\>[^:;{}#=<>!~%.\\w]*("; |
| // List of function names goes here... |
| const char* e3 = |
| ")\\s*\\([^;()]*\\)\\s*;)"; |
| |
| std::string class_name_list; |
| std::set<std::string>::const_iterator i = class_names[libname].begin(), j = class_names[libname].end(); |
| if(i != j) |
| { |
| class_name_list = *i; |
| ++i; |
| while(i != j) |
| { |
| class_name_list += "|" + *i; |
| ++i; |
| } |
| } |
| else |
| { |
| class_name_list = "[\\x0]"; |
| } |
| std::string function_name_list; |
| i = free_function_names[libname].begin(); |
| j = free_function_names[libname].end(); |
| if(i != j) |
| { |
| function_name_list = *i; |
| ++i; |
| while(i != j) |
| { |
| function_name_list += "|" + *i; |
| ++i; |
| } |
| } |
| else |
| { |
| function_name_list = "[\\x0]"; |
| } |
| |
| scanner[libname] = boost::regex(e1 + class_name_list + e2 + function_name_list + e3); |
| } |
| } |
| |
| void bcp_implementation::add_dependent_lib(const std::string& libname, const fs::path& p, const fileview& view) |
| { |
| // |
| // if the boost library libname has source associated with it |
| // then add the source to our list: |
| // |
| if(fs::exists(m_boost_path / "libs" / libname / "src")) |
| { |
| if(!m_dependencies.count(fs::path("libs") / libname / "src")) |
| { |
| if(scanner.count(libname) == 0) |
| init_library_scanner(m_boost_path / "libs" / libname / "src", m_cvs_mode, libname); |
| boost::cmatch what; |
| if(regex_search(view.begin(), view.end(), what, scanner[libname])) |
| { |
| std::cout << "INFO: tracking source dependencies of library " << libname |
| << " due to presence of \"" << what << "\" in file " << p << std::endl; |
| //std::cout << "Full text match was: " << what << std::endl; |
| m_dependencies[fs::path("libs") / libname / "src"] = p; // set up dependency tree |
| add_path(fs::path("libs") / libname / "src"); |
| |
| if(fs::exists(m_boost_path / "libs" / libname / "build")) |
| { |
| if(!m_dependencies.count(fs::path("libs") / libname / "build")) |
| { |
| m_dependencies[fs::path("libs") / libname / "build"] = p; // set up dependency tree |
| add_path(fs::path("libs") / libname / "build"); |
| //m_dependencies[fs::path("boost-build.jam")] = p; |
| //add_path(fs::path("boost-build.jam")); |
| m_dependencies[fs::path("Jamroot")] = p; |
| add_path(fs::path("Jamroot")); |
| //m_dependencies[fs::path("tools/build")] = p; |
| //add_path(fs::path("tools/build")); |
| } |
| } |
| } |
| } |
| } |
| } |