]> git.saurik.com Git - wxWidgets.git/blobdiff - src/common/fileconf.cpp
static wxFile::Access() added
[wxWidgets.git] / src / common / fileconf.cpp
index d0c6ac80627c6a7c59dc2a1b5ab5039242fdec55..24d10b9833054977f866c2928537af6b676d4334 100644 (file)
@@ -58,7 +58,7 @@
 // ----------------------------------------------------------------------------
 
 // is 'c' a valid character in group name?
-// NB: APPCONF_IMMUTABLE_PREFIX and APPCONF_PATH_SEPARATOR must be valid chars,
+// NB: wxCONFIG_IMMUTABLE_PREFIX and wxCONFIG_PATH_SEPARATOR must be valid chars,
 //     but _not_ ']' (group name delimiter)
 inline bool IsValid(char c) { return isalnum(c) || strchr("@_/-!.*%", c); }
 
@@ -79,60 +79,88 @@ static wxString FilterOut(const wxString& str);
 // ----------------------------------------------------------------------------
 // static functions
 // ----------------------------------------------------------------------------
-wxString wxFileConfig::GetGlobalFileName(const char *szFile)
+wxString wxFileConfig::GetGlobalDir()
 {
-  wxString str;
-
-  bool bNoExt = strchr(szFile, '.') == NULL;
+  wxString strDir;
 
-  #ifdef  __UNIX__
-    str << "/etc/" << szFile;
-    if ( bNoExt )
-      str << ".conf";
-  #else   // Windows
+  #ifdef __UNIX__
+    strDir = "/etc/";
+  #else // Windows
     #ifndef _MAX_PATH
       #define _MAX_PATH 512
     #endif
 
     char szWinDir[_MAX_PATH];
     ::GetWindowsDirectory(szWinDir, _MAX_PATH);
-    str << szWinDir <<  "\\" << szFile;
-    if ( bNoExt )
-      str << ".ini";
-  #endif  // UNIX/Win
 
-  return str;
+    strDir = szWinDir;
+    strDir << '\\';
+  #endif // Unix/Windows
+
+  return strDir;
 }
 
-wxString wxFileConfig::GetLocalFileName(const char *szFile)
+wxString wxFileConfig::GetLocalDir()
 {
-  wxString str;
+  wxString strDir;
 
-  #ifdef  __UNIX__
+  #ifdef __UNIX__
     const char *szHome = getenv("HOME");
     if ( szHome == NULL ) {
       // we're homeless...
       wxLogWarning(_("can't find user's HOME, using current directory."));
-      szHome = ".";
+      strDir = ".";
     }
-    str << szHome << "/." << szFile;
+    else
+       strDir = szHome;
+    strDir << '/'; // a double slash is no problem, a missin one yes
   #else   // Windows
     #ifdef  __WIN32__
       const char *szHome = getenv("HOMEDRIVE");
       if ( szHome != NULL )
-        str << szHome;
+        strDir << szHome;
       szHome = getenv("HOMEPATH");
       if ( szHome != NULL )
-        str << szHome;
-      str << szFile;
-      if ( strchr(szFile, '.') == NULL )
-        str << ".ini";
+        strDir << szHome;
     #else   // Win16
       // Win16 has no idea about home, so use the current directory instead
-      str << ".\\" << szFile;
+      strDir = ".\\";
     #endif  // WIN16/32
   #endif  // UNIX/Win
 
+  return strDir;
+}
+
+wxString wxFileConfig::GetGlobalFileName(const char *szFile)
+{
+  wxString str = GetGlobalDir();
+  str << szFile;
+
+  if ( strchr(szFile, '.') == NULL )
+  #ifdef  __UNIX__
+    str << ".conf";
+  #else   // Windows
+    str << ".ini";
+  #endif  // UNIX/Win
+
+  return str;
+}
+
+wxString wxFileConfig::GetLocalFileName(const char *szFile)
+{
+  wxString str = GetLocalDir();
+
+  #ifdef  __UNIX__
+    str << '.';
+  #endif
+
+  str << szFile;
+
+  #ifdef __WXMSW__
+    if ( strchr(szFile, '.') == NULL )
+      str << ".ini";
+  #endif
+
   return str;
 }
 
@@ -148,47 +176,67 @@ void wxFileConfig::Init()
   m_linesHead =
   m_linesTail = NULL;
 
-  m_strPath.Empty();
-}
-
-wxFileConfig::wxFileConfig(const wxString& strLocal, const wxString& strGlobal)
-            : m_strLocalFile(strLocal), m_strGlobalFile(strGlobal)
-{
-  Init();
-
   // it's not an error if (one of the) file(s) doesn't exist
 
   // parse the global file
-  if ( !strGlobal.IsEmpty() ) {
-    if ( wxFile::Exists(strGlobal) ) {
-      wxTextFile fileGlobal(strGlobal);
+  if ( !m_strGlobalFile.IsEmpty() && wxFile::Exists(m_strGlobalFile) ) {
+    wxTextFile fileGlobal(m_strGlobalFile);
 
-      if ( fileGlobal.Open() ) {
-        Parse(fileGlobal, FALSE /* global */);
-        SetRootPath();
-      }
-      else
-        wxLogWarning(_("can't open global configuration file '%s'."),
-                     strGlobal.c_str());
+    if ( fileGlobal.Open() ) {
+      Parse(fileGlobal, FALSE /* global */);
+      SetRootPath();
     }
+    else
+      wxLogWarning(_("can't open global configuration file '%s'."),
+                   m_strGlobalFile.c_str());
   }
 
   // parse the local file
-  if ( wxFile::Exists(strLocal) ) {
-    wxTextFile fileLocal(strLocal);
+  if ( !m_strLocalFile.IsEmpty() && wxFile::Exists(m_strLocalFile) ) {
+    wxTextFile fileLocal(m_strLocalFile);
     if ( fileLocal.Open() ) {
       Parse(fileLocal, TRUE /* local */);
       SetRootPath();
     }
     else
       wxLogWarning(_("can't open user configuration file '%s'."),
-                   strLocal.c_str());
+                   m_strLocalFile.c_str());
   }
 }
 
-wxFileConfig::~wxFileConfig()
+wxFileConfig::wxFileConfig(const char *szAppName, bool bLocalOnly)
+{
+  wxASSERT( !IsEmpty(szAppName) ); // invent a name for your application!
+
+  m_strLocalFile = GetLocalFileName(szAppName);
+  if ( !bLocalOnly )
+    m_strGlobalFile = GetGlobalFileName(szAppName);
+  //else: it's going to be empty and we won't use the global file
+
+  Init();
+}
+
+wxFileConfig::wxFileConfig(const wxString& strLocal, const wxString& strGlobal)
+            : m_strLocalFile(strLocal), m_strGlobalFile(strGlobal)
+{
+  // if the path is not absolute, prepend the standard directory to it
+  if ( !strLocal.IsEmpty() && !wxIsAbsolutePath(strLocal) )
+  {
+     m_strLocalFile = GetLocalDir();
+     m_strLocalFile << strLocal;
+  }
+  
+  if ( !strGlobal.IsEmpty() && !wxIsAbsolutePath(strGlobal) )
+  {
+     m_strGlobalFile = GetGlobalDir();
+     m_strGlobalFile << strGlobal;
+  }
+
+  Init();
+}
+
+void wxFileConfig::CleanUp()
 {
-  Flush();
   delete m_pRootGroup;
 
   LineList *pCur = m_linesHead;
@@ -199,6 +247,13 @@ wxFileConfig::~wxFileConfig()
   }
 }
 
+wxFileConfig::~wxFileConfig()
+{
+  Flush();
+
+  CleanUp();
+}
+
 // ----------------------------------------------------------------------------
 // parse a config file
 // ----------------------------------------------------------------------------
@@ -242,7 +297,7 @@ void wxFileConfig::Parse(wxTextFile& file, bool bLocal)
       // group name here is always considered as abs path
       wxString strGroup;
       pStart++;
-      strGroup << APPCONF_PATH_SEPARATOR << wxString(pStart, pEnd - pStart);
+      strGroup << wxCONFIG_PATH_SEPARATOR << wxString(pStart, pEnd - pStart);
 
       // will create it if doesn't yet exist
       SetPath(strGroup);
@@ -349,14 +404,14 @@ void wxFileConfig::SetPath(const wxString& strPath)
     return;
   }
 
-  if ( strPath[0] == APPCONF_PATH_SEPARATOR ) {
+  if ( strPath[0] == wxCONFIG_PATH_SEPARATOR ) {
     // absolute path
     wxSplitPath(aParts, strPath);
   }
   else {
     // relative path, combine with current one
     wxString strFullPath = m_strPath;
-    strFullPath << APPCONF_PATH_SEPARATOR << strPath;
+    strFullPath << wxCONFIG_PATH_SEPARATOR << strPath;
     wxSplitPath(aParts, strFullPath);
   }
 
@@ -373,7 +428,7 @@ void wxFileConfig::SetPath(const wxString& strPath)
   // recombine path parts in one variable
   m_strPath.Empty();
   for ( n = 0; n < aParts.Count(); n++ ) {
-    m_strPath << APPCONF_PATH_SEPARATOR << aParts[n];
+    m_strPath << wxCONFIG_PATH_SEPARATOR << aParts[n];
   }
 }
 
@@ -381,13 +436,13 @@ void wxFileConfig::SetPath(const wxString& strPath)
 // enumeration
 // ----------------------------------------------------------------------------
 
-bool wxFileConfig::GetFirstGroup(wxString& str, long& lIndex)
+bool wxFileConfig::GetFirstGroup(wxString& str, long& lIndex) const
 {
   lIndex = 0;
   return GetNextGroup(str, lIndex);
 }
 
-bool wxFileConfig::GetNextGroup (wxString& str, long& lIndex)
+bool wxFileConfig::GetNextGroup (wxString& str, long& lIndex) const
 {
   if ( uint(lIndex) < m_pCurrentGroup->Groups().Count() ) {
     str = m_pCurrentGroup->Groups()[lIndex++]->Name();
@@ -397,13 +452,13 @@ bool wxFileConfig::GetNextGroup (wxString& str, long& lIndex)
     return FALSE;
 }
 
-bool wxFileConfig::GetFirstEntry(wxString& str, long& lIndex)
+bool wxFileConfig::GetFirstEntry(wxString& str, long& lIndex) const
 {
   lIndex = 0;
   return GetNextEntry(str, lIndex);
 }
 
-bool wxFileConfig::GetNextEntry (wxString& str, long& lIndex)
+bool wxFileConfig::GetNextEntry (wxString& str, long& lIndex) const
 {
   if ( uint(lIndex) < m_pCurrentGroup->Entries().Count() ) {
     str = m_pCurrentGroup->Entries()[lIndex++]->Name();
@@ -477,6 +532,8 @@ bool wxFileConfig::Read(wxString   *pstr,
 
   ConfigEntry *pEntry = m_pCurrentGroup->FindEntry(path.Name());
   if (pEntry == NULL) {
+    if( IsRecordingDefaults() )
+      ((wxFileConfig *)this)->Write(szKey,szDefault);
     *pstr = ExpandEnvVars(szDefault);
     return FALSE;
   }
@@ -515,7 +572,7 @@ bool wxFileConfig::Write(const char *szKey, const char *szValue)
   wxString strName = path.Name();
   if ( strName.IsEmpty() ) {
     // setting the value of a group is an error
-    wxASSERT_MSG( IsEmpty(szValue), "can't set value of a group!" );
+    wxASSERT_MSG( IsEmpty(szValue), _("can't set value of a group!") );
 
     // ... except if it's empty in which case it's a way to force it's creation
     m_pCurrentGroup->SetDirty();
@@ -527,9 +584,9 @@ bool wxFileConfig::Write(const char *szKey, const char *szValue)
     // writing an entry
 
     // check that the name is reasonable
-    if ( strName[0u] == APPCONF_IMMUTABLE_PREFIX ) {
+    if ( strName[0u] == wxCONFIG_IMMUTABLE_PREFIX ) {
       wxLogError(_("Entry name can't start with '%c'."),
-                 APPCONF_IMMUTABLE_PREFIX);
+                 wxCONFIG_IMMUTABLE_PREFIX);
       return FALSE;
     }
 
@@ -597,7 +654,7 @@ bool wxFileConfig::DeleteEntry(const char *szKey, bool bGroupIfEmptyAlso)
     if ( m_pCurrentGroup != m_pRootGroup ) {
       ConfigGroup *pGroup = m_pCurrentGroup;
       SetPath("..");  // changes m_pCurrentGroup!
-      m_pCurrentGroup->DeleteSubgroup(pGroup->Name());
+      m_pCurrentGroup->DeleteSubgroupByName(pGroup->Name());
     }
     //else: never delete the root group
   }
@@ -609,21 +666,20 @@ bool wxFileConfig::DeleteGroup(const char *szKey)
 {
   PathChanger path(this, szKey);
 
-  return m_pCurrentGroup->DeleteSubgroup(path.Name());
+  return m_pCurrentGroup->DeleteSubgroupByName(path.Name());
 }
 
 bool wxFileConfig::DeleteAll()
 {
+  CleanUp();
+
   const char *szFile = m_strLocalFile;
-  delete m_pRootGroup;
-  Init();
 
   if ( remove(szFile) == -1 )
     wxLogSysError(_("can't delete user configuration file '%s'"), szFile);
 
-  szFile = m_strGlobalFile;
-  if ( remove(szFile) )
-    wxLogSysError(_("can't delete system configuration file '%s'"), szFile);
+  m_strLocalFile = m_strGlobalFile = "";
+  Init();
 
   return TRUE;
 }
@@ -849,7 +905,7 @@ wxFileConfig::LineList *wxFileConfig::ConfigGroup::GetLastEntryLine()
 wxString wxFileConfig::ConfigGroup::GetFullName() const
 {
   if ( Parent() )
-    return Parent()->GetFullName() + APPCONF_PATH_SEPARATOR + Name();
+    return Parent()->GetFullName() + wxCONFIG_PATH_SEPARATOR + Name();
   else
     return "";
 }
@@ -872,7 +928,7 @@ wxFileConfig::ConfigGroup::FindEntry(const char *szName) const
     i = (lo + hi)/2;
     pEntry = m_aEntries[i];
 
-    #if APPCONF_CASE_SENSITIVE
+    #if wxCONFIG_CASE_SENSITIVE
       res = strcmp(pEntry->Name(), szName);
     #else
       res = Stricmp(pEntry->Name(), szName);
@@ -902,7 +958,7 @@ wxFileConfig::ConfigGroup::FindSubgroup(const char *szName) const
     i = (lo + hi)/2;
     pGroup = m_aSubgroups[i];
 
-    #if APPCONF_CASE_SENSITIVE
+    #if wxCONFIG_CASE_SENSITIVE
       res = strcmp(pGroup->Name(), szName);
     #else
       res = Stricmp(pGroup->Name(), szName);
@@ -958,9 +1014,16 @@ wxFileConfig::ConfigGroup::AddSubgroup(const wxString& strName)
   delete several of them.
  */
 
-bool wxFileConfig::ConfigGroup::DeleteSubgroup(const char *szName)
+bool wxFileConfig::ConfigGroup::DeleteSubgroupByName(const char *szName)
+{
+  return DeleteSubgroup(FindSubgroup(szName));
+}
+
+// doesn't delete the subgroup itself, but does remove references to it from
+// all other data structures (and normally the returned pointer should be
+// deleted a.s.a.p. because there is nothing much to be done with it anyhow)
+bool wxFileConfig::ConfigGroup::DeleteSubgroup(ConfigGroup *pGroup)
 {
-  ConfigGroup *pGroup = FindSubgroup(szName);
   wxCHECK( pGroup != NULL, FALSE ); // deleting non existing group?
 
   // delete all entries
@@ -971,6 +1034,12 @@ bool wxFileConfig::ConfigGroup::DeleteSubgroup(const char *szName)
       m_pConfig->LineListRemove(pLine);
   }
 
+  // and subgroups of this sungroup
+  nCount = pGroup->m_aSubgroups.Count();
+  for ( uint nGroup = 0; nGroup < nCount; nGroup++ ) {
+    pGroup->DeleteSubgroup(pGroup->m_aSubgroups[nGroup]);
+  }
+
   LineList *pLine = pGroup->m_pLine;
   if ( pLine != NULL ) {
     // notice that we may do this test inside the previous "if" because the
@@ -982,7 +1051,8 @@ bool wxFileConfig::ConfigGroup::DeleteSubgroup(const char *szName)
       // go back until we find a subgroup or reach the group's line
       ConfigGroup *pNewLast = NULL;
       uint n, nSubgroups = m_aSubgroups.Count();
-      for ( LineList *pl = pLine->Prev(); pl != m_pLine; pl = pl->Prev() ) {
+      LineList *pl;
+      for ( pl = pLine->Prev(); pl != m_pLine; pl = pl->Prev() ) {
         // is it our subgroup?
         for ( n = 0; (pNewLast == NULL) && (n < nSubgroups); n++ ) {
           // do _not_ call GetGroupLine! we don't want to add it to the local
@@ -1032,7 +1102,8 @@ bool wxFileConfig::ConfigGroup::DeleteEntry(const char *szName)
       // go back until we find another entry or reach the group's line
       ConfigEntry *pNewLast = NULL;
       uint n, nEntries = m_aEntries.Count();
-      for ( LineList *pl = pLine->Prev(); pl != m_pLine; pl = pl->Prev() ) {
+      LineList *pl;
+      for ( pl = pLine->Prev(); pl != m_pLine; pl = pl->Prev() ) {
         // is it our subgroup?
         for ( n = 0; (pNewLast == NULL) && (n < nEntries); n++ ) {
           if ( m_aEntries[n]->GetLine() == m_pLine )
@@ -1095,7 +1166,7 @@ wxFileConfig::ConfigEntry::ConfigEntry(wxFileConfig::ConfigGroup *pParent,
 
   m_bDirty  = FALSE;
 
-  m_bImmutable = strName[0] == APPCONF_IMMUTABLE_PREFIX;
+  m_bImmutable = strName[0] == wxCONFIG_IMMUTABLE_PREFIX;
   if ( m_bImmutable )
     m_strName.erase(0, 1);  // remove first character
 }
@@ -1170,7 +1241,7 @@ void wxFileConfig::ConfigEntry::SetDirty()
 int CompareEntries(wxFileConfig::ConfigEntry *p1,
                    wxFileConfig::ConfigEntry *p2)
 {
-  #if APPCONF_CASE_SENSITIVE
+  #if wxCONFIG_CASE_SENSITIVE
     return strcmp(p1->Name(), p2->Name());
   #else
     return Stricmp(p1->Name(), p2->Name());
@@ -1180,7 +1251,7 @@ int CompareEntries(wxFileConfig::ConfigEntry *p1,
 int CompareGroups(wxFileConfig::ConfigGroup *p1,
                   wxFileConfig::ConfigGroup *p2)
 {
-  #if APPCONF_CASE_SENSITIVE
+  #if wxCONFIG_CASE_SENSITIVE
     return strcmp(p1->Name(), p2->Name());
   #else
     return Stricmp(p1->Name(), p2->Name());
@@ -1269,8 +1340,10 @@ wxString FilterOut(const wxString& str)
         break;
 
       case '"':
-        if ( bQuote )
+        if ( bQuote ) {
           c = '"';
+          break;
+        }
         //else: fall through
 
       default: