home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / wxos2240.zip / wxWindows-2.4.0 / src / common / config.cpp < prev    next >
C/C++ Source or Header  |  2002-11-04  |  15KB  |  434 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.2.3 2002/11/04 19:09:27 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;
  72.     m_bRecordDefaults = FALSE;
  73. }
  74.  
  75. wxConfigBase::~wxConfigBase()
  76. {
  77. }
  78.  
  79. wxConfigBase *wxConfigBase::Set(wxConfigBase *pConfig)
  80. {
  81.   wxConfigBase *pOld = ms_pConfig;
  82.   ms_pConfig = pConfig;
  83.   return pOld;
  84. }
  85.  
  86. wxConfigBase *wxConfigBase::Create()
  87. {
  88.   if ( ms_bAutoCreate && ms_pConfig == NULL ) {
  89.     ms_pConfig =
  90.     #if defined(__WXMSW__) && wxUSE_CONFIG_NATIVE
  91.       #ifdef __WIN32__
  92.         new wxRegConfig(wxTheApp->GetAppName(), wxTheApp->GetVendorName());
  93.       #else  //WIN16
  94.         new wxIniConfig(wxTheApp->GetAppName(), wxTheApp->GetVendorName());
  95.       #endif
  96.     #else // either we're under Unix or wish to use files even under Windows
  97.       new wxFileConfig(wxTheApp->GetAppName());
  98.     #endif
  99.   }
  100.  
  101.   return ms_pConfig;
  102. }
  103.  
  104. // ----------------------------------------------------------------------------
  105. // wxConfigBase reading entries
  106. // ----------------------------------------------------------------------------
  107.  
  108. // implement both Read() overloads for the given type in terms of DoRead()
  109. #define IMPLEMENT_READ_FOR_TYPE(name, type, deftype, extra)                 \
  110.     bool wxConfigBase::Read(const wxString& key, type *val) const           \
  111.     {                                                                       \
  112.         wxCHECK_MSG( val, FALSE, _T("wxConfig::Read(): NULL parameter") );  \
  113.                                                                             \
  114.         if ( !DoRead##name(key, val) )                                      \
  115.             return FALSE;                                                   \
  116.                                                                             \
  117.         *val = extra(*val);                                                 \
  118.                                                                             \
  119.         return TRUE;                                                        \
  120.     }                                                                       \
  121.                                                                             \
  122.     bool wxConfigBase::Read(const wxString& key,                            \
  123.                             type *val,                                      \
  124.                             deftype defVal) const                           \
  125.     {                                                                       \
  126.         wxCHECK_MSG( val, FALSE, _T("wxConfig::Read(): NULL parameter") );  \
  127.                                                                             \
  128.         bool read = DoRead##name(key, val);                                 \
  129.         if ( !read )                                                        \
  130.         {                                                                   \
  131.             if ( IsRecordingDefaults() )                                    \
  132.             {                                                               \
  133.                 ((wxConfigBase *)this)->DoWrite##name(key, defVal);         \
  134.             }                                                               \
  135.                                                                             \
  136.             *val = defVal;                                                  \
  137.         }                                                                   \
  138.                                                                             \
  139.         *val = extra(*val);                                                 \
  140.                                                                             \
  141.         return read;                                                        \
  142.     }
  143.  
  144.  
  145. IMPLEMENT_READ_FOR_TYPE(String, wxString, const wxString&, ExpandEnvVars)
  146. IMPLEMENT_READ_FOR_TYPE(Long, long, long, long)
  147. IMPLEMENT_READ_FOR_TYPE(Int, int, int, int)
  148. IMPLEMENT_READ_FOR_TYPE(Double, double, double, double)
  149. IMPLEMENT_READ_FOR_TYPE(Bool, bool, bool, bool)
  150.  
  151. #undef IMPLEMENT_READ_FOR_TYPE
  152.  
  153. // the DoReadXXX() for the other types have implementation in the base class
  154. // but can be overridden in the derived ones
  155. bool wxConfigBase::DoReadInt(const wxString& key, int *pi) const
  156. {
  157.     wxCHECK_MSG( pi, FALSE, _T("wxConfig::Read(): NULL parameter") );
  158.  
  159.     long l;
  160.     if ( !DoReadLong(key, &l) )
  161.         return FALSE;
  162.  
  163.     wxASSERT_MSG( l < INT_MAX, _T("overflow in wxConfig::DoReadInt") );
  164.  
  165.     *pi = (int)l;
  166.  
  167.     return TRUE;
  168. }
  169.  
  170. bool wxConfigBase::DoReadBool(const wxString& key, bool* val) const
  171. {
  172.     wxCHECK_MSG( val, FALSE, _T("wxConfig::Read(): NULL parameter") );
  173.  
  174.     long l;
  175.     if ( !DoReadLong(key, &l) )
  176.         return FALSE;
  177.  
  178.     wxASSERT_MSG( l == 0 || l == 1, _T("bad bool value in wxConfig::DoReadInt") );
  179.  
  180.     *val = l != 0;
  181.  
  182.     return TRUE;
  183. }
  184.  
  185. bool wxConfigBase::DoReadDouble(const wxString& key, double* val) const
  186. {
  187.     wxString str;
  188.     if ( Read(key, &str) )
  189.     {
  190.         return str.ToDouble(val);
  191.     }
  192.  
  193.     return FALSE;
  194. }
  195.  
  196. // string reading helper
  197. wxString wxConfigBase::ExpandEnvVars(const wxString& str) const
  198. {
  199.     wxString tmp; // Required for BC++
  200.     if (IsExpandingEnvVars())
  201.         tmp = wxExpandEnvVars(str);
  202.     else
  203.         tmp = str;
  204.     return tmp;
  205. }
  206.  
  207. // ----------------------------------------------------------------------------
  208. // wxConfigBase writing
  209. // ----------------------------------------------------------------------------
  210.  
  211. bool wxConfigBase::DoWriteDouble(const wxString& key, double val)
  212. {
  213.     return DoWriteString(key, wxString::Format(_T("%g"), val));
  214. }
  215.  
  216. bool wxConfigBase::DoWriteInt(const wxString& key, int value)
  217. {
  218.     return DoWriteLong(key, (long)value);
  219. }
  220.  
  221. bool wxConfigBase::DoWriteBool(const wxString& key, bool value)
  222. {
  223.     return DoWriteLong(key, value ? 1l : 0l);
  224. }
  225.  
  226. // ----------------------------------------------------------------------------
  227. // wxConfigPathChanger
  228. // ----------------------------------------------------------------------------
  229.  
  230. wxConfigPathChanger::wxConfigPathChanger(const wxConfigBase *pContainer,
  231.                                  const wxString& strEntry)
  232. {
  233.   m_pContainer = (wxConfigBase *)pContainer;
  234.  
  235.   // the path is everything which precedes the last slash
  236.   wxString strPath = strEntry.BeforeLast(wxCONFIG_PATH_SEPARATOR);
  237.  
  238.   // except in the special case of "/keyname" when there is nothing before "/"
  239.   if ( strPath.IsEmpty() &&
  240.        ((!strEntry.IsEmpty()) && strEntry[0] == wxCONFIG_PATH_SEPARATOR) )
  241.   {
  242.     strPath = wxCONFIG_PATH_SEPARATOR;
  243.   }
  244.  
  245.   if ( !strPath.IsEmpty() ) {
  246.     // do change the path
  247.     m_bChanged = TRUE;
  248.     m_strName = strEntry.AfterLast(wxCONFIG_PATH_SEPARATOR);
  249.     m_strOldPath = m_pContainer->GetPath();
  250.     if ( m_strOldPath.Len() == 0 || 
  251.          m_strOldPath.Last() != wxCONFIG_PATH_SEPARATOR )
  252.         m_strOldPath += wxCONFIG_PATH_SEPARATOR;
  253.     m_pContainer->SetPath(strPath);
  254.   }
  255.   else {
  256.     // it's a name only, without path - nothing to do
  257.     m_bChanged = FALSE;
  258.     m_strName = strEntry;
  259.   }
  260. }
  261.  
  262. wxConfigPathChanger::~wxConfigPathChanger()
  263. {
  264.   // only restore path if it was changed
  265.   if ( m_bChanged ) {
  266.     m_pContainer->SetPath(m_strOldPath);
  267.   }
  268. }
  269.  
  270. #endif // wxUSE_CONFIG
  271.  
  272. // ----------------------------------------------------------------------------
  273. // static & global functions
  274. // ----------------------------------------------------------------------------
  275.  
  276. // understands both Unix and Windows (but only under Windows) environment
  277. // variables expansion: i.e. $var, $(var) and ${var} are always understood
  278. // and in addition under Windows %var% is also.
  279. wxString wxExpandEnvVars(const wxString& str)
  280. {
  281.   wxString strResult;
  282.   strResult.Alloc(str.Len());
  283.  
  284.   // don't change the values the enum elements: they must be equal
  285.   // to the matching [closing] delimiter.
  286.   enum Bracket
  287.   {
  288.     Bracket_None,
  289.     Bracket_Normal  = ')',
  290.     Bracket_Curly   = '}',
  291. #ifdef  __WXMSW__
  292.     Bracket_Windows = '%',    // yeah, Windows people are a bit strange ;-)
  293. #endif
  294.     Bracket_Max
  295.   };
  296.  
  297.   size_t m;
  298.   for ( size_t n = 0; n < str.Len(); n++ ) {
  299.     switch ( str[n] ) {
  300. #ifdef  __WXMSW__
  301.       case wxT('%'):
  302. #endif  //WINDOWS
  303.       case wxT('$'):
  304.         {
  305.           Bracket bracket;
  306.           #ifdef  __WXMSW__
  307.             if ( str[n] == wxT('%') )
  308.               bracket = Bracket_Windows;
  309.             else
  310.           #endif  //WINDOWS
  311.           if ( n == str.Len() - 1 ) {
  312.             bracket = Bracket_None;
  313.           }
  314.           else {
  315.             switch ( str[n + 1] ) {
  316.               case wxT('('):
  317.                 bracket = Bracket_Normal;
  318.                 n++;                   // skip the bracket
  319.                 break;
  320.  
  321.               case wxT('{'):
  322.                 bracket = Bracket_Curly;
  323.                 n++;                   // skip the bracket
  324.                 break;
  325.  
  326.               default:
  327.                 bracket = Bracket_None;
  328.             }
  329.           }
  330.  
  331.           m = n + 1;
  332.  
  333.           while ( m < str.Len() && (wxIsalnum(str[m]) || str[m] == wxT('_')) )
  334.             m++;
  335.  
  336.           wxString strVarName(str.c_str() + n + 1, m - n - 1);
  337.  
  338.           const wxChar *pszValue = wxGetenv(strVarName);
  339.           if ( pszValue != NULL ) {
  340.             strResult += pszValue;
  341.           }
  342.           else {
  343.             // variable doesn't exist => don't change anything
  344.             #ifdef  __WXMSW__
  345.               if ( bracket != Bracket_Windows )
  346.             #endif
  347.                 if ( bracket != Bracket_None )
  348.                   strResult << str[n - 1];
  349.             strResult << str[n] << strVarName;
  350.           }
  351.  
  352.           // check the closing bracket
  353.           if ( bracket != Bracket_None ) {
  354.             if ( m == str.Len() || str[m] != (char)bracket ) {
  355.               // under MSW it's common to have '%' characters in the registry
  356.               // and it's annoying to have warnings about them each time, so
  357.               // ignroe them silently if they are not used for env vars
  358.               //
  359.               // under Unix, OTOH, this warning could be useful for the user to
  360.               // understand why isn't the variable expanded as intended
  361.               #ifndef __WXMSW__
  362.                 wxLogWarning(_("Environment variables expansion failed: missing '%c' at position %d in '%s'."),
  363.                              (char)bracket, m + 1, str.c_str());
  364.               #endif // __WXMSW__
  365.             }
  366.             else {
  367.               // skip closing bracket unless the variables wasn't expanded
  368.               if ( pszValue == NULL )
  369.                 strResult << (char)bracket;
  370.               m++;
  371.             }
  372.           }
  373.  
  374.           n = m - 1;  // skip variable name
  375.         }
  376.         break;
  377.  
  378.       case '\\':
  379.         // backslash can be used to suppress special meaning of % and $
  380.         if ( n != str.Len() && (str[n + 1] == wxT('%') || str[n + 1] == wxT('$')) ) {
  381.           strResult += str[++n];
  382.  
  383.           break;
  384.         }
  385.         //else: fall through
  386.  
  387.       default:
  388.         strResult += str[n];
  389.     }
  390.   }
  391.  
  392.   return strResult;
  393. }
  394.  
  395. // this function is used to properly interpret '..' in path
  396. void wxSplitPath(wxArrayString& aParts, const wxChar *sz)
  397. {
  398.   aParts.Empty();
  399.  
  400.   wxString strCurrent;
  401.   const wxChar *pc = sz;
  402.   for ( ;; ) {
  403.     if ( *pc == wxT('\0') || *pc == wxCONFIG_PATH_SEPARATOR ) {
  404.       if ( strCurrent == wxT(".") ) {
  405.         // ignore
  406.       }
  407.       else if ( strCurrent == wxT("..") ) {
  408.         // go up one level
  409.         if ( aParts.IsEmpty() )
  410.           wxLogWarning(_("'%s' has extra '..', ignored."), sz);
  411.         else
  412.           aParts.Remove(aParts.Count() - 1);
  413.  
  414.         strCurrent.Empty();
  415.       }
  416.       else if ( !strCurrent.IsEmpty() ) {
  417.         aParts.Add(strCurrent);
  418.         strCurrent.Empty();
  419.       }
  420.       //else:
  421.         // could log an error here, but we prefer to ignore extra '/'
  422.  
  423.       if ( *pc == wxT('\0') )
  424.         break;
  425.     }
  426.     else
  427.       strCurrent += *pc;
  428.  
  429.     pc++;
  430.   }
  431. }
  432.  
  433.  
  434.