cmCacheManager.cxx 11.7 KB
Newer Older
1 2 3 4 5 6 7 8
/*=========================================================================

  Program:   Insight Segmentation & Registration Toolkit
  Module:    $RCSfile$
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

Will Schroeder's avatar
Will Schroeder committed
9 10
Copyright (c) 2001 Insight Consortium
All rights reserved.
11

Will Schroeder's avatar
Will Schroeder committed
12 13
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
14

Will Schroeder's avatar
Will Schroeder committed
15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
 * Redistributions of source code must retain the above copyright notice,
   this list of conditions and the following disclaimer.

 * Redistributions in binary form must reproduce the above copyright notice,
   this list of conditions and the following disclaimer in the documentation
   and/or other materials provided with the distribution.

 * The name of the Insight Consortium, nor the names of any consortium members,
   nor of any contributors, may be used to endorse or promote products derived
   from this software without specific prior written permission.

  * Modified source versions must be plainly marked as such, and must not be
    misrepresented as being the original software.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS ``AS IS''
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39 40 41 42 43

=========================================================================*/

#include "cmCacheManager.h"
#include "cmSystemTools.h"
44 45
#include "cmCacheManager.h"
#include "cmMakefile.h"
Bill Hoffman's avatar
Bill Hoffman committed
46
#include "cmRegularExpression.h"
47
#include "stdio.h"
48 49 50 51

const char* cmCacheManagerTypes[] = 
{ "BOOL",
  "PATH",
52
  "FILEPATH",
53
  "STRING",
Ken Martin's avatar
Ken Martin committed
54
  "INTERNAL",
Bill Hoffman's avatar
Bill Hoffman committed
55
  "STATIC",
56 57 58 59 60 61 62 63 64 65 66 67
  0
};

cmCacheManager::CacheEntryType cmCacheManager::StringToType(const char* s)
{
  int i = 0;
  while(cmCacheManagerTypes[i])
    {
    if(strcmp(s, cmCacheManagerTypes[i]) == 0)
      {
      return static_cast<CacheEntryType>(i);
      }
68
    ++i;
69 70 71 72 73
    }
  return STRING;
}

    
Bill Hoffman's avatar
Bill Hoffman committed
74 75 76 77 78 79 80 81 82 83 84
struct CleanUpCacheManager
{
  ~CleanUpCacheManager()
  {
    delete cmCacheManager::GetInstance();
  }
  void Use() {}
};

CleanUpCacheManager cleanup;

85 86 87 88 89 90
cmCacheManager* cmCacheManager::s_Instance = 0;

cmCacheManager* cmCacheManager::GetInstance()
{
  if(!cmCacheManager::s_Instance)
    {
Bill Hoffman's avatar
Bill Hoffman committed
91
    cleanup.Use();
92 93 94 95 96 97 98
    cmCacheManager::s_Instance = new cmCacheManager;
    }
  return cmCacheManager::s_Instance;
}



99
bool cmCacheManager::LoadCache(cmMakefile* mf)
100
{
101 102 103 104 105
  return this->LoadCache(mf->GetHomeOutputDirectory());
}


bool cmCacheManager::LoadCache(const char* path)
106
{
107
  return this->LoadCache(path,true);
108 109 110
}
bool cmCacheManager::LoadCache(const char* path,
			       bool internal)
111 112
{
  std::string cacheFile = path;
113
  cacheFile += "/CMakeCache.txt";
114 115 116 117 118
  // clear the old cache, if we are reading in internal values
  if ( internal )
    {
    m_Cache.clear();
    }
119
  std::ifstream fin(cacheFile.c_str());
120 121 122 123 124 125
  if(!fin)
    {
    return false;
    }
  const int bsize = 4096;
  char buffer[bsize];
Bill Hoffman's avatar
Bill Hoffman committed
126
  // input line is:         key:type=value
127
  cmRegularExpression reg("^([^:]*):([^=]*)=(.*[^\t ]|[\t ]*)[\t ]*$");
128
  // input line is:         "key":type=value
129
  cmRegularExpression regQuoted("^\"([^\"]*)\":([^=]*)=(.*[^\t ]|[\t ]*)[\t ]*$");
130 131
  while(fin)
    {
132
    // Format is key:type=value
133
    CacheEntry e;
Bill Hoffman's avatar
Bill Hoffman committed
134 135 136
    fin.getline(buffer, bsize);
    // skip blank lines and comment lines
    if(buffer[0] == '#' || buffer[0] == 0)
137
      {
Bill Hoffman's avatar
Bill Hoffman committed
138 139
      continue;
      }
Bill Hoffman's avatar
Bill Hoffman committed
140 141 142 143 144 145 146 147 148
    while(buffer[0] == '/')
      {
      e.m_HelpString += &buffer[2];
      fin.getline(buffer, bsize);
      if(!fin)
        {
        continue;
        }
      }
149 150 151 152 153 154 155 156 157 158 159
    if(regQuoted.find(buffer))
      {
      e.m_Type = cmCacheManager::StringToType(regQuoted.match(2).c_str());
      // only load internal values if internal is set
      if (internal || e.m_Type != INTERNAL)
	{
	  e.m_Value = regQuoted.match(3);
	  m_Cache[regQuoted.match(1)] = e;
	}
      }
    else if (reg.find(buffer))
Bill Hoffman's avatar
Bill Hoffman committed
160 161
      {
      e.m_Type = cmCacheManager::StringToType(reg.match(2).c_str());
162 163 164 165 166 167
      // only load internal values if internal is set
      if (internal || e.m_Type != INTERNAL)
	{
	  e.m_Value = reg.match(3);
	  m_Cache[reg.match(1)] = e;
	}
Bill Hoffman's avatar
Bill Hoffman committed
168 169 170
      }
    else
      {
171 172
	cmSystemTools::Error("Parse error in cache file ", cacheFile.c_str(),
			     ". Offending entry: ", buffer);
173 174
      }
    }
175 176 177 178 179 180 181 182 183 184 185 186
  // if CMAKE version not found in the list file
  // add them as version 0.0
  if(!this->GetCacheValue("CMAKE_CACHE_MINOR_VERSION"))
    {
    this->AddCacheEntry("CMAKE_CACHE_MINOR_VERSION", "0",
                        "Minor version of cmake used to create the "
                        "current loaded cache", cmCacheManager::INTERNAL);
    this->AddCacheEntry("CMAKE_CACHE_MAJOR_VERSION", "0",
                        "Major version of cmake used to create the "
                        "current loaded cache", cmCacheManager::INTERNAL);
    
    }
187
  return true;
188 189
}

190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205
void cmCacheManager::DefineCache(cmMakefile *mf)
{
  if (!mf)
    {
    return;
    }
  
  // add definition to the makefile
  for( std::map<std::string, CacheEntry>::const_iterator i = m_Cache.begin();
       i != m_Cache.end(); ++i)
    {
    const CacheEntry& ce = (*i).second;
    mf->AddDefinition((*i).first.c_str(), ce.m_Value.c_str());
    }
}

206
bool cmCacheManager::SaveCache(cmMakefile* mf) 
207
{
208 209 210 211
  return this->SaveCache(mf->GetHomeOutputDirectory());
}


212
bool cmCacheManager::SaveCache(const char* path) 
213 214
{
  std::string cacheFile = path;
215
  cacheFile += "/CMakeCache.txt";
Bill Hoffman's avatar
Bill Hoffman committed
216 217 218
  std::string tempFile = cacheFile;
  tempFile += ".tmp";
  std::ofstream fout(tempFile.c_str());
219 220
  if(!fout)
    {
221 222
    cmSystemTools::Error("Unable to open cache file for save. ", 
                         cacheFile.c_str());
223 224
    return false;
    }
225 226 227 228 229 230 231 232 233 234 235
  // before writting the cache, update the version numbers
  // to the 
  char temp[1024];
  sprintf(temp, "%d", cmMakefile::GetMinorVersion());
  this->AddCacheEntry("CMAKE_CACHE_MINOR_VERSION", temp,
                      "Minor version of cmake used to create the "
                      "current loaded cache", cmCacheManager::INTERNAL);
  sprintf(temp, "%d", cmMakefile::GetMajorVersion());
  this->AddCacheEntry("CMAKE_CACHE_MAJOR_VERSION", temp,
                      "Major version of cmake used to create the "
                      "current loaded cache", cmCacheManager::INTERNAL);
Bill Hoffman's avatar
Bill Hoffman committed
236
  fout << "# This is the CMakeCache file.\n"
237
       << "# For build in directory: " << path << "\n"
Bill Hoffman's avatar
Bill Hoffman committed
238 239 240 241 242 243 244 245 246
       << "# You can edit this file to change values found and used by cmake.\n"
       << "# If you do not want to change any of the values, simply exit the editor.\n"
       << "# If you do want to change a value, simply edit, save, and exit the editor.\n"
       << "# The syntax for the file is as follows:\n"
       << "# KEY:TYPE=VALUE\n"
       << "# KEY is the name of a varible in the cache.\n"
       << "# TYPE is a hint to GUI's for the type of VALUE, DO NOT EDIT TYPE!.\n"
       << "# VALUE is the current value for the KEY.\n\n";

Geoffrey Cross's avatar
Geoffrey Cross committed
247 248 249 250 251
  fout << "########################\n";
  fout << "# EXTERNAL cache entries\n";
  fout << "########################\n";
  fout << "\n";

Bill Hoffman's avatar
Bill Hoffman committed
252 253 254 255 256 257 258 259 260
  for( std::map<std::string, CacheEntry>::const_iterator i = m_Cache.begin();
       i != m_Cache.end(); ++i)
    {
    const CacheEntry& ce = (*i).second; 
    CacheEntryType t = ce.m_Type;
    if(t != INTERNAL)
      {
      // Format is key:type=value
      cmCacheManager::OutputHelpString(fout, ce.m_HelpString);
261 262 263 264 265 266 267 268 269 270 271 272 273
      std::string key;
      // support : in key name by double quoting 
      if((*i).first.find(':') != std::string::npos)
        {
        key = "\"";
        key += i->first;
        key += "\"";
        }
      else
        {
        key = i->first;
        }
      fout << key.c_str() << ":"
Bill Hoffman's avatar
Bill Hoffman committed
274
           << cmCacheManagerTypes[t] << "="
Geoffrey Cross's avatar
Geoffrey Cross committed
275
           << ce.m_Value << "\n\n";
Bill Hoffman's avatar
Bill Hoffman committed
276 277
      }
    }
Geoffrey Cross's avatar
Geoffrey Cross committed
278 279 280 281 282 283 284

  fout << "\n";
  fout << "########################\n";
  fout << "# INTERNAL cache entries\n";
  fout << "########################\n";
  fout << "\n";

285
  for( std::map<std::string, CacheEntry>::const_iterator i = m_Cache.begin();
286 287
       i != m_Cache.end(); ++i)
    {
Bill Hoffman's avatar
Bill Hoffman committed
288 289
    const CacheEntry& ce = (*i).second;
    CacheEntryType t = ce.m_Type;
Bill Hoffman's avatar
Bill Hoffman committed
290 291 292 293
    if(t == INTERNAL)
      {
      // Format is key:type=value
      cmCacheManager::OutputHelpString(fout, ce.m_HelpString);
294 295 296 297 298 299 300 301 302 303 304 305 306
      std::string key;
      // support : in key name by double quoting 
      if((*i).first.find(':') != std::string::npos)
        {
        key = "\"";
        key += i->first;
        key += "\"";
        }
      else
        {
        key = i->first;
        }
      fout << key.c_str() << ":"
Bill Hoffman's avatar
Bill Hoffman committed
307 308 309
           << cmCacheManagerTypes[t] << "="
           << ce.m_Value << "\n";
      }
310 311
    }
  fout << "\n";
Bill Hoffman's avatar
Bill Hoffman committed
312 313 314 315
  fout.close();
  cmSystemTools::CopyFileIfDifferent(tempFile.c_str(),
                                     cacheFile.c_str());
  cmSystemTools::RemoveFile(tempFile.c_str());
316
  return true;
317 318
}

Bill Hoffman's avatar
Bill Hoffman committed
319 320
void cmCacheManager::OutputHelpString(std::ofstream& fout, 
                                      const std::string& helpString)
321
{
Bill Hoffman's avatar
Bill Hoffman committed
322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350
  std::string::size_type end = helpString.size();
  if(end == 0)
    {
    return;
    }
  std::string oneLine;
  std::string::size_type pos = 0;
  std::string::size_type nextBreak = 60;
  bool done = false;

  while(!done)
    {
    if(nextBreak >= end)
      {
      nextBreak = end;
      done = true;
      }
    else
      {
      while(nextBreak < end && helpString[nextBreak] != ' ')
        {
        nextBreak++;
        }
      }
    oneLine = helpString.substr(pos, nextBreak - pos);
    fout << "//" << oneLine.c_str() << "\n";
    pos = nextBreak;
    nextBreak += 60;
    }
351 352
}

Bill Hoffman's avatar
Bill Hoffman committed
353
void cmCacheManager::RemoveCacheEntry(const char* key)
354
{
Bill Hoffman's avatar
Bill Hoffman committed
355
  m_Cache.erase(key);
356 357
}

Bill Hoffman's avatar
Bill Hoffman committed
358

359
cmCacheManager::CacheEntry *cmCacheManager::GetCacheEntry(const char* key)
360 361 362
{
  if(m_Cache.count(key))
    {
363 364 365 366 367 368 369 370 371 372
    return &(m_Cache.find(key)->second);
    }
  return 0;
}

const char* cmCacheManager::GetCacheValue(const char* key) const
{
  if(m_Cache.count(key))
    {
    return m_Cache.find(key)->second.m_Value.c_str();
373 374 375
    }
  return 0;
}
Bill Hoffman's avatar
Bill Hoffman committed
376 377


378
void cmCacheManager::PrintCache(std::ostream& out) const
Bill Hoffman's avatar
Bill Hoffman committed
379 380 381
{
  out << "=================================================" << std::endl;
  out << "CMakeCache Contents:" << std::endl;
382
  for(std::map<std::string, CacheEntry>::const_iterator i = m_Cache.begin();
Bill Hoffman's avatar
Bill Hoffman committed
383 384
      i != m_Cache.end(); ++i)
    {
Bill Hoffman's avatar
Bill Hoffman committed
385 386 387 388
    if((*i).second.m_Type != INTERNAL)
      {
      out << (*i).first.c_str() << " = " << (*i).second.m_Value.c_str() << std::endl;
      }
Bill Hoffman's avatar
Bill Hoffman committed
389 390 391 392 393 394 395
    }
  out << "\n\n";
  out << "To change values in the CMakeCache, \nedit CMakeCache.txt in your output directory.\n";
  out << "=================================================" << std::endl;
}


Bill Hoffman's avatar
Bill Hoffman committed
396 397 398 399 400 401 402 403
void cmCacheManager::AddCacheEntry(const char* key, 
                                   const char* value, 
                                   const char* helpString,
				   CacheEntryType type)
{
  CacheEntry e;
  e.m_Value = value;
  e.m_Type = type;
404 405 406 407 408
  // make sure we only use unix style paths
  if(type == FILEPATH || type == PATH)
    {
    cmSystemTools::ConvertToUnixSlashes(e.m_Value);
    }  
Bill Hoffman's avatar
Bill Hoffman committed
409 410 411 412 413 414
  e.m_HelpString = helpString;
  m_Cache[key] = e;
}

void cmCacheManager::AddCacheEntry(const char* key, bool v, 
                                   const char* helpString)
415 416 417
{
  if(v)
    {
Bill Hoffman's avatar
Bill Hoffman committed
418
    this->AddCacheEntry(key, "ON", helpString, cmCacheManager::BOOL);
419 420 421
    }
  else
    {
Bill Hoffman's avatar
Bill Hoffman committed
422
    this->AddCacheEntry(key, "OFF", helpString, cmCacheManager::BOOL);
423 424 425
    }
}