+ // remember the old path
+ wxString strOldPath = m_strPath;
+
+#ifdef WX_DEBUG_SET_PATH // non optimized version kept here for testing
+ wxString m_strPathAlt;
+
+ {
+ wxArrayString aParts;
+
+ // because GetPath() returns "" when we're at root, we must understand
+ // empty string as "/"
+ if ( strPath.IsEmpty() || (strPath[0] == wxCONFIG_PATH_SEPARATOR) ) {
+ // absolute path
+ wxSplitPath(aParts, strPath);
+ }
+ else {
+ // relative path, combine with current one
+ wxString strFullPath = GetPath();
+ strFullPath << wxCONFIG_PATH_SEPARATOR << strPath;
+ wxSplitPath(aParts, strFullPath);
+ }
+
+ // recombine path parts in one variable
+ wxString strRegPath;
+ m_strPathAlt.Empty();
+ for ( size_t n = 0; n < aParts.Count(); n++ ) {
+ strRegPath << '\\' << aParts[n];
+ m_strPathAlt << wxCONFIG_PATH_SEPARATOR << aParts[n];
+ }
+ }
+#endif // 0
+
+ // check for the most common case first
+ if ( strPath.empty() )
+ {
+ m_strPath = wxCONFIG_PATH_SEPARATOR;
+ }
+ else // not root
+ {
+ // construct the full path
+ wxString strFullPath;
+ if ( strPath[0u] == wxCONFIG_PATH_SEPARATOR )
+ {
+ // absolute path
+ strFullPath = strPath;
+ }
+ else // relative path
+ {
+ strFullPath.reserve(2*m_strPath.length());
+
+ strFullPath << m_strPath << wxCONFIG_PATH_SEPARATOR << strPath;
+ }
+
+ // simplify it: we need to handle ".." here
+
+ // count the total number of slashes we have to know if we can go upper
+ size_t totalSlashes = 0;
+
+ // position of the last slash to be able to backtrack to it quickly if
+ // needed, but we set it to -1 if we don't have a valid position
+ //
+ // we only remember the last position which means that we handle ".."
+ // quite efficiently but not "../.." - however the latter should be
+ // much more rare, so it is probably ok
+ int posLastSlash = -1;
+
+ const wxChar *src = strFullPath.c_str();
+ size_t len = strFullPath.length();
+ const wxChar *end = src + len;
+
+ wxChar *dst = m_strPath.GetWriteBuf(len);
+ wxChar *start = dst;
+
+ for ( ; src < end; src++, dst++ )
+ {
+ if ( *src == wxCONFIG_PATH_SEPARATOR )
+ {
+ // check for "/.."
+
+ // note that we don't have to check for src < end here as
+ // *end == 0 so can't be '.'
+ if ( src[1] == _T('.') && src[2] == _T('.') &&
+ (src + 3 == end || src[3] == wxCONFIG_PATH_SEPARATOR) )
+ {
+ if ( !totalSlashes )
+ {
+ wxLogWarning(_("'%s' has extra '..', ignored."),
+ strFullPath.c_str());
+ }
+ else // return to the previous path component
+ {
+ // do we already have its position?
+ if ( posLastSlash == -1 )
+ {
+ // no, find it: note that we are sure to have one
+ // because totalSlashes > 0 so we don't have to
+ // check the boundary condition below
+
+ // this is more efficient than strrchr()
+ while ( *dst != wxCONFIG_PATH_SEPARATOR )
+ {
+ dst--;
+ }
+ }
+ else // the position of last slash was stored
+ {
+ // go directly there
+ dst = start + posLastSlash;
+
+ // invalidate posLastSlash
+ posLastSlash = -1;
+ }
+
+ // this shouldn't happen
+ wxASSERT_MSG( *dst == wxCONFIG_PATH_SEPARATOR,
+ _T("error in wxRegConfig::SetPath") );
+
+ // we killed one
+ totalSlashes--;
+ }
+
+ // skip both dots
+ src += 2;
+ }
+ else // not "/.."
+ {
+ if ( (dst == start) || (dst[-1] != wxCONFIG_PATH_SEPARATOR) )
+ {
+ *dst = wxCONFIG_PATH_SEPARATOR;
+
+ posLastSlash = dst - start;
+
+ totalSlashes++;
+ }
+ //else: nothing to do, we squeeze several subseuquent
+ // slashes into one
+ }
+ }
+ else // normal character
+ {
+ // just copy
+ *dst = *src;
+ }
+ }
+
+ // NUL terminate the string
+ if ( dst[-1] == wxCONFIG_PATH_SEPARATOR && (dst != start + 1) )
+ {
+ // if it has a trailing slash we remove it unless it is the only
+ // string character
+ dst--;
+ }
+
+ *dst = _T('\0');
+
+ m_strPath.UngetWriteBuf(dst - start);
+ }