blob: bb1818a2e2577a9049575908d239a4b4be59cd37 [file] [log] [blame]
/*
*
* 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"));
}
}
}
}
}
}