1 /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
2 file Copyright.txt or https://cmake.org/licensing for details. */
3 #include "cmGccDepfileLexerHelper.h"
10 #include "cmGccDepfileReaderTypes.h"
12 #include "LexerParser/cmGccDepfileLexer.h"
17 # include "cmsys/Encoding.h"
20 bool cmGccDepfileLexerHelper::readFile(const char* filePath
)
23 wchar_t* wpath
= cmsysEncoding_DupToWide(filePath
);
24 FILE* file
= _wfopen(wpath
, L
"rb");
27 FILE* file
= fopen(filePath
, "r");
34 cmGccDepfile_yylex_init(&scanner
);
35 cmGccDepfile_yyset_extra(this, scanner
);
36 cmGccDepfile_yyrestart(file
, scanner
);
37 cmGccDepfile_yylex(scanner
);
38 cmGccDepfile_yylex_destroy(scanner
);
39 this->sanitizeContent();
41 return this->HelperState
!= State::Failed
;
44 void cmGccDepfileLexerHelper::newEntry()
46 if (this->HelperState
== State::Rule
&& !this->Content
.empty()) {
47 if (!this->Content
.back().rules
.empty() &&
48 !this->Content
.back().rules
.back().empty()) {
49 this->HelperState
= State::Failed
;
53 this->HelperState
= State::Rule
;
54 this->Content
.emplace_back();
58 void cmGccDepfileLexerHelper::newRule()
60 auto& entry
= this->Content
.back();
61 if (entry
.rules
.empty() || !entry
.rules
.back().empty()) {
62 entry
.rules
.emplace_back();
66 void cmGccDepfileLexerHelper::newDependency()
68 if (this->HelperState
== State::Failed
) {
71 this->HelperState
= State::Dependency
;
72 auto& entry
= this->Content
.back();
73 if (entry
.paths
.empty() || !entry
.paths
.back().empty()) {
74 entry
.paths
.emplace_back();
78 void cmGccDepfileLexerHelper::newRuleOrDependency()
80 if (this->HelperState
== State::Rule
) {
82 } else if (this->HelperState
== State::Dependency
) {
83 this->newDependency();
87 void cmGccDepfileLexerHelper::addToCurrentPath(const char* s
)
89 if (this->Content
.empty()) {
92 cmGccStyleDependency
* dep
= &this->Content
.back();
93 std::string
* dst
= nullptr;
94 switch (this->HelperState
) {
96 if (dep
->rules
.empty()) {
99 dst
= &dep
->rules
.back();
101 case State::Dependency
: {
102 if (dep
->paths
.empty()) {
105 dst
= &dep
->paths
.back();
113 void cmGccDepfileLexerHelper::sanitizeContent()
115 for (auto it
= this->Content
.begin(); it
!= this->Content
.end();) {
116 // remove duplicate path entries
117 std::sort(it
->paths
.begin(), it
->paths
.end());
118 auto last
= std::unique(it
->paths
.begin(), it
->paths
.end());
119 it
->paths
.erase(last
, it
->paths
.end());
121 // Remove empty paths and normalize windows paths
122 for (auto pit
= it
->paths
.begin(); pit
!= it
->paths
.end();) {
124 pit
= it
->paths
.erase(pit
);
127 // Unescape the colon following the drive letter.
128 // Some versions of GNU compilers can escape this character.
129 // c\:\path must be transformed to c:\path
130 if (pit
->size() >= 3 && std::toupper((*pit
)[0]) >= 'A' &&
131 std::toupper((*pit
)[0]) <= 'Z' && (*pit
)[1] == '\\' &&
139 // Remove empty rules
140 for (auto rit
= it
->rules
.begin(); rit
!= it
->rules
.end();) {
142 rit
= it
->rules
.erase(rit
);
147 // Remove the entry if rules are empty
148 if (it
->rules
.empty()) {
149 it
= this->Content
.erase(it
);