Skip to content

Commit

Permalink
mingw: prefer unix sep if MSYSTEM environment variable
Browse files Browse the repository at this point in the history
Co-authored-by: Алексей <alexey.pawlow@gmail.com>
Co-authored-by: Christoph Reiter <reiter.christoph@gmail.com>
Co-authored-by: cat <cat@wolfgirl.org>
Co-authored-by: Naveen M K <naveen521kk@gmail.com>
  • Loading branch information
5 people committed Dec 22, 2024
1 parent 6fd092a commit a0fd237
Show file tree
Hide file tree
Showing 6 changed files with 203 additions and 50 deletions.
6 changes: 6 additions & 0 deletions Include/pylifecycle.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
106 changes: 58 additions & 48 deletions Lib/ntpath.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,7 @@
curdir = '.'
pardir = '..'
extsep = '.'
sep = '\\'
pathsep = ';'
altsep = '/'
defpath = '.;C:\\bin'
devnull = 'nul'

Expand All @@ -23,6 +21,14 @@
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","splitroot","split","splitext",
"basename","dirname","commonprefix","getsize","getmtime",
Expand All @@ -34,9 +40,33 @@

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 '\\/'
return sep

def _get_altsep(path):
if isinstance(path, bytes):
return baltsep
else:
return altsep

def _get_colon(path):
if isinstance(path, bytes):
return b':'
else:
return ':'

def _get_unc_prefix(path):
if isinstance(path, bytes):
return b'\\\\?\\UNC\\'
else:
return '\\\\?\\UNC\\'

# Normalize the case of a pathname and map slashes to backslashes.
# Other normalizations (such as optimizing '../' away) are not done
Expand All @@ -58,14 +88,14 @@ def normcase(s):
return s
if isinstance(s, bytes):
encoding = sys.getfilesystemencoding()
s = s.decode(encoding, 'surrogateescape').replace('/', '\\')
s = s.decode(encoding, 'surrogateescape').replace(altsep, sep)
s = _LCMapStringEx(_LOCALE_NAME_INVARIANT,
_LCMAP_LOWERCASE, s)
return s.encode(encoding, 'surrogateescape')
else:
return _LCMapStringEx(_LOCALE_NAME_INVARIANT,
_LCMAP_LOWERCASE,
s.replace('/', '\\'))
s.replace(altsep, sep))
except ImportError:
def normcase(s):
"""Normalize case of pathname.
Expand All @@ -74,8 +104,8 @@ def normcase(s):
"""
s = os.fspath(s)
if isinstance(s, bytes):
return os.fsencode(os.fsdecode(s).replace('/', '\\').lower())
return s.replace('/', '\\').lower()
return os.fsencode(os.fsdecode(s).replace(altsep, sep).lower())
return s.replace(altsep, sep).lower()


# Return whether a path is absolute.
Expand All @@ -87,14 +117,9 @@ def normcase(s):
def isabs(s):
"""Test whether a path is absolute"""
s = os.fspath(s)
if isinstance(s, bytes):
sep = b'\\'
altsep = b'/'
colon_sep = b':\\'
else:
sep = '\\'
altsep = '/'
colon_sep = ':\\'
sep = _get_sep(s)
altsep = _get_altsep(s)
colon_sep = _get_colon(s) + sep
s = s[:3].replace(altsep, sep)
# Absolute: UNC, device, and paths with a drive and root.
# LEGACY BUG: isabs("/x") should be false since the path has no drive.
Expand All @@ -106,14 +131,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.
Expand Down Expand Up @@ -188,18 +208,12 @@ def splitroot(p):
splitroot('Windows/notepad') == ('', '', 'Windows/notepad')
"""
p = os.fspath(p)
if isinstance(p, bytes):
sep = b'\\'
altsep = b'/'
colon = b':'
unc_prefix = b'\\\\?\\UNC\\'
empty = b''
else:
sep = '\\'
altsep = '/'
colon = ':'
unc_prefix = '\\\\?\\UNC\\'
empty = ''
sep = _get_sep(p)
altsep = _get_altsep(p)
colon = _get_colon(p)
unc_prefix = _get_unc_prefix(p)
empty = b'' if isinstance(p, bytes) else ''

normp = p.replace(altsep, sep)
if normp[:1] == sep:
if normp[1:2] == sep:
Expand Down Expand Up @@ -257,9 +271,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__


Expand Down Expand Up @@ -527,14 +541,12 @@ 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'..'
else:
sep = '\\'
altsep = '/'
curdir = '.'
pardir = '..'
path = path.replace(altsep, sep)
Expand Down Expand Up @@ -762,6 +774,7 @@ def realpath(path, *, strict=False):
# strip the prefix anyway.
if ex.winerror == initial_winerror:
path = spath
path = normpath(path)
return path


Expand All @@ -771,12 +784,11 @@ def realpath(path, *, strict=False):
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 = '..'

Expand Down Expand Up @@ -831,13 +843,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:
Expand Down
2 changes: 2 additions & 0 deletions Modules/posixmodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -4003,6 +4003,7 @@ posix_getcwd(int use_bytes)
return NULL;
}

Py_NormalizeSepsW(wbuf2);
PyObject *resobj = PyUnicode_FromWideChar(wbuf2, len);
if (wbuf2 != wbuf) {
PyMem_RawFree(wbuf2);
Expand Down Expand Up @@ -4889,6 +4890,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 && PyBytes_Check(path->object)) {
Py_SETREF(result, PyUnicode_EncodeFSDefault(result));
Expand Down
2 changes: 1 addition & 1 deletion Python/initconfig.c
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ static const char usage_envvars[] =
"PYTHONWARNINGS : warning control (-W)\n"
;

#if defined(MS_WINDOWS)
#if defined(_MSC_VER)
# define PYTHONHOMEHELP "<prefix>\\python{major}{minor}"
#else
# define PYTHONHOMEHELP "<prefix>/lib/pythonX.X"
Expand Down
Loading

0 comments on commit a0fd237

Please sign in to comment.