]> git.saurik.com Git - wxWidgets.git/blob - src/common/config.cpp
fix from Robert
[wxWidgets.git] / src / common / config.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: config.cpp
3 // Purpose: implementation of wxConfigBase class
4 // Author: Vadim Zeitlin
5 // Modified by:
6 // Created: 07.04.98
7 // RCS-ID: $Id$
8 // Copyright: (c) 1997 Karsten Ballüder Ballueder@usa.net
9 // Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>
10 // Licence: wxWindows license
11 ///////////////////////////////////////////////////////////////////////////////
12
13 // ----------------------------------------------------------------------------
14 // headers
15 // ----------------------------------------------------------------------------
16 #ifdef __GNUG__
17 #pragma implementation "confbase.h"
18 #endif
19
20 #include "wx/wxprec.h"
21
22 #ifdef __BORLANDC__
23 #pragma hdrstop
24 #endif //__BORLANDC__
25
26 #ifndef wxUSE_CONFIG_NATIVE
27 #define wxUSE_CONFIG_NATIVE 1
28 #endif
29
30 #if wxUSE_CONFIG && ((wxUSE_FILE && wxUSE_TEXTFILE) || wxUSE_CONFIG_NATIVE)
31
32 #include "wx/app.h"
33 #include "wx/file.h"
34 #include "wx/log.h"
35 #include "wx/textfile.h"
36 #include "wx/utils.h"
37 #include "wx/log.h"
38 #include "wx/utils.h"
39 #include "wx/intl.h"
40
41 #include "wx/config.h"
42
43 #include <stdlib.h>
44 #include <math.h>
45 #include <ctype.h>
46
47 // ----------------------------------------------------------------------------
48 // global and class static variables
49 // ----------------------------------------------------------------------------
50
51 wxConfigBase *wxConfigBase::ms_pConfig = NULL;
52 bool wxConfigBase::ms_bAutoCreate = TRUE;
53
54 // ============================================================================
55 // implementation
56 // ============================================================================
57
58 // ----------------------------------------------------------------------------
59 // wxConfigBase
60 // ----------------------------------------------------------------------------
61
62 // Not all args will always be used by derived classes, but including them all
63 // in each class ensures compatibility.
64 wxConfigBase::wxConfigBase(const wxString& appName,
65 const wxString& vendorName,
66 const wxString& WXUNUSED(localFilename),
67 const wxString& WXUNUSED(globalFilename),
68 long style)
69 : m_appName(appName), m_vendorName(vendorName), m_style(style)
70 {
71 m_bExpandEnvVars = TRUE; m_bRecordDefaults = FALSE;
72 }
73
74 wxConfigBase::~wxConfigBase()
75 {
76 }
77
78 wxConfigBase *wxConfigBase::Set(wxConfigBase *pConfig)
79 {
80 wxConfigBase *pOld = ms_pConfig;
81 ms_pConfig = pConfig;
82 return pOld;
83 }
84
85 wxConfigBase *wxConfigBase::Create()
86 {
87 if ( ms_bAutoCreate && ms_pConfig == NULL ) {
88 ms_pConfig =
89 #if defined(__WXMSW__) && wxUSE_CONFIG_NATIVE
90 #ifdef __WIN32__
91 new wxRegConfig(wxTheApp->GetAppName(), wxTheApp->GetVendorName());
92 #else //WIN16
93 new wxIniConfig(wxTheApp->GetAppName(), wxTheApp->GetVendorName());
94 #endif
95 #else // either we're under Unix or wish to use files even under Windows
96 new wxFileConfig(wxTheApp->GetAppName());
97 #endif
98 }
99
100 return ms_pConfig;
101 }
102
103 wxString wxConfigBase::Read(const wxString& key, const wxString& defVal) const
104 {
105 wxString s;
106 Read(key, &s, defVal);
107 return s;
108 }
109
110 bool wxConfigBase::Read(const wxString& key, wxString *str, const wxString& defVal) const
111 {
112 if (!Read(key, str))
113 {
114 *str = ExpandEnvVars(defVal);
115 return FALSE;
116 }
117 else
118 return TRUE;
119 }
120
121 bool wxConfigBase::Read(const wxString& key, long *pl, long defVal) const
122 {
123 if (!Read(key, pl))
124 {
125 *pl = defVal;
126 return FALSE;
127 }
128 else
129 return TRUE;
130 }
131
132 bool wxConfigBase::Read(const wxString& key, double* val) const
133 {
134 wxString str;
135 if (Read(key, & str))
136 {
137 *val = wxAtof(str);
138 return TRUE;
139 }
140
141 return FALSE;
142 }
143
144 bool wxConfigBase::Read(const wxString& key, double* val, double defVal) const
145 {
146 if (!Read(key, val))
147 {
148 *val = defVal;
149 return FALSE;
150 }
151 else
152 return TRUE;
153 }
154
155 bool wxConfigBase::Read(const wxString& key, bool* val) const
156 {
157 long l;
158 if (Read(key, & l))
159 {
160 *val = (l != 0);
161 return TRUE;
162 }
163 else
164 return FALSE;
165 }
166
167 bool wxConfigBase::Read(const wxString& key, bool* val, bool defVal) const
168 {
169 if (!Read(key, val))
170 {
171 *val = defVal;
172 return FALSE;
173 }
174 else
175 return TRUE;
176 }
177
178 // Convenience functions
179
180 bool wxConfigBase::Read(const wxString& key, int *pi) const
181 {
182 long l;
183 bool ret = Read(key, &l);
184 if (ret)
185 *pi = (int) l;
186 return ret;
187 }
188
189 bool wxConfigBase::Read(const wxString& key, int *pi, int defVal) const
190 {
191 long l;
192 bool ret = Read(key, &l, (long) defVal);
193 *pi = (int) l;
194 return ret;
195 }
196
197 bool wxConfigBase::Write(const wxString& key, double val)
198 {
199 wxString str;
200 str.Printf(wxT("%f"), val);
201 return Write(key, str);
202 }
203
204 bool wxConfigBase::Write(const wxString& key, bool value)
205 {
206 long l = (value ? 1 : 0);
207 return Write(key, l);
208 }
209
210 bool wxConfigBase::Write( const wxString &key, const wxChar *text )
211 {
212 wxString str( text ) ;
213 return Write( key, str ) ;
214 }
215 wxString wxConfigBase::ExpandEnvVars(const wxString& str) const
216 {
217 wxString tmp; // Required for BC++
218 if (IsExpandingEnvVars())
219 tmp = wxExpandEnvVars(str);
220 else
221 tmp = str;
222 return tmp;
223 }
224
225 // ----------------------------------------------------------------------------
226 // wxConfigPathChanger
227 // ----------------------------------------------------------------------------
228
229 wxConfigPathChanger::wxConfigPathChanger(const wxConfigBase *pContainer,
230 const wxString& strEntry)
231 {
232 m_pContainer = (wxConfigBase *)pContainer;
233
234 // the path is everything which precedes the last slash
235 wxString strPath = strEntry.BeforeLast(wxCONFIG_PATH_SEPARATOR);
236
237 // except in the special case of "/keyname" when there is nothing before "/"
238 if ( strPath.IsEmpty() &&
239 ((!strEntry.IsEmpty()) && strEntry[0] == wxCONFIG_PATH_SEPARATOR) )
240 {
241 strPath = wxCONFIG_PATH_SEPARATOR;
242 }
243
244 if ( !strPath.IsEmpty() ) {
245 // do change the path
246 m_bChanged = TRUE;
247 m_strName = strEntry.AfterLast(wxCONFIG_PATH_SEPARATOR);
248 m_strOldPath = m_pContainer->GetPath();
249 m_strOldPath += wxCONFIG_PATH_SEPARATOR;
250 m_pContainer->SetPath(strPath);
251 }
252 else {
253 // it's a name only, without path - nothing to do
254 m_bChanged = FALSE;
255 m_strName = strEntry;
256 }
257 }
258
259 wxConfigPathChanger::~wxConfigPathChanger()
260 {
261 // only restore path if it was changed
262 if ( m_bChanged ) {
263 m_pContainer->SetPath(m_strOldPath);
264 }
265 }
266
267 // ----------------------------------------------------------------------------
268 // static & global functions
269 // ----------------------------------------------------------------------------
270
271 // understands both Unix and Windows (but only under Windows) environment
272 // variables expansion: i.e. $var, $(var) and ${var} are always understood
273 // and in addition under Windows %var% is also.
274 wxString wxExpandEnvVars(const wxString& str)
275 {
276 wxString strResult;
277 strResult.Alloc(str.Len());
278
279 // don't change the values the enum elements: they must be equal
280 // to the matching [closing] delimiter.
281 enum Bracket
282 {
283 Bracket_None,
284 Bracket_Normal = ')',
285 Bracket_Curly = '}'
286 #ifdef __WXMSW__
287 ,Bracket_Windows = '%' // yeah, Windows people are a bit strange ;-)
288 #endif
289 };
290
291 size_t m;
292 for ( size_t n = 0; n < str.Len(); n++ ) {
293 switch ( str[n] ) {
294 #ifdef __WXMSW__
295 case wxT('%'):
296 #endif //WINDOWS
297 case wxT('$'):
298 {
299 Bracket bracket;
300 #ifdef __WXMSW__
301 if ( str[n] == wxT('%') )
302 bracket = Bracket_Windows;
303 else
304 #endif //WINDOWS
305 if ( n == str.Len() - 1 ) {
306 bracket = Bracket_None;
307 }
308 else {
309 switch ( str[n + 1] ) {
310 case wxT('('):
311 bracket = Bracket_Normal;
312 n++; // skip the bracket
313 break;
314
315 case wxT('{'):
316 bracket = Bracket_Curly;
317 n++; // skip the bracket
318 break;
319
320 default:
321 bracket = Bracket_None;
322 }
323 }
324
325 m = n + 1;
326
327 while ( m < str.Len() && (wxIsalnum(str[m]) || str[m] == wxT('_')) )
328 m++;
329
330 wxString strVarName(str.c_str() + n + 1, m - n - 1);
331
332 const wxChar *pszValue = wxGetenv(strVarName);
333 if ( pszValue != NULL ) {
334 strResult += pszValue;
335 }
336 else {
337 // variable doesn't exist => don't change anything
338 #ifdef __WXMSW__
339 if ( bracket != Bracket_Windows )
340 #endif
341 if ( bracket != Bracket_None )
342 strResult << str[n - 1];
343 strResult << str[n] << strVarName;
344 }
345
346 // check the closing bracket
347 if ( bracket != Bracket_None ) {
348 if ( m == str.Len() || str[m] != (char)bracket ) {
349 wxLogWarning(_("Environment variables expansion failed: missing '%c' at position %d in '%s'."),
350 (char)bracket, m + 1, str.c_str());
351 }
352 else {
353 // skip closing bracket unless the variables wasn't expanded
354 if ( pszValue == NULL )
355 strResult << (char)bracket;
356 m++;
357 }
358 }
359
360 n = m - 1; // skip variable name
361 }
362 break;
363
364 case '\\':
365 // backslash can be used to suppress special meaning of % and $
366 if ( n != str.Len() && (str[n + 1] == wxT('%') || str[n + 1] == wxT('$')) ) {
367 strResult += str[++n];
368
369 break;
370 }
371 //else: fall through
372
373 default:
374 strResult += str[n];
375 }
376 }
377
378 return strResult;
379 }
380
381 // this function is used to properly interpret '..' in path
382 void wxSplitPath(wxArrayString& aParts, const wxChar *sz)
383 {
384 aParts.Empty();
385
386 wxString strCurrent;
387 const wxChar *pc = sz;
388 for ( ;; ) {
389 if ( *pc == wxT('\0') || *pc == wxCONFIG_PATH_SEPARATOR ) {
390 if ( strCurrent == wxT(".") ) {
391 // ignore
392 }
393 else if ( strCurrent == wxT("..") ) {
394 // go up one level
395 if ( aParts.IsEmpty() )
396 wxLogWarning(_("'%s' has extra '..', ignored."), sz);
397 else
398 aParts.Remove(aParts.Count() - 1);
399
400 strCurrent.Empty();
401 }
402 else if ( !strCurrent.IsEmpty() ) {
403 aParts.Add(strCurrent);
404 strCurrent.Empty();
405 }
406 //else:
407 // could log an error here, but we prefer to ignore extra '/'
408
409 if ( *pc == wxT('\0') )
410 break;
411 }
412 else
413 strCurrent += *pc;
414
415 pc++;
416 }
417 }
418
419 #endif // wxUSE_CONFIG
420