| From 8264c28205f988c0e7147f4f82c68511bb5ec611 Mon Sep 17 00:00:00 2001 |
| From: Ray Donnelly <mingw.android@gmail.com> |
| Date: Thu, 17 Jun 2021 18:51:46 +0530 |
| Subject: [PATCH 038/N] msys mingw prefer unix sep if MSYSTEM |
| MIME-Version: 1.0 |
| Content-Type: text/plain; charset=UTF-8 |
| Content-Transfer-Encoding: 8bit |
| |
| Co-authored-by: Алексей <alexey.pawlow@gmail.com> |
| Co-authored-by: Christoph Reiter <reiter.christoph@gmail.com> |
| --- |
| Include/pylifecycle.h | 6 +++ |
| Lib/ntpath.py | 79 +++++++++++++++++------------- |
| Modules/posixmodule.c | 2 + |
| Python/initconfig.c | 4 +- |
| Python/pathconfig.c | 109 ++++++++++++++++++++++++++++++++++++++++++ |
| Python/traceback.c | 2 +- |
| 6 files changed, 165 insertions(+), 37 deletions(-) |
| |
| diff --git a/Include/pylifecycle.h b/Include/pylifecycle.h |
| index 783fcb4..4eec669 100644 |
| --- a/Include/pylifecycle.h |
| +++ b/Include/pylifecycle.h |
| @@ -21,6 +21,12 @@ PyAPI_FUNC(int) Py_IsInitialized(void); |
| PyAPI_FUNC(PyThreadState *) Py_NewInterpreter(void); |
| PyAPI_FUNC(void) Py_EndInterpreter(PyThreadState *); |
| |
| +PyAPI_FUNC(wchar_t) Py_GetSepW(const wchar_t *); |
| +PyAPI_FUNC(char) Py_GetSepA(const char *); |
| + |
| +PyAPI_FUNC(void) Py_NormalizeSepsW(wchar_t *); |
| +PyAPI_FUNC(void) Py_NormalizeSepsA(char *); |
| + |
| |
| /* Py_PyAtExit is for the atexit module, Py_AtExit is for low-level |
| * exit functions. |
| diff --git a/Lib/ntpath.py b/Lib/ntpath.py |
| index 6f77177..77f5614 100644 |
| --- a/Lib/ntpath.py |
| +++ b/Lib/ntpath.py |
| @@ -11,9 +11,7 @@ module as os.path. |
| curdir = '.' |
| pardir = '..' |
| extsep = '.' |
| -sep = '\\' |
| pathsep = ';' |
| -altsep = '/' |
| defpath = '.;C:\\bin' |
| devnull = 'nul' |
| |
| @@ -23,6 +21,15 @@ import stat |
| import genericpath |
| from genericpath import * |
| |
| +if sys.platform == "win32" and "MSYSTEM" in os.environ: |
| + sep = '/' |
| + altsep = '\\' |
| +else: |
| + sep = '\\' |
| + altsep = '/' |
| +bsep = str.encode(sep) |
| +baltsep = str.encode(altsep) |
| + |
| __all__ = ["normcase","isabs","join","splitdrive","split","splitext", |
| "basename","dirname","commonprefix","getsize","getmtime", |
| "getatime","getctime", "islink","exists","lexists","isdir","isfile", |
| @@ -33,9 +40,27 @@ __all__ = ["normcase","isabs","join","splitdrive","split","splitext", |
| |
| def _get_bothseps(path): |
| if isinstance(path, bytes): |
| - return b'\\/' |
| + return bsep+baltsep |
| + else: |
| + return sep+altsep |
| + |
| +def _get_sep(path): |
| + if isinstance(path, bytes): |
| + return bsep |
| + else: |
| + return sep |
| + |
| +def _get_altsep(path): |
| + if isinstance(path, bytes): |
| + return baltsep |
| else: |
| - return '\\/' |
| + return altsep |
| + |
| +def _get_colon(path): |
| + if isinstance(path, bytes): |
| + return b':' |
| + else: |
| + return ':' |
| |
| # Normalize the case of a pathname and map slashes to backslashes. |
| # Other normalizations (such as optimizing '../' away) are not done |
| @@ -47,9 +72,9 @@ def normcase(s): |
| Makes all characters lowercase and all slashes into backslashes.""" |
| s = os.fspath(s) |
| if isinstance(s, bytes): |
| - return s.replace(b'/', b'\\').lower() |
| + return s.replace(baltsep, bsep).lower() |
| else: |
| - return s.replace('/', '\\').lower() |
| + return s.replace(altsep, sep).lower() |
| |
| |
| # Return whether a path is absolute. |
| @@ -76,14 +101,9 @@ def isabs(s): |
| # Join two (or more) paths. |
| def join(path, *paths): |
| path = os.fspath(path) |
| - if isinstance(path, bytes): |
| - sep = b'\\' |
| - seps = b'\\/' |
| - colon = b':' |
| - else: |
| - sep = '\\' |
| - seps = '\\/' |
| - colon = ':' |
| + sep = _get_sep(path) |
| + seps = _get_bothseps(path) |
| + colon = _get_colon(path) |
| try: |
| if not paths: |
| path[:0] + sep #23780: Ensure compatible data type even if p is null. |
| @@ -142,14 +162,9 @@ def splitdrive(p): |
| """ |
| p = os.fspath(p) |
| if len(p) >= 2: |
| - if isinstance(p, bytes): |
| - sep = b'\\' |
| - altsep = b'/' |
| - colon = b':' |
| - else: |
| - sep = '\\' |
| - altsep = '/' |
| - colon = ':' |
| + sep = _get_sep(p) |
| + altsep = _get_altsep(p) |
| + colon = _get_colon(p) |
| normp = p.replace(altsep, sep) |
| if (normp[0:2] == sep*2) and (normp[2:3] != sep): |
| # is a UNC path: |
| @@ -203,9 +218,9 @@ def split(p): |
| def splitext(p): |
| p = os.fspath(p) |
| if isinstance(p, bytes): |
| - return genericpath._splitext(p, b'\\', b'/', b'.') |
| + return genericpath._splitext(p, bsep, baltsep, b'.') |
| else: |
| - return genericpath._splitext(p, '\\', '/', '.') |
| + return genericpath._splitext(p, sep, altsep, '.') |
| splitext.__doc__ = genericpath._splitext.__doc__ |
| |
| |
| @@ -450,15 +465,13 @@ def expandvars(path): |
| def normpath(path): |
| """Normalize path, eliminating double slashes, etc.""" |
| path = os.fspath(path) |
| + sep = _get_sep(path) |
| + altsep = _get_altsep(path) |
| if isinstance(path, bytes): |
| - sep = b'\\' |
| - altsep = b'/' |
| curdir = b'.' |
| pardir = b'..' |
| special_prefixes = (b'\\\\.\\', b'\\\\?\\') |
| else: |
| - sep = '\\' |
| - altsep = '/' |
| curdir = '.' |
| pardir = '..' |
| special_prefixes = ('\\\\.\\', '\\\\?\\') |
| @@ -668,6 +681,7 @@ else: |
| # strip the prefix anyway. |
| if ex.winerror == initial_winerror: |
| path = spath |
| + path = normpath(path) |
| return path |
| |
| |
| @@ -678,12 +692,11 @@ supports_unicode_filenames = (hasattr(sys, "getwindowsversion") and |
| def relpath(path, start=None): |
| """Return a relative version of a path""" |
| path = os.fspath(path) |
| + sep = _get_sep(path) |
| if isinstance(path, bytes): |
| - sep = b'\\' |
| curdir = b'.' |
| pardir = b'..' |
| else: |
| - sep = '\\' |
| curdir = '.' |
| pardir = '..' |
| |
| @@ -738,13 +751,11 @@ def commonpath(paths): |
| raise ValueError('commonpath() arg is an empty sequence') |
| |
| paths = tuple(map(os.fspath, paths)) |
| + sep = _get_sep(paths[0]) |
| + altsep = _get_altsep(paths[0]) |
| if isinstance(paths[0], bytes): |
| - sep = b'\\' |
| - altsep = b'/' |
| curdir = b'.' |
| else: |
| - sep = '\\' |
| - altsep = '/' |
| curdir = '.' |
| |
| try: |
| diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c |
| index 3f3e1f3..1e61545 100644 |
| --- a/Modules/posixmodule.c |
| +++ b/Modules/posixmodule.c |
| @@ -3759,6 +3759,7 @@ posix_getcwd(int use_bytes) |
| return PyErr_SetFromWindowsErr(0); |
| } |
| |
| + Py_NormalizeSepsW(wbuf2); |
| PyObject *resobj = PyUnicode_FromWideChar(wbuf2, len); |
| if (wbuf2 != wbuf) { |
| PyMem_RawFree(wbuf2); |
| @@ -4322,6 +4323,7 @@ os__getfinalpathname_impl(PyObject *module, path_t *path) |
| target_path = tmp; |
| } |
| |
| + Py_NormalizeSepsW(target_path); |
| result = PyUnicode_FromWideChar(target_path, result_length); |
| if (result && path->narrow) { |
| Py_SETREF(result, PyUnicode_EncodeFSDefault(result)); |
| diff --git a/Python/initconfig.c b/Python/initconfig.c |
| index 3caed38..d8f0005 100644 |
| --- a/Python/initconfig.c |
| +++ b/Python/initconfig.c |
| @@ -136,7 +136,7 @@ static const char usage_6[] = |
| "PYTHONDEVMODE: enable the development mode.\n" |
| "PYTHONPYCACHEPREFIX: root directory for bytecode cache (pyc) files.\n"; |
| |
| -#if defined(MS_WINDOWS) |
| +#if defined(_MSC_VER) |
| # define PYTHONHOMEHELP "<prefix>\\python{major}{minor}" |
| #else |
| # define PYTHONHOMEHELP "<prefix>/lib/pythonX.X" |
| @@ -1187,7 +1187,7 @@ config_init_program_name(PyConfig *config) |
| } |
| |
| /* Last fall back: hardcoded name */ |
| -#ifdef MS_WINDOWS |
| +#ifdef _MSC_VER |
| const wchar_t *default_program_name = L"python"; |
| #else |
| const wchar_t *default_program_name = L"python3"; |
| diff --git a/Python/pathconfig.c b/Python/pathconfig.c |
| index 9a30221..267ee4d 100644 |
| --- a/Python/pathconfig.c |
| +++ b/Python/pathconfig.c |
| @@ -15,6 +15,114 @@ |
| extern "C" { |
| #endif |
| |
| +#ifdef __MINGW32__ |
| +#define wcstok wcstok_s |
| +#include <windows.h> |
| +#endif |
| + |
| +char |
| +Py_GetSepA(const char *name) |
| +{ |
| + char* msystem = (char*)2; /* So that non Windows use / as sep */ |
| + static char sep = '\0'; |
| +#ifdef _WIN32 |
| + /* https://msdn.microsoft.com/en-gb/library/windows/desktop/aa365247%28v=vs.85%29.aspx |
| + * The "\\?\" prefix .. indicate that the path should be passed to the system with minimal |
| + * modification, which means that you cannot use forward slashes to represent path separators |
| + */ |
| + if (name != NULL && memcmp(name, "\\\\?\\", sizeof("\\\\?\\") - sizeof(char)) == 0) |
| + { |
| + return '\\'; |
| + } |
| +#endif |
| + if (sep != '\0') |
| + return sep; |
| +#if defined(__MINGW32__) |
| + msystem = Py_GETENV("MSYSTEM"); |
| +#endif |
| + if (msystem != NULL) |
| + sep = '/'; |
| + else |
| + sep = '\\'; |
| + return sep; |
| +} |
| + |
| +static char |
| +Py_GetAltSepA(const char *name) |
| +{ |
| + char sep = Py_GetSepA(name); |
| + if (sep == '/') |
| + return '\\'; |
| + return '/'; |
| +} |
| + |
| +void |
| +Py_NormalizeSepsA(char *name) |
| +{ |
| + char sep = Py_GetSepA(name); |
| + char altsep = Py_GetAltSepA(name); |
| + char* seps; |
| + if (strlen(name) > 1 && name[1] == ':') { |
| + name[0] = toupper(name[0]); |
| + } |
| + seps = strchr(name, altsep); |
| + while(seps) { |
| + *seps = sep; |
| + seps = strchr(seps, altsep); |
| + } |
| +} |
| + |
| +wchar_t |
| +Py_GetSepW(const wchar_t *name) |
| +{ |
| + char* msystem = (char*)2; /* So that non Windows use / as sep */ |
| + static wchar_t sep = L'\0'; |
| +#ifdef _WIN32 |
| + /* https://msdn.microsoft.com/en-gb/library/windows/desktop/aa365247%28v=vs.85%29.aspx |
| + * The "\\?\" prefix .. indicate that the path should be passed to the system with minimal |
| + * modification, which means that you cannot use forward slashes to represent path separators |
| + */ |
| + if (name != NULL && memcmp(name, L"\\\\?\\", sizeof(L"\\\\?\\") - sizeof(wchar_t)) == 0) |
| + { |
| + return L'\\'; |
| + } |
| +#endif |
| + if (sep != L'\0') |
| + return sep; |
| +#if defined(__MINGW32__) |
| + msystem = Py_GETENV("MSYSTEM"); |
| +#endif |
| + if (msystem != NULL) |
| + sep = L'/'; |
| + else |
| + sep = L'\\'; |
| + return sep; |
| +} |
| + |
| +static wchar_t |
| +Py_GetAltSepW(const wchar_t *name) |
| +{ |
| + char sep = Py_GetSepW(name); |
| + if (sep == L'/') |
| + return L'\\'; |
| + return L'/'; |
| +} |
| + |
| +void |
| +Py_NormalizeSepsW(wchar_t *name) |
| +{ |
| + wchar_t sep = Py_GetSepW(name); |
| + wchar_t altsep = Py_GetAltSepW(name); |
| + wchar_t* seps; |
| + if (wcslen(name) > 1 && name[1] == L':') { |
| + name[0] = towupper(name[0]); |
| + } |
| + seps = wcschr(name, altsep); |
| + while(seps) { |
| + *seps = sep; |
| + seps = wcschr(seps, altsep); |
| + } |
| +} |
| |
| _PyPathConfig _Py_path_config = _PyPathConfig_INIT; |
| |
| @@ -541,6 +649,7 @@ _Py_SetProgramFullPath(const wchar_t *program_full_path) |
| if (_Py_path_config.program_full_path == NULL) { |
| path_out_of_memory(__func__); |
| } |
| + Py_NormalizeSepsW(_Py_path_config.program_name); |
| } |
| |
| |
| diff --git a/Python/traceback.c b/Python/traceback.c |
| index a9a9dd9..e8d2786 100644 |
| --- a/Python/traceback.c |
| +++ b/Python/traceback.c |
| @@ -314,7 +314,7 @@ _Py_FindSourceFile(PyObject *filename, char* namebuf, size_t namelen, PyObject * |
| filepath = PyBytes_AS_STRING(filebytes); |
| |
| /* Search tail of filename in sys.path before giving up */ |
| - tail = strrchr(filepath, SEP); |
| + tail = strrchr(filepath, Py_GetSepA(filepath)); |
| if (tail == NULL) |
| tail = filepath; |
| else |
| -- |
| 2.32.0 |
| |