ENH: mark some vars as advanced (and resort the list)
[cmake.git] / Source / cmCacheManager.cxx
bloba315949c9099486c4c8c8627554a4664e3332120
1 /*=========================================================================
3 Program: Insight Segmentation & Registration Toolkit
4 Module: $RCSfile: cmCacheManager.cxx,v $
5 Language: C++
6 Date: $Date: 2002-10-04 18:01:22 $
7 Version: $Revision: 1.64 $
9 Copyright (c) 2002 Insight Consortium. All rights reserved.
10 See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
12 This software is distributed WITHOUT ANY WARRANTY; without even
13 the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
14 PURPOSE. See the above copyright notices for more information.
16 =========================================================================*/
18 #include "cmCacheManager.h"
19 #include "cmSystemTools.h"
20 #include "cmCacheManager.h"
21 #include "cmMakefile.h"
22 #include "cmRegularExpression.h"
23 #include "stdio.h"
25 #if defined(_WIN32) || defined(__CYGWIN__)
26 # include <windows.h>
27 #endif // _WIN32
29 const char* cmCacheManagerTypes[] =
30 { "BOOL",
31 "PATH",
32 "FILEPATH",
33 "STRING",
34 "INTERNAL",
35 "STATIC",
36 "UNINITIALIZED",
40 cmCacheManager::CacheEntryType cmCacheManager::StringToType(const char* s)
42 int i = 0;
43 while(cmCacheManagerTypes[i])
45 if(strcmp(s, cmCacheManagerTypes[i]) == 0)
47 return static_cast<CacheEntryType>(i);
49 ++i;
51 return STRING;
54 bool cmCacheManager::LoadCache(cmMakefile* mf)
56 return this->LoadCache(mf->GetHomeOutputDirectory());
60 bool cmCacheManager::LoadCache(const char* path)
62 return this->LoadCache(path,true);
65 bool cmCacheManager::LoadCache(const char* path,
66 bool internal)
68 std::set<std::string> emptySet;
69 return this->LoadCache(path, internal, emptySet, emptySet);
72 bool cmCacheManager::ParseEntry(const char* entry,
73 std::string& var,
74 std::string& value,
75 CacheEntryType& type)
77 // input line is: key:type=value
78 cmRegularExpression reg("^([^:]*):([^=]*)=(.*[^\t ]|[\t ]*)[\t ]*$");
79 // input line is: "key":type=value
80 cmRegularExpression regQuoted("^\"([^\"]*)\":([^=]*)=(.*[^\t ]|[\t ]*)[\t ]*$");
81 bool flag = false;
82 if(regQuoted.find(entry))
84 var = regQuoted.match(1);
85 type = cmCacheManager::StringToType(regQuoted.match(2).c_str());
86 value = regQuoted.match(3);
87 flag = true;
89 else if (reg.find(entry))
91 var = reg.match(1);
92 type = cmCacheManager::StringToType(reg.match(2).c_str());
93 value = reg.match(3);
94 flag = true;
97 // if value is enclosed in single quotes ('foo') then remove them
98 // it is used to enclose trailing space or tab
99 if (flag &&
100 value.size() >= 2 &&
101 value[0] == '\'' &&
102 value[value.size() - 1] == '\'')
104 value = value.substr(1,
105 value.size() - 2);
108 return flag;
111 bool cmCacheManager::LoadCache(const char* path,
112 bool internal,
113 std::set<std::string>& excludes,
114 std::set<std::string>& includes)
116 std::string cacheFile = path;
117 cacheFile += "/CMakeCache.txt";
118 // clear the old cache, if we are reading in internal values
119 if ( internal )
121 m_Cache.clear();
123 std::ifstream fin(cacheFile.c_str());
124 if(!fin)
126 return false;
128 const int bsize = 4096;
129 char buffer[bsize];
130 char *realbuffer;
131 std::string entryKey;
132 while(fin)
134 // Format is key:type=value
135 CacheEntry e;
136 fin.getline(buffer, bsize);
137 realbuffer = buffer;
138 while(*realbuffer != '0' &&
139 (*realbuffer == ' ' ||
140 *realbuffer == '\t' ||
141 *realbuffer == '\n'))
143 realbuffer++;
145 // skip blank lines and comment lines
146 if(realbuffer[0] == '#' || realbuffer[0] == 0)
148 continue;
150 while(realbuffer[0] == '/' && realbuffer[1] == '/')
152 e.m_Properties["HELPSTRING"] += &realbuffer[2];
153 fin.getline(realbuffer, bsize);
154 if(!fin)
156 continue;
159 if(cmCacheManager::ParseEntry(realbuffer, entryKey, e.m_Value, e.m_Type))
161 if ( excludes.find(entryKey) == excludes.end() )
163 // Load internal values if internal is set.
164 // If the entry is not internal to the cache being loaded
165 // or if it is in the list of internal entries to be
166 // imported, load it.
167 if ( internal || (e.m_Type != INTERNAL) ||
168 (includes.find(entryKey) != includes.end()) )
170 // If we are loading the cache from another project,
171 // make all loaded entries internal so that it is
172 // not visible in the gui
173 if (!internal)
175 e.m_Type = INTERNAL;
176 e.m_Properties["HELPSTRING"] = "DO NOT EDIT, ";
177 e.m_Properties["HELPSTRING"] += entryKey;
178 e.m_Properties["HELPSTRING"] += " loaded from external file. "
179 "To change this value edit this file: ";
180 e.m_Properties["HELPSTRING"] += path;
181 e.m_Properties["HELPSTRING"] += "/CMakeCache.txt" ;
183 if ( e.m_Type == cmCacheManager::INTERNAL &&
184 (entryKey.size() > strlen("-ADVANCED")) &&
185 strcmp(entryKey.c_str() + (entryKey.size() - strlen("-ADVANCED")),
186 "-ADVANCED") == 0 )
188 std::string value = e.m_Value;
189 std::string akey = entryKey.substr(0, (entryKey.size() - strlen("-ADVANCED")));
190 cmCacheManager::CacheIterator it = this->GetCacheIterator(akey.c_str());
191 if ( it.IsAtEnd() )
193 e.m_Type = cmCacheManager::UNINITIALIZED;
194 m_Cache[akey] = e;
196 if (!it.Find(akey.c_str()))
198 cmSystemTools::Error("Internal CMake error when reading cache");
200 it.SetProperty("ADVANCED", value.c_str());
202 else
204 m_Cache[entryKey] = e;
209 else
211 cmSystemTools::Error("Parse error in cache file ", cacheFile.c_str(),
212 ". Offending entry: ", realbuffer);
215 // if CMAKE version not found in the list file
216 // add them as version 0.0
217 if(!this->GetCacheValue("CMAKE_CACHE_MINOR_VERSION"))
219 this->AddCacheEntry("CMAKE_CACHE_MINOR_VERSION", "0",
220 "Minor version of cmake used to create the "
221 "current loaded cache", cmCacheManager::INTERNAL);
222 this->AddCacheEntry("CMAKE_CACHE_MAJOR_VERSION", "0",
223 "Major version of cmake used to create the "
224 "current loaded cache", cmCacheManager::INTERNAL);
227 // check to make sure the cache directory has not
228 // been moved
229 if ( internal && this->GetCacheValue("CMAKE_CACHEFILE_DIR") )
231 std::string currentcwd = path;
232 std::string oldcwd = this->GetCacheValue("CMAKE_CACHEFILE_DIR");
233 cmSystemTools::ConvertToUnixSlashes(currentcwd);
234 currentcwd += "/CMakeCache.txt";
235 oldcwd += "/CMakeCache.txt";
236 if(!cmSystemTools::SameFile(oldcwd.c_str(), currentcwd.c_str()))
238 std::string message =
239 std::string("The current CMakeCache.txt directory ") +
240 currentcwd + std::string(" is different than the directory ") +
241 std::string(this->GetCacheValue("CMAKE_CACHEFILE_DIR")) +
242 std::string(" where CMackeCache.txt was created. This may result "
243 "in binaries being created in the wrong place. If you "
244 "are not sure, reedit the CMakeCache.txt");
245 cmSystemTools::Error(message.c_str());
248 return true;
251 bool cmCacheManager::SaveCache(cmMakefile* mf)
253 return this->SaveCache(mf->GetHomeOutputDirectory());
257 bool cmCacheManager::SaveCache(const char* path)
259 std::string cacheFile = path;
260 cacheFile += "/CMakeCache.txt";
261 std::string tempFile = cacheFile;
262 tempFile += ".tmp";
263 std::ofstream fout(tempFile.c_str());
264 if(!fout)
266 cmSystemTools::Error("Unable to open cache file for save. ",
267 cacheFile.c_str());
268 return false;
270 // before writting the cache, update the version numbers
271 // to the
272 char temp[1024];
273 sprintf(temp, "%d", cmMakefile::GetMinorVersion());
274 this->AddCacheEntry("CMAKE_CACHE_MINOR_VERSION", temp,
275 "Minor version of cmake used to create the "
276 "current loaded cache", cmCacheManager::INTERNAL);
277 sprintf(temp, "%d", cmMakefile::GetMajorVersion());
278 this->AddCacheEntry("CMAKE_CACHE_MAJOR_VERSION", temp,
279 "Major version of cmake used to create the "
280 "current loaded cache", cmCacheManager::INTERNAL);
282 // Let us store the current working directory so that if somebody
283 // Copies it, he will not be surprised
284 std::string currentcwd = path;
285 if ( currentcwd[0] >= 'A' && currentcwd[0] <= 'Z' &&
286 currentcwd[1] == ':' )
288 currentcwd[0] = currentcwd[0] - 'A' + 'a';
290 cmSystemTools::ConvertToUnixSlashes(currentcwd);
291 this->AddCacheEntry("CMAKE_CACHEFILE_DIR", currentcwd.c_str(),
292 "This is the directory where this CMakeCahe.txt"
293 " was created", cmCacheManager::INTERNAL);
295 fout << "# This is the CMakeCache file.\n"
296 << "# For build in directory: " << currentcwd << "\n"
297 << "# You can edit this file to change values found and used by cmake.\n"
298 << "# If you do not want to change any of the values, simply exit the editor.\n"
299 << "# If you do want to change a value, simply edit, save, and exit the editor.\n"
300 << "# The syntax for the file is as follows:\n"
301 << "# KEY:TYPE=VALUE\n"
302 << "# KEY is the name of a varible in the cache.\n"
303 << "# TYPE is a hint to GUI's for the type of VALUE, DO NOT EDIT TYPE!.\n"
304 << "# VALUE is the current value for the KEY.\n\n";
306 fout << "########################\n";
307 fout << "# EXTERNAL cache entries\n";
308 fout << "########################\n";
309 fout << "\n";
311 for( std::map<cmStdString, CacheEntry>::const_iterator i = m_Cache.begin();
312 i != m_Cache.end(); ++i)
314 const CacheEntry& ce = (*i).second;
315 CacheEntryType t = ce.m_Type;
316 if(t == cmCacheManager::UNINITIALIZED)
319 // This should be added in, but is not for now.
320 cmSystemTools::Error("Cache entry \"", (*i).first.c_str(),
321 "\" is uninitialized");
324 else if(t != INTERNAL)
326 // Format is key:type=value
327 std::map<cmStdString,cmStdString>::const_iterator it =
328 ce.m_Properties.find("HELPSTRING");
329 if ( it == ce.m_Properties.end() )
331 cmCacheManager::OutputHelpString(fout, "Missing description");
333 else
335 cmCacheManager::OutputHelpString(fout, it->second);
337 std::string key;
338 // support : in key name by double quoting
339 if((*i).first.find(':') != std::string::npos ||
340 (*i).first.find("//") == 0)
342 key = "\"";
343 key += i->first;
344 key += "\"";
346 else
348 key = i->first;
350 fout << key.c_str() << ":"
351 << cmCacheManagerTypes[t] << "=";
352 // if value has trailing space or tab, enclose it in single quotes
353 if (ce.m_Value.size() &&
354 (ce.m_Value[ce.m_Value.size() - 1] == ' ' ||
355 ce.m_Value[ce.m_Value.size() - 1] == '\t'))
357 fout << '\'' << ce.m_Value << '\'';
359 else
361 fout << ce.m_Value;
363 fout << "\n\n";
367 fout << "\n";
368 fout << "########################\n";
369 fout << "# INTERNAL cache entries\n";
370 fout << "########################\n";
371 fout << "\n";
373 for( cmCacheManager::CacheIterator i = this->NewIterator();
374 !i.IsAtEnd(); i.Next())
376 CacheEntryType t = i.GetType();
377 bool advanced = i.PropertyExists("ADVANCED");
378 if ( advanced )
380 // Format is key:type=value
381 std::string key;
382 std::string rkey = i.GetName();
383 std::string helpstring;
384 // If this is advanced variable, we have to do some magic for
385 // backward compatibility
386 helpstring = "Advanced flag for variable: ";
387 helpstring += i.GetName();
388 rkey += "-ADVANCED";
389 cmCacheManager::OutputHelpString(fout, helpstring.c_str());
390 // support : in key name by double quoting
391 if(rkey.find(':') != std::string::npos ||
392 rkey.find("//") == 0)
394 key = "\"";
395 key += rkey;
396 key += "\"";
398 else
400 key = rkey;
402 fout << key.c_str() << ":INTERNAL="
403 << (i.GetPropertyAsBool("ADVANCED") ? "1" : "0") << "\n";
405 if(t == cmCacheManager::INTERNAL)
407 // Format is key:type=value
408 std::string key;
409 std::string rkey = i.GetName();
410 std::string helpstring;
411 const char* hs = i.GetProperty("HELPSTRING");
412 if ( hs )
414 helpstring = i.GetProperty("HELPSTRING");
416 else
418 helpstring = "";
420 cmCacheManager::OutputHelpString(fout, helpstring.c_str());
421 // support : in key name by double quoting
422 if(rkey.find(':') != std::string::npos ||
423 rkey.find("//") == 0)
425 key = "\"";
426 key += rkey;
427 key += "\"";
429 else
431 key = rkey;
433 fout << key.c_str() << ":"
434 << cmCacheManagerTypes[t] << "=";
435 // if value has trailing space or tab, enclose it in single quotes
436 std::string value = i.GetValue();
437 if (value.size() &&
438 (value[value.size() - 1] == ' ' ||
439 value[value.size() - 1] == '\t'))
441 fout << '\'' << value << '\'';
443 else
445 fout << value;
447 fout << "\n";
450 fout << "\n";
451 fout.close();
452 cmSystemTools::CopyFileIfDifferent(tempFile.c_str(),
453 cacheFile.c_str());
454 cmSystemTools::RemoveFile(tempFile.c_str());
455 return true;
458 void cmCacheManager::OutputHelpString(std::ofstream& fout,
459 const std::string& helpString)
461 std::string::size_type end = helpString.size();
462 if(end == 0)
464 return;
466 std::string oneLine;
467 std::string::size_type pos = 0;
468 std::string::size_type nextBreak = 60;
469 bool done = false;
471 while(!done)
473 if(nextBreak >= end)
475 nextBreak = end;
476 done = true;
478 else
480 while(nextBreak < end && helpString[nextBreak] != ' ')
482 nextBreak++;
485 oneLine = helpString.substr(pos, nextBreak - pos);
486 fout << "//" << oneLine.c_str() << "\n";
487 pos = nextBreak;
488 nextBreak += 60;
492 void cmCacheManager::RemoveCacheEntry(const char* key)
494 CacheEntryMap::iterator i = m_Cache.find(key);
495 if(i != m_Cache.end())
497 m_Cache.erase(i);
499 else
501 std::cerr << "Failed to remove entry:" << key << std::endl;
506 cmCacheManager::CacheEntry *cmCacheManager::GetCacheEntry(const char* key)
508 CacheEntryMap::iterator i = m_Cache.find(key);
509 if(i != m_Cache.end())
511 return &i->second;
513 return 0;
516 cmCacheManager::CacheIterator cmCacheManager::GetCacheIterator(const char *key)
518 return CacheIterator(*this, key);
521 const char* cmCacheManager::GetCacheValue(const char* key) const
523 CacheEntryMap::const_iterator i = m_Cache.find(key);
524 if(i != m_Cache.end() && i->second.m_Type != cmCacheManager::UNINITIALIZED)
526 return i->second.m_Value.c_str();
528 return 0;
532 void cmCacheManager::PrintCache(std::ostream& out) const
534 out << "=================================================" << std::endl;
535 out << "CMakeCache Contents:" << std::endl;
536 for(std::map<cmStdString, CacheEntry>::const_iterator i = m_Cache.begin();
537 i != m_Cache.end(); ++i)
539 if((*i).second.m_Type != INTERNAL)
541 out << (*i).first.c_str() << " = " << (*i).second.m_Value.c_str() << std::endl;
544 out << "\n\n";
545 out << "To change values in the CMakeCache, \nedit CMakeCache.txt in your output directory.\n";
546 out << "=================================================" << std::endl;
550 void cmCacheManager::AddCacheEntry(const char* key,
551 const char* value,
552 const char* helpString,
553 CacheEntryType type)
555 CacheEntry& e = m_Cache[key];
556 if ( value )
558 e.m_Value = value;
560 else
562 e.m_Value = "(none)";
564 e.m_Type = type;
565 // make sure we only use unix style paths
566 if(type == FILEPATH || type == PATH)
568 cmSystemTools::ConvertToUnixSlashes(e.m_Value);
570 if ( helpString )
572 e.m_Properties["HELPSTRING"] = helpString;
574 else
576 e.m_Properties["HELPSTRING"] = "(This variable does not exists and should not be used)";
578 m_Cache[key] = e;
581 void cmCacheManager::AddCacheEntry(const char* key, bool v,
582 const char* helpString)
584 if(v)
586 this->AddCacheEntry(key, "ON", helpString, cmCacheManager::BOOL);
588 else
590 this->AddCacheEntry(key, "OFF", helpString, cmCacheManager::BOOL);
594 bool cmCacheManager::CacheIterator::IsAtEnd()
596 return m_Position == m_Container.m_Cache.end();
599 void cmCacheManager::CacheIterator::Begin()
601 m_Position = m_Container.m_Cache.begin();
604 bool cmCacheManager::CacheIterator::Find(const char* key)
606 m_Position = m_Container.m_Cache.find(key);
607 return !this->IsAtEnd();
610 void cmCacheManager::CacheIterator::Next()
612 ++m_Position;
615 void cmCacheManager::CacheIterator::SetValue(const char* value)
617 CacheEntry* entry = &this->GetEntry();
618 entry->m_Value = value;
621 const char* cmCacheManager::CacheIterator::GetProperty(const char* property) const
623 if ( !strcmp(property, "TYPE") || !strcmp(property, "VALUE") )
625 cmSystemTools::Error("Property \"", property,
626 "\" cannot be accessed through the GetProperty()");
627 return 0;
629 const CacheEntry* ent = &this->GetEntry();
630 std::map<cmStdString,cmStdString>::const_iterator it =
631 ent->m_Properties.find(property);
632 if ( it == ent->m_Properties.end() )
634 return 0;
636 return it->second.c_str();
639 void cmCacheManager::CacheIterator::SetProperty(const char* p, const char* v)
641 if ( !strcmp(p, "TYPE") || !strcmp(p, "VALUE") )
643 cmSystemTools::Error("Property \"", p,
644 "\" cannot be accessed through the SetProperty()");
645 return;
647 CacheEntry* ent = &this->GetEntry();
648 ent->m_Properties[p] = v;
651 bool cmCacheManager::CacheIterator::GetPropertyAsBool(const char* property) const
653 if ( !strcmp(property, "TYPE") || !strcmp(property, "VALUE") )
655 cmSystemTools::Error("Property \"", property,
656 "\" cannot be accessed through the GetPropertyAsBool()");
657 return false;
659 const CacheEntry* ent = &this->GetEntry();
660 std::map<cmStdString,cmStdString>::const_iterator it =
661 ent->m_Properties.find(property);
662 if ( it == ent->m_Properties.end() )
664 return false;
666 return cmSystemTools::IsOn(it->second.c_str());
670 void cmCacheManager::CacheIterator::SetProperty(const char* p, bool v)
672 if ( !strcmp(p, "TYPE") || !strcmp(p, "VALUE") )
674 cmSystemTools::Error("Property \"", p,
675 "\" cannot be accessed through the SetProperty()");
676 return;
678 CacheEntry* ent = &this->GetEntry();
679 ent->m_Properties[p] = v ? "ON" : "OFF";
682 bool cmCacheManager::CacheIterator::PropertyExists(const char* property) const
684 if ( !strcmp(property, "TYPE") || !strcmp(property, "VALUE") )
686 cmSystemTools::Error("Property \"", property,
687 "\" cannot be accessed through the PropertyExists()");
688 return false;
690 const CacheEntry* ent = &this->GetEntry();
691 std::map<cmStdString,cmStdString>::const_iterator it =
692 ent->m_Properties.find(property);
693 if ( it == ent->m_Properties.end() )
695 return false;
697 return true;