summaryrefslogtreecommitdiff
path: root/src/deps.cc
blob: 9400b352dca9021f1622b2b76c556d4790fbb7eb (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
// -*- c++ -*-
// Distributed under the BSD 2-Clause License.
// See accompanying file LICENSE for details.
#include "deps.h"

#include "util.h"

#include <fstream>

namespace {
/* Format example:
build/src/libctor_a-libctor_cc.o: src/libctor.cc \
 src/getoptpp/getoptpp.hpp src/ctor.h src/configure.h src/rebuild.h \
 src/A\ B\ C.h src/task.h src/build.h src/unittest.h
 */
std::vector<std::string> readDepsMake(const std::string& dep_file)
{
	auto str = readFile(dep_file);

	std::vector<std::string> output;
	std::string tmp;

	enum class State
	{
		pre_colon,
		post_colon,
		in_escape,
	} state{State::pre_colon};

	auto old_state{state};
	for(const auto& c : str)
	{
		if(c == '\r')
		{
			// just always ignore windows extra newline char
			continue;
		}

		switch(state)
		{
		case State::pre_colon:
			if(c == ':') // ignore everything until the colon
			{
				state = State::post_colon;
				continue;
			}
			continue;

		case State::post_colon:
			if(c == '\n')
			{
				// done
				if(!tmp.empty())
				{
					output.emplace_back(tmp);
				}
				return output;
			}
			if(c == '\\')
			{
				old_state = state;
				state = State::in_escape;
				continue;
			}
			if(c == '\t' || c == ' ') // new token
			{
				if(!tmp.empty())
				{
					output.emplace_back(tmp);
				}
				tmp.clear();
				continue;
			}
			break;

		case State::in_escape:
			if(c == '\n')
			{
				// linewrap
				state = old_state;
				continue;
			}
			state = old_state;
			break;
		}

		tmp += c;
	}

	if(!tmp.empty())
	{
		output.emplace_back(tmp);
	}

	return output;
}
}

std::vector<std::string> readDeps(const std::string& dep_file,
                                  ctor::toolchain toolchain)
{
	if(!std::filesystem::exists(dep_file))
	{
		return {};
	}

	switch(toolchain)
	{
	case ctor::toolchain::any:
	case ctor::toolchain::none:
		return {};

	// makefile .d file based:
	case ctor::toolchain::gcc:
	case ctor::toolchain::clang:
		return readDepsMake(dep_file);
	}

	return {};
}