/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmGccDepfileLexerHelper.h" #include #include #include #include #include "cmGccDepfileReaderTypes.h" #include "LexerParser/cmGccDepfileLexer.h" #ifdef _WIN32 # include "cmsys/Encoding.h" #endif bool cmGccDepfileLexerHelper::readFile(const char* filePath) { #ifdef _WIN32 wchar_t* wpath = cmsysEncoding_DupToWide(filePath); FILE* file = _wfopen(wpath, L"rb"); free(wpath); #else FILE* file = fopen(filePath, "r"); #endif if (!file) { return false; } newEntry(); yyscan_t scanner; cmGccDepfile_yylex_init(&scanner); cmGccDepfile_yyset_extra(this, scanner); cmGccDepfile_yyrestart(file, scanner); cmGccDepfile_yylex(scanner); cmGccDepfile_yylex_destroy(scanner); sanitizeContent(); fclose(file); return true; } void cmGccDepfileLexerHelper::newEntry() { this->HelperState = State::Rule; this->Content.emplace_back(); newRule(); } void cmGccDepfileLexerHelper::newRule() { auto& entry = this->Content.back(); if (entry.rules.empty() || !entry.rules.back().empty()) { entry.rules.emplace_back(); } } void cmGccDepfileLexerHelper::newDependency() { // printf("NEW DEP\n"); this->HelperState = State::Dependency; if (this->Content.back().paths.empty() || !this->Content.back().paths.back().empty()) { this->Content.back().paths.emplace_back(); } } void cmGccDepfileLexerHelper::newRuleOrDependency() { if (this->HelperState == State::Rule) { newRule(); } else { newDependency(); } } void cmGccDepfileLexerHelper::addToCurrentPath(const char* s) { if (this->Content.empty()) { return; } cmGccStyleDependency* dep = &this->Content.back(); std::string* dst = nullptr; switch (this->HelperState) { case State::Rule: { if (dep->rules.empty()) { return; } dst = &dep->rules.back(); } break; case State::Dependency: { if (dep->paths.empty()) { return; } dst = &dep->paths.back(); } break; } dst->append(s); } void cmGccDepfileLexerHelper::sanitizeContent() { for (auto it = this->Content.begin(); it != this->Content.end();) { // Remove empty rules for (auto rit = it->rules.begin(); rit != it->rules.end();) { if (rit->empty()) { rit = it->rules.erase(rit); } else { ++rit; } } // Remove the entry if rules are empty if (it->rules.empty()) { it = this->Content.erase(it); } else { // Remove empty paths for (auto pit = it->paths.begin(); pit != it->paths.end();) { if (pit->empty()) { pit = it->paths.erase(pit); } else { ++pit; } } ++it; } } }