cmCacheManager.cxx 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705
  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 "cmCacheManager.h"
  4. #include <algorithm>
  5. #include <cstdio>
  6. #include <cstring>
  7. #include <sstream>
  8. #include <string>
  9. #include "cmsys/FStream.hxx"
  10. #include "cmsys/Glob.hxx"
  11. #include "cmGeneratedFileStream.h"
  12. #include "cmMessageType.h"
  13. #include "cmMessenger.h"
  14. #include "cmState.h"
  15. #include "cmStringAlgorithms.h"
  16. #include "cmSystemTools.h"
  17. #include "cmVersion.h"
  18. cmCacheManager::cmCacheManager()
  19. {
  20. this->CacheMajorVersion = 0;
  21. this->CacheMinorVersion = 0;
  22. }
  23. void cmCacheManager::CleanCMakeFiles(const std::string& path)
  24. {
  25. std::string glob = cmStrCat(path, "/CMakeFiles/*.cmake");
  26. cmsys::Glob globIt;
  27. globIt.FindFiles(glob);
  28. std::vector<std::string> files = globIt.GetFiles();
  29. std::for_each(files.begin(), files.end(), cmSystemTools::RemoveFile);
  30. }
  31. bool cmCacheManager::LoadCache(const std::string& path, bool internal,
  32. std::set<std::string>& excludes,
  33. std::set<std::string>& includes)
  34. {
  35. std::string cacheFile = cmStrCat(path, "/CMakeCache.txt");
  36. // clear the old cache, if we are reading in internal values
  37. if (internal) {
  38. this->Cache.clear();
  39. }
  40. if (!cmSystemTools::FileExists(cacheFile)) {
  41. this->CleanCMakeFiles(path);
  42. return false;
  43. }
  44. cmsys::ifstream fin(cacheFile.c_str());
  45. if (!fin) {
  46. return false;
  47. }
  48. const char* realbuffer;
  49. std::string buffer;
  50. std::string entryKey;
  51. unsigned int lineno = 0;
  52. while (fin) {
  53. // Format is key:type=value
  54. std::string helpString;
  55. CacheEntry e;
  56. cmSystemTools::GetLineFromStream(fin, buffer);
  57. lineno++;
  58. realbuffer = buffer.c_str();
  59. while (*realbuffer != '0' &&
  60. (*realbuffer == ' ' || *realbuffer == '\t' || *realbuffer == '\r' ||
  61. *realbuffer == '\n')) {
  62. if (*realbuffer == '\n') {
  63. lineno++;
  64. }
  65. realbuffer++;
  66. }
  67. // skip blank lines and comment lines
  68. if (realbuffer[0] == '#' || realbuffer[0] == 0) {
  69. continue;
  70. }
  71. while (realbuffer[0] == '/' && realbuffer[1] == '/') {
  72. if ((realbuffer[2] == '\\') && (realbuffer[3] == 'n')) {
  73. helpString += '\n';
  74. helpString += &realbuffer[4];
  75. } else {
  76. helpString += &realbuffer[2];
  77. }
  78. cmSystemTools::GetLineFromStream(fin, buffer);
  79. lineno++;
  80. realbuffer = buffer.c_str();
  81. if (!fin) {
  82. continue;
  83. }
  84. }
  85. e.SetProperty("HELPSTRING", helpString.c_str());
  86. if (cmState::ParseCacheEntry(realbuffer, entryKey, e.Value, e.Type)) {
  87. if (excludes.find(entryKey) == excludes.end()) {
  88. // Load internal values if internal is set.
  89. // If the entry is not internal to the cache being loaded
  90. // or if it is in the list of internal entries to be
  91. // imported, load it.
  92. if (internal || (e.Type != cmStateEnums::INTERNAL) ||
  93. (includes.find(entryKey) != includes.end())) {
  94. // If we are loading the cache from another project,
  95. // make all loaded entries internal so that it is
  96. // not visible in the gui
  97. if (!internal) {
  98. e.Type = cmStateEnums::INTERNAL;
  99. helpString = cmStrCat("DO NOT EDIT, ", entryKey,
  100. " loaded from external file. "
  101. "To change this value edit this file: ",
  102. path, "/CMakeCache.txt");
  103. e.SetProperty("HELPSTRING", helpString.c_str());
  104. }
  105. if (!this->ReadPropertyEntry(entryKey, e)) {
  106. e.Initialized = true;
  107. this->Cache[entryKey] = e;
  108. }
  109. }
  110. }
  111. } else {
  112. std::ostringstream error;
  113. error << "Parse error in cache file " << cacheFile << " on line "
  114. << lineno << ". Offending entry: " << realbuffer;
  115. cmSystemTools::Error(error.str());
  116. }
  117. }
  118. this->CacheMajorVersion = 0;
  119. this->CacheMinorVersion = 0;
  120. if (cmProp cmajor =
  121. this->GetInitializedCacheValue("CMAKE_CACHE_MAJOR_VERSION")) {
  122. unsigned int v = 0;
  123. if (sscanf(cmajor->c_str(), "%u", &v) == 1) {
  124. this->CacheMajorVersion = v;
  125. }
  126. if (cmProp cminor =
  127. this->GetInitializedCacheValue("CMAKE_CACHE_MINOR_VERSION")) {
  128. if (sscanf(cminor->c_str(), "%u", &v) == 1) {
  129. this->CacheMinorVersion = v;
  130. }
  131. }
  132. } else {
  133. // CMake version not found in the list file.
  134. // Set as version 0.0
  135. this->AddCacheEntry("CMAKE_CACHE_MINOR_VERSION", "0",
  136. "Minor version of cmake used to create the "
  137. "current loaded cache",
  138. cmStateEnums::INTERNAL);
  139. this->AddCacheEntry("CMAKE_CACHE_MAJOR_VERSION", "0",
  140. "Major version of cmake used to create the "
  141. "current loaded cache",
  142. cmStateEnums::INTERNAL);
  143. }
  144. // check to make sure the cache directory has not
  145. // been moved
  146. cmProp oldDir = this->GetInitializedCacheValue("CMAKE_CACHEFILE_DIR");
  147. if (internal && oldDir) {
  148. std::string currentcwd = path;
  149. std::string oldcwd = *oldDir;
  150. cmSystemTools::ConvertToUnixSlashes(currentcwd);
  151. currentcwd += "/CMakeCache.txt";
  152. oldcwd += "/CMakeCache.txt";
  153. if (!cmSystemTools::SameFile(oldcwd, currentcwd)) {
  154. cmProp dir = this->GetInitializedCacheValue("CMAKE_CACHEFILE_DIR");
  155. std::ostringstream message;
  156. message << "The current CMakeCache.txt directory " << currentcwd
  157. << " is different than the directory " << (dir ? *dir : "")
  158. << " where CMakeCache.txt was created. This may result "
  159. "in binaries being created in the wrong place. If you "
  160. "are not sure, reedit the CMakeCache.txt";
  161. cmSystemTools::Error(message.str());
  162. }
  163. }
  164. return true;
  165. }
  166. const char* cmCacheManager::PersistentProperties[] = { "ADVANCED", "MODIFIED",
  167. "STRINGS", nullptr };
  168. bool cmCacheManager::ReadPropertyEntry(std::string const& entryKey,
  169. CacheEntry& e)
  170. {
  171. // All property entries are internal.
  172. if (e.Type != cmStateEnums::INTERNAL) {
  173. return false;
  174. }
  175. const char* end = entryKey.c_str() + entryKey.size();
  176. for (const char** p = cmCacheManager::PersistentProperties; *p; ++p) {
  177. std::string::size_type plen = strlen(*p) + 1;
  178. if (entryKey.size() > plen && *(end - plen) == '-' &&
  179. strcmp(end - plen + 1, *p) == 0) {
  180. std::string key = entryKey.substr(0, entryKey.size() - plen);
  181. cmCacheManager::CacheIterator it = this->GetCacheIterator(key);
  182. if (it.IsAtEnd()) {
  183. // Create an entry and store the property.
  184. CacheEntry& ne = this->Cache[key];
  185. ne.Type = cmStateEnums::UNINITIALIZED;
  186. ne.SetProperty(*p, e.Value.c_str());
  187. } else {
  188. // Store this property on its entry.
  189. it.SetProperty(*p, e.Value.c_str());
  190. }
  191. return true;
  192. }
  193. }
  194. return false;
  195. }
  196. void cmCacheManager::WritePropertyEntries(std::ostream& os, CacheIterator i,
  197. cmMessenger* messenger)
  198. {
  199. for (const char** p = cmCacheManager::PersistentProperties; *p; ++p) {
  200. if (cmProp value = i.GetProperty(*p)) {
  201. std::string helpstring =
  202. cmStrCat(*p, " property for variable: ", i.GetName());
  203. cmCacheManager::OutputHelpString(os, helpstring);
  204. std::string key = cmStrCat(i.GetName(), '-', *p);
  205. cmCacheManager::OutputKey(os, key);
  206. os << ":INTERNAL=";
  207. cmCacheManager::OutputValue(os, *value);
  208. os << '\n';
  209. cmCacheManager::OutputNewlineTruncationWarning(os, key, *value,
  210. messenger);
  211. }
  212. }
  213. }
  214. bool cmCacheManager::SaveCache(const std::string& path, cmMessenger* messenger)
  215. {
  216. std::string cacheFile = cmStrCat(path, "/CMakeCache.txt");
  217. cmGeneratedFileStream fout(cacheFile);
  218. fout.SetCopyIfDifferent(true);
  219. if (!fout) {
  220. cmSystemTools::Error("Unable to open cache file for save. " + cacheFile);
  221. cmSystemTools::ReportLastSystemError("");
  222. return false;
  223. }
  224. // before writing the cache, update the version numbers
  225. // to the
  226. this->AddCacheEntry("CMAKE_CACHE_MAJOR_VERSION",
  227. std::to_string(cmVersion::GetMajorVersion()).c_str(),
  228. "Major version of cmake used to create the "
  229. "current loaded cache",
  230. cmStateEnums::INTERNAL);
  231. this->AddCacheEntry("CMAKE_CACHE_MINOR_VERSION",
  232. std::to_string(cmVersion::GetMinorVersion()).c_str(),
  233. "Minor version of cmake used to create the "
  234. "current loaded cache",
  235. cmStateEnums::INTERNAL);
  236. this->AddCacheEntry("CMAKE_CACHE_PATCH_VERSION",
  237. std::to_string(cmVersion::GetPatchVersion()).c_str(),
  238. "Patch version of cmake used to create the "
  239. "current loaded cache",
  240. cmStateEnums::INTERNAL);
  241. // Let us store the current working directory so that if somebody
  242. // Copies it, he will not be surprised
  243. std::string currentcwd = path;
  244. if (currentcwd[0] >= 'A' && currentcwd[0] <= 'Z' && currentcwd[1] == ':') {
  245. // Cast added to avoid compiler warning. Cast is ok because
  246. // value is guaranteed to fit in char by the above if...
  247. currentcwd[0] = static_cast<char>(currentcwd[0] - 'A' + 'a');
  248. }
  249. cmSystemTools::ConvertToUnixSlashes(currentcwd);
  250. this->AddCacheEntry("CMAKE_CACHEFILE_DIR", currentcwd.c_str(),
  251. "This is the directory where this CMakeCache.txt"
  252. " was created",
  253. cmStateEnums::INTERNAL);
  254. /* clang-format off */
  255. fout << "# This is the CMakeCache file.\n"
  256. "# For build in directory: " << currentcwd << "\n"
  257. "# It was generated by CMake: "
  258. << cmSystemTools::GetCMakeCommand()
  259. << "\n"
  260. "# You can edit this file to change values found and used by cmake."
  261. "\n"
  262. "# If you do not want to change any of the values, simply exit the "
  263. "editor.\n"
  264. "# If you do want to change a value, simply edit, save, and exit "
  265. "the editor.\n"
  266. "# The syntax for the file is as follows:\n"
  267. "# KEY:TYPE=VALUE\n"
  268. "# KEY is the name of a variable in the cache.\n"
  269. "# TYPE is a hint to GUIs for the type of VALUE, DO NOT EDIT TYPE!."
  270. "\n"
  271. "# VALUE is the current value for the KEY.\n"
  272. "\n"
  273. "########################\n"
  274. "# EXTERNAL cache entries\n"
  275. "########################\n"
  276. "\n";
  277. /* clang-format on */
  278. for (auto const& i : this->Cache) {
  279. CacheEntry const& ce = i.second;
  280. cmStateEnums::CacheEntryType t = ce.Type;
  281. if (!ce.Initialized) {
  282. /*
  283. // This should be added in, but is not for now.
  284. cmSystemTools::Error("Cache entry \"" + i.first + "\" is uninitialized");
  285. */
  286. } else if (t != cmStateEnums::INTERNAL) {
  287. // Format is key:type=value
  288. if (cmProp help = ce.GetProperty("HELPSTRING")) {
  289. cmCacheManager::OutputHelpString(fout, *help);
  290. } else {
  291. cmCacheManager::OutputHelpString(fout, "Missing description");
  292. }
  293. cmCacheManager::OutputKey(fout, i.first);
  294. fout << ':' << cmState::CacheEntryTypeToString(t) << '=';
  295. cmCacheManager::OutputValue(fout, ce.Value);
  296. fout << '\n';
  297. cmCacheManager::OutputNewlineTruncationWarning(fout, i.first, ce.Value,
  298. messenger);
  299. fout << '\n';
  300. }
  301. }
  302. fout << "\n"
  303. "########################\n"
  304. "# INTERNAL cache entries\n"
  305. "########################\n"
  306. "\n";
  307. for (cmCacheManager::CacheIterator i = this->NewIterator(); !i.IsAtEnd();
  308. i.Next()) {
  309. if (!i.Initialized()) {
  310. continue;
  311. }
  312. cmStateEnums::CacheEntryType t = i.GetType();
  313. this->WritePropertyEntries(fout, i, messenger);
  314. if (t == cmStateEnums::INTERNAL) {
  315. // Format is key:type=value
  316. if (cmProp help = i.GetProperty("HELPSTRING")) {
  317. cmCacheManager::OutputHelpString(fout, *help);
  318. }
  319. cmCacheManager::OutputKey(fout, i.GetName());
  320. fout << ':' << cmState::CacheEntryTypeToString(t) << '=';
  321. cmCacheManager::OutputValue(fout, i.GetValue());
  322. fout << '\n';
  323. cmCacheManager::OutputNewlineTruncationWarning(fout, i.GetName(),
  324. i.GetValue(), messenger);
  325. }
  326. }
  327. fout << '\n';
  328. fout.Close();
  329. std::string checkCacheFile = cmStrCat(path, "/CMakeFiles");
  330. cmSystemTools::MakeDirectory(checkCacheFile);
  331. checkCacheFile += "/cmake.check_cache";
  332. cmsys::ofstream checkCache(checkCacheFile.c_str());
  333. if (!checkCache) {
  334. cmSystemTools::Error("Unable to open check cache file for write. " +
  335. checkCacheFile);
  336. return false;
  337. }
  338. checkCache << "# This file is generated by cmake for dependency checking "
  339. "of the CMakeCache.txt file\n";
  340. return true;
  341. }
  342. bool cmCacheManager::DeleteCache(const std::string& path)
  343. {
  344. std::string cacheFile = path;
  345. cmSystemTools::ConvertToUnixSlashes(cacheFile);
  346. std::string cmakeFiles = cacheFile;
  347. cacheFile += "/CMakeCache.txt";
  348. if (cmSystemTools::FileExists(cacheFile)) {
  349. cmSystemTools::RemoveFile(cacheFile);
  350. // now remove the files in the CMakeFiles directory
  351. // this cleans up language cache files
  352. cmakeFiles += "/CMakeFiles";
  353. if (cmSystemTools::FileIsDirectory(cmakeFiles)) {
  354. cmSystemTools::RemoveADirectory(cmakeFiles);
  355. }
  356. }
  357. return true;
  358. }
  359. void cmCacheManager::OutputKey(std::ostream& fout, std::string const& key)
  360. {
  361. // support : in key name by double quoting
  362. const char* q =
  363. (key.find(':') != std::string::npos || cmHasLiteralPrefix(key, "//"))
  364. ? "\""
  365. : "";
  366. fout << q << key << q;
  367. }
  368. void cmCacheManager::OutputValue(std::ostream& fout, std::string const& value)
  369. {
  370. // look for and truncate newlines
  371. std::string::size_type newline = value.find('\n');
  372. if (newline != std::string::npos) {
  373. std::string truncated = value.substr(0, newline);
  374. OutputValueNoNewlines(fout, truncated);
  375. } else {
  376. OutputValueNoNewlines(fout, value);
  377. }
  378. }
  379. void cmCacheManager::OutputValueNoNewlines(std::ostream& fout,
  380. std::string const& value)
  381. {
  382. // if value has trailing space or tab, enclose it in single quotes
  383. if (!value.empty() && (value.back() == ' ' || value.back() == '\t')) {
  384. fout << '\'' << value << '\'';
  385. } else {
  386. fout << value;
  387. }
  388. }
  389. void cmCacheManager::OutputHelpString(std::ostream& fout,
  390. const std::string& helpString)
  391. {
  392. std::string::size_type end = helpString.size();
  393. if (end == 0) {
  394. return;
  395. }
  396. std::string oneLine;
  397. std::string::size_type pos = 0;
  398. for (std::string::size_type i = 0; i <= end; i++) {
  399. if ((i == end) || (helpString[i] == '\n') ||
  400. ((i - pos >= 60) && (helpString[i] == ' '))) {
  401. fout << "//";
  402. if (helpString[pos] == '\n') {
  403. pos++;
  404. fout << "\\n";
  405. }
  406. oneLine = helpString.substr(pos, i - pos);
  407. fout << oneLine << '\n';
  408. pos = i;
  409. }
  410. }
  411. }
  412. void cmCacheManager::OutputWarningComment(std::ostream& fout,
  413. std::string const& message,
  414. bool wrapSpaces)
  415. {
  416. std::string::size_type end = message.size();
  417. std::string oneLine;
  418. std::string::size_type pos = 0;
  419. for (std::string::size_type i = 0; i <= end; i++) {
  420. if ((i == end) || (message[i] == '\n') ||
  421. ((i - pos >= 60) && (message[i] == ' ') && wrapSpaces)) {
  422. fout << "# ";
  423. if (message[pos] == '\n') {
  424. pos++;
  425. fout << "\\n";
  426. }
  427. oneLine = message.substr(pos, i - pos);
  428. fout << oneLine << '\n';
  429. pos = i;
  430. }
  431. }
  432. }
  433. void cmCacheManager::OutputNewlineTruncationWarning(std::ostream& fout,
  434. std::string const& key,
  435. std::string const& value,
  436. cmMessenger* messenger)
  437. {
  438. if (value.find('\n') != std::string::npos) {
  439. if (messenger) {
  440. std::string message =
  441. cmStrCat("Value of ", key, " contained a newline; truncating");
  442. messenger->IssueMessage(MessageType::WARNING, message);
  443. }
  444. std::string comment =
  445. cmStrCat("WARNING: Value of ", key,
  446. " contained a newline and was truncated. Original value:");
  447. OutputWarningComment(fout, comment, true);
  448. OutputWarningComment(fout, value, false);
  449. }
  450. }
  451. void cmCacheManager::RemoveCacheEntry(const std::string& key)
  452. {
  453. auto i = this->Cache.find(key);
  454. if (i != this->Cache.end()) {
  455. this->Cache.erase(i);
  456. }
  457. }
  458. cmCacheManager::CacheEntry* cmCacheManager::GetCacheEntry(
  459. const std::string& key)
  460. {
  461. auto i = this->Cache.find(key);
  462. if (i != this->Cache.end()) {
  463. return &i->second;
  464. }
  465. return nullptr;
  466. }
  467. cmCacheManager::CacheIterator cmCacheManager::GetCacheIterator(
  468. const std::string& key)
  469. {
  470. return { *this, key.c_str() };
  471. }
  472. cmCacheManager::CacheIterator cmCacheManager::GetCacheIterator()
  473. {
  474. return { *this, nullptr };
  475. }
  476. cmProp cmCacheManager::GetInitializedCacheValue(const std::string& key) const
  477. {
  478. auto i = this->Cache.find(key);
  479. if (i != this->Cache.end() && i->second.Initialized) {
  480. return &i->second.Value;
  481. }
  482. return nullptr;
  483. }
  484. void cmCacheManager::PrintCache(std::ostream& out) const
  485. {
  486. out << "=================================================\n"
  487. "CMakeCache Contents:\n";
  488. for (auto const& i : this->Cache) {
  489. if (i.second.Type != cmStateEnums::INTERNAL) {
  490. out << i.first << " = " << i.second.Value << '\n';
  491. }
  492. }
  493. out << "\n\n"
  494. "To change values in the CMakeCache, \n"
  495. "edit CMakeCache.txt in your output directory.\n"
  496. "=================================================\n";
  497. }
  498. void cmCacheManager::AddCacheEntry(const std::string& key, const char* value,
  499. const char* helpString,
  500. cmStateEnums::CacheEntryType type)
  501. {
  502. CacheEntry& e = this->Cache[key];
  503. if (value) {
  504. e.Value = value;
  505. e.Initialized = true;
  506. } else {
  507. e.Value.clear();
  508. }
  509. e.Type = type;
  510. // make sure we only use unix style paths
  511. if (type == cmStateEnums::FILEPATH || type == cmStateEnums::PATH) {
  512. if (e.Value.find(';') != std::string::npos) {
  513. std::vector<std::string> paths = cmExpandedList(e.Value);
  514. const char* sep = "";
  515. e.Value = "";
  516. for (std::string& i : paths) {
  517. cmSystemTools::ConvertToUnixSlashes(i);
  518. e.Value += sep;
  519. e.Value += i;
  520. sep = ";";
  521. }
  522. } else {
  523. cmSystemTools::ConvertToUnixSlashes(e.Value);
  524. }
  525. }
  526. e.SetProperty("HELPSTRING",
  527. helpString
  528. ? helpString
  529. : "(This variable does not exist and should not be used)");
  530. }
  531. bool cmCacheManager::CacheIterator::IsAtEnd() const
  532. {
  533. return this->Position == this->Container.Cache.end();
  534. }
  535. void cmCacheManager::CacheIterator::Begin()
  536. {
  537. this->Position = this->Container.Cache.begin();
  538. }
  539. bool cmCacheManager::CacheIterator::Find(const std::string& key)
  540. {
  541. this->Position = this->Container.Cache.find(key);
  542. return !this->IsAtEnd();
  543. }
  544. void cmCacheManager::CacheIterator::Next()
  545. {
  546. if (!this->IsAtEnd()) {
  547. ++this->Position;
  548. }
  549. }
  550. std::vector<std::string> cmCacheManager::CacheIterator::GetPropertyList() const
  551. {
  552. return this->GetEntry().GetPropertyList();
  553. }
  554. void cmCacheManager::CacheIterator::SetValue(const char* value)
  555. {
  556. if (this->IsAtEnd()) {
  557. return;
  558. }
  559. CacheEntry* entry = &this->GetEntry();
  560. if (value) {
  561. entry->Value = value;
  562. entry->Initialized = true;
  563. } else {
  564. entry->Value.clear();
  565. }
  566. }
  567. bool cmCacheManager::CacheIterator::GetValueAsBool() const
  568. {
  569. return cmIsOn(this->GetEntry().Value);
  570. }
  571. std::vector<std::string> cmCacheManager::CacheEntry::GetPropertyList() const
  572. {
  573. return this->Properties.GetKeys();
  574. }
  575. cmProp cmCacheManager::CacheEntry::GetProperty(const std::string& prop) const
  576. {
  577. if (prop == "TYPE") {
  578. return &cmState::CacheEntryTypeToString(this->Type);
  579. }
  580. if (prop == "VALUE") {
  581. return &this->Value;
  582. }
  583. return this->Properties.GetPropertyValue(prop);
  584. }
  585. void cmCacheManager::CacheEntry::SetProperty(const std::string& prop,
  586. const char* value)
  587. {
  588. if (prop == "TYPE") {
  589. this->Type = cmState::StringToCacheEntryType(value ? value : "STRING");
  590. } else if (prop == "VALUE") {
  591. this->Value = value ? value : "";
  592. } else {
  593. this->Properties.SetProperty(prop, value);
  594. }
  595. }
  596. void cmCacheManager::CacheEntry::AppendProperty(const std::string& prop,
  597. const std::string& value,
  598. bool asString)
  599. {
  600. if (prop == "TYPE") {
  601. this->Type =
  602. cmState::StringToCacheEntryType(!value.empty() ? value : "STRING");
  603. } else if (prop == "VALUE") {
  604. if (!value.empty()) {
  605. if (!this->Value.empty() && !asString) {
  606. this->Value += ";";
  607. }
  608. this->Value += value;
  609. }
  610. } else {
  611. this->Properties.AppendProperty(prop, value, asString);
  612. }
  613. }
  614. cmProp cmCacheManager::CacheIterator::GetProperty(
  615. const std::string& prop) const
  616. {
  617. if (!this->IsAtEnd()) {
  618. return this->GetEntry().GetProperty(prop);
  619. }
  620. return nullptr;
  621. }
  622. void cmCacheManager::CacheIterator::SetProperty(const std::string& p,
  623. const char* v)
  624. {
  625. if (!this->IsAtEnd()) {
  626. this->GetEntry().SetProperty(p, v);
  627. }
  628. }
  629. void cmCacheManager::CacheIterator::AppendProperty(const std::string& p,
  630. const std::string& v,
  631. bool asString)
  632. {
  633. if (!this->IsAtEnd()) {
  634. this->GetEntry().AppendProperty(p, v, asString);
  635. }
  636. }
  637. bool cmCacheManager::CacheIterator::GetPropertyAsBool(
  638. const std::string& prop) const
  639. {
  640. if (cmProp value = this->GetProperty(prop)) {
  641. return cmIsOn(*value);
  642. }
  643. return false;
  644. }
  645. void cmCacheManager::CacheIterator::SetProperty(const std::string& p, bool v)
  646. {
  647. this->SetProperty(p, v ? "ON" : "OFF");
  648. }
  649. bool cmCacheManager::CacheIterator::PropertyExists(
  650. const std::string& prop) const
  651. {
  652. return this->GetProperty(prop) != nullptr;
  653. }