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.
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"
37 #include <ctype.h> // for isspace
39 #include <string.h> /* strlen, strncpy */
40 #include <stdlib.h> /* getenv */
47 namespace KWSYS_NAMESPACE
49 class RegistryHelper
{
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
,
70 // Close the registry.
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
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
);
90 kwsys_stl::string m_TopLevel
;
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
;
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
)
120 this->Helper
= new RegistryHelper(registryType
);
123 //----------------------------------------------------------------------------
124 Registry::~Registry()
128 kwsys_ios::cerr
<< "Registry::Close should be "
129 "called here. The registry is not closed."
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
)
158 if ( !this->Close() )
163 if ( !toplevel
|| !*toplevel
)
165 kwsys_ios::cerr
<< "Registry::Opened() Toplevel not defined"
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
;
178 res
= this->Helper
->Open(toplevel
, subkey
, readonly
);
179 if ( readonly
!= Registry::READONLY
)
187 this->Helper
->SetTopLevel(toplevel
);
192 //----------------------------------------------------------------------------
193 bool Registry::Close()
198 res
= this->Helper
->Close();
205 this->Helper
->SetChanged(false);
210 //----------------------------------------------------------------------------
211 bool Registry::ReadValue(const char *subkey
,
224 if ( !this->Open(this->GetTopLevel(), subkey
,
225 Registry::READONLY
) )
231 res
= this->Helper
->ReadValue(key
, value
);
235 if ( !this->Close() )
243 //----------------------------------------------------------------------------
244 bool Registry::DeleteKey(const char *subkey
, const char *key
)
250 if ( !this->Open(this->GetTopLevel(), subkey
,
251 Registry::READWRITE
) )
258 res
= this->Helper
->DeleteKey(key
);
261 this->Helper
->SetChanged(true);
266 if ( !this->Close() )
274 //----------------------------------------------------------------------------
275 bool Registry::DeleteValue(const char *subkey
, const char *key
)
281 if ( !this->Open(this->GetTopLevel(), subkey
,
282 Registry::READWRITE
) )
289 res
= this->Helper
->DeleteValue(key
);
292 this->Helper
->SetChanged(true);
297 if ( !this->Close() )
305 //----------------------------------------------------------------------------
306 bool Registry::SetValue(const char *subkey
, const char *key
,
313 if ( !this->Open(this->GetTopLevel(), subkey
,
314 Registry::READWRITE
) )
321 res
= this->Helper
->SetValue( key
, value
);
324 this->Helper
->SetChanged(true);
329 if ( !this->Close() )
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
)
362 //----------------------------------------------------------------------------
363 RegistryHelper::RegistryHelper(Registry::RegistryType registryType
)
368 m_SubKeySpecified
= false;
370 m_GlobalScope
= false;
371 m_RegistryType
= registryType
;
374 //----------------------------------------------------------------------------
375 RegistryHelper::~RegistryHelper()
380 //----------------------------------------------------------------------------
381 bool RegistryHelper::Open(const char *toplevel
, const char *subkey
,
384 this->EntriesMap
.clear();
388 if ( m_RegistryType
== Registry::WIN32_REGISTRY
)
390 HKEY scope
= HKEY_CURRENT_USER
;
391 if ( this->GetGlobalScope() )
393 scope
= HKEY_LOCAL_MACHINE
;
396 kwsys_ios::ostringstream str
;
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
);
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
);
412 this->SetSubKey( subkey
);
417 if ( m_RegistryType
== Registry::FILE_REGISTRY
)
421 kwsys_ios::ostringstream str
;
422 const char* homeDirectory
;
423 if ( (homeDirectory
= getenv("HOME")) == 0 )
425 if ( (homeDirectory
= getenv("USERPROFILE")) == 0 )
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
);
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
458 char buffer
[Registry_BUFFER_SIZE
];
459 while( !ifs
->fail() )
461 ifs
->getline(buffer
, Registry_BUFFER_SIZE
);
462 if ( ifs
->fail() || ifs
->eof() )
466 char *line
= this->Strip(buffer
);
467 if ( *line
== '#' || *line
== 0 )
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
);
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
);
491 this->SetSubKey( subkey
);
498 //----------------------------------------------------------------------------
499 bool RegistryHelper::Close()
502 if ( m_RegistryType
== Registry::WIN32_REGISTRY
)
505 res
= ( RegCloseKey(this->HKey
) == ERROR_SUCCESS
);
509 if ( m_RegistryType
== Registry::FILE_REGISTRY
)
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
);
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();
543 *ofs
<< it
->first
.c_str() << " = " << this->EncodeValue(it
->second
.c_str()).c_str() << kwsys_ios::endl
;
546 this->EntriesMap
.clear();
556 //----------------------------------------------------------------------------
557 bool RegistryHelper::ReadValue(const char *skey
, const char **value
)
561 if ( m_RegistryType
== Registry::WIN32_REGISTRY
)
563 kwsys_stl::string key
= this->CreateKey( skey
);
568 DWORD dwType
, dwSize
;
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
);
578 this->EntriesMap
[key
] = buffer
;
579 RegistryHelper::StringToStringMap::iterator it
580 = this->EntriesMap
.find(key
);
581 *value
= it
->second
.c_str();
585 if ( m_RegistryType
== Registry::FILE_REGISTRY
)
588 kwsys_stl::string key
= this->CreateKey( skey
);
594 RegistryHelper::StringToStringMap::iterator it
595 = this->EntriesMap
.find(key
);
596 if ( it
!= this->EntriesMap
.end() )
598 *value
= it
->second
.c_str();
606 //----------------------------------------------------------------------------
607 bool RegistryHelper::DeleteKey(const char* skey
)
610 if ( m_RegistryType
== Registry::WIN32_REGISTRY
)
612 int res
= ( RegDeleteKey( this->HKey
, skey
) == ERROR_SUCCESS
);
616 if ( m_RegistryType
== Registry::FILE_REGISTRY
)
618 kwsys_stl::string key
= this->CreateKey( skey
);
623 this->EntriesMap
.erase(key
);
629 //----------------------------------------------------------------------------
630 bool RegistryHelper::DeleteValue(const char *skey
)
633 if ( m_RegistryType
== Registry::WIN32_REGISTRY
)
635 int res
= ( RegDeleteValue( this->HKey
, skey
) == ERROR_SUCCESS
);
639 if ( m_RegistryType
== Registry::FILE_REGISTRY
)
641 kwsys_stl::string key
= this->CreateKey( skey
);
646 this->EntriesMap
.erase(key
);
652 //----------------------------------------------------------------------------
653 bool RegistryHelper::SetValue(const char *skey
, const char *value
)
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
);
665 if ( m_RegistryType
== Registry::FILE_REGISTRY
)
667 kwsys_stl::string key
= this->CreateKey( skey
);
672 this->EntriesMap
[key
] = value
;
678 //----------------------------------------------------------------------------
679 kwsys_stl::string
RegistryHelper::CreateKey( const char *key
)
681 if ( !m_SubKeySpecified
|| m_SubKey
.empty() || !key
)
685 kwsys_ios::ostringstream ostr
;
686 ostr
<< this->EncodeKey(this->m_SubKey
.c_str()).c_str()
687 << "\\" << this->EncodeKey(key
).c_str();
691 //----------------------------------------------------------------------------
692 void RegistryHelper::SetSubKey(const char* sk
)
697 m_SubKeySpecified
= false;
702 m_SubKeySpecified
= true;
706 //----------------------------------------------------------------------------
707 char *RegistryHelper::Strip(char *str
)
718 for( cc
=0; cc
< static_cast<int>(len
); cc
++ )
720 if ( !isspace( *nstr
) )
726 for( cc
= static_cast<int>(strlen(nstr
))-1; cc
>=0; cc
-- )
728 if ( !isspace( nstr
[cc
] ) )
737 //----------------------------------------------------------------------------
738 void RegistryHelper::SetGlobalScope(bool 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
;
757 case '%': case '=': case '\n': case '\r': case '\t':
759 sprintf(buffer
, "%%%02X", *str
);
770 //----------------------------------------------------------------------------
771 kwsys_stl::string
RegistryHelper::EncodeValue(const char* str
)
773 kwsys_ios::ostringstream ostr
;
778 case '%': case '=': case '\n': case '\r': case '\t':
780 sprintf(buffer
, "%%%02X", *str
);
791 //----------------------------------------------------------------------------
792 kwsys_stl::string
RegistryHelper::DecodeValue(const char* str
)
794 kwsys_ios::ostringstream ostr
;
801 if ( *(str
+1) && *(str
+2) && sscanf(str
+1, "%x", &val
) == 1 )
803 ostr
<< static_cast<char>(val
);
819 } // namespace KWSYS_NAMESPACE