2
* This file is part of the Code::Blocks IDE and licensed under the GNU Lesser General Public License, version 3
3
* http://www.gnu.org/licenses/lgpl-3.0.html
6
* $Id: configmanager.cpp 6014 2009-12-31 21:44:01Z jenslody $
7
* $HeadURL: svn+ssh://jenslody@svn.berlios.de/svnroot/repos/codeblocks/trunk/src/sdk/configmanager.cpp $
10
#include "sdk_precomp.h"
13
#include "configmanager.h"
15
#include "personalitymanager.h"
16
#include "cbexception.h"
17
#include "logmanager.h"
20
#include <wx/log.h> // for wxSafeShowMessage()
26
#include <wx/stream.h>
27
#include <wx/stdpaths.h>
33
#if defined(__APPLE__) && defined(__MACH__)
34
#include <sys/param.h>
35
#include <mach-o/dyld.h>
39
#include "wx/mac/corefoundation/cfstring.h"
42
#include <CoreFoundation/CFBundle.h>
43
#include <CoreFoundation/CFURL.h>
46
#include "tinyxml/tinywxuni.h"
49
template<> CfgMgrBldr* Mgr<CfgMgrBldr>::instance = 0;
50
template<> bool Mgr<CfgMgrBldr>::isShutdown = false;
52
wxString ConfigManager::config_folder;
53
wxString ConfigManager::home_folder;
54
wxString ConfigManager::data_path_user;
55
wxString ConfigManager::data_path_global;
57
wxString ConfigManager::plugin_path_global;
59
wxString ConfigManager::app_path;
60
wxString ConfigManager::temp_folder;
61
bool ConfigManager::relo = 0;
64
wxString GetPortableConfigDir()
68
int ret = GetEnvironmentVariable(_T("APPDATA"), buffer, bufLen);
71
return wxStandardPathsBase::Get().GetUserDataDir();
75
return wxString::Format(_T("%s\\codeblocks"), buffer);
80
namespace CfgMgrConsts
82
const wxString app_path(_T("app_path"));
83
const wxString data_path(_T("data_path"));
84
const wxString dotDot(_T(".."));
85
const int version = 1;
91
wxString DetermineExecutablePath()
94
wxChar name[MAX_PATH];
95
GetModuleFileName(0L, name, MAX_PATH);
96
wxFileName fname(name);
97
return fname.GetPath(wxPATH_GET_VOLUME);
101
char *p = realpath("/proc/self/exe", &c[0]);
104
wxFileName fname(cbC2U(p));
105
return fname.GetPath(wxPATH_GET_VOLUME);
106
#elif defined(sun) || defined(__sun)
107
wxFileName fname(cbC2U(getexecname()));
108
return fname.GetPath(wxPATH_GET_VOLUME);
109
#elif defined(__APPLE__) && defined(__MACH__)
110
char path[MAXPATHLEN+1];
111
uint32_t path_len = MAXPATHLEN;
112
// SPI first appeared in Mac OS X 10.2
113
_NSGetExecutablePath(path, &path_len);
114
wxFileName fname(wxString(path, wxConvUTF8));
115
return fname.GetPath(wxPATH_GET_VOLUME);
122
wxString DetermineResourcesPath()
124
#if defined(__WXMAC__)
125
CFURLRef resourcesURL = CFBundleCopyResourcesDirectoryURL(CFBundleGetMainBundle());
126
CFURLRef absoluteURL = CFURLCopyAbsoluteURL(resourcesURL); // relative -> absolute
127
CFRelease(resourcesURL);
128
CFStringRef cfStrPath = CFURLCopyFileSystemPath(absoluteURL,kCFURLPOSIXPathStyle);
129
CFRelease(absoluteURL);
130
wxString str = wxMacCFStringHolder(cfStrPath).AsString(wxLocale::GetSystemEncoding());
131
if (!str.Contains(wxString(_T("/Resources"))))
132
return ::DetermineExecutablePath() + _T("/.."); // not a bundle, use relative path
141
inline void ConfigManager::Collapse(wxString& str) const
143
const wxChar *src = str.c_str();
144
wxChar *dst = (wxChar*) src;
157
while(*src == _T('/'))
163
ISerializable::ISerializable()
166
ISerializable::~ISerializable()
172
/* ------------------------------------------------------------------------------------------------------------------
173
* "Builder pattern" class for ConfigManager
174
* Do not use this class - Manager::Get()->GetConfigManager() is a lot friendlier
177
CfgMgrBldr::CfgMgrBldr() : doc(0), volatile_doc(0), r(false)
179
TiXmlBase::SetCondenseWhiteSpace(false);
180
wxString personality(Manager::Get()->GetPersonalityManager()->GetPersonality());
182
if(personality.StartsWith(_T("http://")))
184
SwitchToR(personality);
188
cfg = FindConfigFile(personality + _T(".conf"));
193
cfg = GetPortableConfigDir() + wxFILE_SEP_PATH + personality + _T(".conf");
195
cfg = wxStandardPathsBase::Get().GetUserDataDir() + wxFILE_SEP_PATH + personality + _T(".conf");
197
doc = new TiXmlDocument();
198
doc->InsertEndChild(TiXmlDeclaration("1.0", "UTF-8", "yes"));
199
doc->InsertEndChild(TiXmlElement("CodeBlocksConfig"));
200
doc->FirstChildElement("CodeBlocksConfig")->SetAttribute("version", CfgMgrConsts::version);
207
wxString CfgMgrBldr::FindConfigFile(const wxString& filename)
209
wxPathList searchPaths;
212
wxString u(GetPortableConfigDir() + wxFILE_SEP_PATH + filename);
214
wxString u(wxStandardPathsBase::Get().GetUserDataDir() + wxFILE_SEP_PATH + filename);
216
wxString e(::DetermineExecutablePath() + wxFILE_SEP_PATH +filename);
218
if(::wxFileExists(u))
222
if(::wxFileExists(e))
224
ConfigManager::relo = true;
227
return wxEmptyString;
231
void CfgMgrBldr::SwitchTo(const wxString& fileName)
233
doc = new TiXmlDocument();
235
if(!TinyXML::LoadDocument(fileName, doc))
236
cbThrow(wxString::Format(_T("Error accessing file:\n%s"), fileName.c_str()));
239
cbThrow(wxString::Format(_T("TinyXML error: %s\nIn file: %s\nAt row %d, column: %d."), cbC2U(doc->ErrorDesc()).c_str(), fileName.c_str(), doc->ErrorRow(), doc->ErrorCol()));
241
TiXmlElement* docroot = doc->FirstChildElement("CodeBlocksConfig");
244
cbThrow(wxString::Format(_T("TinyXML error: %s\nIn file: %s\nAt row %d, column: %d."), cbC2U(doc->ErrorDesc()).c_str(), fileName.c_str(), doc->ErrorRow(), doc->ErrorCol()));
246
const char *vers = docroot->Attribute("version");
247
if(!vers || atoi(vers) != 1)
248
cbMessageBox(_("ConfigManager encountered an unknown config file version. Continuing happily."), _("Warning"), wxICON_WARNING);
255
info.Printf(_T( " application info:\n"
256
"\t svn_revision:\t%d\n"
257
"\t build_date:\t%s, %s "), ConfigManager::GetRevisionNumber(), wxT(__DATE__), wxT(__TIME__));
260
info.Printf(_T( " application info:\n"
261
"\t svn_revision:\t%d\n"
262
"\t build_date:\t%s, %s\n"
263
"\t gcc_version:\t%d.%d.%d "), ConfigManager::GetRevisionNumber(), wxT(__DATE__), wxT(__TIME__),
264
__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__);
267
if(platform::windows)
268
info.append(_T("\n\t Windows "));
270
info.append(_T("\n\t Linux "));
272
info.append(_T("\n\t Mac OS X "));
274
info.append(_T("\n\t Unix "));
276
info.append(platform::unicode ? _T("Unicode ") : _T("ANSI "));
279
c.SetValue((const char*) info.mb_str());
281
TiXmlNode *firstchild = docroot->FirstChild();
282
if(firstchild && firstchild->ToComment())
284
docroot->RemoveChild(firstchild);
285
firstchild = docroot->FirstChild();
289
docroot->InsertBeforeChild(firstchild, c);
291
docroot->InsertEndChild(c);
294
void CfgMgrBldr::SwitchToR(const wxString& absFileName)
298
doc = new TiXmlDocument();
303
wxURL url(absFileName);
304
url.SetProxy(ConfigManager::GetProxy());
305
if (url.GetError() == wxURL_NOERR)
307
wxInputStream *is = url.GetInputStream();
308
if (is && is->IsOk())
310
size_t size = is->GetSize();
312
#if wxCHECK_VERSION(2, 9, 0)
313
wxChar* c = wxStringBuffer(str, size);
315
wxChar* c = str.GetWriteBuf(size);
318
#if !wxCHECK_VERSION(2, 9, 0)
319
str.UngetWriteBuf(size);
322
doc = new TiXmlDocument();
324
if(doc->Parse(cbU2C(str)))
330
if(Manager::Get()->GetLogManager())
332
Manager::Get()->GetLogManager()->DebugLog(_T("##### Error loading or parsing remote config file"));
333
Manager::Get()->GetLogManager()->DebugLog(cbC2U(doc->ErrorDesc()));
340
SwitchTo(wxEmptyString); // fall back
343
CfgMgrBldr::~CfgMgrBldr()
345
NamespaceMap::iterator it;
346
for( it = namespaces.begin(); it != namespaces.end(); ++it )
355
void CfgMgrBldr::Close()
359
if(!cfg.StartsWith(_T("http://")))
361
if (!TinyXML::SaveDocument(cfg, doc))
363
wxSafeShowMessage(_T("Could not save config file..."), _("Warning"));
364
// TODO (thomas#1#): add "retry" option
369
// implement WebDAV another time
377
ConfigManager* CfgMgrBldr::GetConfigManager(const wxString& name_space)
379
return Get()->Build(name_space);
383
ConfigManager* CfgMgrBldr::Build(const wxString& name_space)
385
if(name_space.IsEmpty())
386
cbThrow(_T("You attempted to get a ConfigManager instance without providing a namespace."));
388
wxCriticalSectionLocker locker(cs);
389
NamespaceMap::iterator it = namespaces.find(name_space);
390
if(it != namespaces.end())
393
TiXmlElement* docroot;
395
if(name_space.StartsWith(_T("volatile:")))
399
volatile_doc = new TiXmlDocument();
400
volatile_doc->InsertEndChild(TiXmlElement("CodeBlocksConfig"));
401
volatile_doc->SetCondenseWhiteSpace(false);
403
docroot = volatile_doc->FirstChildElement("CodeBlocksConfig");
407
docroot = doc->FirstChildElement("CodeBlocksConfig");
410
wxString err(_("Fatal error parsing supplied configuration file.\nParser error message:\n"));
411
err << wxString::Format(_T("%s\nAt row %d, column: %d."), cbC2U(doc->ErrorDesc()).c_str(), doc->ErrorRow(), doc->ErrorCol());
416
TiXmlElement* root = docroot->FirstChildElement(cbU2C(name_space));
418
if(!root) // namespace does not exist
420
docroot->InsertEndChild(TiXmlElement(cbU2C(name_space)));
421
root = docroot->FirstChildElement(cbU2C(name_space));
424
if(!root) // now what!
425
cbThrow(_T("Unable to create namespace in document tree (actually not possible..?)"));
427
ConfigManager *c = new ConfigManager(root);
428
namespaces[name_space] = c;
435
* Hack to enable Turkish language. wxString::Upper will convert lowercase 'i' to \u0130 instead of \u0069 in Turkish locale,
436
* which will break the config file when used in a tag
438
inline void to_upper(wxString& s)
440
#if wxCHECK_VERSION(2, 9, 0)
441
wxStringCharType *p = const_cast<wxStringCharType*>(s.wx_str());
444
wxChar *p = (wxChar*) s.c_str();
447
size_t len = s.length()+1;
451
if(q >= 'a' && q <= 'z')
456
inline void to_lower(wxString& s)
458
#if wxCHECK_VERSION(2, 9, 0)
459
wxStringCharType *p = const_cast<wxStringCharType*>(s.wx_str());
462
wxChar *p = (wxChar*) s.c_str();
465
size_t len = s.length()+1;
469
if(q >= 'A' && q <= 'Z')
475
/* ------------------------------------------------------------------------------------------------------------------
476
* Functions to retrieve system paths and locate data files in a defined, consistent way.
477
* Please note that the application determines app_path and data_path at runtime and passes the results
478
* to ConfigManager. GetExecutableFolder() and GetDataFolder() are therefore under normal conditions
479
* simply more efficient shortcuts for Read("app_path") and Read("data_path").
482
wxString ConfigManager::GetProxy()
484
return Manager::Get()->GetConfigManager(_T("app"))->Read(_T("network_proxy"));
488
wxString ConfigManager::GetFolder(SearchDirs dir)
490
static bool once = 1;
501
return ConfigManager::home_folder;
504
return ConfigManager::app_path;
507
return ConfigManager::temp_folder;
510
return ConfigManager::config_folder;
515
case sdPluginsGlobal:
517
return ConfigManager::data_path_global + _T("/plugins");
519
return ConfigManager::plugin_path_global;
523
return ConfigManager::data_path_user + _T("/plugins");
525
case sdScriptsGlobal:
526
return ConfigManager::data_path_global + _T("/scripts");
529
return ConfigManager::data_path_user + _T("/scripts");
532
return ConfigManager::data_path_global;
535
return ConfigManager::data_path_user;
538
return wxEmptyString;
542
wxString ConfigManager::LocateDataFile(const wxString& filename, int search_dirs)
544
wxPathList searchPaths;
546
// user dirs have precedence
547
if (search_dirs & sdPluginsUser)
548
searchPaths.Add(GetPluginsFolder(false));
549
if (search_dirs & sdScriptsUser)
550
searchPaths.Add(GetScriptsFolder(false));
551
if (search_dirs & sdDataUser)
552
searchPaths.Add(GetDataFolder(false));
554
// then we have global dirs
555
if (search_dirs & sdPluginsGlobal)
556
searchPaths.Add(GetPluginsFolder(true));
557
if (search_dirs & sdScriptsGlobal)
558
searchPaths.Add(GetScriptsFolder(true));
559
if (search_dirs & sdDataGlobal)
560
searchPaths.Add(GetDataFolder(true));
563
if (search_dirs & sdCurrent)
564
searchPaths.Add(::wxGetCwd());
565
if (search_dirs & sdConfig)
566
searchPaths.Add(GetConfigFolder());
567
if (search_dirs & sdHome)
568
searchPaths.Add(GetHomeFolder());
569
if (search_dirs & sdBase)
570
searchPaths.Add(GetExecutableFolder());
571
if (search_dirs & sdTemp)
572
searchPaths.Add(GetTempFolder());
575
if (search_dirs & sdPath)
576
searchPaths.AddEnvList(_T("PATH"));
578
return searchPaths.FindValidPath(filename);
583
/* ------------------------------------------------------------------------------------------------------------------
587
ConfigManager::ConfigManager(TiXmlElement* r) : doc(r->GetDocument()), root(r), pathNode(r)
594
/* ------------------------------------------------------------------------------------------------------------------
595
* Configuration path handling
596
* Note that due to namespaces, you do no longer need to care about saving/restoring the current path in the normal case.
597
* Mostly, there will be only one module working with one namespace, and every namespace keeps track of its own path.
598
* Also, please note that GetPath() is more expensive than it seems (not a mere accessor to a member variable!), while
599
* SetPath() not only sets the current path, but also creates the respective nodes in the XML document if these don't exist.
602
wxString ConfigManager::GetPath() const
604
TiXmlElement *e = pathNode;
608
ret = cbC2U(e->Value());
609
while((e = e->Parent()->ToElement()) && e != root)
611
ret.Prepend(_T('/'));
612
ret.Prepend(cbC2U(e->Value()));
614
ret.Prepend(_T('/'));
618
void ConfigManager::SetPath(const wxString& path)
620
wxString p(path + _T('/'));
621
pathNode = AssertPath(p);
624
wxString ConfigManager::InvalidNameMessage(const wxString& what, const wxString& sub, TiXmlElement *localPath) const
627
s.Printf(_T("The %s %s (child of node \"%s\" in namespace \"%s\") does not meet the standard for path naming (must start with a letter)."),
630
cbC2U(localPath->Value()).c_str(),
631
cbC2U(root->Value()).c_str());
637
TiXmlElement* ConfigManager::AssertPath(wxString& path)
641
wxString illegal(_T(" -:.\"\'$&()[]<>+#"));
643
while((i = path.find_first_of(illegal, i)) != wxString::npos)
646
TiXmlElement *localPath = pathNode ? pathNode : root;
648
if(path.GetChar(0) == '/') // absolute path
654
if(path.find(_T('/')) != wxString::npos) // need for path walking
659
while(path.find(_T('/')) != wxString::npos)
661
sub = path.BeforeFirst(_T('/'));
662
path = path.AfterFirst(_T('/'));
664
if(localPath != root && sub.IsSameAs(CfgMgrConsts::dotDot))
665
localPath = localPath->Parent()->ToElement();
666
else if(sub.GetChar(0) < _T('a') || sub.GetChar(0) > _T('z'))
668
cbThrow(InvalidNameMessage(_T("subpath"), sub, localPath));
672
TiXmlElement* n = localPath->FirstChildElement(cbU2C(sub));
676
localPath = (TiXmlElement*) localPath->InsertEndChild(TiXmlElement(cbU2C(sub)));
682
if(!path.IsEmpty() && (path.GetChar(0) < _T('A') || path.GetChar(0) > _T('Z')))
683
cbThrow(InvalidNameMessage(_T("key"), path, localPath));
689
/* -----------------------------------------------------------------------------------------------------
690
* Clear all nodes from your namespace or delete the namespace alltogether (removing it from the config file).
691
* After Delete() returns, the pointer to your instance is invalid.
694
void ConfigManager::Clear()
699
void ConfigManager::Delete()
701
CfgMgrBldr * bld = CfgMgrBldr::Get();
702
wxString ns(cbC2U(root->Value()));
705
doc->RootElement()->RemoveChild(root);
707
wxCriticalSectionLocker(bld->cs);
708
NamespaceMap::iterator it = bld->namespaces.find(ns);
709
if(it != bld->namespaces.end())
710
bld->namespaces.erase(it);
715
void ConfigManager::DeleteAll()
717
CfgMgrBldr * bld = CfgMgrBldr::Get();
718
wxString ns(cbC2U(root->Value()));
720
if(!ns.IsSameAs(_T("app")))
721
cbThrow(_T("Illegal attempt to invoke DeleteAll()."));
723
wxCriticalSectionLocker(bld->cs);
724
doc->RootElement()->Clear();
725
for(NamespaceMap::iterator it = bld->namespaces.begin(); it != bld->namespaces.end(); ++it)
728
bld->namespaces.erase(it);
733
/* ------------------------------------------------------------------------------------------------------------------
734
* Utility functions for writing nodes
737
TiXmlElement* ConfigManager::GetUniqElement(TiXmlElement* p, const wxString& q)
740
if((r = p->FirstChildElement(cbU2C(q))))
743
return (TiXmlElement*)(p->InsertEndChild(TiXmlElement(cbU2C(q))));
746
void ConfigManager::SetNodeText(TiXmlElement* n, const TiXmlText& t)
748
TiXmlNode *c = n->FirstChild();
750
n->ReplaceChild(c, t);
752
n->InsertEndChild(t);
757
/* ------------------------------------------------------------------------------------------------------------------
758
* Write and read values
759
* Regardless of namespaces, the string keys app_path and data_path always refer to the location of the application's executable
760
* and the data path, respectively. These values are never saved to the configuration, but kept in static variables.
761
* The application makes use of this by "writing" to the configuration file after determining these values at runtime.
763
void ConfigManager::Write(const wxString& name, const wxString& value, bool ignoreEmpty)
765
if(name.IsSameAs(CfgMgrConsts::app_path))
769
else if(name.IsSameAs(CfgMgrConsts::data_path))
771
data_path_global = value;
774
if(ignoreEmpty && value.IsEmpty())
781
TiXmlElement* e = AssertPath(key);
783
TiXmlElement *str = GetUniqElement(e, key);
785
TiXmlElement *s = GetUniqElement(str, _T("str"));
787
TiXmlText t(value.mb_str(wxConvUTF8));
792
void ConfigManager::Write(const wxString& key, const char* str)
794
/* NOTE (mandrav#1#): Do *not* remove 'false' from the call because in ANSI builds,
795
it matches this very function and overflows the stack... */
796
Write(key, cbC2U(str), false);
799
wxString ConfigManager::Read(const wxString& name, const wxString& defaultVal)
801
if(name.IsSameAs(CfgMgrConsts::app_path))
803
else if(name.IsSameAs(CfgMgrConsts::data_path))
804
return data_path_global;
814
bool ConfigManager::Read(const wxString& name, wxString* str)
816
if(name.IsSameAs(CfgMgrConsts::app_path))
818
str->assign(app_path);
821
else if(name.IsSameAs(CfgMgrConsts::data_path))
823
str->assign(data_path_global);
828
TiXmlElement* e = AssertPath(key);
830
TiXmlHandle parentHandle(e);
831
TiXmlText *t = (TiXmlText *) parentHandle.FirstChild(cbU2C(key)).FirstChild("str").FirstChild().Node();
835
str->assign(cbC2U(t->Value()));
841
void ConfigManager::Write(const wxString& name, const wxColour& c)
844
TiXmlElement* e = AssertPath(key);
846
TiXmlElement *leaf = GetUniqElement(e, key);
848
TiXmlElement *s = GetUniqElement(leaf, _T("colour"));
849
s->SetAttribute("r", c.Red());
850
s->SetAttribute("g", c.Green());
851
s->SetAttribute("b", c.Blue());
854
wxColour ConfigManager::ReadColour(const wxString& name, const wxColour& defaultVal)
864
bool ConfigManager::Read(const wxString& name, wxColour* ret)
867
TiXmlElement* e = AssertPath(key);
869
TiXmlHandle parentHandle(e);
870
TiXmlElement *c = (TiXmlElement *) parentHandle.FirstChild(cbU2C(key)).FirstChild("colour").Element();
875
if(c->QueryIntAttribute("r", &r) == TIXML_SUCCESS
876
&& c->QueryIntAttribute("g", &g) == TIXML_SUCCESS
877
&& c->QueryIntAttribute("b", &b) == TIXML_SUCCESS)
884
void ConfigManager::Write(const wxString& name, int value)
887
TiXmlElement* e = AssertPath(key);
888
TiXmlElement *leaf = GetUniqElement(e, key);
890
leaf->SetAttribute("int", value);
893
int ConfigManager::ReadInt(const wxString& name, int defaultVal)
903
bool ConfigManager::Read(const wxString& name, int* value)
906
TiXmlElement* e = AssertPath(key);
908
TiXmlHandle parentHandle(e);
909
TiXmlElement *leaf = parentHandle.FirstChild(cbU2C(key)).Element();
912
return leaf->QueryIntAttribute("int", value) == TIXML_SUCCESS;
917
void ConfigManager::Write(const wxString& name, bool value)
920
TiXmlElement* e = AssertPath(key);
921
TiXmlElement *leaf = GetUniqElement(e, key);
923
leaf->SetAttribute("bool", value ? "1" : "0");
926
bool ConfigManager::ReadBool(const wxString& name, bool defaultVal)
936
bool ConfigManager::Read(const wxString& name, bool* value)
939
TiXmlElement* e = AssertPath(key);
941
TiXmlHandle parentHandle(e);
942
TiXmlElement *leaf = parentHandle.FirstChild(cbU2C(key)).Element();
944
if(leaf && leaf->Attribute("bool"))
946
*value = leaf->Attribute("bool")[0] == '1';
953
void ConfigManager::Write(const wxString& name, double value)
956
TiXmlElement* e = AssertPath(key);
957
TiXmlElement *leaf = GetUniqElement(e, key);
959
leaf->SetDoubleAttribute("double", value);
962
double ConfigManager::ReadDouble(const wxString& name, double defaultVal)
972
bool ConfigManager::Read(const wxString& name, double* value)
975
TiXmlElement* e = AssertPath(key);
977
TiXmlHandle parentHandle(e);
978
TiXmlElement *leaf = parentHandle.FirstChild(cbU2C(key)).Element();
981
return leaf->QueryDoubleAttribute("double", value) == TIXML_SUCCESS;
986
void ConfigManager::Set(const wxString& name)
989
TiXmlElement* e = AssertPath(key);
990
GetUniqElement(e, key);
993
void ConfigManager::UnSet(const wxString& name)
996
TiXmlElement* e = AssertPath(key);
998
TiXmlNode *leaf = GetUniqElement(e, key);
999
e->RemoveChild(leaf);
1002
bool ConfigManager::Exists(const wxString& name)
1005
TiXmlElement* e = AssertPath(key);
1007
TiXmlHandle parentHandle(e);
1008
TiXmlElement *leaf = parentHandle.FirstChild(cbU2C(key)).Element();
1015
void ConfigManager::Write(const wxString& name, const wxArrayString& arrayString)
1018
TiXmlElement* e = AssertPath(key);
1020
TiXmlElement *leaf = GetUniqElement(e, key);
1023
as = GetUniqElement(leaf, _T("astr"));
1024
leaf->RemoveChild(as);
1025
as = GetUniqElement(leaf, _T("astr"));
1027
for(unsigned int i = 0; i < arrayString.GetCount(); ++i)
1029
TiXmlElement s("s");
1031
TiXmlText t(arrayString[i].mb_str(wxConvUTF8));
1034
s.InsertEndChild(t);
1035
as->InsertEndChild(s);
1039
void ConfigManager::Read(const wxString& name, wxArrayString *arrayString)
1042
TiXmlElement* e = AssertPath(key);
1044
TiXmlHandle parentHandle(e);
1045
TiXmlNode *asNode = parentHandle.FirstChild(cbU2C(key)).FirstChild("astr").Node();
1047
TiXmlNode *curr = 0;
1050
while((curr = asNode->IterateChildren("s", curr)))
1052
arrayString->Add(cbC2U(curr->FirstChild()->ToText()->Value()));
1057
wxArrayString ConfigManager::ReadArrayString(const wxString& name)
1064
void ConfigManager::WriteBinary(const wxString& name, const wxString& source)
1067
TiXmlElement* e = AssertPath(key);
1069
TiXmlElement *str = GetUniqElement(e, key);
1071
TiXmlElement *s = GetUniqElement(str, _T("bin"));
1072
s->SetAttribute("crc", wxCrc32::FromString(source));
1073
SetNodeText(s, TiXmlText(wxBase64::Encode(source).mb_str(wxConvUTF8)));
1076
void ConfigManager::WriteBinary(const wxString& name, void* ptr, size_t len)
1078
wxString s((wxChar*)ptr, len);
1079
WriteBinary(name, s);
1082
wxString ConfigManager::ReadBinary(const wxString& name)
1086
TiXmlElement* e = AssertPath(key);
1087
unsigned int crc = 0;
1089
TiXmlHandle parentHandle(e);
1090
TiXmlElement* bin = parentHandle.FirstChild(cbU2C(key)).FirstChild("bin").Element();
1093
return wxEmptyString;
1095
if(bin->QueryIntAttribute("crc", (int*)&crc) != TIXML_SUCCESS)
1096
return wxEmptyString;
1098
if (const TiXmlText* t = bin->FirstChild()->ToText())
1100
str.assign(cbC2U(t->Value()));
1101
str = wxBase64::Decode(str);
1102
if(crc == wxCrc32::FromString(str))
1105
return wxEmptyString;
1109
wxArrayString ConfigManager::EnumerateSubPaths(const wxString& path)
1111
wxString key(path + _T('/')); // the trailing slash hack is required because AssertPath expects a key name
1112
TiXmlNode* e = AssertPath(key);
1115
TiXmlElement *curr = 0;
1118
while(e->IterateChildren(curr) && (curr = e->IterateChildren(curr)->ToElement()))
1120
#if wxCHECK_VERSION(2, 9, 0)
1121
wxUniChar c = cbC2U(curr->Value())[0];
1123
wxChar c = *(cbC2U(curr->Value()));
1125
if(c < _T('A') || c > _T('Z')) // first char must be a letter, uppercase letters are key names
1126
ret.Add(cbC2U(curr->Value()));
1132
void ConfigManager::DeleteSubPath(const wxString& thePath)
1136
cbMessageBox(wxString(_T("### TinyXML error:\n")) << cbC2U(doc->ErrorDesc()));
1140
wxString path(thePath);
1145
wxString illegal(_T(" :.,;!\"\'$%&()[]<>{}?*+-|#"));
1147
while((i = path.find_first_of(illegal)) != wxString::npos)
1150
if(path.Last() == _T('/'))
1153
if(path.IsSameAs(_T("/"))) // this function will refuse to remove root!
1156
TiXmlElement* parent = pathNode ? pathNode : root;
1158
if(path.find(_T('/')) != wxString::npos)
1163
sub = path.BeforeFirst(_T('/'));
1164
path = path.AfterFirst(_T('/'));
1168
else if(sub.IsSameAs(_T(".")))
1170
else if(parent != root && sub.IsSameAs(_T("..")))
1171
parent = parent->Parent()->ToElement();
1174
TiXmlElement* n = parent->FirstChildElement(cbU2C(sub));
1181
while(path.find(_T('/')) != wxString::npos);
1186
if(TiXmlNode *toRemove = parent->FirstChild(cbU2C(path)))
1189
parent->RemoveChild(toRemove);
1195
wxArrayString ConfigManager::EnumerateKeys(const wxString& path)
1197
wxString key(path + _T('/')); // the trailing slash hack is required because AssertPath expects a key name
1198
TiXmlNode* e = AssertPath(key);
1201
TiXmlElement *curr = 0;
1204
while(e->IterateChildren(curr) && (curr = e->IterateChildren(curr)->ToElement()))
1206
#if wxCHECK_VERSION(2, 9, 0)
1207
wxUniChar c = cbC2U(curr->Value())[0];
1209
wxChar c = *(cbC2U(curr->Value()));
1211
if(c >= _T('A') && c <= _T('Z')) // opposite of the above
1212
ret.Add(cbC2U(curr->Value()));
1218
void ConfigManager::Write(const wxString& name, const ISerializable& object)
1221
TiXmlElement* e = AssertPath(key);
1223
TiXmlElement *obj = GetUniqElement(e, key);
1225
TiXmlElement *s = GetUniqElement(obj, _T("obj"));
1226
SetNodeText(s, TiXmlText(cbU2C(wxBase64::Encode(object.SerializeOut()))));
1229
bool ConfigManager::Read(const wxString& name, ISerializable* object)
1233
TiXmlElement* e = AssertPath(key);
1235
TiXmlHandle parentHandle(e);
1236
TiXmlText *t = (TiXmlText *) parentHandle.FirstChild(cbU2C(key)).FirstChild("obj").FirstChild().Node();
1240
str.assign(cbC2U(t->Value()));
1241
object->SerializeIn(wxBase64::Decode(str));
1243
return wxEmptyString;
1246
void ConfigManager::Write(const wxString& name, const ConfigManagerContainer::StringToStringMap& map)
1249
TiXmlElement* e = AssertPath(key);
1251
TiXmlElement *leaf = GetUniqElement(e, key);
1253
TiXmlElement *mNode;
1254
mNode = GetUniqElement(leaf, _T("ssmap"));
1255
leaf->RemoveChild(mNode);
1256
mNode = GetUniqElement(leaf, _T("ssmap"));
1258
for(ConfigManagerContainer::StringToStringMap::const_iterator it = map.begin(); it != map.end(); ++it)
1260
TiXmlElement s(cbU2C(it->first));
1262
TiXmlText t(cbU2C(it->second));
1265
s.InsertEndChild(t);
1266
mNode->InsertEndChild(s);
1270
void ConfigManager::Read(const wxString& name, ConfigManagerContainer::StringToStringMap* map)
1273
TiXmlElement* e = AssertPath(key);
1275
TiXmlHandle parentHandle(e);
1276
TiXmlNode *mNode = parentHandle.FirstChild(cbU2C(key)).FirstChild("ssmap").Node();
1278
TiXmlNode *curr = 0;
1281
while((curr = mNode->IterateChildren(curr)))
1282
(*map)[cbC2U(curr->Value())] = cbC2U(curr->FirstChild()->ToText()->Value());
1286
ConfigManagerContainer::StringToStringMap ConfigManager::ReadSSMap(const wxString& name)
1288
ConfigManagerContainer::StringToStringMap ret;
1293
void ConfigManager::Write(const wxString& name, const ConfigManagerContainer::IntToStringMap& map)
1296
TiXmlElement* e = AssertPath(key);
1298
TiXmlElement *leaf = GetUniqElement(e, key);
1300
TiXmlElement *mNode;
1301
mNode = GetUniqElement(leaf, _T("ismap"));
1302
leaf->RemoveChild(mNode);
1303
mNode = GetUniqElement(leaf, _T("ismap"));
1306
for(ConfigManagerContainer::IntToStringMap::const_iterator it = map.begin(); it != map.end(); ++it)
1308
tmp.Printf(_T("x%d"), (int) it->first);
1309
TiXmlElement s(tmp.mb_str());
1311
TiXmlText t(cbU2C(it->second));
1314
s.InsertEndChild(t);
1315
mNode->InsertEndChild(s);
1319
void ConfigManager::Read(const wxString& name, ConfigManagerContainer::IntToStringMap* map)
1322
TiXmlElement* e = AssertPath(key);
1324
TiXmlHandle parentHandle(e);
1325
TiXmlNode *mNode = parentHandle.FirstChild(cbU2C(key)).FirstChild("ismap").Node();
1327
TiXmlNode *curr = 0;
1331
while((curr = mNode->IterateChildren(curr)))
1333
cbC2U(curr->Value()).Mid(1).ToLong(&tmp);
1334
(*map)[tmp] = cbC2U(curr->FirstChild()->ToText()->Value());
1339
ConfigManagerContainer::IntToStringMap ConfigManager::ReadISMap(const wxString& name)
1341
ConfigManagerContainer::IntToStringMap ret;
1351
void ConfigManager::Write(const wxString& name, const ConfigManagerContainer::StringSet& set)
1354
TiXmlElement* e = AssertPath(key);
1356
TiXmlElement *leaf = GetUniqElement(e, key);
1358
TiXmlElement *mNode;
1359
mNode = GetUniqElement(leaf, _T("sset"));
1360
leaf->RemoveChild(mNode);
1361
mNode = GetUniqElement(leaf, _T("sset"));
1363
for(ConfigManagerContainer::StringSet::const_iterator it = set.begin(); it != set.end(); ++it)
1365
TiXmlElement s("s");
1367
TiXmlText t(cbU2C(*it));
1370
s.InsertEndChild(t);
1371
mNode->InsertEndChild(s);
1376
void ConfigManager::Read(const wxString& name, ConfigManagerContainer::StringSet* set)
1379
TiXmlElement* e = AssertPath(key);
1381
TiXmlHandle parentHandle(e);
1382
TiXmlNode *mNode = parentHandle.FirstChild(cbU2C(key)).FirstChild("sset").Node();
1384
TiXmlNode *curr = 0;
1387
while((curr = mNode->IterateChildren(curr)))
1388
set->insert(cbC2U(curr->FirstChild()->ToText()->Value()));
1392
ConfigManagerContainer::StringSet ConfigManager::ReadSSet(const wxString& name)
1394
ConfigManagerContainer::StringSet ret;
1400
void ConfigManager::Write(const wxString& name, const ConfigManagerContainer::SerializableObjectMap* map)
1403
TiXmlElement* e = AssertPath(key);
1405
TiXmlElement *leaf = GetUniqElement(e, key);
1407
TiXmlElement *mNode;
1408
mNode = GetUniqElement(leaf, _T("objmap"));
1409
leaf->RemoveChild(mNode);
1410
mNode = GetUniqElement(leaf, _T("objmap"));
1412
for(ConfigManagerContainer::SerializableObjectMap::const_iterator it = map->begin(); it != map->end(); ++it)
1414
TiXmlElement s(cbU2C(it->first));
1415
s.InsertEndChild(TiXmlText(cbU2C(wxBase64::Encode(it->second->SerializeOut()))));
1416
mNode->InsertEndChild(s);
1421
void ConfigManager::InitPaths()
1424
ConfigManager::config_folder = GetPortableConfigDir();
1426
ConfigManager::config_folder = wxStandardPathsBase::Get().GetUserDataDir();
1428
ConfigManager::home_folder = wxStandardPathsBase::Get().GetUserConfigDir();
1429
ConfigManager::app_path = ::DetermineExecutablePath();
1430
wxString res_path = ::DetermineResourcesPath();
1432
// if non-empty, the app has overriden it (e.g. "--prefix" was passed in the command line)
1433
if (data_path_global.IsEmpty())
1435
if(platform::windows)
1436
ConfigManager::data_path_global = app_path + _T("/share/codeblocks");
1437
else if(platform::macosx)
1438
ConfigManager::data_path_global = res_path + _T("/share/codeblocks");
1440
ConfigManager::data_path_global = wxStandardPathsBase::Get().GetDataDir();
1443
if (plugin_path_global.IsEmpty())
1445
if(platform::windows || platform::macosx)
1446
ConfigManager::plugin_path_global = data_path_global;
1449
ConfigManager::plugin_path_global = wxStandardPathsBase::Get().GetPluginsDir() + _T("/plugins");
1450
// first assume, we use standard-paths
1451
if(!wxDirExists(ConfigManager::plugin_path_global) && wxIsPlatform64Bit())
1453
// if standard-path does not exist and we are on 64-bit system, use lib64 instead
1454
ConfigManager::plugin_path_global = ((const wxStandardPaths&)wxStandardPaths::Get()).GetInstallPrefix() + _T("/lib64/codeblocks/plugins");
1460
ConfigManager::data_path_user = ConfigManager::relo ? data_path_global : config_folder + _T("/share/codeblocks");
1462
CreateDirRecursively(ConfigManager::config_folder);
1463
CreateDirRecursively(ConfigManager::data_path_user + _T("/plugins/"));
1464
CreateDir(ConfigManager::data_path_user + _T("/scripts/"));
1466
ConfigManager::temp_folder = wxStandardPathsBase::Get().GetTempDir();