home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / wxos2233.zip / wxOS2-2_3_3.zip / wxWindows-2.3.3 / src / common / config.cpp < prev    next >
C/C++ Source or Header  |  2001-12-17  |  14KB  |  418 lines

  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: config.cpp,v 1.54 2001/12/14 00:58:59 VZ Exp $
  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. #include <limits.h>     // for INT_MAX
  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. // ----------------------------------------------------------------------------
  104. // wxConfigBase reading entries
  105. // ----------------------------------------------------------------------------
  106.  
  107. // implement both Read() overloads for the given type in terms of DoRead()
  108. #define IMPLEMENT_READ_FOR_TYPE(name, type, deftype, extra)                 \
  109.     bool wxConfigBase::Read(const wxString& key, type *val) const           \
  110.     {                                                                       \
  111.         wxCHECK_MSG( val, FALSE, _T("wxConfig::Read(): NULL parameter") );  \
  112.                                                                             \
  113.         return DoRead##name(key, val);                                      \
  114.     }                                                                       \
  115.                                                                             \
  116.     bool wxConfigBase::Read(const wxString& key,                            \
  117.                             type *val,                                      \
  118.                             deftype defVal) const                           \
  119.     {                                                                       \
  120.         wxCHECK_MSG( val, FALSE, _T("wxConfig::Read(): NULL parameter") );  \
  121.                                                                             \
  122.         if ( DoRead##name(key, val) )                                       \
  123.             return TRUE;                                                    \
  124.                                                                             \
  125.         if ( IsRecordingDefaults() )                                        \
  126.         {                                                                   \
  127.             ((wxConfigBase *)this)->DoWrite##name(key, defVal);             \
  128.         }                                                                   \
  129.                                                                             \
  130.         *val = extra(defVal);                                               \
  131.                                                                             \
  132.         return FALSE;                                                       \
  133.     }
  134.  
  135.  
  136. IMPLEMENT_READ_FOR_TYPE(String, wxString, const wxString&, ExpandEnvVars)
  137. IMPLEMENT_READ_FOR_TYPE(Long, long, long, long)
  138. IMPLEMENT_READ_FOR_TYPE(Int, int, int, int)
  139. IMPLEMENT_READ_FOR_TYPE(Double, double, double, double)
  140. IMPLEMENT_READ_FOR_TYPE(Bool, bool, bool, bool)
  141.  
  142. #undef IMPLEMENT_READ_FOR_TYPE
  143.  
  144. // the DoReadXXX() for the other types have implementation in the base class
  145. // but can be overridden in the derived ones
  146. bool wxConfigBase::DoReadInt(const wxString& key, int *pi) const
  147. {
  148.     wxCHECK_MSG( pi, FALSE, _T("wxConfig::Read(): NULL parameter") );
  149.  
  150.     long l;
  151.     if ( !DoReadLong(key, &l) )
  152.         return FALSE;
  153.  
  154.     wxASSERT_MSG( l < INT_MAX, _T("overflow in wxConfig::DoReadInt") );
  155.  
  156.     *pi = (int)l;
  157.  
  158.     return TRUE;
  159. }
  160.  
  161. bool wxConfigBase::DoReadBool(const wxString& key, bool* val) const
  162. {
  163.     wxCHECK_MSG( val, FALSE, _T("wxConfig::Read(): NULL parameter") );
  164.  
  165.     long l;
  166.     if ( !DoReadLong(key, &l) )
  167.         return FALSE;
  168.  
  169.     wxASSERT_MSG( l == 0 || l == 1, _T("bad bool value in wxConfig::DoReadInt") );
  170.  
  171.     *val = l != 0;
  172.  
  173.     return TRUE;
  174. }
  175.  
  176. bool wxConfigBase::DoReadDouble(const wxString& key, double* val) const
  177. {
  178.     wxString str;
  179.     if ( Read(key, &str) )
  180.     {
  181.         return str.ToDouble(val);
  182.     }
  183.  
  184.     return FALSE;
  185. }
  186.  
  187. // string reading helper
  188. wxString wxConfigBase::ExpandEnvVars(const wxString& str) const
  189. {
  190.     wxString tmp; // Required for BC++
  191.     if (IsExpandingEnvVars())
  192.         tmp = wxExpandEnvVars(str);
  193.     else
  194.         tmp = str;
  195.     return tmp;
  196. }
  197.  
  198. // ----------------------------------------------------------------------------
  199. // wxConfigBase writing
  200. // ----------------------------------------------------------------------------
  201.  
  202. bool wxConfigBase::DoWriteDouble(const wxString& key, double val)
  203. {
  204.     return DoWriteString(key, wxString::Format(_T("%g"), val));
  205. }
  206.  
  207. bool wxConfigBase::DoWriteInt(const wxString& key, int value)
  208. {
  209.     return DoWriteLong(key, (long)value);
  210. }
  211.  
  212. bool wxConfigBase::DoWriteBool(const wxString& key, bool value)
  213. {
  214.     return DoWriteLong(key, value ? 1l : 0l);
  215. }
  216.  
  217. // ----------------------------------------------------------------------------
  218. // wxConfigPathChanger
  219. // ----------------------------------------------------------------------------
  220.  
  221. wxConfigPathChanger::wxConfigPathChanger(const wxConfigBase *pContainer,
  222.                                  const wxString& strEntry)
  223. {
  224.   m_pContainer = (wxConfigBase *)pContainer;
  225.  
  226.   // the path is everything which precedes the last slash
  227.   wxString strPath = strEntry.BeforeLast(wxCONFIG_PATH_SEPARATOR);
  228.  
  229.   // except in the special case of "/keyname" when there is nothing before "/"
  230.   if ( strPath.IsEmpty() &&
  231.        ((!strEntry.IsEmpty()) && strEntry[0] == wxCONFIG_PATH_SEPARATOR) )
  232.   {
  233.     strPath = wxCONFIG_PATH_SEPARATOR;
  234.   }
  235.  
  236.   if ( !strPath.IsEmpty() ) {
  237.     // do change the path
  238.     m_bChanged = TRUE;
  239.     m_strName = strEntry.AfterLast(wxCONFIG_PATH_SEPARATOR);
  240.     m_strOldPath = m_pContainer->GetPath();
  241.     if ( m_strOldPath.Len() == 0 || 
  242.          m_strOldPath.Last() != wxCONFIG_PATH_SEPARATOR )
  243.         m_strOldPath += wxCONFIG_PATH_SEPARATOR;
  244.     m_pContainer->SetPath(strPath);
  245.   }
  246.   else {
  247.     // it's a name only, without path - nothing to do
  248.     m_bChanged = FALSE;
  249.     m_strName = strEntry;
  250.   }
  251. }
  252.  
  253. wxConfigPathChanger::~wxConfigPathChanger()
  254. {
  255.   // only restore path if it was changed
  256.   if ( m_bChanged ) {
  257.     m_pContainer->SetPath(m_strOldPath);
  258.   }
  259. }
  260.  
  261. #endif // wxUSE_CONFIG
  262.  
  263. // ----------------------------------------------------------------------------
  264. // static & global functions
  265. // ----------------------------------------------------------------------------
  266.  
  267. // understands both Unix and Windows (but only under Windows) environment
  268. // variables expansion: i.e. $var, $(var) and ${var} are always understood
  269. // and in addition under Windows %var% is also.
  270. wxString wxExpandEnvVars(const wxString& str)
  271. {
  272.   wxString strResult;
  273.   strResult.Alloc(str.Len());
  274.  
  275.   // don't change the values the enum elements: they must be equal
  276.   // to the matching [closing] delimiter.
  277.   enum Bracket
  278.   {
  279.     Bracket_None,
  280.     Bracket_Normal  = ')',
  281.     Bracket_Curly   = '}'
  282. #ifdef  __WXMSW__
  283.     ,Bracket_Windows = '%'     // yeah, Windows people are a bit strange ;-)
  284. #endif
  285.   };
  286.  
  287.   size_t m;
  288.   for ( size_t n = 0; n < str.Len(); n++ ) {
  289.     switch ( str[n] ) {
  290. #ifdef  __WXMSW__
  291.       case wxT('%'):
  292. #endif  //WINDOWS
  293.       case wxT('$'):
  294.         {
  295.           Bracket bracket;
  296.           #ifdef  __WXMSW__
  297.             if ( str[n] == wxT('%') )
  298.               bracket = Bracket_Windows;
  299.             else
  300.           #endif  //WINDOWS
  301.           if ( n == str.Len() - 1 ) {
  302.             bracket = Bracket_None;
  303.           }
  304.           else {
  305.             switch ( str[n + 1] ) {
  306.               case wxT('('):
  307.                 bracket = Bracket_Normal;
  308.                 n++;                   // skip the bracket
  309.                 break;
  310.  
  311.               case wxT('{'):
  312.                 bracket = Bracket_Curly;
  313.                 n++;                   // skip the bracket
  314.                 break;
  315.  
  316.               default:
  317.                 bracket = Bracket_None;
  318.             }
  319.           }
  320.  
  321.           m = n + 1;
  322.  
  323.           while ( m < str.Len() && (wxIsalnum(str[m]) || str[m] == wxT('_')) )
  324.             m++;
  325.  
  326.           wxString strVarName(str.c_str() + n + 1, m - n - 1);
  327.  
  328.           const wxChar *pszValue = wxGetenv(strVarName);
  329.           if ( pszValue != NULL ) {
  330.             strResult += pszValue;
  331.           }
  332.           else {
  333.             // variable doesn't exist => don't change anything
  334.             #ifdef  __WXMSW__
  335.               if ( bracket != Bracket_Windows )
  336.             #endif
  337.                 if ( bracket != Bracket_None )
  338.                   strResult << str[n - 1];
  339.             strResult << str[n] << strVarName;
  340.           }
  341.  
  342.           // check the closing bracket
  343.           if ( bracket != Bracket_None ) {
  344.             if ( m == str.Len() || str[m] != (char)bracket ) {
  345.               wxLogWarning(_("Environment variables expansion failed: missing '%c' at position %d in '%s'."),
  346.                            (char)bracket, m + 1, str.c_str());
  347.             }
  348.             else {
  349.               // skip closing bracket unless the variables wasn't expanded
  350.               if ( pszValue == NULL )
  351.                 strResult << (char)bracket;
  352.               m++;
  353.             }
  354.           }
  355.  
  356.           n = m - 1;  // skip variable name
  357.         }
  358.         break;
  359.  
  360.       case '\\':
  361.         // backslash can be used to suppress special meaning of % and $
  362.         if ( n != str.Len() && (str[n + 1] == wxT('%') || str[n + 1] == wxT('$')) ) {
  363.           strResult += str[++n];
  364.  
  365.           break;
  366.         }
  367.         //else: fall through
  368.  
  369.       default:
  370.         strResult += str[n];
  371.     }
  372.   }
  373.  
  374.   return strResult;
  375. }
  376.  
  377. // this function is used to properly interpret '..' in path
  378. /// separates group and entry names (probably shouldn't be changed)
  379.  
  380. void wxSplitPath(wxArrayString& aParts, const wxChar *sz)
  381. {
  382.   aParts.Empty();
  383.  
  384.   wxString strCurrent;
  385.   const wxChar *pc = sz;
  386.   for ( ;; ) {
  387.     if ( *pc == wxT('\0') || *pc == wxCONFIG_PATH_SEPARATOR ) {
  388.       if ( strCurrent == wxT(".") ) {
  389.         // ignore
  390.       }
  391.       else if ( strCurrent == wxT("..") ) {
  392.         // go up one level
  393.         if ( aParts.IsEmpty() )
  394.           wxLogWarning(_("'%s' has extra '..', ignored."), sz);
  395.         else
  396.           aParts.Remove(aParts.Count() - 1);
  397.  
  398.         strCurrent.Empty();
  399.       }
  400.       else if ( !strCurrent.IsEmpty() ) {
  401.         aParts.Add(strCurrent);
  402.         strCurrent.Empty();
  403.       }
  404.       //else:
  405.         // could log an error here, but we prefer to ignore extra '/'
  406.  
  407.       if ( *pc == wxT('\0') )
  408.         break;
  409.     }
  410.     else
  411.       strCurrent += *pc;
  412.  
  413.     pc++;
  414.   }
  415. }
  416.  
  417.  
  418.