cmCacheManager.cxx 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701
  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 "cmsys/FStream.hxx"
  5. #include "cmsys/Glob.hxx"
  6. #include <algorithm>
  7. #include <sstream>
  8. #include <stdio.h>
  9. #include <string.h>
  10. #include <string>
  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 (const std::string* 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 (const std::string* 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. const std::string* oldDir =
  147. this->GetInitializedCacheValue("CMAKE_CACHEFILE_DIR");
  148. if (internal && oldDir) {
  149. std::string currentcwd = path;
  150. std::string oldcwd = *oldDir;
  151. cmSystemTools::ConvertToUnixSlashes(currentcwd);
  152. currentcwd += "/CMakeCache.txt";
  153. oldcwd += "/CMakeCache.txt";
  154. if (!cmSystemTools::SameFile(oldcwd, currentcwd)) {
  155. const std::string* dir =
  156. this->GetInitializedCacheValue("CMAKE_CACHEFILE_DIR");
  157. std::ostringstream message;
  158. message << "The current CMakeCache.txt directory " << currentcwd
  159. << " is different than the directory " << (dir ? *dir : "")
  160. << " where CMakeCache.txt was created. This may result "
  161. "in binaries being created in the wrong place. If you "
  162. "are not sure, reedit the CMakeCache.txt";
  163. cmSystemTools::Error(message.str());
  164. }
  165. }
  166. return true;
  167. }
  168. const char* cmCacheManager::PersistentProperties[] = { "ADVANCED", "MODIFIED",
  169. "STRINGS", nullptr };
  170. bool cmCacheManager::ReadPropertyEntry(std::string const& entryKey,
  171. CacheEntry& e)
  172. {
  173. // All property entries are internal.
  174. if (e.Type != cmStateEnums::INTERNAL) {
  175. return false;
  176. }
  177. const char* end = entryKey.c_str() + entryKey.size();
  178. for (const char** p = cmCacheManager::PersistentProperties; *p; ++p) {
  179. std::string::size_type plen = strlen(*p) + 1;
  180. if (entryKey.size() > plen && *(end - plen) == '-' &&
  181. strcmp(end - plen + 1, *p) == 0) {
  182. std::string key = entryKey.substr(0, entryKey.size() - plen);
  183. cmCacheManager::CacheIterator it = this->GetCacheIterator(key.c_str());
  184. if (it.IsAtEnd()) {
  185. // Create an entry and store the property.
  186. CacheEntry& ne = this->Cache[key];
  187. ne.Type = cmStateEnums::UNINITIALIZED;
  188. ne.SetProperty(*p, e.Value.c_str());
  189. } else {
  190. // Store this property on its entry.
  191. it.SetProperty(*p, e.Value.c_str());
  192. }
  193. return true;
  194. }
  195. }
  196. return false;
  197. }
  198. void cmCacheManager::WritePropertyEntries(std::ostream& os, CacheIterator i,
  199. cmMessenger* messenger)
  200. {
  201. for (const char** p = cmCacheManager::PersistentProperties; *p; ++p) {
  202. if (const char* value = i.GetProperty(*p)) {
  203. std::string helpstring =
  204. cmStrCat(*p, " property for variable: ", i.GetName());
  205. cmCacheManager::OutputHelpString(os, helpstring);
  206. std::string key = cmStrCat(i.GetName(), '-', *p);
  207. cmCacheManager::OutputKey(os, key);
  208. os << ":INTERNAL=";
  209. cmCacheManager::OutputValue(os, value);
  210. os << "\n";
  211. cmCacheManager::OutputNewlineTruncationWarning(os, key, value,
  212. messenger);
  213. }
  214. }
  215. }
  216. bool cmCacheManager::SaveCache(const std::string& path, cmMessenger* messenger)
  217. {
  218. std::string cacheFile = cmStrCat(path, "/CMakeCache.txt");
  219. cmGeneratedFileStream fout(cacheFile);
  220. fout.SetCopyIfDifferent(true);
  221. if (!fout) {
  222. cmSystemTools::Error("Unable to open cache file for save. " + cacheFile);
  223. cmSystemTools::ReportLastSystemError("");
  224. return false;
  225. }
  226. // before writing the cache, update the version numbers
  227. // to the
  228. this->AddCacheEntry("CMAKE_CACHE_MAJOR_VERSION",
  229. std::to_string(cmVersion::GetMajorVersion()).c_str(),
  230. "Major version of cmake used to create the "
  231. "current loaded cache",
  232. cmStateEnums::INTERNAL);
  233. this->AddCacheEntry("CMAKE_CACHE_MINOR_VERSION",
  234. std::to_string(cmVersion::GetMinorVersion()).c_str(),
  235. "Minor version of cmake used to create the "
  236. "current loaded cache",
  237. cmStateEnums::INTERNAL);
  238. this->AddCacheEntry("CMAKE_CACHE_PATCH_VERSION",
  239. std::to_string(cmVersion::GetPatchVersion()).c_str(),
  240. "Patch version of cmake used to create the "
  241. "current loaded cache",
  242. cmStateEnums::INTERNAL);
  243. // Let us store the current working directory so that if somebody
  244. // Copies it, he will not be surprised
  245. std::string currentcwd = path;
  246. if (currentcwd[0] >= 'A' && currentcwd[0] <= 'Z' && currentcwd[1] == ':') {
  247. // Cast added to avoid compiler warning. Cast is ok because
  248. // value is guaranteed to fit in char by the above if...
  249. currentcwd[0] = static_cast<char>(currentcwd[0] - 'A' + 'a');
  250. }
  251. cmSystemTools::ConvertToUnixSlashes(currentcwd);
  252. this->AddCacheEntry("CMAKE_CACHEFILE_DIR", currentcwd.c_str(),
  253. "This is the directory where this CMakeCache.txt"
  254. " was created",
  255. cmStateEnums::INTERNAL);
  256. /* clang-format off */
  257. fout << "# This is the CMakeCache file.\n"
  258. << "# For build in directory: " << currentcwd << "\n"
  259. << "# It was generated by CMake: "
  260. << cmSystemTools::GetCMakeCommand() << std::endl;
  261. /* clang-format on */
  262. /* clang-format off */
  263. fout << "# You can edit this file to change values found and used by cmake."
  264. << std::endl
  265. << "# If you do not want to change any of the values, simply exit the "
  266. "editor." << std::endl
  267. << "# If you do want to change a value, simply edit, save, and exit "
  268. "the editor." << std::endl
  269. << "# The syntax for the file is as follows:\n"
  270. << "# KEY:TYPE=VALUE\n"
  271. << "# KEY is the name of a variable in the cache.\n"
  272. << "# TYPE is a hint to GUIs for the type of VALUE, DO NOT EDIT "
  273. "TYPE!." << std::endl
  274. << "# VALUE is the current value for the KEY.\n\n";
  275. /* clang-format on */
  276. fout << "########################\n";
  277. fout << "# EXTERNAL cache entries\n";
  278. fout << "########################\n";
  279. fout << "\n";
  280. for (auto const& i : this->Cache) {
  281. CacheEntry const& ce = i.second;
  282. cmStateEnums::CacheEntryType t = ce.Type;
  283. if (!ce.Initialized) {
  284. /*
  285. // This should be added in, but is not for now.
  286. cmSystemTools::Error("Cache entry \"" + i.first + "\" is uninitialized");
  287. */
  288. } else if (t != cmStateEnums::INTERNAL) {
  289. // Format is key:type=value
  290. if (const char* help = ce.GetProperty("HELPSTRING")) {
  291. cmCacheManager::OutputHelpString(fout, help);
  292. } else {
  293. cmCacheManager::OutputHelpString(fout, "Missing description");
  294. }
  295. cmCacheManager::OutputKey(fout, i.first);
  296. fout << ":" << cmState::CacheEntryTypeToString(t) << "=";
  297. cmCacheManager::OutputValue(fout, ce.Value);
  298. fout << "\n";
  299. cmCacheManager::OutputNewlineTruncationWarning(fout, i.first, ce.Value,
  300. messenger);
  301. fout << "\n";
  302. }
  303. }
  304. fout << "\n";
  305. fout << "########################\n";
  306. fout << "# INTERNAL cache entries\n";
  307. fout << "########################\n";
  308. fout << "\n";
  309. for (cmCacheManager::CacheIterator i = this->NewIterator(); !i.IsAtEnd();
  310. i.Next()) {
  311. if (!i.Initialized()) {
  312. continue;
  313. }
  314. cmStateEnums::CacheEntryType t = i.GetType();
  315. this->WritePropertyEntries(fout, i, messenger);
  316. if (t == cmStateEnums::INTERNAL) {
  317. // Format is key:type=value
  318. if (const char* help = i.GetProperty("HELPSTRING")) {
  319. cmCacheManager::OutputHelpString(fout, help);
  320. }
  321. cmCacheManager::OutputKey(fout, i.GetName());
  322. fout << ":" << cmState::CacheEntryTypeToString(t) << "=";
  323. cmCacheManager::OutputValue(fout, i.GetValue());
  324. fout << "\n";
  325. cmCacheManager::OutputNewlineTruncationWarning(fout, i.GetName(),
  326. i.GetValue(), messenger);
  327. }
  328. }
  329. fout << "\n";
  330. fout.Close();
  331. std::string checkCacheFile = cmStrCat(path, "/CMakeFiles");
  332. cmSystemTools::MakeDirectory(checkCacheFile);
  333. checkCacheFile += "/cmake.check_cache";
  334. cmsys::ofstream checkCache(checkCacheFile.c_str());
  335. if (!checkCache) {
  336. cmSystemTools::Error("Unable to open check cache file for write. " +
  337. checkCacheFile);
  338. return false;
  339. }
  340. checkCache << "# This file is generated by cmake for dependency checking "
  341. "of the CMakeCache.txt file\n";
  342. return true;
  343. }
  344. bool cmCacheManager::DeleteCache(const std::string& path)
  345. {
  346. std::string cacheFile = path;
  347. cmSystemTools::ConvertToUnixSlashes(cacheFile);
  348. std::string cmakeFiles = cacheFile;
  349. cacheFile += "/CMakeCache.txt";
  350. if (cmSystemTools::FileExists(cacheFile)) {
  351. cmSystemTools::RemoveFile(cacheFile);
  352. // now remove the files in the CMakeFiles directory
  353. // this cleans up language cache files
  354. cmakeFiles += "/CMakeFiles";
  355. if (cmSystemTools::FileIsDirectory(cmakeFiles)) {
  356. cmSystemTools::RemoveADirectory(cmakeFiles);
  357. }
  358. }
  359. return true;
  360. }
  361. void cmCacheManager::OutputKey(std::ostream& fout, std::string const& key)
  362. {
  363. // support : in key name by double quoting
  364. const char* q =
  365. (key.find(':') != std::string::npos || key.find("//") == 0) ? "\"" : "";
  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. CacheEntryMap::iterator 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. CacheEntryMap::iterator 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(const char* key)
  468. {
  469. return { *this, key };
  470. }
  471. const std::string* cmCacheManager::GetInitializedCacheValue(
  472. const std::string& key) const
  473. {
  474. CacheEntryMap::const_iterator i = this->Cache.find(key);
  475. if (i != this->Cache.end() && i->second.Initialized) {
  476. return &i->second.Value;
  477. }
  478. return nullptr;
  479. }
  480. void cmCacheManager::PrintCache(std::ostream& out) const
  481. {
  482. out << "=================================================" << std::endl;
  483. out << "CMakeCache Contents:" << std::endl;
  484. for (auto const& i : this->Cache) {
  485. if (i.second.Type != cmStateEnums::INTERNAL) {
  486. out << i.first << " = " << i.second.Value << std::endl;
  487. }
  488. }
  489. out << "\n\n";
  490. out << "To change values in the CMakeCache, " << std::endl
  491. << "edit CMakeCache.txt in your output directory.\n";
  492. out << "=================================================" << std::endl;
  493. }
  494. void cmCacheManager::AddCacheEntry(const std::string& key, const char* value,
  495. const char* helpString,
  496. cmStateEnums::CacheEntryType type)
  497. {
  498. CacheEntry& e = this->Cache[key];
  499. if (value) {
  500. e.Value = value;
  501. e.Initialized = true;
  502. } else {
  503. e.Value.clear();
  504. }
  505. e.Type = type;
  506. // make sure we only use unix style paths
  507. if (type == cmStateEnums::FILEPATH || type == cmStateEnums::PATH) {
  508. if (e.Value.find(';') != std::string::npos) {
  509. std::vector<std::string> paths = cmExpandedList(e.Value);
  510. const char* sep = "";
  511. e.Value = "";
  512. for (std::string& i : paths) {
  513. cmSystemTools::ConvertToUnixSlashes(i);
  514. e.Value += sep;
  515. e.Value += i;
  516. sep = ";";
  517. }
  518. } else {
  519. cmSystemTools::ConvertToUnixSlashes(e.Value);
  520. }
  521. }
  522. e.SetProperty("HELPSTRING",
  523. helpString
  524. ? helpString
  525. : "(This variable does not exist and should not be used)");
  526. }
  527. bool cmCacheManager::CacheIterator::IsAtEnd() const
  528. {
  529. return this->Position == this->Container.Cache.end();
  530. }
  531. void cmCacheManager::CacheIterator::Begin()
  532. {
  533. this->Position = this->Container.Cache.begin();
  534. }
  535. bool cmCacheManager::CacheIterator::Find(const std::string& key)
  536. {
  537. this->Position = this->Container.Cache.find(key);
  538. return !this->IsAtEnd();
  539. }
  540. void cmCacheManager::CacheIterator::Next()
  541. {
  542. if (!this->IsAtEnd()) {
  543. ++this->Position;
  544. }
  545. }
  546. std::vector<std::string> cmCacheManager::CacheIterator::GetPropertyList() const
  547. {
  548. return this->GetEntry().GetPropertyList();
  549. }
  550. void cmCacheManager::CacheIterator::SetValue(const char* value)
  551. {
  552. if (this->IsAtEnd()) {
  553. return;
  554. }
  555. CacheEntry* entry = &this->GetEntry();
  556. if (value) {
  557. entry->Value = value;
  558. entry->Initialized = true;
  559. } else {
  560. entry->Value.clear();
  561. }
  562. }
  563. bool cmCacheManager::CacheIterator::GetValueAsBool() const
  564. {
  565. return cmIsOn(this->GetEntry().Value);
  566. }
  567. std::vector<std::string> cmCacheManager::CacheEntry::GetPropertyList() const
  568. {
  569. return this->Properties.GetKeys();
  570. }
  571. const char* cmCacheManager::CacheEntry::GetProperty(
  572. const std::string& prop) const
  573. {
  574. if (prop == "TYPE") {
  575. return cmState::CacheEntryTypeToString(this->Type);
  576. }
  577. if (prop == "VALUE") {
  578. return this->Value.c_str();
  579. }
  580. return this->Properties.GetPropertyValue(prop);
  581. }
  582. void cmCacheManager::CacheEntry::SetProperty(const std::string& prop,
  583. const char* value)
  584. {
  585. if (prop == "TYPE") {
  586. this->Type = cmState::StringToCacheEntryType(value ? value : "STRING");
  587. } else if (prop == "VALUE") {
  588. this->Value = value ? value : "";
  589. } else {
  590. this->Properties.SetProperty(prop, value);
  591. }
  592. }
  593. void cmCacheManager::CacheEntry::AppendProperty(const std::string& prop,
  594. const char* value,
  595. bool asString)
  596. {
  597. if (prop == "TYPE") {
  598. this->Type = cmState::StringToCacheEntryType(value ? value : "STRING");
  599. } else if (prop == "VALUE") {
  600. if (value) {
  601. if (!this->Value.empty() && *value && !asString) {
  602. this->Value += ";";
  603. }
  604. this->Value += value;
  605. }
  606. } else {
  607. this->Properties.AppendProperty(prop, value, asString);
  608. }
  609. }
  610. const char* cmCacheManager::CacheIterator::GetProperty(
  611. const std::string& prop) const
  612. {
  613. if (!this->IsAtEnd()) {
  614. return this->GetEntry().GetProperty(prop);
  615. }
  616. return nullptr;
  617. }
  618. void cmCacheManager::CacheIterator::SetProperty(const std::string& p,
  619. const char* v)
  620. {
  621. if (!this->IsAtEnd()) {
  622. this->GetEntry().SetProperty(p, v);
  623. }
  624. }
  625. void cmCacheManager::CacheIterator::AppendProperty(const std::string& p,
  626. const char* v,
  627. bool asString)
  628. {
  629. if (!this->IsAtEnd()) {
  630. this->GetEntry().AppendProperty(p, v, asString);
  631. }
  632. }
  633. bool cmCacheManager::CacheIterator::GetPropertyAsBool(
  634. const std::string& prop) const
  635. {
  636. if (const char* value = this->GetProperty(prop)) {
  637. return cmIsOn(value);
  638. }
  639. return false;
  640. }
  641. void cmCacheManager::CacheIterator::SetProperty(const std::string& p, bool v)
  642. {
  643. this->SetProperty(p, v ? "ON" : "OFF");
  644. }
  645. bool cmCacheManager::CacheIterator::PropertyExists(
  646. const std::string& prop) const
  647. {
  648. return this->GetProperty(prop) != nullptr;
  649. }