1 /*============================================================================= 2 Copyright (c) 2013 Daniel James 3 4 Use, modification and distribution is subject to the Boost Software 5 License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at 6 http://www.boost.org/LICENSE_1_0.txt) 7 =============================================================================*/ 8 9 #include "dependency_tracker.hpp" 10 #include <boost/filesystem/fstream.hpp> 11 #include <boost/filesystem/operations.hpp> 12 #include "for.hpp" 13 #include "path.hpp" 14 15 namespace quickbook 16 { 17 static char const* control_escapes[16] = { 18 "\\000", "\\001", "\\002", "\\003", "\\004", "\\005", "\\006", "\\a", 19 "\\b", "\\t", "\\n", "\\v", "\\f", "\\r", "\\016", "\\017"}; 20 escaped_path(std::string const & generic)21 static std::string escaped_path(std::string const& generic) 22 { 23 std::string result; 24 result.reserve(generic.size()); 25 26 QUICKBOOK_FOR (char c, generic) { 27 if (c >= 0 && c < 16) { 28 result += control_escapes[(unsigned int)c]; 29 } 30 else if (c == '\\') { 31 result += "\\\\"; 32 } 33 else if (c == 127) { 34 result += "\\177"; 35 } 36 else { 37 result += c; 38 } 39 } 40 41 return result; 42 } 43 get_path(fs::path const & path,dependency_tracker::flags f)44 static std::string get_path( 45 fs::path const& path, dependency_tracker::flags f) 46 { 47 std::string generic = quickbook::detail::path_to_generic(path); 48 49 if (f & dependency_tracker::escaped) { 50 generic = escaped_path(generic); 51 } 52 53 return generic; 54 } 55 dependency_tracker()56 dependency_tracker::dependency_tracker() 57 : dependencies() 58 , glob_dependencies() 59 , last_glob(glob_dependencies.end()) 60 { 61 } 62 add_dependency(fs::path const & f)63 bool dependency_tracker::add_dependency(fs::path const& f) 64 { 65 bool found = fs::exists(fs::status(f)); 66 dependencies[f] |= found; 67 return found; 68 } 69 add_glob(fs::path const & f)70 void dependency_tracker::add_glob(fs::path const& f) 71 { 72 std::pair<glob_list::iterator, bool> r = glob_dependencies.insert( 73 std::make_pair(f, glob_list::mapped_type())); 74 last_glob = r.first; 75 } 76 add_glob_match(fs::path const & f)77 void dependency_tracker::add_glob_match(fs::path const& f) 78 { 79 assert(last_glob != glob_dependencies.end()); 80 last_glob->second.insert(f); 81 } 82 write_dependencies(fs::path const & file_out,flags f)83 void dependency_tracker::write_dependencies( 84 fs::path const& file_out, flags f) 85 { 86 fs::ofstream out(file_out); 87 88 if (out.fail()) { 89 throw std::runtime_error( 90 "Error opening dependency file " + 91 quickbook::detail::path_to_generic(file_out)); 92 } 93 94 out.exceptions(std::ios::badbit); 95 write_dependencies(out, f); 96 } 97 write_dependencies(std::ostream & out,flags f)98 void dependency_tracker::write_dependencies(std::ostream& out, flags f) 99 { 100 if (f & checked) { 101 QUICKBOOK_FOR (dependency_list::value_type const& d, dependencies) { 102 out << (d.second ? "+ " : "- ") << get_path(d.first, f) 103 << std::endl; 104 } 105 106 QUICKBOOK_FOR (glob_list::value_type const& g, glob_dependencies) { 107 out << "g " << get_path(g.first, f) << std::endl; 108 109 QUICKBOOK_FOR (fs::path const& p, g.second) { 110 out << "+ " << get_path(p, f) << std::endl; 111 } 112 } 113 } 114 else { 115 std::set<std::string> paths; 116 117 QUICKBOOK_FOR (dependency_list::value_type const& d, dependencies) { 118 if (d.second) { 119 paths.insert(get_path(d.first, f)); 120 } 121 } 122 123 QUICKBOOK_FOR (glob_list::value_type const& g, glob_dependencies) { 124 QUICKBOOK_FOR (fs::path const& p, g.second) { 125 paths.insert(get_path(p, f)); 126 } 127 } 128 129 QUICKBOOK_FOR (std::string const& p, paths) { 130 out << p << std::endl; 131 } 132 } 133 } 134 } 135