STYLE: Nightly Date Stamp
[cmake.git] / Source / kwsys / Registry.cxx
blob9dd0560f87556623ef3f7236f19d70b62faeef59
1 /*=========================================================================
3 Program: KWSys - Kitware System Library
4 Module: $RCSfile: Registry.cxx,v $
6 Copyright (c) Kitware, Inc., Insight Consortium. All rights reserved.
7 See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
9 This software is distributed WITHOUT ANY WARRANTY; without even
10 the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
11 PURPOSE. See the above copyright notices for more information.
13 =========================================================================*/
14 #include "kwsysPrivate.h"
15 #include KWSYS_HEADER(Registry.hxx)
17 #include KWSYS_HEADER(Configure.hxx)
18 #include KWSYS_HEADER(ios/iostream)
19 #include KWSYS_HEADER(stl/string)
20 #include KWSYS_HEADER(stl/map)
21 #include KWSYS_HEADER(ios/iostream)
22 #include KWSYS_HEADER(ios/fstream)
23 #include KWSYS_HEADER(ios/sstream)
24 // Work-around CMake dependency scanning limitation. This must
25 // duplicate the above list of headers.
26 #if 0
27 # include "Registry.hxx.in"
28 # include "Configure.hxx.in"
29 # include "kwsys_stl.hxx.in"
30 # include "kwsys_stl_string.hxx.in"
31 # include "kwsys_stl_map.hxx.in"
32 # include "kwsys_ios_iostream.h.in"
33 # include "kwsys_ios_fstream.h.in"
34 # include "kwsys_ios_sstream.h.in"
35 #endif
37 #include <ctype.h> // for isspace
38 #include <stdio.h>
39 #include <string.h> /* strlen, strncpy */
40 #include <stdlib.h> /* getenv */
42 #ifdef _WIN32
43 # include <windows.h>
44 #endif
47 namespace KWSYS_NAMESPACE
49 class RegistryHelper {
50 public:
51 RegistryHelper(Registry::RegistryType registryType);
52 virtual ~RegistryHelper();
54 // Read a value from the registry.
55 virtual bool ReadValue(const char *key, const char **value);
57 // Delete a key from the registry.
58 virtual bool DeleteKey(const char *key);
60 // Delete a value from a given key.
61 virtual bool DeleteValue(const char *key);
63 // Set value in a given key.
64 virtual bool SetValue(const char *key, const char *value);
66 // Open the registry at toplevel/subkey.
67 virtual bool Open(const char *toplevel, const char *subkey,
68 int readonly);
70 // Close the registry.
71 virtual bool Close();
73 // Set the value of changed
74 void SetChanged(bool b) { m_Changed = b; }
75 void SetTopLevel(const char* tl);
76 const char* GetTopLevel() { return m_TopLevel.c_str(); }
78 //! Read from local or global scope. On Windows this mean from local machine
79 // or local user. On unix this will read from $HOME/.Projectrc or
80 // /etc/Project
81 void SetGlobalScope(bool b);
82 bool GetGlobalScope();
84 kwsys_stl::string EncodeKey(const char* str);
85 kwsys_stl::string EncodeValue(const char* str);
86 kwsys_stl::string DecodeValue(const char* str);
88 protected:
89 bool m_Changed;
90 kwsys_stl::string m_TopLevel;
91 bool m_GlobalScope;
93 #ifdef _WIN32
94 HKEY HKey;
95 #endif
96 // Strip trailing and ending spaces.
97 char *Strip(char *str);
98 void SetSubKey(const char* sk);
99 kwsys_stl::string CreateKey(const char *key);
101 typedef kwsys_stl::map<kwsys_stl::string, kwsys_stl::string> StringToStringMap;
102 StringToStringMap EntriesMap;
103 kwsys_stl::string m_SubKey;
104 bool m_Empty;
105 bool m_SubKeySpecified;
106 kwsys_stl::string m_HomeDirectory;
108 Registry::RegistryType m_RegistryType;
111 //----------------------------------------------------------------------------
112 #define Registry_BUFFER_SIZE 8192
114 //----------------------------------------------------------------------------
115 Registry::Registry(Registry::RegistryType registryType)
117 m_Opened = false;
118 m_Locked = false;
119 this->Helper = 0;
120 this->Helper = new RegistryHelper(registryType);
123 //----------------------------------------------------------------------------
124 Registry::~Registry()
126 if ( m_Opened )
128 kwsys_ios::cerr << "Registry::Close should be "
129 "called here. The registry is not closed."
130 << kwsys_ios::endl;
132 delete this->Helper;
135 //----------------------------------------------------------------------------
136 void Registry::SetGlobalScope(bool b)
138 this->Helper->SetGlobalScope(b);
141 //----------------------------------------------------------------------------
142 bool Registry::GetGlobalScope()
144 return this->Helper->GetGlobalScope();
147 //----------------------------------------------------------------------------
148 bool Registry::Open(const char *toplevel,
149 const char *subkey, int readonly)
151 bool res = false;
152 if ( m_Locked )
154 return res;
156 if ( m_Opened )
158 if ( !this->Close() )
160 return res;
163 if ( !toplevel || !*toplevel )
165 kwsys_ios::cerr << "Registry::Opened() Toplevel not defined"
166 << kwsys_ios::endl;
167 return res;
170 if ( isspace(toplevel[0]) ||
171 isspace(toplevel[strlen(toplevel)-1]) )
173 kwsys_ios::cerr << "Toplevel has to start with letter or number and end"
174 " with one" << kwsys_ios::endl;
175 return res;
178 res = this->Helper->Open(toplevel, subkey, readonly);
179 if ( readonly != Registry::READONLY )
181 m_Locked = true;
184 if ( res )
186 m_Opened = true;
187 this->Helper->SetTopLevel(toplevel);
189 return res;
192 //----------------------------------------------------------------------------
193 bool Registry::Close()
195 bool res = false;
196 if ( m_Opened )
198 res = this->Helper->Close();
201 if ( res )
203 m_Opened = false;
204 m_Locked = false;
205 this->Helper->SetChanged(false);
207 return res;
210 //----------------------------------------------------------------------------
211 bool Registry::ReadValue(const char *subkey,
212 const char *key,
213 const char **value)
215 bool res = false;
216 bool open = false;
217 if ( ! value )
219 return res;
221 *value = 0;
222 if ( !m_Opened )
224 if ( !this->Open(this->GetTopLevel(), subkey,
225 Registry::READONLY) )
227 return res;
229 open = true;
231 res = this->Helper->ReadValue(key, value);
233 if ( open )
235 if ( !this->Close() )
237 res = false;
240 return res;
243 //----------------------------------------------------------------------------
244 bool Registry::DeleteKey(const char *subkey, const char *key)
246 bool res = false;
247 bool open = false;
248 if ( !m_Opened )
250 if ( !this->Open(this->GetTopLevel(), subkey,
251 Registry::READWRITE) )
253 return res;
255 open = true;
258 res = this->Helper->DeleteKey(key);
259 if ( res )
261 this->Helper->SetChanged(true);
264 if ( open )
266 if ( !this->Close() )
268 res = false;
271 return res;
274 //----------------------------------------------------------------------------
275 bool Registry::DeleteValue(const char *subkey, const char *key)
277 bool res = false;
278 bool open = false;
279 if ( !m_Opened )
281 if ( !this->Open(this->GetTopLevel(), subkey,
282 Registry::READWRITE) )
284 return res;
286 open = true;
289 res = this->Helper->DeleteValue(key);
290 if ( res )
292 this->Helper->SetChanged(true);
295 if ( open )
297 if ( !this->Close() )
299 res = false;
302 return res;
305 //----------------------------------------------------------------------------
306 bool Registry::SetValue(const char *subkey, const char *key,
307 const char *value)
309 bool res = false;
310 bool open = false;
311 if ( !m_Opened )
313 if ( !this->Open(this->GetTopLevel(), subkey,
314 Registry::READWRITE) )
316 return res;
318 open = true;
321 res = this->Helper->SetValue( key, value );
322 if ( res )
324 this->Helper->SetChanged(true);
327 if ( open )
329 if ( !this->Close() )
331 res = false;
334 return res;
337 //----------------------------------------------------------------------------
338 const char* Registry::GetTopLevel()
340 return this->Helper->GetTopLevel();
343 //----------------------------------------------------------------------------
344 void Registry::SetTopLevel(const char* tl)
346 this->Helper->SetTopLevel(tl);
349 //----------------------------------------------------------------------------
350 void RegistryHelper::SetTopLevel(const char* tl)
352 if ( tl )
354 m_TopLevel = tl;
356 else
358 m_TopLevel = "";
362 //----------------------------------------------------------------------------
363 RegistryHelper::RegistryHelper(Registry::RegistryType registryType)
365 m_Changed = false;
366 m_TopLevel = "";
367 m_SubKey = "";
368 m_SubKeySpecified = false;
369 m_Empty = true;
370 m_GlobalScope = false;
371 m_RegistryType = registryType;
374 //----------------------------------------------------------------------------
375 RegistryHelper::~RegistryHelper()
380 //----------------------------------------------------------------------------
381 bool RegistryHelper::Open(const char *toplevel, const char *subkey,
382 int readonly)
384 this->EntriesMap.clear();
385 m_Empty = 1;
387 #ifdef _WIN32
388 if ( m_RegistryType == Registry::WIN32_REGISTRY)
390 HKEY scope = HKEY_CURRENT_USER;
391 if ( this->GetGlobalScope() )
393 scope = HKEY_LOCAL_MACHINE;
395 int res = 0;
396 kwsys_ios::ostringstream str;
397 DWORD dwDummy;
398 str << "Software\\Kitware\\" << toplevel << "\\" << subkey;
399 if ( readonly == Registry::READONLY )
401 res = ( RegOpenKeyEx(scope, str.str().c_str(),
402 0, KEY_READ, &this->HKey) == ERROR_SUCCESS );
404 else
406 res = ( RegCreateKeyEx(scope, str.str().c_str(),
407 0, "", REG_OPTION_NON_VOLATILE, KEY_READ|KEY_WRITE,
408 NULL, &this->HKey, &dwDummy) == ERROR_SUCCESS );
410 if ( res != 0 )
412 this->SetSubKey( subkey );
414 return (res != 0);
416 #endif
417 if ( m_RegistryType == Registry::FILE_REGISTRY )
419 bool res = false;
420 int cc;
421 kwsys_ios::ostringstream str;
422 const char* homeDirectory;
423 if ( (homeDirectory = getenv("HOME")) == 0 )
425 if ( (homeDirectory = getenv("USERPROFILE")) == 0 )
427 return false;
430 m_HomeDirectory = homeDirectory;
431 str << m_HomeDirectory.c_str() << "/." << toplevel << "rc";
432 if ( readonly == Registry::READWRITE )
434 kwsys_ios::ofstream ofs( str.str().c_str(), kwsys_ios::ios::out|kwsys_ios::ios::app );
435 if ( ofs.fail() )
437 return false;
439 ofs.close();
442 kwsys_ios::ifstream *ifs = new kwsys_ios::ifstream(str.str().c_str(), kwsys_ios::ios::in
443 #ifndef KWSYS_IOS_USE_ANSI
444 | kwsys_ios::ios::nocreate
445 #endif
447 if ( !ifs )
449 return false;
451 if ( ifs->fail())
453 delete ifs;
454 return false;
457 res = true;
458 char buffer[Registry_BUFFER_SIZE];
459 while( !ifs->fail() )
461 ifs->getline(buffer, Registry_BUFFER_SIZE);
462 if ( ifs->fail() || ifs->eof() )
464 break;
466 char *line = this->Strip(buffer);
467 if ( *line == '#' || *line == 0 )
469 // Comment
470 continue;
472 int linelen = static_cast<int>(strlen(line));
473 for ( cc = 0; cc < linelen; cc++ )
475 if ( line[cc] == '=' )
477 char *key = new char[ cc+1 ];
478 strncpy( key, line, cc );
479 key[cc] = 0;
480 char *value = line + cc + 1;
481 char *nkey = this->Strip(key);
482 char *nvalue = this->Strip(value);
483 this->EntriesMap[nkey] = this->DecodeValue(nvalue);
484 m_Empty = 0;
485 delete [] key;
486 break;
490 ifs->close();
491 this->SetSubKey( subkey );
492 delete ifs;
493 return res;
495 return false;
498 //----------------------------------------------------------------------------
499 bool RegistryHelper::Close()
501 #ifdef _WIN32
502 if ( m_RegistryType == Registry::WIN32_REGISTRY)
504 int res;
505 res = ( RegCloseKey(this->HKey) == ERROR_SUCCESS );
506 return (res != 0);
508 #endif
509 if ( m_RegistryType == Registry::FILE_REGISTRY )
511 if ( !m_Changed )
513 this->SetSubKey(0);
514 return true;
517 kwsys_ios::ostringstream str;
518 str << m_HomeDirectory.c_str() << "/." << this->GetTopLevel() << "rc";
519 kwsys_ios::ofstream *ofs = new kwsys_ios::ofstream(str.str().c_str(), kwsys_ios::ios::out);
520 if ( !ofs )
522 return false;
524 if ( ofs->fail())
526 delete ofs;
527 return false;
529 *ofs << "# This file is automatically generated by the application" << kwsys_ios::endl
530 << "# If you change any lines or add new lines, note that all" << kwsys_ios::endl
531 << "# comments and empty lines will be deleted. Every line has" << kwsys_ios::endl
532 << "# to be in format: " << kwsys_ios::endl
533 << "# key = value" << kwsys_ios::endl
534 << "#" << kwsys_ios::endl;
536 if ( !this->EntriesMap.empty() )
538 RegistryHelper::StringToStringMap::iterator it;
539 for ( it = this->EntriesMap.begin();
540 it != this->EntriesMap.end();
541 ++ it )
543 *ofs << it->first.c_str() << " = " << this->EncodeValue(it->second.c_str()).c_str() << kwsys_ios::endl;
546 this->EntriesMap.clear();
547 ofs->close();
548 delete ofs;
549 this->SetSubKey(0);
550 m_Empty = 1;
551 return true;
553 return false;
556 //----------------------------------------------------------------------------
557 bool RegistryHelper::ReadValue(const char *skey, const char **value)
560 #ifdef _WIN32
561 if ( m_RegistryType == Registry::WIN32_REGISTRY)
563 kwsys_stl::string key = this->CreateKey( skey );
564 if ( key.empty() )
566 return false;
568 DWORD dwType, dwSize;
569 dwType = REG_SZ;
570 char buffer[1024]; // Replace with RegQueryInfoKey
571 dwSize = sizeof(buffer);
572 int res = ( RegQueryValueEx(this->HKey, skey, NULL, &dwType,
573 (BYTE *)buffer, &dwSize) == ERROR_SUCCESS );
574 if ( !res )
576 return false;
578 this->EntriesMap[key] = buffer;
579 RegistryHelper::StringToStringMap::iterator it
580 = this->EntriesMap.find(key);
581 *value = it->second.c_str();
582 return true;
584 #endif
585 if ( m_RegistryType == Registry::FILE_REGISTRY )
587 bool res = false;
588 kwsys_stl::string key = this->CreateKey( skey );
589 if ( key.empty() )
591 return false;
594 RegistryHelper::StringToStringMap::iterator it
595 = this->EntriesMap.find(key);
596 if ( it != this->EntriesMap.end() )
598 *value = it->second.c_str();
599 res = true;
601 return res;
603 return false;
606 //----------------------------------------------------------------------------
607 bool RegistryHelper::DeleteKey(const char* skey)
609 #ifdef _WIN32
610 if ( m_RegistryType == Registry::WIN32_REGISTRY)
612 int res = ( RegDeleteKey( this->HKey, skey ) == ERROR_SUCCESS );
613 return (res != 0);
615 #endif
616 if ( m_RegistryType == Registry::FILE_REGISTRY )
618 kwsys_stl::string key = this->CreateKey( skey );
619 if ( key.empty() )
621 return false;
623 this->EntriesMap.erase(key);
624 return true;
626 return false;
629 //----------------------------------------------------------------------------
630 bool RegistryHelper::DeleteValue(const char *skey)
632 #ifdef _WIN32
633 if ( m_RegistryType == Registry::WIN32_REGISTRY)
635 int res = ( RegDeleteValue( this->HKey, skey ) == ERROR_SUCCESS );
636 return (res != 0);
638 #endif
639 if ( m_RegistryType == Registry::FILE_REGISTRY )
641 kwsys_stl::string key = this->CreateKey( skey );
642 if ( key.empty() )
644 return false;
646 this->EntriesMap.erase(key);
647 return true;
649 return false;
652 //----------------------------------------------------------------------------
653 bool RegistryHelper::SetValue(const char *skey, const char *value)
655 #ifdef _WIN32
656 if ( m_RegistryType == Registry::WIN32_REGISTRY)
658 DWORD len = (DWORD)(value ? strlen(value) : 0);
659 int res = ( RegSetValueEx(this->HKey, skey, 0, REG_SZ,
660 (CONST BYTE *)(const char *)value,
661 len+1) == ERROR_SUCCESS );
662 return (res != 0);
664 #endif
665 if ( m_RegistryType == Registry::FILE_REGISTRY )
667 kwsys_stl::string key = this->CreateKey( skey );
668 if ( key.empty() )
670 return 0;
672 this->EntriesMap[key] = value;
673 return 1;
675 return false;
678 //----------------------------------------------------------------------------
679 kwsys_stl::string RegistryHelper::CreateKey( const char *key )
681 if ( !m_SubKeySpecified || m_SubKey.empty() || !key )
683 return "";
685 kwsys_ios::ostringstream ostr;
686 ostr << this->EncodeKey(this->m_SubKey.c_str()).c_str()
687 << "\\" << this->EncodeKey(key).c_str();
688 return ostr.str();
691 //----------------------------------------------------------------------------
692 void RegistryHelper::SetSubKey(const char* sk)
694 if ( !sk )
696 m_SubKey = "";
697 m_SubKeySpecified = false;
699 else
701 m_SubKey = sk;
702 m_SubKeySpecified = true;
706 //----------------------------------------------------------------------------
707 char *RegistryHelper::Strip(char *str)
709 int cc;
710 size_t len;
711 char *nstr;
712 if ( !str )
714 return NULL;
716 len = strlen(str);
717 nstr = str;
718 for( cc=0; cc < static_cast<int>(len); cc++ )
720 if ( !isspace( *nstr ) )
722 break;
724 nstr ++;
726 for( cc= static_cast<int>(strlen(nstr))-1; cc>=0; cc-- )
728 if ( !isspace( nstr[cc] ) )
730 nstr[cc+1] = 0;
731 break;
734 return nstr;
737 //----------------------------------------------------------------------------
738 void RegistryHelper::SetGlobalScope(bool b)
740 m_GlobalScope = b;
743 //----------------------------------------------------------------------------
744 bool RegistryHelper::GetGlobalScope()
746 return m_GlobalScope;
749 //----------------------------------------------------------------------------
750 kwsys_stl::string RegistryHelper::EncodeKey(const char* str)
752 kwsys_ios::ostringstream ostr;
753 while ( *str )
755 switch ( *str )
757 case '%': case '=': case '\n': case '\r': case '\t':
758 char buffer[4];
759 sprintf(buffer, "%%%02X", *str);
760 ostr << buffer;
761 break;
762 default:
763 ostr << *str;
765 str ++;
767 return ostr.str();
770 //----------------------------------------------------------------------------
771 kwsys_stl::string RegistryHelper::EncodeValue(const char* str)
773 kwsys_ios::ostringstream ostr;
774 while ( *str )
776 switch ( *str )
778 case '%': case '=': case '\n': case '\r': case '\t':
779 char buffer[4];
780 sprintf(buffer, "%%%02X", *str);
781 ostr << buffer;
782 break;
783 default:
784 ostr << *str;
786 str ++;
788 return ostr.str();
791 //----------------------------------------------------------------------------
792 kwsys_stl::string RegistryHelper::DecodeValue(const char* str)
794 kwsys_ios::ostringstream ostr;
795 while ( *str )
797 unsigned int val;
798 switch ( *str )
800 case '%':
801 if ( *(str+1) && *(str+2) && sscanf(str+1, "%x", &val) == 1 )
803 ostr << static_cast<char>(val);
804 str += 2;
806 else
808 ostr << *str;
810 break;
811 default:
812 ostr << *str;
814 str ++;
816 return ostr.str();
819 } // namespace KWSYS_NAMESPACE