/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmIDEOptions.h" #include #include #include #include #include #include "cmsys/String.h" #include "cmIDEFlagTable.h" #include "cmList.h" #include "cmStringAlgorithms.h" cmIDEOptions::cmIDEOptions() { this->DoingDefine = false; this->AllowDefine = true; this->DoingInclude = false; this->AllowSlash = false; this->DoingFollowing = nullptr; for (auto& flag : this->FlagTable) { flag = nullptr; } } cmIDEOptions::~cmIDEOptions() = default; void cmIDEOptions::HandleFlag(std::string const& flag) { // If the last option was -D then this option is the definition. if (this->DoingDefine) { this->DoingDefine = false; this->Defines.push_back(flag); return; } // If the last option was -I then this option is the include directory. if (this->DoingInclude) { this->DoingInclude = false; this->Includes.push_back(flag); return; } // If the last option expected a following value, this is it. if (this->DoingFollowing) { this->FlagMapUpdate(this->DoingFollowing, flag); this->DoingFollowing = nullptr; return; } // Look for known arguments. size_t len = flag.length(); if (len > 0 && (flag[0] == '-' || (this->AllowSlash && flag[0] == '/'))) { // Look for preprocessor definitions. if (this->AllowDefine && len > 1 && flag[1] == 'D') { if (len <= 2) { // The next argument will have the definition. this->DoingDefine = true; } else { // Store this definition. this->Defines.push_back(flag.substr(2)); } return; } // Look for include directory. if (this->AllowInclude && len > 1 && flag[1] == 'I') { if (len <= 2) { // The next argument will have the include directory. this->DoingInclude = true; } else { // Store this include directory. this->Includes.push_back(flag.substr(2)); } return; } // Look through the available flag tables. bool flag_handled = false; for (int i = 0; i < FlagTableCount && this->FlagTable[i]; ++i) { if (this->CheckFlagTable(this->FlagTable[i], flag, flag_handled)) { return; } } // If any map entry handled the flag we are done. if (flag_handled) { return; } } // This option is not known. Store it in the output flags. this->StoreUnknownFlag(flag); } bool cmIDEOptions::CheckFlagTable(cmIDEFlagTable const* table, std::string const& flag, bool& flag_handled) { const char* pf = flag.c_str() + 1; // Look for an entry in the flag table matching this flag. for (cmIDEFlagTable const* entry = table; !entry->IDEName.empty(); ++entry) { bool entry_found = false; if (entry->special & cmIDEFlagTable::UserValue) { // This flag table entry accepts a user-specified value. If // the entry specifies UserRequired we must match only if a // non-empty value is given. int n = static_cast(entry->commandFlag.length()); if ((strncmp(pf, entry->commandFlag.c_str(), n) == 0 || (entry->special & cmIDEFlagTable::CaseInsensitive && cmsysString_strncasecmp(pf, entry->commandFlag.c_str(), n))) && (!(entry->special & cmIDEFlagTable::UserRequired) || static_cast(strlen(pf)) > n)) { this->FlagMapUpdate(entry, std::string(pf + n)); entry_found = true; } } else if (strcmp(pf, entry->commandFlag.c_str()) == 0 || (entry->special & cmIDEFlagTable::CaseInsensitive && cmsysString_strcasecmp(pf, entry->commandFlag.c_str()) == 0)) { if (entry->special & cmIDEFlagTable::UserFollowing) { // This flag expects a value in the following argument. this->DoingFollowing = entry; } else { // This flag table entry provides a fixed value. this->FlagMap[entry->IDEName] = entry->value; } entry_found = true; } // If the flag has been handled by an entry not requesting a // search continuation we are done. if (entry_found && !(entry->special & cmIDEFlagTable::Continue)) { return true; } // If the entry was found the flag has been handled. flag_handled = flag_handled || entry_found; } return false; } void cmIDEOptions::FlagMapUpdate(cmIDEFlagTable const* entry, std::string const& new_value) { if (entry->special & cmIDEFlagTable::UserIgnored) { // Ignore the user-specified value. this->FlagMap[entry->IDEName] = entry->value; } else if (entry->special & cmIDEFlagTable::SemicolonAppendable) { this->FlagMap[entry->IDEName].push_back(new_value); } else if (entry->special & cmIDEFlagTable::SpaceAppendable) { this->FlagMap[entry->IDEName].append_with_space(new_value); } else if (entry->special & cmIDEFlagTable::CommaAppendable) { this->FlagMap[entry->IDEName].append_with_comma(new_value); } else { // Use the user-specified value. this->FlagMap[entry->IDEName] = new_value; } } void cmIDEOptions::AddDefine(const std::string& def) { this->Defines.push_back(def); } void cmIDEOptions::AddDefines(std::string const& defines) { if (!defines.empty()) { // Expand the list of definitions. cmExpandList(defines, this->Defines); } } void cmIDEOptions::AddDefines(const std::vector& defines) { cm::append(this->Defines, defines); } std::vector const& cmIDEOptions::GetDefines() const { return this->Defines; } void cmIDEOptions::AddInclude(const std::string& include) { this->Includes.push_back(include); } void cmIDEOptions::AddIncludes(std::string const& includes) { if (!includes.empty()) { // Expand the list of includes. cmExpandList(includes, this->Includes); } } void cmIDEOptions::AddIncludes(const std::vector& includes) { cm::append(this->Includes, includes); } std::vector const& cmIDEOptions::GetIncludes() const { return this->Includes; } void cmIDEOptions::AddFlag(std::string const& flag, std::string const& value) { this->FlagMap[flag] = value; } void cmIDEOptions::AddFlag(std::string const& flag, std::vector const& value) { this->FlagMap[flag] = value; } void cmIDEOptions::AppendFlag(std::string const& flag, std::string const& value) { this->FlagMap[flag].push_back(value); } void cmIDEOptions::AppendFlag(std::string const& flag, std::vector const& value) { FlagValue& fv = this->FlagMap[flag]; std::copy(value.begin(), value.end(), std::back_inserter(fv)); } void cmIDEOptions::AppendFlagString(std::string const& flag, std::string const& value) { this->FlagMap[flag].append_with_space(value); } void cmIDEOptions::RemoveFlag(std::string const& flag) { this->FlagMap.erase(flag); } bool cmIDEOptions::HasFlag(std::string const& flag) const { return this->FlagMap.find(flag) != this->FlagMap.end(); } const char* cmIDEOptions::GetFlag(std::string const& flag) const { // This method works only for single-valued flags! auto i = this->FlagMap.find(flag); if (i != this->FlagMap.cend() && i->second.size() == 1) { return i->second[0].c_str(); } return nullptr; }