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 empty paths and normalize windows paths
117 for (auto pit = it->paths.begin(); pit != it->paths.end();) {
119 pit = it->paths.erase(pit);
122 // Unescape the colon following the drive letter.
123 // Some versions of GNU compilers can escape this character.
124 // c\:\path must be transformed to c:\path
125 if (pit->size() >= 3 && std::toupper((*pit)[0]) >= 'A' &&
126 std::toupper((*pit)[0]) <= 'Z' && (*pit)[1] == '\\' &&
134 // Remove empty rules
135 for (auto rit = it->rules.begin(); rit != it->rules.end();) {
137 rit = it->rules.erase(rit);
142 // Remove the entry if rules are empty or do not have any paths
143 if (it->rules.empty() || it->paths.empty()) {
144 it = this->Content.erase(it);