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