diff --git a/CMakeLists.txt b/CMakeLists.txt
index b1f926e..8ef6463 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -128,6 +128,7 @@ add_subdirectory(src/machinery)
add_subdirectory(lib/pbl)
add_subdirectory(lib/glob2regex)
add_subdirectory(src/backends)
+add_subdirectory(src/core)
#Actions
add_subdirectory(src/main)
diff --git a/include/dindexer-core/searchpaths.hpp b/include/dindexer-core/searchpaths.hpp
new file mode 100644
index 0000000..6ab5664
--- /dev/null
+++ b/include/dindexer-core/searchpaths.hpp
@@ -0,0 +1,66 @@
+/* Copyright 2015, 2016, Michele Santullo
+ * This file is part of "dindexer".
+ *
+ * "dindexer" is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * "dindexer" is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with "dindexer". If not, see .
+ */
+
+#ifndef idDD90110B9C7E44C4AAF8B46A663B11DC
+#define idDD90110B9C7E44C4AAF8B46A663B11DC
+
+#include
+#include
+#include
+#include
+#include
+
+namespace dincore {
+ class SearchPaths {
+ public:
+ enum SearchType {
+ Directory,
+ File,
+ Any
+ };
+ using Predicate = std::function;
+
+ SearchPaths ( void ) = default;
+ explicit SearchPaths ( std::vector&& parList );
+ SearchPaths ( std::initializer_list parInit );
+ ~SearchPaths ( void ) noexcept;
+
+ void add_path ( std::string&& parPath );
+ std::string first_hit ( boost::string_ref parFile, SearchType parType=Any ) const;
+ std::string first_hit ( Predicate parPredicate, SearchType parType=Any ) const;
+
+ private:
+ std::vector m_paths;
+ };
+
+ class ShallowSearchPaths {
+ public:
+ ShallowSearchPaths ( void ) = default;
+ explicit ShallowSearchPaths ( std::vector&& parList );
+ ShallowSearchPaths ( std::initializer_list parInit );
+ ~ShallowSearchPaths ( void ) noexcept;
+
+ void add_path ( boost::string_ref parPath );
+ std::string first_hit ( boost::string_ref parFile, SearchPaths::SearchType parType=SearchPaths::Any ) const;
+ std::string first_hit ( SearchPaths::Predicate parPredicate, SearchPaths::SearchType parType=SearchPaths::Any ) const;
+
+ private:
+ std::vector m_paths;
+ };
+} //namespace dincore
+
+#endif
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
new file mode 100644
index 0000000..fd9d26e
--- /dev/null
+++ b/src/core/CMakeLists.txt
@@ -0,0 +1,35 @@
+project(${bare_name}-core CXX)
+
+add_library(${PROJECT_NAME}
+ searchpaths.cpp
+)
+
+target_link_libraries(${PROJECT_NAME}
+ PRIVATE ${bare_name}-if
+)
+
+target_include_directories(${PROJECT_NAME}
+ PRIVATE ${DINDEXER_PUB_INCLUDE_DIR}/${bare_name}-core
+)
+
+target_compile_features(${PROJECT_NAME}
+ INTERFACE cxx_nullptr
+ INTERFACE cxx_range_for
+ INTERFACE cxx_lambdas
+ INTERFACE cxx_decltype_auto
+ INTERFACE cxx_defaulted_functions
+ INTERFACE cxx_deleted_functions
+ INTERFACE cxx_auto_type
+ INTERFACE cxx_decltype_incomplete_return_types
+ INTERFACE cxx_defaulted_move_initializers
+ INTERFACE cxx_noexcept
+ INTERFACE cxx_rvalue_references
+ INTERFACE cxx_generalized_initializers
+ INTERFACE cxx_variadic_templates
+)
+
+install(TARGETS ${PROJECT_NAME}
+ LIBRARY DESTINATION lib
+ RUNTIME DESTINATION bin
+ ARCHIVE DESTINATION lib/static
+)
diff --git a/src/core/searchpaths.cpp b/src/core/searchpaths.cpp
new file mode 100644
index 0000000..573361b
--- /dev/null
+++ b/src/core/searchpaths.cpp
@@ -0,0 +1,136 @@
+/* Copyright 2015, 2016, Michele Santullo
+ * This file is part of "dindexer".
+ *
+ * "dindexer" is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * "dindexer" is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with "dindexer". If not, see .
+ */
+
+#include "searchpaths.hpp"
+#include
+#include
+#include
+#include
+#include
+
+namespace dincore {
+ namespace {
+ const std::string& STR_to_string (const std::string& parString) {
+ return parString;
+ }
+
+ std::string STR_to_string (boost::string_ref parString) {
+ return std::string(parString.data(), parString.size());
+ }
+
+ template
+ std::string first_hit_impl (const std::vector& parPaths, SearchPaths::Predicate parPredicate, SearchPaths::SearchType parType) {
+ using boost::filesystem::path;
+ using boost::filesystem::is_directory;
+ using boost::filesystem::directory_iterator;
+ using boost::filesystem::directory_entry;
+ using boost::make_iterator_range;
+
+ for (const auto& curr_dir_path : parPaths) {
+ path curr_path(STR_to_string(curr_dir_path));
+ auto listing = make_iterator_range(directory_iterator(curr_path), directory_iterator());
+ for (const directory_entry& entry : listing) {
+ if (
+ (parType == SearchPaths::Any) or
+ (parType == SearchPaths::Directory and is_directory(entry)) or
+ (parType == SearchPaths::File and not is_directory(entry))
+ ) {
+ auto str_path = entry.path().string();
+ if (parPredicate(curr_dir_path, str_path))
+ return str_path;
+ }
+ }
+ }
+ return std::string();
+ }
+
+ //std::string make_file_path (boost::string_ref parPath, boost::string_ref parName) {
+ // assert(not parName.empty());
+ // if (parName.empty())
+ // return std::string(parPath.data(), parPath.size());
+
+ // std::string retval;
+ // const std::size_t slash = (not parPath.empty() and parPath[parPath.size() - 1] != '/' ? 1 : 0);
+ // retval.reserve(parPath.size() + parName.size() + slash);
+ // std::copy(parPath.begin(), parPath.end(), retval.begin());
+ // retval[parPath.size()] = '/';
+ // std::copy(parName.begin(), parName.end(), retval.begin() + parPath.size() + slash);
+ // return retval;
+ //}
+
+ bool is_same_filename (boost::string_ref parBaseDir, const std::string& parFullPath, boost::string_ref parFilename) {
+ assert(parBaseDir.size() < parFullPath.size());
+ return boost::string_ref(parFullPath).substr(parBaseDir.size() + 1) == parFilename;
+ }
+ } //unnamed namespace
+
+ SearchPaths::SearchPaths (std::vector&& parList) :
+ m_paths(std::move(parList))
+ {
+ }
+
+ SearchPaths::SearchPaths (std::initializer_list parInit) :
+ m_paths(parInit)
+ {
+ }
+
+ SearchPaths::~SearchPaths() noexcept = default;
+
+ void SearchPaths::add_path (std::string&& parPath) {
+ if (std::find(m_paths.begin(), m_paths.end(), parPath) == m_paths.end()) {
+ m_paths.emplace_back(std::move(parPath));
+ }
+ }
+
+ std::string SearchPaths::first_hit (boost::string_ref parFile, SearchType parType) const {
+ using std::placeholders::_1;
+ using std::placeholders::_2;
+ return first_hit_impl(m_paths, std::bind(&is_same_filename, _1, _2, parFile), parType);
+ }
+
+ std::string SearchPaths::first_hit (Predicate parPredicate, SearchType parType) const {
+ return first_hit_impl(m_paths, parPredicate, parType);
+ }
+
+ ShallowSearchPaths::ShallowSearchPaths (std::vector&& parList) :
+ m_paths(std::move(parList))
+ {
+ }
+
+ ShallowSearchPaths::ShallowSearchPaths (std::initializer_list parInit) :
+ m_paths(parInit)
+ {
+ }
+
+ ShallowSearchPaths::~ShallowSearchPaths() noexcept = default;
+
+ void ShallowSearchPaths::add_path (boost::string_ref parPath) {
+ if (std::find(m_paths.begin(), m_paths.end(), parPath) == m_paths.end()) {
+ m_paths.push_back(parPath);
+ }
+ }
+
+ std::string ShallowSearchPaths::first_hit (boost::string_ref parFile, SearchPaths::SearchType parType) const {
+ using std::placeholders::_1;
+ using std::placeholders::_2;
+ return first_hit_impl(m_paths, std::bind(&is_same_filename, _1, _2, parFile), parType);
+ }
+
+ std::string ShallowSearchPaths::first_hit (SearchPaths::Predicate parPredicate, SearchPaths::SearchType parType) const {
+ return first_hit_impl(m_paths, parPredicate, parType);
+ }
+} //namespace dincore