diff --git a/include/wx/filename.h b/include/wx/filename.h index 1a51030b89..f592996548 100644 --- a/include/wx/filename.h +++ b/include/wx/filename.h @@ -70,9 +70,19 @@ enum wxPathNormalize wxPATH_NORM_TILDE = 0x0004, // Unix only: replace ~ and ~user wxPATH_NORM_CASE = 0x0008, // if case insensitive => tolower wxPATH_NORM_ABSOLUTE = 0x0010, // make the path absolute - wxPATH_NORM_LONG = 0x0020, // make the path the long form + wxPATH_NORM_LONG = 0x0020, // make the path the long form (MSW-only) wxPATH_NORM_SHORTCUT = 0x0040, // resolve the shortcut, if it is a shortcut - wxPATH_NORM_ALL = 0x00ff & ~wxPATH_NORM_CASE + + // Don't use this constant, it used to correspond to the default + // Normalize() behaviour but this is deprecated now. + wxPATH_NORM_DEPR_OLD_DEFAULT= 0x00ff & ~wxPATH_NORM_CASE, + + // This constant name is misleading, as it doesn't really include all the + // flags above, so its use is discouraged, please use the flags you want + // explicitly instead. + wxPATH_NORM_ALL + wxDEPRECATED_ATTR("specify the wanted flags explicitly to avoid surprises") + = wxPATH_NORM_DEPR_OLD_DEFAULT }; // what exactly should GetPath() return? @@ -341,15 +351,21 @@ public: // operations on the path - // normalize the path: with the default flags value, the path will be - // made absolute, without any ".." and "." and all environment - // variables will be expanded in it + // normalize the path using the specified normalizations, use + // MakeAbsolute() for a simpler form applying the standard ones // // this may be done using another (than current) value of cwd - bool Normalize(int flags = wxPATH_NORM_ALL, + bool Normalize(int flags, const wxString& cwd = wxEmptyString, wxPathFormat format = wxPATH_NATIVE); + // using wxPATH_NORM_ALL may give unexpected results, so avoid using + // this function and call Normalize(wxPATH_NORM_ENV_VARS | ...) + // explicitly if you really need environment variables expansion + wxDEPRECATED_MSG("specify the wanted flags explicitly to avoid surprises") + bool Normalize() + { return Normalize(wxPATH_NORM_DEPR_OLD_DEFAULT); } + // get a path path relative to the given base directory, i.e. opposite // of Normalize // @@ -361,7 +377,7 @@ public: bool MakeRelativeTo(const wxString& pathBase = wxEmptyString, wxPathFormat format = wxPATH_NATIVE); - // make the path absolute + // make the path absolute and resolve any "." and ".." in it // // this may be done using another (than current) value of cwd bool MakeAbsolute(const wxString& cwd = wxEmptyString, @@ -369,6 +385,15 @@ public: { return Normalize(wxPATH_NORM_DOTS | wxPATH_NORM_ABSOLUTE | wxPATH_NORM_TILDE, cwd, format); } + // Convenient helper for returning the absolute path corresponding to + // the given one. + wxString GetAbsolutePath(const wxString& cwd = wxEmptyString, + wxPathFormat format = wxPATH_NATIVE) const + { + wxFileName fn(*this); + fn.MakeAbsolute(cwd, format); + return fn.GetFullPath(); + } // If the path is a symbolic link (Unix-only), indicate that all // filesystem operations on this path should be performed on the link diff --git a/include/wx/fswatcher.h b/include/wx/fswatcher.h index a9a9d8342c..2030ee5434 100644 --- a/include/wx/fswatcher.h +++ b/include/wx/fswatcher.h @@ -370,15 +370,7 @@ protected: static wxString GetCanonicalPath(const wxFileName& path) { - wxFileName path_copy = wxFileName(path); - if ( !path_copy.Normalize() ) - { - wxFAIL_MSG(wxString::Format(wxASCII_STR("Unable to normalize path '%s'"), - path.GetFullPath())); - return wxEmptyString; - } - - return path_copy.GetFullPath(); + return path.GetAbsolutePath(); } diff --git a/interface/wx/filename.h b/interface/wx/filename.h index bacf59ad4f..7dc34abdac 100644 --- a/interface/wx/filename.h +++ b/interface/wx/filename.h @@ -54,20 +54,52 @@ enum wxSizeConvention */ enum wxPathNormalize { - //! Replace environment variables with their values. - //! wxFileName understands both Unix and Windows (but only under Windows) environment - //! variables expansion: i.e. @c "$var", @c "$(var)" and @c "${var}" are always understood - //! and in addition under Windows @c "%var%" is also. + /** + Replace environment variables with their values. + + wxFileName understands both Unix and Windows (but only under Windows) environment + variables expansion: i.e. @c "$var", @c "$(var)" and @c "${var}" are always understood + and in addition under Windows @c "%var%" is also. + + Note that when this flag is used, dollar or percent signs may be + escaped with backslashes to prevent them from being used for the + variable expansion, meaning that normalizing any path with a directory + starting with a dollar sign under Windows can give unexpected results, + as normalizing @c c:\\foo\\$bar results in @c c:\\foo$bar. Because of + this, using this flag with arbitrary paths is not recommended. + */ wxPATH_NORM_ENV_VARS = 0x0001, wxPATH_NORM_DOTS = 0x0002, //!< Squeeze all @c ".." and @c ".". wxPATH_NORM_TILDE = 0x0004, //!< Replace @c "~" and @c "~user" (Unix only). wxPATH_NORM_CASE = 0x0008, //!< If the platform is case insensitive, make lowercase the path. wxPATH_NORM_ABSOLUTE = 0x0010, //!< Make the path absolute. - wxPATH_NORM_LONG = 0x0020, //!< Expand the path to the "long" form (Windows only). + + /** + Expand the path to the "long" form under Windows. + + This flag converts DOS short paths in 8.3 format to long form under + Windows and does nothing under the other platforms. It is mostly + irrelevant nowadays as short paths are not used any longer in practice. + + Notice that it only works for the existing file paths. + + @see wxFileName::GetLongPath() + */ + wxPATH_NORM_LONG = 0x0020, + wxPATH_NORM_SHORTCUT = 0x0040, //!< Resolve the shortcut, if it is a shortcut (Windows only). - //! A value indicating all normalization flags except for @c wxPATH_NORM_CASE. + /** + Flags used by wxFileName::Normalize() by default. + + This includes all normalization flags except for @c wxPATH_NORM_CASE + and notably does include @c wxPATH_NORM_ENV_VARS which may yield + unexpected results, as described above. Because of this, this flag is + deprecated and shouldn't be used in the new code and the existing code + should be reviewed to check if expanding environment variables is + really needed. + */ wxPATH_NORM_ALL = 0x00ff & ~wxPATH_NORM_CASE }; @@ -601,6 +633,17 @@ public: static wxFileName FileName(const wxString& file, wxPathFormat format = wxPATH_NATIVE); + /** + Returns full absolute path for this file. + + This is just a convenient shortcut using MakeAbsolute() and + GetFullPath() internally. + + @since 3.1.6 + */ + wxString GetAbsolutePath(const wxString& cwd = wxEmptyString, + wxPathFormat format = wxPATH_NATIVE) const; + /** Retrieves the value of the current working directory on the specified volume. If the volume is empty, the program's current working directory is returned for @@ -1067,7 +1110,9 @@ public: Normalize the path. With the default flags value, the path will be made absolute, without - any ".." and "." and all environment variables will be expanded in it. + any ".." and ".", and, for the Unix format paths, any occurrences of + tilde (@c ~) character will be replaced with the home directory of the + user following it. Notice that in some rare cases normalizing a valid path may result in an invalid wxFileName object. E.g. normalizing "./" path using @@ -1078,6 +1123,9 @@ public: @param flags The kind of normalization to do with the file name. It can be any or-combination of the ::wxPathNormalize enumeration values. + These values should be explicitly specified, omitting them uses the + deprecated wxPATH_NORM_ALL value which is not recommended, see + wxPathNormalize enum for more details. @param cwd If not empty, this directory will be used instead of current working directory in normalization (see @c wxPATH_NORM_ABSOLUTE). @@ -1086,7 +1134,7 @@ public: @return @true if normalization was successfully or @false otherwise. */ - bool Normalize(int flags = wxPATH_NORM_ALL, + bool Normalize(int flags, const wxString& cwd = wxEmptyString, wxPathFormat format = wxPATH_NATIVE); diff --git a/samples/menu/menu.cpp b/samples/menu/menu.cpp index 3adf4db013..6387705fc4 100644 --- a/samples/menu/menu.cpp +++ b/samples/menu/menu.cpp @@ -574,17 +574,9 @@ MyFrame::MyFrame() m_fileHistory = new wxFileHistory(); m_fileHistory->UseMenu(m_fileHistoryMenu); - wxFileName fn( "menu.cpp" ); - fn.Normalize(); - m_fileHistory->AddFileToHistory( fn.GetFullPath() ); - - fn = "Makefile.in"; - fn.Normalize(); - m_fileHistory->AddFileToHistory( fn.GetFullPath() ); - - fn.Assign("minimal", "minimal", "cpp"); - fn.Normalize(); - m_fileHistory->AddFileToHistory( fn.GetFullPath() ); + m_fileHistory->AddFileToHistory( wxFileName("menu.cpp").GetAbsolutePath() ); + m_fileHistory->AddFileToHistory( wxFileName("Makefile.in").GetAbsolutePath() ); + m_fileHistory->AddFileToHistory( wxFileName("minimal", "minimal", "cpp").GetAbsolutePath() ); fileMenu->AppendSubMenu(m_fileHistoryMenu, "Sample file history"); #endif diff --git a/samples/stc/stctest.cpp b/samples/stc/stctest.cpp index 07a8c4a6ad..de078dba04 100644 --- a/samples/stc/stctest.cpp +++ b/samples/stc/stctest.cpp @@ -601,8 +601,7 @@ void AppFrame::CreateMenu () void AppFrame::FileOpen (wxString fname) { - wxFileName w(fname); w.Normalize(); fname = w.GetFullPath(); - m_edit->LoadFile (fname); + m_edit->LoadFile (wxFileName(fname).GetAbsolutePath()); m_edit->SelectNone(); } diff --git a/samples/webview/webview.cpp b/samples/webview/webview.cpp index c8d585a2de..0d9148c5d5 100644 --- a/samples/webview/webview.cpp +++ b/samples/webview/webview.cpp @@ -748,9 +748,7 @@ void WebFrame::OnLoadScheme(wxCommandEvent& WXUNUSED(evt)) pathlist.Add("../help"); pathlist.Add("../../../samples/help"); - wxFileName helpfile(pathlist.FindValidPath("doc.zip")); - helpfile.MakeAbsolute(); - wxString path = helpfile.GetFullPath(); + wxString path = wxFileName(pathlist.FindValidPath("doc.zip")).GetAbsolutePath(); //Under MSW we need to flip the slashes path.Replace("\\", "/"); path = "wxfs:///" + path + ";protocol=zip/doc.htm"; diff --git a/src/common/filename.cpp b/src/common/filename.cpp index 5d96f045fd..d31d3a5f35 100644 --- a/src/common/filename.cpp +++ b/src/common/filename.cpp @@ -1765,14 +1765,14 @@ bool wxFileName::MakeRelativeTo(const wxString& pathBase, wxPathFormat format) // get cwd only once - small time saving wxString cwd = wxGetCwd(); - // Normalize both paths to be absolute but avoid expanding environment - // variables in them, this could be unexpected. - const int normFlags = wxPATH_NORM_DOTS | - wxPATH_NORM_TILDE | - wxPATH_NORM_ABSOLUTE | - wxPATH_NORM_LONG; - Normalize(normFlags, cwd, format); - fnBase.Normalize(normFlags, cwd, format); + // Bring both paths to canonical form. + MakeAbsolute(cwd, format); + fnBase.MakeAbsolute(cwd, format); + + // Do this here for compatibility, as we used to do it before. + Normalize(wxPATH_NORM_LONG, cwd, format); + fnBase.Normalize(wxPATH_NORM_LONG, cwd, format); + bool withCase = IsCaseSensitive(format); @@ -1841,8 +1841,20 @@ bool wxFileName::SameAs(const wxFileName& filepath, wxPathFormat format) const // get cwd only once - small time saving wxString cwd = wxGetCwd(); - fn1.Normalize(wxPATH_NORM_ALL | wxPATH_NORM_CASE, cwd, format); - fn2.Normalize(wxPATH_NORM_ALL | wxPATH_NORM_CASE, cwd, format); + + // apply really all normalizations here + const int normAll = + wxPATH_NORM_ENV_VARS | + wxPATH_NORM_DOTS | + wxPATH_NORM_TILDE | + wxPATH_NORM_CASE | + wxPATH_NORM_ABSOLUTE | + wxPATH_NORM_LONG | + wxPATH_NORM_SHORTCUT + ; + + fn1.Normalize(normAll, cwd, format); + fn2.Normalize(normAll, cwd, format); if ( fn1.GetFullPath() == fn2.GetFullPath() ) return true; @@ -2619,9 +2631,7 @@ static wxString EscapeFileNameCharsInURL(const char *in) // Returns the file URL for a native path wxString wxFileName::FileNameToURL(const wxFileName& filename) { - wxFileName fn = filename; - fn.Normalize(wxPATH_NORM_DOTS | wxPATH_NORM_TILDE | wxPATH_NORM_ABSOLUTE); - wxString url = fn.GetFullPath(wxPATH_NATIVE); + wxString url = filename.GetAbsolutePath(wxString(), wxPATH_NATIVE); #ifndef __UNIX__ // unc notation, wxMSW diff --git a/src/common/stdpbase.cpp b/src/common/stdpbase.cpp index 5f5c12a0c8..e78fd0c28e 100644 --- a/src/common/stdpbase.cpp +++ b/src/common/stdpbase.cpp @@ -77,9 +77,7 @@ wxString wxStandardPathsBase::GetExecutablePath() const if ( path.empty() ) return argv0; // better than nothing - wxFileName filename(path); - filename.Normalize(); - return filename.GetFullPath(); + return wxFileName(path).GetAbsolutePath(); } wxStandardPaths& wxAppTraitsBase::GetStandardPaths() diff --git a/src/gtk/filedlg.cpp b/src/gtk/filedlg.cpp index 6ab3fcae7c..c68c7c7256 100644 --- a/src/gtk/filedlg.cpp +++ b/src/gtk/filedlg.cpp @@ -429,9 +429,7 @@ void wxFileDialog::SetPath(const wxString& path) // we need an absolute path for GTK native chooser so ensure that we have // it: use the initial directory if it was set or just CWD otherwise (this // is the default behaviour if m_dir is empty) - wxFileName fn(path); - fn.MakeAbsolute(m_dir); - m_fc.SetPath(fn.GetFullPath()); + m_fc.SetPath(wxFileName(path).GetAbsolutePath(m_dir)); } void wxFileDialog::SetDirectory(const wxString& dir) diff --git a/src/html/chm.cpp b/src/html/chm.cpp index 2d77d88f95..7927d282d6 100644 --- a/src/html/chm.cpp +++ b/src/html/chm.cpp @@ -817,9 +817,7 @@ wxFSFile* wxChmFSHandler::OpenFile(wxFileSystem& WXUNUSED(fs), // now work on the right location if (right.Contains(wxT(".."))) { - wxFileName abs(right); - abs.MakeAbsolute(wxT("/")); - right = abs.GetFullPath(); + right = wxFileName(right).GetAbsolutePath(wxT("/")); } // a workaround for absolute links to root diff --git a/src/xrc/xmlres.cpp b/src/xrc/xmlres.cpp index 65918e929f..046b0004c4 100644 --- a/src/xrc/xmlres.cpp +++ b/src/xrc/xmlres.cpp @@ -314,12 +314,7 @@ wxString wxXmlResource::ConvertFileNameToURL(const wxString& filename) { // Make the name absolute filename, because the app may // change working directory later: - wxFileName fn(fnd); - if (fn.IsRelative()) - { - fn.MakeAbsolute(); - fnd = fn.GetFullPath(); - } + fnd = wxFileName(fnd).GetAbsolutePath(); #if wxUSE_FILESYSTEM fnd = wxFileSystem::FileNameToURL(fnd); #endif diff --git a/tests/filename/filenametest.cpp b/tests/filename/filenametest.cpp index f14e58474f..a650deff7e 100644 --- a/tests/filename/filenametest.cpp +++ b/tests/filename/filenametest.cpp @@ -36,6 +36,10 @@ #include "testfile.h" #include "testdate.h" +// Use a hack to keep using wxPATH_NORM_ALL in this test code without getting +// deprecation warnings for it. +#define wxPATH_NORM_ALL wxPATH_NORM_DEPR_OLD_DEFAULT + // ---------------------------------------------------------------------------- // test data // ---------------------------------------------------------------------------- @@ -201,8 +205,8 @@ TEST_CASE("wxFileName::Comparison", "[filename]") { wxFileName fn1(wxT("/tmp/file1")); wxFileName fn2(wxT("/tmp/dir2/../file2")); - fn1.Normalize(); - fn2.Normalize(); + fn1.MakeAbsolute(); + fn2.MakeAbsolute(); CHECK(fn1.GetPath() == fn2.GetPath()); } @@ -258,6 +262,14 @@ TEST_CASE("wxFileName::Normalize", "[filename]") if (cwd.Contains(wxT(':'))) cwd = cwd.AfterFirst(wxT(':')); + static const char* pathWithEnvVar = +#ifdef __WINDOWS__ + "%ABCDEF%/g/h/i" +#else + "$(ABCDEF)/g/h/i" +#endif + ; + static const struct FileNameTest { const char *original; @@ -267,11 +279,7 @@ TEST_CASE("wxFileName::Normalize", "[filename]") } tests[] = { // test wxPATH_NORM_ENV_VARS -#ifdef __WINDOWS__ - { "%ABCDEF%/g/h/i", wxPATH_NORM_ENV_VARS, "abcdef/g/h/i", wxPATH_UNIX }, -#else - { "$(ABCDEF)/g/h/i", wxPATH_NORM_ENV_VARS, "abcdef/g/h/i", wxPATH_UNIX }, -#endif + { pathWithEnvVar, wxPATH_NORM_ENV_VARS, "abcdef/g/h/i", wxPATH_UNIX }, // test wxPATH_NORM_DOTS { "a/.././b/c/../../", wxPATH_NORM_DOTS, "", wxPATH_UNIX }, @@ -317,6 +325,9 @@ TEST_CASE("wxFileName::Normalize", "[filename]") { ".\\foo", wxPATH_NORM_LONG, ".\\foo", wxPATH_DOS }, { "..\\Makefile.in", wxPATH_NORM_LONG, "..\\Makefile.in", wxPATH_DOS }, { "..\\foo", wxPATH_NORM_LONG, "..\\foo", wxPATH_DOS }, + + // test default behaviour with deprecated wxPATH_NORM_ALL + { pathWithEnvVar, wxPATH_NORM_ALL, "CWD/abcdef/g/h/i", wxPATH_UNIX }, }; // set the env var ABCDEF @@ -345,6 +356,11 @@ TEST_CASE("wxFileName::Normalize", "[filename]") ); } + // Check that paths are made absolute, but environment variables are not + // expanded in them. + CHECK( wxFileName(pathWithEnvVar).GetAbsolutePath() + == wxFileName(wxGetCwd() + "/" + pathWithEnvVar).GetFullPath() ); + // MSW-only test for wxPATH_NORM_LONG: notice that we only run it if short // names generation is not disabled for this system as otherwise the file // MKINST~1 doesn't exist at all and normalizing it fails (it's possible diff --git a/utils/screenshotgen/src/autocapture.cpp b/utils/screenshotgen/src/autocapture.cpp index 427c26af8a..275b428fb2 100644 --- a/utils/screenshotgen/src/autocapture.cpp +++ b/utils/screenshotgen/src/autocapture.cpp @@ -44,9 +44,7 @@ wxString AutoCaptureMechanism::default_dir = wxT("screenshots"); /* static */ wxString AutoCaptureMechanism::GetDefaultDirectoryAbsPath() { - wxFileName output = wxFileName::DirName(GetDefaultDirectory()); - output.MakeAbsolute(); - return output.GetFullPath(); + return wxFileName::DirName(GetDefaultDirectory()).GetAbsolutePath(); } /* static */ diff --git a/utils/wxrc/wxrc.cpp b/utils/wxrc/wxrc.cpp index d18afcc766..348525f13c 100644 --- a/utils/wxrc/wxrc.cpp +++ b/utils/wxrc/wxrc.cpp @@ -337,9 +337,7 @@ void XmlResApp::ParseParams(const wxCmdLineParser& cmdline) } if (!parOutput.empty()) { - wxFileName fn(parOutput); - fn.Normalize(); - parOutput = fn.GetFullPath(); + parOutput = wxFileName(parOutput).GetAbsolutePath(); parOutputPath = wxPathOnly(parOutput); } if (!parOutputPath) parOutputPath = wxT(".");