diff --git a/sprout/config/suffix.hpp b/sprout/config/suffix.hpp index 7bd30b93..e518aa3d 100644 --- a/sprout/config/suffix.hpp +++ b/sprout/config/suffix.hpp @@ -236,4 +236,9 @@ # define NS_SSCRISK_CEL_OR_SPROUT sscrisk::cel #endif // #ifndef SPROUT_CONFIG_USE_SSCRISK_CEL +// +// SPROUT_PREVENT_MACRO_SUBSTITUTION +// +#define SPROUT_PREVENT_MACRO_SUBSTITUTION + #endif // #ifndef SPROUT_CONFIG_SUFFIX_HPP diff --git a/sprout/net/endian.hpp b/sprout/net/endian.hpp index 94b870cc..09d18277 100644 --- a/sprout/net/endian.hpp +++ b/sprout/net/endian.hpp @@ -122,7 +122,7 @@ namespace sprout { // template<> // constexpr unsigned-integral hton(unsigned-integral host) template - SPROUT_CONSTEXPR T hton(T host) { + SPROUT_CONSTEXPR T hton SPROUT_PREVENT_MACRO_SUBSTITUTION (T host) { #if defined(BOOST_BIG_ENDIAN) return host; #elif defined(BOOST_LITTLE_ENDIAN) @@ -136,7 +136,7 @@ namespace sprout { // template<> // constexpr unsigned-integral ntoh(unsigned-integral net) template - SPROUT_CONSTEXPR T ntoh(T net) { + SPROUT_CONSTEXPR T ntoh SPROUT_PREVENT_MACRO_SUBSTITUTION (T net) { #if defined(BOOST_BIG_ENDIAN) return net; #elif defined(BOOST_LITTLE_ENDIAN) @@ -148,26 +148,26 @@ namespace sprout { // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3620.pdf // uint32_t htonl(uint32_t host32) - SPROUT_CONSTEXPR std::uint32_t htonl(std::uint32_t host32) { - return sprout::net::hton(host32); + SPROUT_CONSTEXPR std::uint32_t htonl SPROUT_PREVENT_MACRO_SUBSTITUTION (std::uint32_t host32) { + return sprout::net::hton SPROUT_PREVENT_MACRO_SUBSTITUTION (host32); } // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3620.pdf // uint16_t htons(uint16_t host16) - SPROUT_CONSTEXPR std::uint16_t htons(std::uint16_t host16) { - return sprout::net::hton(host16); + SPROUT_CONSTEXPR std::uint16_t htons SPROUT_PREVENT_MACRO_SUBSTITUTION (std::uint16_t host16) { + return sprout::net::hton SPROUT_PREVENT_MACRO_SUBSTITUTION (host16); } // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3620.pdf // uint32_t ntohl(uint32_t net32) - SPROUT_CONSTEXPR std::uint32_t ntohl(std::uint32_t net32) { - return sprout::net::ntoh(net32); + SPROUT_CONSTEXPR std::uint32_t ntohl SPROUT_PREVENT_MACRO_SUBSTITUTION (std::uint32_t net32) { + return sprout::net::ntoh SPROUT_PREVENT_MACRO_SUBSTITUTION (net32); } // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3620.pdf // uint16_t ntohs(uint32_t net16) - SPROUT_CONSTEXPR std::uint16_t ntohs(std::uint16_t net16) { - return sprout::net::ntoh(net16); + SPROUT_CONSTEXPR std::uint16_t ntohs SPROUT_PREVENT_MACRO_SUBSTITUTION (std::uint16_t net16) { + return sprout::net::ntoh SPROUT_PREVENT_MACRO_SUBSTITUTION (net16); } } //namespace net } // namespace sprout diff --git a/tools/files/CMakeLists.txt b/tools/files/CMakeLists.txt new file mode 100644 index 00000000..bf6494e8 --- /dev/null +++ b/tools/files/CMakeLists.txt @@ -0,0 +1,6 @@ +add_executable( tools_files_filegraph filegraph.cpp ) +set_target_properties( tools_files_filegraph PROPERTIES OUTPUT_NAME "filegraph" ) +install( TARGETS tools_files_filegraph + RUNTIME DESTINATION bin + LIBRARY DESTINATION lib +) diff --git a/tools/files/filegraph.cpp b/tools/files/filegraph.cpp new file mode 100644 index 00000000..1e87e7e8 --- /dev/null +++ b/tools/files/filegraph.cpp @@ -0,0 +1,417 @@ +/*============================================================================= + Copyright (c) 2011-2014 Bolero MURAKAMI + https://github.com/bolero-MURAKAMI/Sprout + + 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "../sprig/algorithm/string.hpp" +#include "../sprig/graph/depth_first_search.hpp" + +class include_graph_hooks + : public boost::wave::context_policies::default_preprocessing_hooks +{ +private: + typedef boost::wave::context_policies::default_preprocessing_hooks base_type; +public: + // グラフのノード + struct node_type { + boost::filesystem::path absolute; + boost::filesystem::path filename; + bool has_include_guard; + public: + node_type(boost::filesystem::path const& absolute, boost::filesystem::path const& filename) + : absolute(absolute), filename(filename), has_include_guard(false) + {} + operator boost::filesystem::path const&() const { + return filename; + } + operator std::string() const { + return filename.generic_string(); + } + friend bool operator==(node_type const& lhs, node_type const& rhs) { + return lhs.absolute == rhs.absolute; + } + friend bool operator==(node_type const& lhs, boost::filesystem::path const& rhs) { + return lhs.absolute == rhs; + } + friend bool operator==(boost::filesystem::path const& lhs, node_type const& rhs) { + return lhs == rhs.absolute; + } + friend bool operator!=(node_type const& lhs, node_type const& rhs) { + return !(lhs == rhs); + } + friend bool operator!=(node_type const& lhs, boost::filesystem::path const& rhs) { + return !(lhs == rhs); + } + friend bool operator!=(boost::filesystem::path const& lhs, node_type const& rhs) { + return !(lhs == rhs); + } + template + friend std::basic_ostream& operator<<(std::basic_ostream& lhs, node_type const& rhs) { + return lhs << rhs.filename.generic_string(); + } + }; + typedef std::pair edge_type; + typedef boost::adjacency_list< + boost::vecS, + boost::vecS, + boost::bidirectionalS, + boost::no_property + > graph_type; +private: + std::vector node_list_; + std::vector edge_list_; + std::vector current_list_; + int current_; +public: + explicit include_graph_hooks(boost::filesystem::path const& start) + : node_list_{node_type{boost::filesystem::absolute(start), start.filename()}} + , edge_list_{} + , current_list_{0} + , current_(0) + {} + std::vector const& + nodes() const { + return node_list_; + } + std::vector const& + edges() const { + return edge_list_; + } + // グラフ生成 + template + Graph make_graph() const { + return Graph(edge_list_.begin(), edge_list_.end(), node_list_.size()); + } + graph_type make_graph() const { + return make_graph(); + } + // graphviz 出力 + void write_graphviz(std::ostream& out) const { + boost::write_graphviz( + out, + make_graph(), + boost::make_label_writer(&node_list_[0]) + ); + } + // 非インクルードガード検出 + template + void collect_no_include_guard_files(OutputIterator result) const { + std::copy_if( + node_list_.begin() + 1, node_list_.end(), result, + [](node_type const& e) { return !e.has_include_guard; } + ); + } + // 循環インクルード検出 + template + void collect_circulated_includes(OutputIterator result) const { + boost::depth_first_search( + make_graph(), + boost::visitor(sprig::make_back_edge_recorder(result)) + ); + } + // 孤立ファイル検出 + template + void collect_isolated_files(OutputIterator result, boost::filesystem::path const& path) const { + typedef boost::filesystem::recursive_directory_iterator iterator; + for (auto it = iterator(path), last = iterator(); it != last; ++it) { + if (!boost::filesystem::is_directory(*it)) { + boost::filesystem::path abspath(boost::filesystem::absolute(*it)); + auto found = std::find(node_list_.begin(), node_list_.end(), abspath); + if (found == node_list_.end()) { // インクルードされていないならば結果に追加 + *result++ = abspath.generic_string(); + } + } + } + } +public: + // インクルードファイルパス設定処理をフック + template + bool locate_include_file( + Context& ctx, + std::string& file_path, + bool is_system, + char const* current_name, + std::string& dir_path, + std::string& native_name + ) + { + std::string filename = is_system ? ('<' + file_path + '>') : ('\"' + file_path + '\"'); + if (!base_type::locate_include_file(ctx, file_path, is_system, current_name, dir_path, native_name)) { + return false; + } + dir_path = filename; // インクルードディレクティブのテキストで上書き + return true; + } + // インクルードファイル解析開始をフック + template + void opened_include_file( + Context const& /*ctx*/, + std::string const& relname, + std::string const& absname, + bool /*is_system_include*/ + ) + { + boost::filesystem::path abspath(boost::filesystem::absolute(absname)); + auto found = std::find(node_list_.begin(), node_list_.end(), abspath); + auto to = std::distance(node_list_.begin(), found); + if (found == node_list_.end()) { // 最初のインクルードならばノードに追加 + node_list_.emplace_back(abspath, relname); + } + edge_list_.emplace_back(current_list_.back(), to); + current_list_.push_back(to); // カレントを更新 + current_ = to; + } + // インクルードファイル解析完了をフック + template + void returning_from_include_file(Context const& /*ctx*/) { + current_ = current_list_.back(); + current_list_.pop_back(); // カレントを戻す + } + // インクルードガード検出をフック + template + void detected_include_guard( + Context const& /*ctx*/, + std::string const& /*filename*/, + std::string const& /*include_guard*/ + ) + { + node_list_.at(current_).has_include_guard = true; + } + template + void detected_pragma_once( + Context const& /*ctx*/, + Token const& /*pragma_token*/, + std::string const& /*filename*/ + ) + { + node_list_.at(current_).has_include_guard = true; + } +}; + +// システムインクルードパスの取得 +template +void collect_sysinclude_paths(OutputIterator result, std::string const& command = "g++") { + { + std::ofstream ofs("_collect_sysinclude_paths.cpp"); + } + std::system((command + " -v -E _collect_sysinclude_paths.cpp 1> /dev/null 2> _collect_sysinclude_paths").c_str()); + { + std::ifstream ifs("_collect_sysinclude_paths"); + std::string text( + std::istreambuf_iterator(ifs.rdbuf()), + std::istreambuf_iterator() + ); + auto rng = boost::make_iterator_range(text); + rng = sprig::find_skip(rng, boost::algorithm::first_finder("#include <...>")); // インクルードパスの始点までスキップ + rng = sprig::find_skip(rng, boost::algorithm::first_finder("\n")); + while (boost::algorithm::starts_with(rng, " ")) { + auto found = sprig::find_between( + rng, + boost::algorithm::token_finder(boost::algorithm::is_space(), boost::algorithm::token_compress_on), + boost::algorithm::first_finder("\n") + ); + *result++ = std::string(boost::begin(found), boost::end(found)); + rng = boost::make_iterator_range(boost::end(found), boost::end(rng)); + rng = sprig::find_skip(rng, boost::algorithm::first_finder("\n")); + } + } +} + +int main(int argc, const char* argv[]) { + std::string src; + std::string text; + + if (argc >= 2) { + src = argv[1]; + + // ファイルの内容を全部 text に読み込む + std::ifstream ifs(argv[1]); + text = std::string( + std::istreambuf_iterator(ifs.rdbuf()), + std::istreambuf_iterator() + ); + } + + try { + // プリプロセッサを用意 + typedef boost::wave::context< + std::string::iterator, + boost::wave::cpplexer::lex_iterator >, + boost::wave::iteration_context_policies::load_file_to_string, + ::include_graph_hooks + > context_type; + context_type ctx(text.begin(), text.end(), src.c_str(), ::include_graph_hooks(src)); + + // ランゲージの設定 + ctx.set_language( + boost::wave::language_support( + boost::wave::support_cpp11 + | boost::wave::support_option_include_guard_detection // インクルードガード検出 + ) + ); + // インクルードパスの設定 + { + std::vector list; + ::collect_sysinclude_paths(std::back_inserter(list)); + std::cout + << "sysinclude paths :\n" + ; + for (auto&& e : list) { + std::cout + << " " << e << "\n" + ; + ctx.add_sysinclude_path(e.c_str()); + } + std::cout + << std::flush + ; + } + + if (!src.empty()) { + // プリプロセスを走らせる + for (auto&& e : ctx) { + //std::cout << e.get_value(); + } + } + + for ( ; ;) { + std::cout + << "> " + << std::flush + ; + std::string line; + std::getline(std::cin, line); + if (line.empty()) { + break; + } + std::vector tokens; + boost::algorithm::split(tokens, line, boost::algorithm::is_space()); + if (tokens.at(0) == "find") { + // インクルードファイルを検索 + if (tokens.size() < 2) { + std::cout + << "missing parameter.\n" + << std::flush + ; + continue; + } + std::cout + << "find <" << tokens.at(1) << "> :\n" + ; + std::string filepath(tokens.at(1)); + std::string dirpath; + if (!ctx.find_include_file(filepath, dirpath, true, 0)) { + std::cout + << " not found\n" + << std::flush + ; + continue; + } + std::cout + << " " << filepath << "\n" + << std::flush + ; + } else if (tokens.at(0) == "graph") { + // グラフ出力 + std::cout + << "graph output > out.graph.dot\n" + ; + std::ofstream ofs("out.graph.dot"); + ctx.get_hooks().write_graphviz(ofs); + std::cout + << std::flush + ; + } else if (tokens.at(0) == "noguard") { + // 非インクルードガードを出力 + std::vector<::include_graph_hooks::node_type> list; + ctx.get_hooks().collect_no_include_guard_files(std::back_inserter(list)); + std::cout + << "no include guarde files (" << list.size() << ") :\n" + ; + for (auto const& e : list) { + std::cout + << " " << e << "\n" + ; + } + std::cout + << std::flush + ; + } else if (tokens.at(0) == "circulated") { + // 循環インクルードを出力 + std::vector::edge_descriptor> list; + ctx.get_hooks().collect_circulated_includes(std::back_inserter(list)); + auto g = ctx.get_hooks().make_graph(); + std::cout + << "circulated includes (" << list.size() << ") :\n" + ; + for (auto const& e : list) { + std::cout + << " " << boost::source(e, g) << "[" << ctx.get_hooks().nodes()[boost::source(e, g)] << "]\n" + << " -> " << boost::target(e, g) << "[" << ctx.get_hooks().nodes()[boost::target(e, g)] << "]\n" + ; + } + std::cout + << std::flush + ; + } else if (tokens.at(0) == "isolated") { + // Sprout の孤立ファイルを出力 + std::cout + << "isolated files output > out.isolated.txt\n" + ; + std::ofstream ofs("out.isolated.txt"); + // Sprout のシステムインクル−ドパスを取得 + std::string filepath("sprout/config.hpp"); + std::string dirpath; + if (!ctx.find_include_file(filepath, dirpath, true, 0)) { + std::cerr + << "#error sprout not found\n" + << std::flush + ; + continue; + } + dirpath = boost::filesystem::path(filepath).parent_path().generic_string(); + // リスト出力 + std::vector list; + ctx.get_hooks().collect_isolated_files(std::back_inserter(list), dirpath); + std::sort(list.begin(), list.end()); + std::copy(list.begin(), list.end(), std::ostream_iterator(ofs, "\n")); + std::cout + << std::flush + ; + } else { + std::cout + << "invalid command\n" + << std::flush + ; + } + } + } catch (boost::wave::cpp_exception& e) { + // プリプロセスでエラー発生 + std::cerr + << "#error " << e.file_name() << "(" << e.line_no() << "):" << e.description() << "\n" + << std::flush + ; + } +} diff --git a/tools/sprig/algorithm/string.hpp b/tools/sprig/algorithm/string.hpp new file mode 100644 index 00000000..37a46f93 --- /dev/null +++ b/tools/sprig/algorithm/string.hpp @@ -0,0 +1,13 @@ +/*============================================================================= + Copyright (c) 2011-2014 Bolero MURAKAMI + https://github.com/bolero-MURAKAMI/Sprout + + 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 TOOLS_SPRIG_ALGORITHM_STRING_HPP +#define TOOLS_SPRIG_ALGORITHM_STRING_HPP + +#include "./string/find.hpp" + +#endif // #ifndef TOOLS_SPRIG_ALGORITHM_STRING_HPP diff --git a/tools/sprig/algorithm/string/find.hpp b/tools/sprig/algorithm/string/find.hpp new file mode 100644 index 00000000..d4539579 --- /dev/null +++ b/tools/sprig/algorithm/string/find.hpp @@ -0,0 +1,14 @@ +/*============================================================================= + Copyright (c) 2011-2014 Bolero MURAKAMI + https://github.com/bolero-MURAKAMI/Sprout + + 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 TOOLS_SPRIG_ALGORITHM_STRING_FIND_HPP +#define TOOLS_SPRIG_ALGORITHM_STRING_FIND_HPP + +#include "./find_skip.hpp" +#include "./find_between.hpp" + +#endif // #ifndef TOOLS_SPRIG_ALGORITHM_STRING_FIND_HPP diff --git a/tools/sprig/algorithm/string/find_between.hpp b/tools/sprig/algorithm/string/find_between.hpp new file mode 100644 index 00000000..b182324c --- /dev/null +++ b/tools/sprig/algorithm/string/find_between.hpp @@ -0,0 +1,51 @@ +/*============================================================================= + Copyright (c) 2011-2014 Bolero MURAKAMI + https://github.com/bolero-MURAKAMI/Sprout + + 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 TOOLS_SPRIG_ALGORITHM_STRING_FIND_BETWEEN_HPP +#define TOOLS_SPRIG_ALGORITHM_STRING_FIND_BETWEEN_HPP + +#include +#include +#include +#include + +namespace sprig { + // + // between_finder + // + template + struct between_finderF { + private: + Finder1 finder1_; + Finder2 finder2_; + public: + between_finderF(Finder1 const& finder1, Finder2 const& finder2) + : finder1_(finder1), finder2_(finder2) + {} + template + boost::iterator_range + operator()(ForwardIterator first, ForwardIterator last) const { + first = boost::end(finder1_(first, last)); + return boost::iterator_range(first, boost::begin(finder2_(first, last))); + } + }; + template + inline sprig::between_finderF + between_finder(Finder1 const& finder1, Finder2 const& finder2) { + return sprig::between_finderF(finder1, finder2); + } + // + // find_between + // + template + inline boost::iterator_range::type> + find_between(Range& input, Finder1 const& finder1, Finder2 const& finder2) { + return boost::algorithm::find(input, sprig::between_finder(finder1, finder2)); + } +} // namespace sprig + +#endif // #ifndef TOOLS_SPRIG_ALGORITHM_STRING_FIND_BETWEEN_HPP diff --git a/tools/sprig/algorithm/string/find_skip.hpp b/tools/sprig/algorithm/string/find_skip.hpp new file mode 100644 index 00000000..72564ff5 --- /dev/null +++ b/tools/sprig/algorithm/string/find_skip.hpp @@ -0,0 +1,80 @@ +/*============================================================================= + Copyright (c) 2011-2014 Bolero MURAKAMI + https://github.com/bolero-MURAKAMI/Sprout + + 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 TOOLS_SPRIG_ALGORITHM_STRING_FIND_SKIP_HPP +#define TOOLS_SPRIG_ALGORITHM_STRING_FIND_SKIP_HPP + +#include +#include +#include +#include + +namespace sprig { + // + // skip_finder + // + template + struct skip_finderF { + private: + Finder finder_; + public: + explicit skip_finderF(Finder const& finder) + : finder_(finder) + {} + template + boost::iterator_range + operator()(ForwardIterator first, ForwardIterator last) const { + return boost::iterator_range(boost::end(finder_(first, last)), last); + } + }; + template + inline sprig::skip_finderF + skip_finder(Finder const& finder) { + return sprig::skip_finderF(finder); + } + // + // find_skip + // + template + inline boost::iterator_range::type> + find_skip(Range& input, Finder const& finder) { + return boost::algorithm::find(input, sprig::skip_finder(finder)); + } + + // + // skip_backward_finder + // + template + struct skip_backward_finderF { + private: + Finder finder_; + public: + explicit skip_backward_finderF(Finder const& finder) + : finder_(finder) + {} + template + boost::iterator_range + operator()(ForwardIterator first, ForwardIterator last) const { + return boost::iterator_range(first, boost::begin(finder_(first, last))); + } + }; + template + inline sprig::skip_backward_finderF + skip_backward_finder(Finder const& finder) { + return sprig::skip_backward_finderF(finder); + } + // + // find_skip_backward + // + template + inline boost::iterator_range::type> + find_skip_backward(Range& input, Finder const& finder) { + return boost::algorithm::find(input, sprig::skip_backward_finder(finder)); + } +} // namespace sprig + +#endif // #ifndef TOOLS_SPRIG_ALGORITHM_STRING_FIND_SKIP_HPP diff --git a/tools/sprig/graph/back_edge_recorder.hpp b/tools/sprig/graph/back_edge_recorder.hpp new file mode 100644 index 00000000..8336383c --- /dev/null +++ b/tools/sprig/graph/back_edge_recorder.hpp @@ -0,0 +1,42 @@ +/*============================================================================= + Copyright (c) 2011-2014 Bolero MURAKAMI + https://github.com/bolero-MURAKAMI/Sprout + + 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 TOOLS_SPRIG_GRAPH_BACK_EDGE_RECORDER_HPP +#define TOOLS_SPRIG_GRAPH_BACK_EDGE_RECORDER_HPP + +#include + +namespace sprig { + // + // back_edge_recorder + // + template + struct back_edge_recorder + : public boost::default_dfs_visitor + { + private: + OutputIterator out_; + public: + explicit back_edge_recorder(OutputIterator out) + : out_(out) + {} + template + void back_edge(Edge const& e, Graph const&) { + *out_++ = e; + } + }; + // + // make_back_edge_recorder + // + template + inline sprig::back_edge_recorder + make_back_edge_recorder(OutputIterator out) { + return sprig::back_edge_recorder(out); + } +} // namespace sprig + +#endif // #ifndef TOOLS_SPRIG_GRAPH_BACK_EDGE_RECORDER_HPP diff --git a/tools/sprig/graph/depth_first_search.hpp b/tools/sprig/graph/depth_first_search.hpp new file mode 100644 index 00000000..9120f7d4 --- /dev/null +++ b/tools/sprig/graph/depth_first_search.hpp @@ -0,0 +1,13 @@ +/*============================================================================= + Copyright (c) 2011-2014 Bolero MURAKAMI + https://github.com/bolero-MURAKAMI/Sprout + + 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 TOOLS_SPRIG_GRAPH_DEPTH_FIRST_SEARCH_HPP +#define TOOLS_SPRIG_GRAPH_DEPTH_FIRST_SEARCH_HPP + +#include "./back_edge_recorder.hpp" + +#endif // #ifndef TOOLS_SPRIG_GRAPH_DEPTH_FIRST_SEARCH_HPP