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;
  114. error << " on line " << 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() << std::endl;
  259. /* clang-format on */
  260. /* clang-format off */
  261. fout << "# You can edit this file to change values found and used by cmake."
  262. << std::endl
  263. << "# If you do not want to change any of the values, simply exit the "
  264. "editor." << std::endl
  265. << "# If you do want to change a value, simply edit, save, and exit "
  266. "the editor." << std::endl
  267. << "# The syntax for the file is as follows:\n"
  268. << "# KEY:TYPE=VALUE\n"
  269. << "# KEY is the name of a variable in the cache.\n"
  270. << "# TYPE is a hint to GUIs for the type of VALUE, DO NOT EDIT "
  271. "TYPE!." << std::endl
  272. << "# VALUE is the current value for the KEY.\n\n";
  273. /* clang-format on */
  274. fout << "########################\n";
  275. fout << "# EXTERNAL cache entries\n";
  276. fout << "########################\n";
  277. fout << "\n";
  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. fout << "########################\n";
  304. fout << "# INTERNAL cache entries\n";
  305. fout << "########################\n";
  306. fout << "\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 || key.find("//") == 0) ? "\"" : "";
  364. fout << q << key << q;
  365. }
  366. void cmCacheManager::OutputValue(std::ostream& fout, std::string const& value)
  367. {
  368. // look for and truncate newlines
  369. std::string::size_type newline = value.find('\n');
  370. if (newline != std::string::npos) {
  371. std::string truncated = value.substr(0, newline);
  372. OutputValueNoNewlines(fout, truncated);
  373. } else {
  374. OutputValueNoNewlines(fout, value);
  375. }
  376. }
  377. void cmCacheManager::OutputValueNoNewlines(std::ostream& fout,
  378. std::string const& value)
  379. {
  380. // if value has trailing space or tab, enclose it in single quotes
  381. if (!value.empty() && (value.back() == ' ' || value.back() == '\t')) {
  382. fout << '\'' << value << '\'';
  383. } else {
  384. fout << value;
  385. }
  386. }
  387. void cmCacheManager::OutputHelpString(std::ostream& fout,
  388. const std::string& helpString)
  389. {
  390. std::string::size_type end = helpString.size();
  391. if (end == 0) {
  392. return;
  393. }
  394. std::string oneLine;
  395. std::string::size_type pos = 0;
  396. for (std::string::size_type i = 0; i <= end; i++) {
  397. if ((i == end) || (helpString[i] == '\n') ||
  398. ((i - pos >= 60) && (helpString[i] == ' '))) {
  399. fout << "//";
  400. if (helpString[pos] == '\n') {
  401. pos++;
  402. fout << "\\n";
  403. }
  404. oneLine = helpString.substr(pos, i - pos);
  405. fout << oneLine << "\n";
  406. pos = i;
  407. }
  408. }
  409. }
  410. void cmCacheManager::OutputWarningComment(std::ostream& fout,
  411. std::string const& message,
  412. bool wrapSpaces)
  413. {
  414. std::string::size_type end = message.size();
  415. std::string oneLine;
  416. std::string::size_type pos = 0;
  417. for (std::string::size_type i = 0; i <= end; i++) {
  418. if ((i == end) || (message[i] == '\n') ||
  419. ((i - pos >= 60) && (message[i] == ' ') && wrapSpaces)) {
  420. fout << "# ";
  421. if (message[pos] == '\n') {
  422. pos++;
  423. fout << "\\n";
  424. }
  425. oneLine = message.substr(pos, i - pos);
  426. fout << oneLine << "\n";
  427. pos = i;
  428. }
  429. }
  430. }
  431. void cmCacheManager::OutputNewlineTruncationWarning(std::ostream& fout,
  432. std::string const& key,
  433. std::string const& value,
  434. cmMessenger* messenger)
  435. {
  436. if (value.find('\n') != std::string::npos) {
  437. if (messenger) {
  438. std::string message =
  439. cmStrCat("Value of ", key, " contained a newline; truncating");
  440. messenger->IssueMessage(MessageType::WARNING, message);
  441. }
  442. std::string comment =
  443. cmStrCat("WARNING: Value of ", key,
  444. " contained a newline and was truncated. Original value:");
  445. OutputWarningComment(fout, comment, true);
  446. OutputWarningComment(fout, value, false);
  447. }
  448. }
  449. void cmCacheManager::RemoveCacheEntry(const std::string& key)
  450. {
  451. auto i = this->Cache.find(key);
  452. if (i != this->Cache.end()) {
  453. this->Cache.erase(i);
  454. }
  455. }
  456. cmCacheManager::CacheEntry* cmCacheManager::GetCacheEntry(
  457. const std::string& key)
  458. {
  459. auto i = this->Cache.find(key);
  460. if (i != this->Cache.end()) {
  461. return &i->second;
  462. }
  463. return nullptr;
  464. }
  465. cmCacheManager::CacheIterator cmCacheManager::GetCacheIterator(
  466. const std::string& key)
  467. {
  468. return { *this, key.c_str() };
  469. }
  470. cmCacheManager::CacheIterator cmCacheManager::GetCacheIterator()
  471. {
  472. return { *this, nullptr };
  473. }
  474. cmProp cmCacheManager::GetInitializedCacheValue(const std::string& key) const
  475. {
  476. auto i = this->Cache.find(key);
  477. if (i != this->Cache.end() && i->second.Initialized) {
  478. return &i->second.Value;
  479. }
  480. return nullptr;
  481. }
  482. void cmCacheManager::PrintCache(std::ostream& out) const
  483. {
  484. out << "=================================================" << std::endl;
  485. out << "CMakeCache Contents:" << std::endl;
  486. for (auto const& i : this->Cache) {
  487. if (i.second.Type != cmStateEnums::INTERNAL) {
  488. out << i.first << " = " << i.second.Value << std::endl;
  489. }
  490. }
  491. out << "\n\n";
  492. out << "To change values in the CMakeCache, " << std::endl
  493. << "edit CMakeCache.txt in your output directory.\n";
  494. out << "=================================================" << std::endl;
  495. }
  496. void cmCacheManager::AddCacheEntry(const std::string& key, const char* value,
  497. const char* helpString,
  498. cmStateEnums::CacheEntryType type)
  499. {
  500. CacheEntry& e = this->Cache[key];
  501. if (value) {
  502. e.Value = value;
  503. e.Initialized = true;
  504. } else {
  505. e.Value.clear();
  506. }
  507. e.Type = type;
  508. // make sure we only use unix style paths
  509. if (type == cmStateEnums::FILEPATH || type == cmStateEnums::PATH) {
  510. if (e.Value.find(';') != std::string::npos) {
  511. std::vector<std::string> paths = cmExpandedList(e.Value);
  512. const char* sep = "";
  513. e.Value = "";
  514. for (std::string& i : paths) {
  515. cmSystemTools::ConvertToUnixSlashes(i);
  516. e.Value += sep;
  517. e.Value += i;
  518. sep = ";";
  519. }
  520. } else {
  521. cmSystemTools::ConvertToUnixSlashes(e.Value);
  522. }
  523. }
  524. e.SetProperty("HELPSTRING",
  525. helpString
  526. ? helpString
  527. : "(This variable does not exist and should not be used)");
  528. }
  529. bool cmCacheManager::CacheIterator::IsAtEnd() const
  530. {
  531. return this->Position == this->Container.Cache.end();
  532. }
  533. void cmCacheManager::CacheIterator::Begin()
  534. {
  535. this->Position = this->Container.Cache.begin();
  536. }
  537. bool cmCacheManager::CacheIterator::Find(const std::string& key)
  538. {
  539. this->Position = this->Container.Cache.find(key);
  540. return !this->IsAtEnd();
  541. }
  542. void cmCacheManager::CacheIterator::Next()
  543. {
  544. if (!this->IsAtEnd()) {
  545. ++this->Position;
  546. }
  547. }
  548. std::vector<std::string> cmCacheManager::CacheIterator::GetPropertyList() const
  549. {
  550. return this->GetEntry().GetPropertyList();
  551. }
  552. void cmCacheManager::CacheIterator::SetValue(const char* value)
  553. {
  554. if (this->IsAtEnd()) {
  555. return;
  556. }
  557. CacheEntry* entry = &this->GetEntry();
  558. if (value) {
  559. entry->Value = value;
  560. entry->Initialized = true;
  561. } else {
  562. entry->Value.clear();
  563. }
  564. }
  565. bool cmCacheManager::CacheIterator::GetValueAsBool() const
  566. {
  567. return cmIsOn(this->GetEntry().Value);
  568. }
  569. std::vector<std::string> cmCacheManager::CacheEntry::GetPropertyList() const
  570. {
  571. return this->Properties.GetKeys();
  572. }
  573. cmProp cmCacheManager::CacheEntry::GetProperty(const std::string& prop) const
  574. {
  575. if (prop == "TYPE") {
  576. return &cmState::CacheEntryTypeToString(this->Type);
  577. }
  578. if (prop == "VALUE") {
  579. return &this->Value;
  580. }
  581. return this->Properties.GetPropertyValue(prop);
  582. }
  583. void cmCacheManager::CacheEntry::SetProperty(const std::string& prop,
  584. const char* value)
  585. {
  586. if (prop == "TYPE") {
  587. this->Type = cmState::StringToCacheEntryType(value ? value : "STRING");
  588. } else if (prop == "VALUE") {
  589. this->Value = value ? value : "";
  590. } else {
  591. this->Properties.SetProperty(prop, value);
  592. }
  593. }
  594. void cmCacheManager::CacheEntry::AppendProperty(const std::string& prop,
  595. const std::string& value,
  596. bool asString)
  597. {
  598. if (prop == "TYPE") {
  599. this->Type =
  600. cmState::StringToCacheEntryType(!value.empty() ? value : "STRING");
  601. } else if (prop == "VALUE") {
  602. if (!value.empty()) {
  603. if (!this->Value.empty() && !asString) {
  604. this->Value += ";";
  605. }
  606. this->Value += value;
  607. }
  608. } else {
  609. this->Properties.AppendProperty(prop, value, asString);
  610. }
  611. }
  612. cmProp cmCacheManager::CacheIterator::GetProperty(
  613. const std::string& prop) const
  614. {
  615. if (!this->IsAtEnd()) {
  616. return this->GetEntry().GetProperty(prop);
  617. }
  618. return nullptr;
  619. }
  620. void cmCacheManager::CacheIterator::SetProperty(const std::string& p,
  621. const char* v)
  622. {
  623. if (!this->IsAtEnd()) {
  624. this->GetEntry().SetProperty(p, v);
  625. }
  626. }
  627. void cmCacheManager::CacheIterator::AppendProperty(const std::string& p,
  628. const std::string& v,
  629. bool asString)
  630. {
  631. if (!this->IsAtEnd()) {
  632. this->GetEntry().AppendProperty(p, v, asString);
  633. }
  634. }
  635. bool cmCacheManager::CacheIterator::GetPropertyAsBool(
  636. const std::string& prop) const
  637. {
  638. if (cmProp value = this->GetProperty(prop)) {
  639. return cmIsOn(*value);
  640. }
  641. return false;
  642. }
  643. void cmCacheManager::CacheIterator::SetProperty(const std::string& p, bool v)
  644. {
  645. this->SetProperty(p, v ? "ON" : "OFF");
  646. }
  647. bool cmCacheManager::CacheIterator::PropertyExists(
  648. const std::string& prop) const
  649. {
  650. return this->GetProperty(prop) != nullptr;
  651. }