summaryrefslogtreecommitdiffstats
path: root/src/boost/tools/quickbook/src/dependency_tracker.cpp
blob: 5f50352b1815d254a55236708aff1f9a23385224 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
/*=============================================================================
    Copyright (c) 2013 Daniel James

    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)
=============================================================================*/

#include "dependency_tracker.hpp"
#include <boost/filesystem/fstream.hpp>
#include <boost/filesystem/operations.hpp>
#include "for.hpp"
#include "path.hpp"

namespace quickbook
{
    static char const* control_escapes[16] = {
        "\\000", "\\001", "\\002", "\\003", "\\004", "\\005", "\\006", "\\a",
        "\\b",   "\\t",   "\\n",   "\\v",   "\\f",   "\\r",   "\\016", "\\017"};

    static std::string escaped_path(std::string const& generic)
    {
        std::string result;
        result.reserve(generic.size());

        QUICKBOOK_FOR (char c, generic) {
            if (c >= 0 && c < 16) {
                result += control_escapes[(unsigned int)c];
            }
            else if (c == '\\') {
                result += "\\\\";
            }
            else if (c == 127) {
                result += "\\177";
            }
            else {
                result += c;
            }
        }

        return result;
    }

    static std::string get_path(
        fs::path const& path, dependency_tracker::flags f)
    {
        std::string generic = quickbook::detail::path_to_generic(path);

        if (f & dependency_tracker::escaped) {
            generic = escaped_path(generic);
        }

        return generic;
    }

    dependency_tracker::dependency_tracker()
        : dependencies()
        , glob_dependencies()
        , last_glob(glob_dependencies.end())
    {
    }

    bool dependency_tracker::add_dependency(fs::path const& f)
    {
        bool found = fs::exists(fs::status(f));
        dependencies[f] |= found;
        return found;
    }

    void dependency_tracker::add_glob(fs::path const& f)
    {
        std::pair<glob_list::iterator, bool> r = glob_dependencies.insert(
            std::make_pair(f, glob_list::mapped_type()));
        last_glob = r.first;
    }

    void dependency_tracker::add_glob_match(fs::path const& f)
    {
        assert(last_glob != glob_dependencies.end());
        last_glob->second.insert(f);
    }

    void dependency_tracker::write_dependencies(
        fs::path const& file_out, flags f)
    {
        fs::ofstream out(file_out);

        if (out.fail()) {
            throw std::runtime_error(
                "Error opening dependency file " +
                quickbook::detail::path_to_generic(file_out));
        }

        out.exceptions(std::ios::badbit);
        write_dependencies(out, f);
    }

    void dependency_tracker::write_dependencies(std::ostream& out, flags f)
    {
        if (f & checked) {
            QUICKBOOK_FOR (dependency_list::value_type const& d, dependencies) {
                out << (d.second ? "+ " : "- ") << get_path(d.first, f)
                    << std::endl;
            }

            QUICKBOOK_FOR (glob_list::value_type const& g, glob_dependencies) {
                out << "g " << get_path(g.first, f) << std::endl;

                QUICKBOOK_FOR (fs::path const& p, g.second) {
                    out << "+ " << get_path(p, f) << std::endl;
                }
            }
        }
        else {
            std::set<std::string> paths;

            QUICKBOOK_FOR (dependency_list::value_type const& d, dependencies) {
                if (d.second) {
                    paths.insert(get_path(d.first, f));
                }
            }

            QUICKBOOK_FOR (glob_list::value_type const& g, glob_dependencies) {
                QUICKBOOK_FOR (fs::path const& p, g.second) {
                    paths.insert(get_path(p, f));
                }
            }

            QUICKBOOK_FOR (std::string const& p, paths) {
                out << p << std::endl;
            }
        }
    }
}