From 9adc285e3f57a87bce15a48663da1edbeaa240e7 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Sun, 31 May 2026 13:47:54 +0200 Subject: [PATCH 1/2] Remove wxPathOnly(wxChar*) overload This overload was not declared nor exported from (shared) libraries, so just remove it. --- src/common/filefn.cpp | 49 ------------------------------------------- 1 file changed, 49 deletions(-) diff --git a/src/common/filefn.cpp b/src/common/filefn.cpp index 98c6f2338a..b046e758fb 100644 --- a/src/common/filefn.cpp +++ b/src/common/filefn.cpp @@ -261,55 +261,6 @@ wxString wxFileNameFromPath (const wxString& path) return wxFileName(path).GetFullName(); } -// Return just the directory, or nullptr if no directory -wxChar * -wxPathOnly (wxChar *path) -{ - if (path && *path) - { - static wxChar buf[_MAXPATHLEN]; - - int l = wxStrlen(path); - int i = l - 1; - if ( i >= _MAXPATHLEN ) - return nullptr; - - // Local copy - wxStrcpy (buf, path); - - // Search backward for a backward or forward slash - while (i > -1) - { - // Unix like or Windows - if (path[i] == wxT('/') || path[i] == wxT('\\')) - { - buf[i] = 0; - return buf; - } -#ifdef __VMS__ - if (path[i] == wxT(']')) - { - buf[i+1] = 0; - return buf; - } -#endif - i --; - } - -#if defined(__WINDOWS__) - // Try Drive specifier - if (wxIsalpha (buf[0]) && buf[1] == wxT(':')) - { - // A:junk --> A:. (since A:.\junk Not A:\junk) - buf[2] = wxT('.'); - buf[3] = wxT('\0'); - return buf; - } -#endif - } - return nullptr; -} - // Return just the directory, or nullptr if no directory wxString wxPathOnly (const wxString& path) { From f19fdb5b1c750e95cb0fe411b8c671fee5165b11 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Sun, 31 May 2026 13:51:22 +0200 Subject: [PATCH 2/2] Reimplement wxPathOnly() using wxFileName::GetPath() Add tests checking that the function still performs as before and document that its behaviour slightly differs from GetPath(). --- interface/wx/filefn.h | 13 +++++++++ src/common/filefn.cpp | 64 ++++++++++++++----------------------------- tests/file/filefn.cpp | 11 ++++++++ 3 files changed, 45 insertions(+), 43 deletions(-) diff --git a/interface/wx/filefn.h b/interface/wx/filefn.h index a41363f3d2..04365206db 100644 --- a/interface/wx/filefn.h +++ b/interface/wx/filefn.h @@ -294,6 +294,19 @@ wxString wxGetWorkingDirectory(char* buf = nullptr, int sz = 1000); /** Returns the directory part of the filename. + @deprecated Please use wxFileName::GetPath() instead. + + Note that the behaviour of this function is slightly different for Windows + paths including drive letters: it returns a string without trailing + backslash for the absolute paths with drive letters and a string with + trailing dot for the relative paths with drive letters. + + Since wxWidgets 3.3.3 all path separators are normalized to the current + platform path separator in the returned path, i.e. under Windows forward + slashes in @a path will be replaced with backslashes in the returned value. + Previous versions of wxWidgets didn't perform this normalization and + returned the path with the same separators as in @a path. + @header{wx/filefn.h} */ wxString wxPathOnly(const wxString& path); diff --git a/src/common/filefn.cpp b/src/common/filefn.cpp index b046e758fb..1e8517e4eb 100644 --- a/src/common/filefn.cpp +++ b/src/common/filefn.cpp @@ -261,56 +261,34 @@ wxString wxFileNameFromPath (const wxString& path) return wxFileName(path).GetFullName(); } -// Return just the directory, or nullptr if no directory +// Return just the directory, or empty string if no directory wxString wxPathOnly (const wxString& path) { - if (!path.empty()) - { - wxChar buf[_MAXPATHLEN]; - - int l = path.length(); - int i = l - 1; - - if ( i >= _MAXPATHLEN ) - return wxString(); - - // Local copy - wxStrcpy(buf, path); - - // Search backward for a backward or forward slash - while (i > -1) - { - // Unix like or Windows - if (path[i] == wxT('/') || path[i] == wxT('\\')) - { - // Don't return an empty string - if (i == 0) - i ++; - buf[i] = 0; - return wxString(buf); - } -#ifdef __VMS__ - if (path[i] == wxT(']')) - { - buf[i+1] = 0; - return wxString(buf); - } -#endif - i --; - } + wxString res = wxFileName(path).GetPath(); + // For compatibility with the old behaviour of this function, we need to + // return "X:" for paths with volume and absolute path under Windows and + // "X:." for paths with volume and relative path. #if defined(__WINDOWS__) - // Try Drive specifier - if (wxIsalpha (buf[0]) && buf[1] == wxT(':')) + if ( res.size() >= 2 && wxIsalpha(res[0]) && res[1] == wxT(':') ) + { + switch ( res.size() ) { - // A:junk --> A:. (since A:.\junk Not A:\junk) - buf[2] = wxT('.'); - buf[3] = wxT('\0'); - return wxString(buf); + case 2: + // "X:" --> "X:." + res += wxT('.'); + break; + + case 3: + // "X:\" --> "X:" + if ( res[2] == wxFILE_SEP_PATH ) + res.erase(2); + break; } -#endif } - return wxEmptyString; +#endif // __WINDOWS__ + + return res; } // Utility for converting delimiters in DOS filenames to UNIX style diff --git a/tests/file/filefn.cpp b/tests/file/filefn.cpp index 620d0097b6..d2fae291a7 100644 --- a/tests/file/filefn.cpp +++ b/tests/file/filefn.cpp @@ -488,6 +488,17 @@ TEST_CASE_METHOD(FileFunctionsTestCase, wxString pathOnly = wxPathOnly(filename.GetFullPath()); if ( !wxDirExists(pathOnly) ) CHECK( pathOnly == wxString() ); + + CHECK( wxPathOnly(wxString{}) == "" ); + CHECK( wxPathOnly("foo") == "" ); + CHECK( wxPathOnly("foo/") == "foo" ); + CHECK( wxPathOnly("/foo/") == wxString(wxFILE_SEP_PATH) + "foo" ); + +#ifdef __WINDOWS__ + CHECK( wxPathOnly("c:\\foo.exe") == "c:" ); + CHECK( wxPathOnly("c:foo.exe") == "c:." ); + CHECK( wxPathOnly("foo\\bar.dll") == "foo" ); +#endif } // Unit tests for Mkdir and Rmdir doesn't cover non-ASCII directory names.