Change command line processing API to use wchar_t.

Fixes #2128.
This commit is contained in:
Martin v. Löwis 2008-04-05 20:41:37 +00:00
parent b9279bc88f
commit 790465fd90
21 changed files with 642 additions and 414 deletions

View file

@ -161,7 +161,7 @@ Initialization, Finalization, and Threads
haven't been explicitly destroyed at that point. haven't been explicitly destroyed at that point.
.. cfunction:: void Py_SetProgramName(char *name) .. cfunction:: void Py_SetProgramName(wchar_t *name)
.. index:: .. index::
single: Py_Initialize() single: Py_Initialize()
@ -170,11 +170,12 @@ Initialization, Finalization, and Threads
This function should be called before :cfunc:`Py_Initialize` is called for This function should be called before :cfunc:`Py_Initialize` is called for
the first time, if it is called at all. It tells the interpreter the value the first time, if it is called at all. It tells the interpreter the value
of the ``argv[0]`` argument to the :cfunc:`main` function of the program. of the ``argv[0]`` argument to the :cfunc:`main` function of the program
(converted to wide characters).
This is used by :cfunc:`Py_GetPath` and some other functions below to find This is used by :cfunc:`Py_GetPath` and some other functions below to find
the Python run-time libraries relative to the interpreter executable. The the Python run-time libraries relative to the interpreter executable. The
default value is ``'python'``. The argument should point to a default value is ``'python'``. The argument should point to a
zero-terminated character string in static storage whose contents will not zero-terminated wide character string in static storage whose contents will not
change for the duration of the program's execution. No code in the Python change for the duration of the program's execution. No code in the Python
interpreter will change the contents of this storage. interpreter will change the contents of this storage.
@ -188,7 +189,7 @@ Initialization, Finalization, and Threads
value. value.
.. cfunction:: char* Py_GetPrefix() .. cfunction:: wchar_t* Py_GetPrefix()
Return the *prefix* for installed platform-independent files. This is derived Return the *prefix* for installed platform-independent files. This is derived
through a number of complicated rules from the program name set with through a number of complicated rules from the program name set with
@ -201,7 +202,7 @@ Initialization, Finalization, and Threads
It is only useful on Unix. See also the next function. It is only useful on Unix. See also the next function.
.. cfunction:: char* Py_GetExecPrefix() .. cfunction:: wchar_t* Py_GetExecPrefix()
Return the *exec-prefix* for installed platform-*dependent* files. This is Return the *exec-prefix* for installed platform-*dependent* files. This is
derived through a number of complicated rules from the program name set with derived through a number of complicated rules from the program name set with
@ -236,7 +237,7 @@ Initialization, Finalization, and Threads
platform. platform.
.. cfunction:: char* Py_GetProgramFullPath() .. cfunction:: wchar_t* Py_GetProgramFullPath()
.. index:: .. index::
single: Py_SetProgramName() single: Py_SetProgramName()
@ -249,7 +250,7 @@ Initialization, Finalization, and Threads
to Python code as ``sys.executable``. to Python code as ``sys.executable``.
.. cfunction:: char* Py_GetPath() .. cfunction:: wchar_t* Py_GetPath()
.. index:: .. index::
triple: module; search; path triple: module; search; path
@ -342,7 +343,7 @@ Initialization, Finalization, and Threads
``sys.version``. ``sys.version``.
.. cfunction:: void PySys_SetArgv(int argc, char **argv) .. cfunction:: void PySys_SetArgv(int argc, wchar_t **argv)
.. index:: .. index::
single: main() single: main()

View file

@ -84,11 +84,11 @@ accessible to C code. They all work with the current interpreter thread's
Reset :data:`sys.warnoptions` to an empty list. Reset :data:`sys.warnoptions` to an empty list.
.. cfunction:: void PySys_AddWarnOption(char *s) .. cfunction:: void PySys_AddWarnOption(wchar_t *s)
Append *s* to :data:`sys.warnoptions`. Append *s* to :data:`sys.warnoptions`.
.. cfunction:: void PySys_SetPath(char *path) .. cfunction:: void PySys_SetPath(wchar_t *path)
Set :data:`sys.path` to a list object of paths found in *path* which should Set :data:`sys.path` to a list object of paths found in *path* which should
be a list of paths separated with the platform's search path delimiter be a list of paths separated with the platform's search path delimiter

View file

@ -336,6 +336,8 @@ the system's :ctype:`wchar_t`.
.. cfunction:: PyObject* PyUnicode_FromWideChar(const wchar_t *w, Py_ssize_t size) .. cfunction:: PyObject* PyUnicode_FromWideChar(const wchar_t *w, Py_ssize_t size)
Create a Unicode object from the :ctype:`wchar_t` buffer *w* of the given size. Create a Unicode object from the :ctype:`wchar_t` buffer *w* of the given size.
Passing -1 as the size indicates that the function must itself compute the length,
using wcslen.
Return *NULL* on failure. Return *NULL* on failure.

View file

@ -25,16 +25,18 @@ are only passed to these functions if it is certain that they were created by
the same library that the Python runtime is using. the same library that the Python runtime is using.
.. cfunction:: int Py_Main(int argc, char **argv) .. cfunction:: int Py_Main(int argc, wchar_t **argv)
The main program for the standard interpreter. This is made available for The main program for the standard interpreter. This is made
programs which embed Python. The *argc* and *argv* parameters should be available for programs which embed Python. The *argc* and *argv*
prepared exactly as those which are passed to a C program's :cfunc:`main` parameters should be prepared exactly as those which are passed to
function. It is important to note that the argument list may be modified (but a C program's :cfunc:`main` function (converted to wchar_t
the contents of the strings pointed to by the argument list are not). The return according to the user's locale). It is important to note that the
value will be the integer passed to the :func:`sys.exit` function, ``1`` if the argument list may be modified (but the contents of the strings
interpreter exits due to an exception, or ``2`` if the parameter list does not pointed to by the argument list are not). The return value will be
represent a valid Python command line. the integer passed to the :func:`sys.exit` function, ``1`` if the
interpreter exits due to an exception, or ``2`` if the parameter
list does not represent a valid Python command line.
.. cfunction:: int PyRun_AnyFile(FILE *fp, const char *filename) .. cfunction:: int PyRun_AnyFile(FILE *fp, const char *filename)

View file

@ -12,20 +12,20 @@ extern "C" {
#if defined(MS_WINDOWS) || defined(__BORLANDC__) || defined(__WATCOMC__) || defined(__DJGPP__) || defined(PYOS_OS2) #if defined(MS_WINDOWS) || defined(__BORLANDC__) || defined(__WATCOMC__) || defined(__DJGPP__) || defined(PYOS_OS2)
#if defined(PYOS_OS2) && defined(PYCC_GCC) #if defined(PYOS_OS2) && defined(PYCC_GCC)
#define MAXPATHLEN 260 #define MAXPATHLEN 260
#define SEP '/' #define SEP L'/'
#define ALTSEP '\\' #define ALTSEP L'\\'
#else #else
#define SEP '\\' #define SEP L'\\'
#define ALTSEP '/' #define ALTSEP L'/'
#define MAXPATHLEN 256 #define MAXPATHLEN 256
#endif #endif
#define DELIM ';' #define DELIM L';'
#endif #endif
#endif #endif
/* Filename separator */ /* Filename separator */
#ifndef SEP #ifndef SEP
#define SEP '/' #define SEP L'/'
#endif #endif
/* Max pathname length */ /* Max pathname length */
@ -39,7 +39,7 @@ extern "C" {
/* Search path entry delimiter */ /* Search path entry delimiter */
#ifndef DELIM #ifndef DELIM
#define DELIM ':' #define DELIM L':'
#endif #endif
#ifdef __cplusplus #ifdef __cplusplus

View file

@ -7,9 +7,9 @@ extern "C" {
PyAPI_DATA(int) _PyOS_opterr; PyAPI_DATA(int) _PyOS_opterr;
PyAPI_DATA(int) _PyOS_optind; PyAPI_DATA(int) _PyOS_optind;
PyAPI_DATA(char *) _PyOS_optarg; PyAPI_DATA(wchar_t *) _PyOS_optarg;
PyAPI_FUNC(int) _PyOS_GetOpt(int argc, char **argv, char *optstring); PyAPI_FUNC(int) _PyOS_GetOpt(int argc, wchar_t **argv, wchar_t *optstring);
#ifdef __cplusplus #ifdef __cplusplus
} }

View file

@ -17,11 +17,11 @@ typedef struct {
int cf_flags; /* bitmask of CO_xxx flags relevant to future */ int cf_flags; /* bitmask of CO_xxx flags relevant to future */
} PyCompilerFlags; } PyCompilerFlags;
PyAPI_FUNC(void) Py_SetProgramName(char *); PyAPI_FUNC(void) Py_SetProgramName(wchar_t *);
PyAPI_FUNC(char *) Py_GetProgramName(void); PyAPI_FUNC(wchar_t *) Py_GetProgramName(void);
PyAPI_FUNC(void) Py_SetPythonHome(char *); PyAPI_FUNC(void) Py_SetPythonHome(wchar_t *);
PyAPI_FUNC(char *) Py_GetPythonHome(void); PyAPI_FUNC(wchar_t *) Py_GetPythonHome(void);
PyAPI_FUNC(void) Py_Initialize(void); PyAPI_FUNC(void) Py_Initialize(void);
PyAPI_FUNC(void) Py_InitializeEx(int); PyAPI_FUNC(void) Py_InitializeEx(int);
@ -81,7 +81,7 @@ PyAPI_FUNC(void) Py_Exit(int);
PyAPI_FUNC(int) Py_FdIsInteractive(FILE *, const char *); PyAPI_FUNC(int) Py_FdIsInteractive(FILE *, const char *);
/* Bootstrap */ /* Bootstrap */
PyAPI_FUNC(int) Py_Main(int argc, char **argv); PyAPI_FUNC(int) Py_Main(int argc, wchar_t **argv);
/* Use macros for a bunch of old variants */ /* Use macros for a bunch of old variants */
#define PyRun_String(str, s, g, l) PyRun_StringFlags(str, s, g, l, NULL) #define PyRun_String(str, s, g, l) PyRun_StringFlags(str, s, g, l, NULL)
@ -103,10 +103,10 @@ PyAPI_FUNC(int) Py_Main(int argc, char **argv);
PyRun_FileExFlags(fp, p, s, g, l, 0, flags) PyRun_FileExFlags(fp, p, s, g, l, 0, flags)
/* In getpath.c */ /* In getpath.c */
PyAPI_FUNC(char *) Py_GetProgramFullPath(void); PyAPI_FUNC(wchar_t *) Py_GetProgramFullPath(void);
PyAPI_FUNC(char *) Py_GetPrefix(void); PyAPI_FUNC(wchar_t *) Py_GetPrefix(void);
PyAPI_FUNC(char *) Py_GetExecPrefix(void); PyAPI_FUNC(wchar_t *) Py_GetExecPrefix(void);
PyAPI_FUNC(char *) Py_GetPath(void); PyAPI_FUNC(wchar_t *) Py_GetPath(void);
/* In their own files */ /* In their own files */
PyAPI_FUNC(const char *) Py_GetVersion(void); PyAPI_FUNC(const char *) Py_GetVersion(void);

View file

@ -9,8 +9,8 @@ extern "C" {
PyAPI_FUNC(PyObject *) PySys_GetObject(const char *); PyAPI_FUNC(PyObject *) PySys_GetObject(const char *);
PyAPI_FUNC(int) PySys_SetObject(const char *, PyObject *); PyAPI_FUNC(int) PySys_SetObject(const char *, PyObject *);
PyAPI_FUNC(void) PySys_SetArgv(int, char **); PyAPI_FUNC(void) PySys_SetArgv(int, wchar_t **);
PyAPI_FUNC(void) PySys_SetPath(const char *); PyAPI_FUNC(void) PySys_SetPath(const wchar_t *);
PyAPI_FUNC(void) PySys_WriteStdout(const char *format, ...) PyAPI_FUNC(void) PySys_WriteStdout(const char *format, ...)
Py_GCC_ATTRIBUTE((format(printf, 1, 2))); Py_GCC_ATTRIBUTE((format(printf, 1, 2)));
@ -21,7 +21,7 @@ PyAPI_DATA(PyObject *) _PySys_TraceFunc, *_PySys_ProfileFunc;
PyAPI_DATA(int) _PySys_CheckInterval; PyAPI_DATA(int) _PySys_CheckInterval;
PyAPI_FUNC(void) PySys_ResetWarnOptions(void); PyAPI_FUNC(void) PySys_ResetWarnOptions(void);
PyAPI_FUNC(void) PySys_AddWarnOption(const char *); PyAPI_FUNC(void) PySys_AddWarnOption(const wchar_t *);
#ifdef __cplusplus #ifdef __cplusplus
} }

View file

@ -12,6 +12,10 @@ What's New in Python 3.0a5?
Core and Builtins Core and Builtins
----------------- -----------------
- The command line processing was converted to pass Unicode strings
through as unmodified as possible; as a consequence, the C API
related to command line arguments was changed to use wchar_t.
Extension Modules Extension Modules
----------------- -----------------

View file

@ -3012,7 +3012,7 @@ ins_string(PyObject *d, char *name, char *val)
PyMODINIT_FUNC PyMODINIT_FUNC
init_tkinter(void) init_tkinter(void)
{ {
PyObject *m, *d; PyObject *m, *d, *uexe, *cexe;
Py_TYPE(&Tkapp_Type) = &PyType_Type; Py_TYPE(&Tkapp_Type) = &PyType_Type;
@ -3065,7 +3065,16 @@ init_tkinter(void)
/* This helps the dynamic loader; in Unicode aware Tcl versions /* This helps the dynamic loader; in Unicode aware Tcl versions
it also helps Tcl find its encodings. */ it also helps Tcl find its encodings. */
Tcl_FindExecutable(Py_GetProgramName()); uexe = PyUnicode_FromWideChar(Py_GetProgramName(), -1);
if (uexe) {
cexe = PyUnicode_AsEncodedString(uexe,
Py_FileSystemDefaultEncoding,
NULL);
if (cexe)
Tcl_FindExecutable(PyString_AsString(cexe));
Py_XDECREF(cexe);
Py_DECREF(uexe);
}
if (PyErr_Occurred()) if (PyErr_Occurred())
return; return;

View file

@ -122,19 +122,81 @@
#endif #endif
#ifndef LANDMARK #ifndef LANDMARK
#define LANDMARK "os.py" #define LANDMARK L"os.py"
#endif #endif
static char prefix[MAXPATHLEN+1]; static wchar_t prefix[MAXPATHLEN+1];
static char exec_prefix[MAXPATHLEN+1]; static wchar_t exec_prefix[MAXPATHLEN+1];
static char progpath[MAXPATHLEN+1]; static wchar_t progpath[MAXPATHLEN+1];
static char *module_search_path = NULL; static wchar_t *module_search_path = NULL;
static char lib_python[] = "lib/python" VERSION; static wchar_t lib_python[] = L"lib/python" VERSION;
/* In principle, this should use HAVE__WSTAT, and _wstat
should be detected by autoconf. However, no current
POSIX system provides that function, so testing for
it is pointless. */
#ifndef MS_WINDOWS
static int
_wstat(const wchar_t* path, struct stat *buf)
{
char fname[PATH_MAX];
size_t res = wcstombs(fname, path, sizeof(fname));
if (res == (size_t)-1) {
errno = EINVAL;
return -1;
}
return stat(fname, buf);
}
#endif
#ifndef MS_WINDOWS
static wchar_t*
_wgetcwd(wchar_t *buf, size_t size)
{
char fname[PATH_MAX];
if (getcwd(fname, PATH_MAX) == NULL)
return NULL;
if (mbstowcs(buf, fname, size) >= size) {
errno = ERANGE;
return NULL;
}
return buf;
}
#endif
#ifdef HAVE_READLINK
int
_Py_wreadlink(const wchar_t *path, wchar_t *buf, size_t bufsiz)
{
char cbuf[PATH_MAX];
char cpath[PATH_MAX];
int res;
size_t r1 = wcstombs(cpath, path, PATH_MAX);
if (r1 == (size_t)-1 || r1 >= PATH_MAX) {
errno = EINVAL;
return -1;
}
res = (int)readlink(cpath, cbuf, PATH_MAX);
if (res == -1)
return -1;
if (res == PATH_MAX) {
errno = EINVAL;
return -1;
}
r1 = mbstowcs(buf, cbuf, bufsiz);
if (r1 == -1) {
errno = EINVAL;
return -1;
}
return (int)r1;
}
#endif
static void static void
reduce(char *dir) reduce(wchar_t *dir)
{ {
size_t i = strlen(dir); size_t i = wcslen(dir);
while (i > 0 && dir[i] != SEP) while (i > 0 && dir[i] != SEP)
--i; --i;
dir[i] = '\0'; dir[i] = '\0';
@ -142,10 +204,10 @@ reduce(char *dir)
static int static int
isfile(char *filename) /* Is file, not directory */ isfile(wchar_t *filename) /* Is file, not directory */
{ {
struct stat buf; struct stat buf;
if (stat(filename, &buf) != 0) if (_wstat(filename, &buf) != 0)
return 0; return 0;
if (!S_ISREG(buf.st_mode)) if (!S_ISREG(buf.st_mode))
return 0; return 0;
@ -154,14 +216,14 @@ isfile(char *filename) /* Is file, not directory */
static int static int
ismodule(char *filename) /* Is module -- check for .pyc/.pyo too */ ismodule(wchar_t *filename) /* Is module -- check for .pyc/.pyo too */
{ {
if (isfile(filename)) if (isfile(filename))
return 1; return 1;
/* Check for the compiled version of prefix. */ /* Check for the compiled version of prefix. */
if (strlen(filename) < MAXPATHLEN) { if (wcslen(filename) < MAXPATHLEN) {
strcat(filename, Py_OptimizeFlag ? "o" : "c"); wcscat(filename, Py_OptimizeFlag ? L"o" : L"c");
if (isfile(filename)) if (isfile(filename))
return 1; return 1;
} }
@ -170,10 +232,10 @@ ismodule(char *filename) /* Is module -- check for .pyc/.pyo too */
static int static int
isxfile(char *filename) /* Is executable file */ isxfile(wchar_t *filename) /* Is executable file */
{ {
struct stat buf; struct stat buf;
if (stat(filename, &buf) != 0) if (_wstat(filename, &buf) != 0)
return 0; return 0;
if (!S_ISREG(buf.st_mode)) if (!S_ISREG(buf.st_mode))
return 0; return 0;
@ -184,10 +246,10 @@ isxfile(char *filename) /* Is executable file */
static int static int
isdir(char *filename) /* Is directory */ isdir(wchar_t *filename) /* Is directory */
{ {
struct stat buf; struct stat buf;
if (stat(filename, &buf) != 0) if (_wstat(filename, &buf) != 0)
return 0; return 0;
if (!S_ISDIR(buf.st_mode)) if (!S_ISDIR(buf.st_mode))
return 0; return 0;
@ -205,34 +267,34 @@ isdir(char *filename) /* Is directory */
stuff as fits will be appended. stuff as fits will be appended.
*/ */
static void static void
joinpath(char *buffer, char *stuff) joinpath(wchar_t *buffer, wchar_t *stuff)
{ {
size_t n, k; size_t n, k;
if (stuff[0] == SEP) if (stuff[0] == SEP)
n = 0; n = 0;
else { else {
n = strlen(buffer); n = wcslen(buffer);
if (n > 0 && buffer[n-1] != SEP && n < MAXPATHLEN) if (n > 0 && buffer[n-1] != SEP && n < MAXPATHLEN)
buffer[n++] = SEP; buffer[n++] = SEP;
} }
if (n > MAXPATHLEN) if (n > MAXPATHLEN)
Py_FatalError("buffer overflow in getpath.c's joinpath()"); Py_FatalError("buffer overflow in getpath.c's joinpath()");
k = strlen(stuff); k = wcslen(stuff);
if (n + k > MAXPATHLEN) if (n + k > MAXPATHLEN)
k = MAXPATHLEN - n; k = MAXPATHLEN - n;
strncpy(buffer+n, stuff, k); wcsncpy(buffer+n, stuff, k);
buffer[n+k] = '\0'; buffer[n+k] = '\0';
} }
/* copy_absolute requires that path be allocated at least /* copy_absolute requires that path be allocated at least
MAXPATHLEN + 1 bytes and that p be no more than MAXPATHLEN bytes. */ MAXPATHLEN + 1 bytes and that p be no more than MAXPATHLEN bytes. */
static void static void
copy_absolute(char *path, char *p) copy_absolute(wchar_t *path, wchar_t *p)
{ {
if (p[0] == SEP) if (p[0] == SEP)
strcpy(path, p); wcscpy(path, p);
else { else {
getcwd(path, MAXPATHLEN); _wgetcwd(path, MAXPATHLEN);
if (p[0] == '.' && p[1] == SEP) if (p[0] == '.' && p[1] == SEP)
p += 2; p += 2;
joinpath(path, p); joinpath(path, p);
@ -241,46 +303,46 @@ copy_absolute(char *path, char *p)
/* absolutize() requires that path be allocated at least MAXPATHLEN+1 bytes. */ /* absolutize() requires that path be allocated at least MAXPATHLEN+1 bytes. */
static void static void
absolutize(char *path) absolutize(wchar_t *path)
{ {
char buffer[MAXPATHLEN + 1]; wchar_t buffer[MAXPATHLEN + 1];
if (path[0] == SEP) if (path[0] == SEP)
return; return;
copy_absolute(buffer, path); copy_absolute(buffer, path);
strcpy(path, buffer); wcscpy(path, buffer);
} }
/* search_for_prefix requires that argv0_path be no more than MAXPATHLEN /* search_for_prefix requires that argv0_path be no more than MAXPATHLEN
bytes long. bytes long.
*/ */
static int static int
search_for_prefix(char *argv0_path, char *home) search_for_prefix(wchar_t *argv0_path, wchar_t *home)
{ {
size_t n; size_t n;
char *vpath; wchar_t *vpath;
/* If PYTHONHOME is set, we believe it unconditionally */ /* If PYTHONHOME is set, we believe it unconditionally */
if (home) { if (home) {
char *delim; wchar_t *delim;
strncpy(prefix, home, MAXPATHLEN); wcsncpy(prefix, home, MAXPATHLEN);
delim = strchr(prefix, DELIM); delim = wcschr(prefix, DELIM);
if (delim) if (delim)
*delim = '\0'; *delim = L'\0';
joinpath(prefix, lib_python); joinpath(prefix, lib_python);
joinpath(prefix, LANDMARK); joinpath(prefix, LANDMARK);
return 1; return 1;
} }
/* Check to see if argv[0] is in the build directory */ /* Check to see if argv[0] is in the build directory */
strcpy(prefix, argv0_path); wcscpy(prefix, argv0_path);
joinpath(prefix, "Modules/Setup"); joinpath(prefix, L"Modules/Setup");
if (isfile(prefix)) { if (isfile(prefix)) {
/* Check VPATH to see if argv0_path is in the build directory. */ /* Check VPATH to see if argv0_path is in the build directory. */
vpath = VPATH; vpath = L"" VPATH;
strcpy(prefix, argv0_path); wcscpy(prefix, argv0_path);
joinpath(prefix, vpath); joinpath(prefix, vpath);
joinpath(prefix, "Lib"); joinpath(prefix, L"Lib");
joinpath(prefix, LANDMARK); joinpath(prefix, LANDMARK);
if (ismodule(prefix)) if (ismodule(prefix))
return -1; return -1;
@ -289,17 +351,17 @@ search_for_prefix(char *argv0_path, char *home)
/* Search from argv0_path, until root is found */ /* Search from argv0_path, until root is found */
copy_absolute(prefix, argv0_path); copy_absolute(prefix, argv0_path);
do { do {
n = strlen(prefix); n = wcslen(prefix);
joinpath(prefix, lib_python); joinpath(prefix, lib_python);
joinpath(prefix, LANDMARK); joinpath(prefix, LANDMARK);
if (ismodule(prefix)) if (ismodule(prefix))
return 1; return 1;
prefix[n] = '\0'; prefix[n] = L'\0';
reduce(prefix); reduce(prefix);
} while (prefix[0]); } while (prefix[0]);
/* Look at configure's PREFIX */ /* Look at configure's PREFIX */
strncpy(prefix, PREFIX, MAXPATHLEN); wcsncpy(prefix, L"" PREFIX, MAXPATHLEN);
joinpath(prefix, lib_python); joinpath(prefix, lib_python);
joinpath(prefix, LANDMARK); joinpath(prefix, LANDMARK);
if (ismodule(prefix)) if (ismodule(prefix))
@ -314,26 +376,26 @@ search_for_prefix(char *argv0_path, char *home)
MAXPATHLEN bytes long. MAXPATHLEN bytes long.
*/ */
static int static int
search_for_exec_prefix(char *argv0_path, char *home) search_for_exec_prefix(wchar_t *argv0_path, wchar_t *home)
{ {
size_t n; size_t n;
/* If PYTHONHOME is set, we believe it unconditionally */ /* If PYTHONHOME is set, we believe it unconditionally */
if (home) { if (home) {
char *delim; wchar_t *delim;
delim = strchr(home, DELIM); delim = wcschr(home, DELIM);
if (delim) if (delim)
strncpy(exec_prefix, delim+1, MAXPATHLEN); wcsncpy(exec_prefix, delim+1, MAXPATHLEN);
else else
strncpy(exec_prefix, home, MAXPATHLEN); wcsncpy(exec_prefix, home, MAXPATHLEN);
joinpath(exec_prefix, lib_python); joinpath(exec_prefix, lib_python);
joinpath(exec_prefix, "lib-dynload"); joinpath(exec_prefix, L"lib-dynload");
return 1; return 1;
} }
/* Check to see if argv[0] is in the build directory */ /* Check to see if argv[0] is in the build directory */
strcpy(exec_prefix, argv0_path); wcscpy(exec_prefix, argv0_path);
joinpath(exec_prefix, "Modules/Setup"); joinpath(exec_prefix, L"Modules/Setup");
if (isfile(exec_prefix)) { if (isfile(exec_prefix)) {
reduce(exec_prefix); reduce(exec_prefix);
return -1; return -1;
@ -342,19 +404,19 @@ search_for_exec_prefix(char *argv0_path, char *home)
/* Search from argv0_path, until root is found */ /* Search from argv0_path, until root is found */
copy_absolute(exec_prefix, argv0_path); copy_absolute(exec_prefix, argv0_path);
do { do {
n = strlen(exec_prefix); n = wcslen(exec_prefix);
joinpath(exec_prefix, lib_python); joinpath(exec_prefix, lib_python);
joinpath(exec_prefix, "lib-dynload"); joinpath(exec_prefix, L"lib-dynload");
if (isdir(exec_prefix)) if (isdir(exec_prefix))
return 1; return 1;
exec_prefix[n] = '\0'; exec_prefix[n] = L'\0';
reduce(exec_prefix); reduce(exec_prefix);
} while (exec_prefix[0]); } while (exec_prefix[0]);
/* Look at configure's EXEC_PREFIX */ /* Look at configure's EXEC_PREFIX */
strncpy(exec_prefix, EXEC_PREFIX, MAXPATHLEN); wcsncpy(exec_prefix, L"" EXEC_PREFIX, MAXPATHLEN);
joinpath(exec_prefix, lib_python); joinpath(exec_prefix, lib_python);
joinpath(exec_prefix, "lib-dynload"); joinpath(exec_prefix, L"lib-dynload");
if (isdir(exec_prefix)) if (isdir(exec_prefix))
return 1; return 1;
@ -366,22 +428,25 @@ search_for_exec_prefix(char *argv0_path, char *home)
static void static void
calculate_path(void) calculate_path(void)
{ {
extern char *Py_GetProgramName(void); extern wchar_t *Py_GetProgramName(void);
static char delimiter[2] = {DELIM, '\0'}; static wchar_t delimiter[2] = {DELIM, '\0'};
static char separator[2] = {SEP, '\0'}; static wchar_t separator[2] = {SEP, '\0'};
char *pythonpath = PYTHONPATH; wchar_t *pythonpath = L"" PYTHONPATH;
char *rtpypath = Py_GETENV("PYTHONPATH"); char *_rtpypath = Py_GETENV("PYTHONPATH"); /* XXX use wide version on Windows */
char *home = Py_GetPythonHome(); wchar_t rtpypath[MAXPATHLEN+1];
char *path = getenv("PATH"); wchar_t *home = Py_GetPythonHome();
char *prog = Py_GetProgramName(); char *_path = getenv("PATH");
char argv0_path[MAXPATHLEN+1]; wchar_t wpath[MAXPATHLEN+1];
char zip_path[MAXPATHLEN+1]; wchar_t *path = NULL;
wchar_t *prog = Py_GetProgramName();
wchar_t argv0_path[MAXPATHLEN+1];
wchar_t zip_path[MAXPATHLEN+1];
int pfound, efound; /* 1 if found; -1 if found build directory */ int pfound, efound; /* 1 if found; -1 if found build directory */
char *buf; wchar_t *buf;
size_t bufsz; size_t bufsz;
size_t prefixsz; size_t prefixsz;
char *defpath = pythonpath; wchar_t *defpath = pythonpath;
#ifdef WITH_NEXT_FRAMEWORK #ifdef WITH_NEXT_FRAMEWORK
NSModule pythonModule; NSModule pythonModule;
#endif #endif
@ -393,13 +458,22 @@ calculate_path(void)
#endif #endif
#endif #endif
if (_path) {
size_t r = mbstowcs(wpath, _path, MAXPATHLEN+1);
path = wpath;
if (r == (size_t)-1 || r > MAXPATHLEN) {
/* Could not convert PATH, or it's too long. */
path = NULL;
}
}
/* If there is no slash in the argv0 path, then we have to /* If there is no slash in the argv0 path, then we have to
* assume python is on the user's $PATH, since there's no * assume python is on the user's $PATH, since there's no
* other way to find a directory to start the search from. If * other way to find a directory to start the search from. If
* $PATH isn't exported, you lose. * $PATH isn't exported, you lose.
*/ */
if (strchr(prog, SEP)) if (wcschr(prog, SEP))
strncpy(progpath, prog, MAXPATHLEN); wcsncpy(progpath, prog, MAXPATHLEN);
#ifdef __APPLE__ #ifdef __APPLE__
/* On Mac OS X, if a script uses an interpreter of the form /* On Mac OS X, if a script uses an interpreter of the form
* "#!/opt/python2.3/bin/python", the kernel only passes "python" * "#!/opt/python2.3/bin/python", the kernel only passes "python"
@ -416,24 +490,24 @@ calculate_path(void)
#endif /* __APPLE__ */ #endif /* __APPLE__ */
else if (path) { else if (path) {
while (1) { while (1) {
char *delim = strchr(path, DELIM); wchar_t *delim = wcschr(path, DELIM);
if (delim) { if (delim) {
size_t len = delim - path; size_t len = delim - path;
if (len > MAXPATHLEN) if (len > MAXPATHLEN)
len = MAXPATHLEN; len = MAXPATHLEN;
strncpy(progpath, path, len); wcsncpy(progpath, path, len);
*(progpath + len) = '\0'; *(progpath + len) = '\0';
} }
else else
strncpy(progpath, path, MAXPATHLEN); wcsncpy(progpath, path, MAXPATHLEN);
joinpath(progpath, prog); joinpath(progpath, prog);
if (isxfile(progpath)) if (isxfile(progpath))
break; break;
if (!delim) { if (!delim) {
progpath[0] = '\0'; progpath[0] = L'\0';
break; break;
} }
path = delim + 1; path = delim + 1;
@ -443,7 +517,7 @@ calculate_path(void)
progpath[0] = '\0'; progpath[0] = '\0';
if (progpath[0] != SEP) if (progpath[0] != SEP)
absolutize(progpath); absolutize(progpath);
strncpy(argv0_path, progpath, MAXPATHLEN); wcsncpy(argv0_path, progpath, MAXPATHLEN);
argv0_path[MAXPATHLEN] = '\0'; argv0_path[MAXPATHLEN] = '\0';
#ifdef WITH_NEXT_FRAMEWORK #ifdef WITH_NEXT_FRAMEWORK
@ -454,7 +528,7 @@ calculate_path(void)
*/ */
pythonModule = NSModuleForSymbol(NSLookupAndBindSymbol("_Py_Initialize")); pythonModule = NSModuleForSymbol(NSLookupAndBindSymbol("_Py_Initialize"));
/* Use dylib functions to find out where the framework was loaded from */ /* Use dylib functions to find out where the framework was loaded from */
buf = (char *)NSLibraryNameForModule(pythonModule); buf = (wchar_t *)NSLibraryNameForModule(pythonModule);
if (buf != NULL) { if (buf != NULL) {
/* We're in a framework. */ /* We're in a framework. */
/* See if we might be in the build directory. The framework in the /* See if we might be in the build directory. The framework in the
@ -464,39 +538,39 @@ calculate_path(void)
** be running the interpreter in the build directory, so we use the ** be running the interpreter in the build directory, so we use the
** build-directory-specific logic to find Lib and such. ** build-directory-specific logic to find Lib and such.
*/ */
strncpy(argv0_path, buf, MAXPATHLEN); wcsncpy(argv0_path, buf, MAXPATHLEN);
reduce(argv0_path); reduce(argv0_path);
joinpath(argv0_path, lib_python); joinpath(argv0_path, lib_python);
joinpath(argv0_path, LANDMARK); joinpath(argv0_path, LANDMARK);
if (!ismodule(argv0_path)) { if (!ismodule(argv0_path)) {
/* We are in the build directory so use the name of the /* We are in the build directory so use the name of the
executable - we know that the absolute path is passed */ executable - we know that the absolute path is passed */
strncpy(argv0_path, prog, MAXPATHLEN); wcsncpy(argv0_path, prog, MAXPATHLEN);
} }
else { else {
/* Use the location of the library as the progpath */ /* Use the location of the library as the progpath */
strncpy(argv0_path, buf, MAXPATHLEN); wcsncpy(argv0_path, buf, MAXPATHLEN);
} }
} }
#endif #endif
#if HAVE_READLINK #if HAVE_READLINK
{ {
char tmpbuffer[MAXPATHLEN+1]; wchar_t tmpbuffer[MAXPATHLEN+1];
int linklen = readlink(progpath, tmpbuffer, MAXPATHLEN); int linklen = _Py_wreadlink(progpath, tmpbuffer, MAXPATHLEN);
while (linklen != -1) { while (linklen != -1) {
/* It's not null terminated! */ /* It's not null terminated! */
tmpbuffer[linklen] = '\0'; tmpbuffer[linklen] = '\0';
if (tmpbuffer[0] == SEP) if (tmpbuffer[0] == SEP)
/* tmpbuffer should never be longer than MAXPATHLEN, /* tmpbuffer should never be longer than MAXPATHLEN,
but extra check does not hurt */ but extra check does not hurt */
strncpy(argv0_path, tmpbuffer, MAXPATHLEN); wcsncpy(argv0_path, tmpbuffer, MAXPATHLEN);
else { else {
/* Interpret relative to progpath */ /* Interpret relative to progpath */
reduce(argv0_path); reduce(argv0_path);
joinpath(argv0_path, tmpbuffer); joinpath(argv0_path, tmpbuffer);
} }
linklen = readlink(argv0_path, tmpbuffer, MAXPATHLEN); linklen = _Py_wreadlink(argv0_path, tmpbuffer, MAXPATHLEN);
} }
} }
#endif /* HAVE_READLINK */ #endif /* HAVE_READLINK */
@ -510,22 +584,22 @@ calculate_path(void)
if (!Py_FrozenFlag) if (!Py_FrozenFlag)
fprintf(stderr, fprintf(stderr,
"Could not find platform independent libraries <prefix>\n"); "Could not find platform independent libraries <prefix>\n");
strncpy(prefix, PREFIX, MAXPATHLEN); wcsncpy(prefix, L"" PREFIX, MAXPATHLEN);
joinpath(prefix, lib_python); joinpath(prefix, lib_python);
} }
else else
reduce(prefix); reduce(prefix);
strncpy(zip_path, prefix, MAXPATHLEN); wcsncpy(zip_path, prefix, MAXPATHLEN);
zip_path[MAXPATHLEN] = '\0'; zip_path[MAXPATHLEN] = L'\0';
if (pfound > 0) { /* Use the reduced prefix returned by Py_GetPrefix() */ if (pfound > 0) { /* Use the reduced prefix returned by Py_GetPrefix() */
reduce(zip_path); reduce(zip_path);
reduce(zip_path); reduce(zip_path);
} }
else else
strncpy(zip_path, PREFIX, MAXPATHLEN); wcsncpy(zip_path, L"" PREFIX, MAXPATHLEN);
joinpath(zip_path, "lib/python00.zip"); joinpath(zip_path, L"lib/python00.zip");
bufsz = strlen(zip_path); /* Replace "00" with version */ bufsz = wcslen(zip_path); /* Replace "00" with version */
zip_path[bufsz - 6] = VERSION[0]; zip_path[bufsz - 6] = VERSION[0];
zip_path[bufsz - 5] = VERSION[2]; zip_path[bufsz - 5] = VERSION[2];
@ -533,8 +607,8 @@ calculate_path(void)
if (!Py_FrozenFlag) if (!Py_FrozenFlag)
fprintf(stderr, fprintf(stderr,
"Could not find platform dependent libraries <exec_prefix>\n"); "Could not find platform dependent libraries <exec_prefix>\n");
strncpy(exec_prefix, EXEC_PREFIX, MAXPATHLEN); wcsncpy(exec_prefix, L"" EXEC_PREFIX, MAXPATHLEN);
joinpath(exec_prefix, "lib/lib-dynload"); joinpath(exec_prefix, L"lib/lib-dynload");
} }
/* If we found EXEC_PREFIX do *not* reduce it! (Yet.) */ /* If we found EXEC_PREFIX do *not* reduce it! (Yet.) */
@ -546,13 +620,19 @@ calculate_path(void)
*/ */
bufsz = 0; bufsz = 0;
if (rtpypath) if (_rtpypath) {
bufsz += strlen(rtpypath) + 1; size_t s = mbstowcs(rtpypath, _rtpypath, sizeof(rtpypath)/sizeof(wchar_t));
if (s == (size_t)-1 || s >=sizeof(rtpypath))
/* XXX deal with errors more gracefully */
_rtpypath = NULL;
if (_rtpypath)
bufsz += wcslen(rtpypath) + 1;
}
prefixsz = strlen(prefix) + 1; prefixsz = wcslen(prefix) + 1;
while (1) { while (1) {
char *delim = strchr(defpath, DELIM); wchar_t *delim = wcschr(defpath, DELIM);
if (defpath[0] != SEP) if (defpath[0] != SEP)
/* Paths are relative to prefix */ /* Paths are relative to prefix */
@ -561,65 +641,65 @@ calculate_path(void)
if (delim) if (delim)
bufsz += delim - defpath + 1; bufsz += delim - defpath + 1;
else { else {
bufsz += strlen(defpath) + 1; bufsz += wcslen(defpath) + 1;
break; break;
} }
defpath = delim + 1; defpath = delim + 1;
} }
bufsz += strlen(zip_path) + 1; bufsz += wcslen(zip_path) + 1;
bufsz += strlen(exec_prefix) + 1; bufsz += wcslen(exec_prefix) + 1;
/* This is the only malloc call in this file */ /* This is the only malloc call in this file */
buf = (char *)PyMem_Malloc(bufsz); buf = (wchar_t *)PyMem_Malloc(bufsz*sizeof(wchar_t));
if (buf == NULL) { if (buf == NULL) {
/* We can't exit, so print a warning and limp along */ /* We can't exit, so print a warning and limp along */
fprintf(stderr, "Not enough memory for dynamic PYTHONPATH.\n"); fprintf(stderr, "Not enough memory for dynamic PYTHONPATH.\n");
fprintf(stderr, "Using default static PYTHONPATH.\n"); fprintf(stderr, "Using default static PYTHONPATH.\n");
module_search_path = PYTHONPATH; module_search_path = L"" PYTHONPATH;
} }
else { else {
/* Run-time value of $PYTHONPATH goes first */ /* Run-time value of $PYTHONPATH goes first */
if (rtpypath) { if (_rtpypath) {
strcpy(buf, rtpypath); wcscpy(buf, rtpypath);
strcat(buf, delimiter); wcscat(buf, delimiter);
} }
else else
buf[0] = '\0'; buf[0] = '\0';
/* Next is the default zip path */ /* Next is the default zip path */
strcat(buf, zip_path); wcscat(buf, zip_path);
strcat(buf, delimiter); wcscat(buf, delimiter);
/* Next goes merge of compile-time $PYTHONPATH with /* Next goes merge of compile-time $PYTHONPATH with
* dynamically located prefix. * dynamically located prefix.
*/ */
defpath = pythonpath; defpath = pythonpath;
while (1) { while (1) {
char *delim = strchr(defpath, DELIM); wchar_t *delim = wcschr(defpath, DELIM);
if (defpath[0] != SEP) { if (defpath[0] != SEP) {
strcat(buf, prefix); wcscat(buf, prefix);
strcat(buf, separator); wcscat(buf, separator);
} }
if (delim) { if (delim) {
size_t len = delim - defpath + 1; size_t len = delim - defpath + 1;
size_t end = strlen(buf) + len; size_t end = wcslen(buf) + len;
strncat(buf, defpath, len); wcsncat(buf, defpath, len);
*(buf + end) = '\0'; *(buf + end) = '\0';
} }
else { else {
strcat(buf, defpath); wcscat(buf, defpath);
break; break;
} }
defpath = delim + 1; defpath = delim + 1;
} }
strcat(buf, delimiter); wcscat(buf, delimiter);
/* Finally, on goes the directory for dynamic-load modules */ /* Finally, on goes the directory for dynamic-load modules */
strcat(buf, exec_prefix); wcscat(buf, exec_prefix);
/* And publish the results */ /* And publish the results */
module_search_path = buf; module_search_path = buf;
@ -636,26 +716,26 @@ calculate_path(void)
/* The prefix is the root directory, but reduce() chopped /* The prefix is the root directory, but reduce() chopped
* off the "/". */ * off the "/". */
if (!prefix[0]) if (!prefix[0])
strcpy(prefix, separator); wcscpy(prefix, separator);
} }
else else
strncpy(prefix, PREFIX, MAXPATHLEN); wcsncpy(prefix, L"" PREFIX, MAXPATHLEN);
if (efound > 0) { if (efound > 0) {
reduce(exec_prefix); reduce(exec_prefix);
reduce(exec_prefix); reduce(exec_prefix);
reduce(exec_prefix); reduce(exec_prefix);
if (!exec_prefix[0]) if (!exec_prefix[0])
strcpy(exec_prefix, separator); wcscpy(exec_prefix, separator);
} }
else else
strncpy(exec_prefix, EXEC_PREFIX, MAXPATHLEN); wcsncpy(exec_prefix, L"" EXEC_PREFIX, MAXPATHLEN);
} }
/* External interface */ /* External interface */
char * wchar_t *
Py_GetPath(void) Py_GetPath(void)
{ {
if (!module_search_path) if (!module_search_path)
@ -663,7 +743,7 @@ Py_GetPath(void)
return module_search_path; return module_search_path;
} }
char * wchar_t *
Py_GetPrefix(void) Py_GetPrefix(void)
{ {
if (!module_search_path) if (!module_search_path)
@ -671,7 +751,7 @@ Py_GetPrefix(void)
return prefix; return prefix;
} }
char * wchar_t *
Py_GetExecPrefix(void) Py_GetExecPrefix(void)
{ {
if (!module_search_path) if (!module_search_path)
@ -679,7 +759,7 @@ Py_GetExecPrefix(void)
return exec_prefix; return exec_prefix;
} }
char * wchar_t *
Py_GetProgramFullPath(void) Py_GetProgramFullPath(void)
{ {
if (!module_search_path) if (!module_search_path)

View file

@ -12,6 +12,7 @@
#include <windows.h> #include <windows.h>
#ifdef HAVE_FCNTL_H #ifdef HAVE_FCNTL_H
#include <fcntl.h> #include <fcntl.h>
#define PATH_MAX MAXPATHLEN
#endif #endif
#endif #endif
@ -40,17 +41,17 @@ extern "C" {
#endif #endif
/* For Py_GetArgcArgv(); set by main() */ /* For Py_GetArgcArgv(); set by main() */
static char **orig_argv; static wchar_t **orig_argv;
static int orig_argc; static int orig_argc;
/* command line options */ /* command line options */
#define BASE_OPTS "bBc:dEhim:OStuvVW:xX?" #define BASE_OPTS L"bBc:dEhim:OStuvVW:xX?"
#define PROGRAM_OPTS BASE_OPTS #define PROGRAM_OPTS BASE_OPTS
/* Short usage message (with %s for argv0) */ /* Short usage message (with %s for argv0) */
static char *usage_line = static char *usage_line =
"usage: %s [option] ... [-c cmd | -m mod | file | -] [arg] ...\n"; "usage: %ls [option] ... [-c cmd | -m mod | file | -] [arg] ...\n";
/* Long usage message, split into parts < 512 bytes */ /* Long usage message, split into parts < 512 bytes */
static char *usage_1 = "\ static char *usage_1 = "\
@ -96,9 +97,30 @@ PYTHONHOME : alternate <prefix> directory (or <prefix>%c<exec_prefix>).\n\
PYTHONCASEOK : ignore case in 'import' statements (Windows).\n\ PYTHONCASEOK : ignore case in 'import' statements (Windows).\n\
"; ";
#ifndef MS_WINDOWS
static FILE*
_wfopen(const wchar_t *path, const wchar_t *mode)
{
char cpath[PATH_MAX];
char cmode[10];
size_t r;
r = wcstombs(cpath, path, PATH_MAX);
if (r == (size_t)-1 || r >= PATH_MAX) {
errno = EINVAL;
return NULL;
}
r = wcstombs(cmode, mode, 10);
if (r == (size_t)-1 || r >= 10) {
errno = EINVAL;
return NULL;
}
return fopen(cpath, cmode);
}
#endif
static int static int
usage(int exitcode, char* program) usage(int exitcode, wchar_t* program)
{ {
FILE *f = exitcode ? stderr : stdout; FILE *f = exitcode ? stderr : stdout;
@ -187,11 +209,11 @@ static int RunModule(char *module, int set_argv0)
return 0; return 0;
} }
static int RunMainFromImporter(char *filename) static int RunMainFromImporter(wchar_t *filename)
{ {
PyObject *argv0 = NULL, *importer = NULL; PyObject *argv0 = NULL, *importer = NULL;
if ((argv0 = PyUnicode_DecodeFSDefault(filename)) && if ((argv0 = PyUnicode_FromWideChar(filename,wcslen(filename))) &&
(importer = PyImport_GetImporter(argv0)) && (importer = PyImport_GetImporter(argv0)) &&
(importer->ob_type != &PyNullImporter_Type)) (importer->ob_type != &PyNullImporter_Type))
{ {
@ -249,12 +271,12 @@ WaitForThreadShutdown(void)
/* Main program */ /* Main program */
int int
Py_Main(int argc, char **argv) Py_Main(int argc, wchar_t **argv)
{ {
int c; int c;
int sts; int sts;
char *command = NULL; char *command = NULL;
char *filename = NULL; wchar_t *filename = NULL;
char *module = NULL; char *module = NULL;
FILE *fp = stdin; FILE *fp = stdin;
char *p; char *p;
@ -275,14 +297,19 @@ Py_Main(int argc, char **argv)
while ((c = _PyOS_GetOpt(argc, argv, PROGRAM_OPTS)) != EOF) { while ((c = _PyOS_GetOpt(argc, argv, PROGRAM_OPTS)) != EOF) {
if (c == 'c') { if (c == 'c') {
size_t r1 = wcslen(_PyOS_optarg) + 2;
size_t r2;
/* -c is the last option; following arguments /* -c is the last option; following arguments
that look like options are left for the that look like options are left for the
command to interpret. */ command to interpret. */
command = (char *)malloc(strlen(_PyOS_optarg) + 2); command = (char *)malloc(r1);
if (command == NULL) if (command == NULL)
Py_FatalError( Py_FatalError(
"not enough memory to copy -c argument"); "not enough memory to copy -c argument");
strcpy(command, _PyOS_optarg); r2 = wcstombs(command, _PyOS_optarg, r1);
if (r2 > r1-2)
Py_FatalError(
"not enough memory to copy -c argument");
strcat(command, "\n"); strcat(command, "\n");
break; break;
} }
@ -291,11 +318,16 @@ Py_Main(int argc, char **argv)
/* -m is the last option; following arguments /* -m is the last option; following arguments
that look like options are left for the that look like options are left for the
module to interpret. */ module to interpret. */
module = (char *)malloc(strlen(_PyOS_optarg) + 2); size_t r1 = wcslen(_PyOS_optarg) + 1;
size_t r2;
module = (char *)malloc(r1);
if (module == NULL) if (module == NULL)
Py_FatalError( Py_FatalError(
"not enough memory to copy -m argument"); "not enough memory to copy -m argument");
strcpy(module, _PyOS_optarg); r2 = wcstombs(module, _PyOS_optarg, r1);
if (r2 >= r1)
Py_FatalError(
"not enough memory to copy -m argument");
break; break;
} }
@ -355,7 +387,7 @@ Py_Main(int argc, char **argv)
version++; version++;
break; break;
case 'W': case 'W':
PySys_AddWarnOption(_PyOS_optarg); PySys_AddWarnOption(_PyOS_optarg);
break; break;
@ -384,7 +416,7 @@ Py_Main(int argc, char **argv)
unbuffered = 1; unbuffered = 1;
if (command == NULL && module == NULL && _PyOS_optind < argc && if (command == NULL && module == NULL && _PyOS_optind < argc &&
strcmp(argv[_PyOS_optind], "-") != 0) wcscmp(argv[_PyOS_optind], L"-") != 0)
{ {
#ifdef __VMS #ifdef __VMS
filename = decc$translate_vms(argv[_PyOS_optind]); filename = decc$translate_vms(argv[_PyOS_optind]);
@ -462,14 +494,14 @@ Py_Main(int argc, char **argv)
if (command != NULL) { if (command != NULL) {
/* Backup _PyOS_optind and force sys.argv[0] = '-c' */ /* Backup _PyOS_optind and force sys.argv[0] = '-c' */
_PyOS_optind--; _PyOS_optind--;
argv[_PyOS_optind] = "-c"; argv[_PyOS_optind] = L"-c";
} }
if (module != NULL) { if (module != NULL) {
/* Backup _PyOS_optind and force sys.argv[0] = '-c' /* Backup _PyOS_optind and force sys.argv[0] = '-c'
so that PySys_SetArgv correctly sets sys.path[0] to ''*/ so that PySys_SetArgv correctly sets sys.path[0] to ''*/
_PyOS_optind--; _PyOS_optind--;
argv[_PyOS_optind] = "-c"; argv[_PyOS_optind] = L"-c";
} }
PySys_SetArgv(argc-_PyOS_optind, argv+_PyOS_optind); PySys_SetArgv(argc-_PyOS_optind, argv+_PyOS_optind);
@ -506,8 +538,8 @@ Py_Main(int argc, char **argv)
} }
if (sts==-1 && filename!=NULL) { if (sts==-1 && filename!=NULL) {
if ((fp = fopen(filename, "r")) == NULL) { if ((fp = _wfopen(filename, L"r")) == NULL) {
fprintf(stderr, "%s: can't open file '%s': [Errno %d] %s\n", fprintf(stderr, "%s: can't open file '%ls': [Errno %d] %s\n",
argv[0], filename, errno, strerror(errno)); argv[0], filename, errno, strerror(errno));
return 2; return 2;
@ -528,7 +560,7 @@ Py_Main(int argc, char **argv)
struct stat sb; struct stat sb;
if (fstat(fileno(fp), &sb) == 0 && if (fstat(fileno(fp), &sb) == 0 &&
S_ISDIR(sb.st_mode)) { S_ISDIR(sb.st_mode)) {
fprintf(stderr, "%s: '%s' is a directory, cannot continue\n", argv[0], filename); fprintf(stderr, "%ls: '%ls' is a directory, cannot continue\n", argv[0], filename);
fclose(fp); fclose(fp);
return 1; return 1;
} }
@ -536,9 +568,17 @@ Py_Main(int argc, char **argv)
} }
if (sts==-1) { if (sts==-1) {
char cfilename[PATH_MAX];
char *p_cfilename = "<stdin>";
if (filename) {
size_t r = wcstombs(cfilename, filename, PATH_MAX);
p_cfilename = cfilename;
if (r == (size_t)-1 || r >= PATH_MAX)
p_cfilename = "<decoding error>";
}
sts = PyRun_AnyFileExFlags( sts = PyRun_AnyFileExFlags(
fp, fp,
filename == NULL ? "<stdin>" : filename, p_cfilename,
filename != NULL, &cf) != 0; filename != NULL, &cf) != 0;
} }
@ -589,7 +629,7 @@ Py_Main(int argc, char **argv)
This is rare, but it is needed by the secureware extension. */ This is rare, but it is needed by the secureware extension. */
void void
Py_GetArgcArgv(int *argc, char ***argv) Py_GetArgcArgv(int *argc, wchar_t ***argv)
{ {
*argc = orig_argc; *argc = orig_argc;
*argv = orig_argv; *argv = orig_argv;

View file

@ -1,14 +1,27 @@
/* Minimal main program -- everything is loaded from the library */ /* Minimal main program -- everything is loaded from the library */
#include "Python.h" #include "Python.h"
#include <locale.h>
#ifdef __FreeBSD__ #ifdef __FreeBSD__
#include <floatingpoint.h> #include <floatingpoint.h>
#endif #endif
#ifdef MS_WINDOWS
int
wmain(int argc, wchar_t **argv)
{
return Py_Main(argc, argv);
}
#else
int int
main(int argc, char **argv) main(int argc, char **argv)
{ {
wchar_t **argv_copy = PyMem_Malloc(sizeof(wchar_t*)*argc);
/* We need a second copies, as Python might modify the first one. */
wchar_t **argv_copy2 = PyMem_Malloc(sizeof(wchar_t*)*argc);
int i, res;
char *oldloc;
/* 754 requires that FP exceptions run in "no stop" mode by default, /* 754 requires that FP exceptions run in "no stop" mode by default,
* and until C vendors implement C99's ways to control FP exceptions, * and until C vendors implement C99's ways to control FP exceptions,
* Python requires non-stop mode. Alas, some platforms enable FP * Python requires non-stop mode. Alas, some platforms enable FP
@ -20,5 +33,33 @@ main(int argc, char **argv)
m = fpgetmask(); m = fpgetmask();
fpsetmask(m & ~FP_X_OFL); fpsetmask(m & ~FP_X_OFL);
#endif #endif
return Py_Main(argc, argv); if (!argv_copy || !argv_copy2) {
fprintf(stderr, "out of memory");
return 1;
}
oldloc = setlocale(LC_ALL, NULL);
setlocale(LC_ALL, "");
for (i = 0; i < argc; i++) {
size_t argsize = mbstowcs(NULL, argv[i], 0);
if (argsize == (size_t)-1) {
fprintf(stderr, "Could not convert argument %d to string", i);
return 1;
}
argv_copy[i] = PyMem_Malloc((argsize+1)*sizeof(wchar_t));
argv_copy2[i] = argv_copy[i];
if (!argv_copy[i]) {
fprintf(stderr, "out of memory");
return 1;
}
mbstowcs(argv_copy[i], argv[i], argsize+1);
}
setlocale(LC_ALL, oldloc);
res = Py_Main(argc, argv_copy);
for (i = 0; i < argc; i++) {
PyMem_Free(argv_copy2[i]);
}
PyMem_Free(argv_copy);
PyMem_Free(argv_copy2);
return res;
} }
#endif

View file

@ -553,10 +553,16 @@ PyObject *PyUnicode_FromWideChar(register const wchar_t *w,
PyUnicodeObject *unicode; PyUnicodeObject *unicode;
if (w == NULL) { if (w == NULL) {
if (size == 0)
return PyUnicode_FromStringAndSize(NULL, 0);
PyErr_BadInternalCall(); PyErr_BadInternalCall();
return NULL; return NULL;
} }
if (size == -1) {
size = wcslen(w);
}
unicode = _PyUnicode_New(size); unicode = _PyUnicode_New(size);
if (!unicode) if (!unicode)
return NULL; return NULL;

View file

@ -12,5 +12,5 @@ int WINAPI WinMain(
int nCmdShow /* show state of window */ int nCmdShow /* show state of window */
) )
{ {
return Py_Main(__argc, __argv); return Py_Main(__argc, __wargv);
} }

View file

@ -56,10 +56,10 @@
#include "Python.h" #include "Python.h"
#include "osdefs.h" #include "osdefs.h"
#include <wchar.h>
#ifdef MS_WINDOWS #ifdef MS_WINDOWS
#include <windows.h> #include <windows.h>
#include <tchar.h>
#endif #endif
#ifdef HAVE_SYS_TYPES_H #ifdef HAVE_SYS_TYPES_H
@ -82,17 +82,17 @@
*/ */
#ifndef LANDMARK #ifndef LANDMARK
#define LANDMARK "lib\\os.py" #define LANDMARK L"lib\\os.py"
#endif #endif
static char prefix[MAXPATHLEN+1]; static wchar_t prefix[MAXPATHLEN+1];
static char progpath[MAXPATHLEN+1]; static wchar_t progpath[MAXPATHLEN+1];
static char dllpath[MAXPATHLEN+1]; static wchar_t dllpath[MAXPATHLEN+1];
static char *module_search_path = NULL; static wchar_t *module_search_path = NULL;
static int static int
is_sep(char ch) /* determine if "ch" is a separator character */ is_sep(wchar_t ch) /* determine if "ch" is a separator character */
{ {
#ifdef ALTSEP #ifdef ALTSEP
return ch == SEP || ch == ALTSEP; return ch == SEP || ch == ALTSEP;
@ -105,9 +105,9 @@ is_sep(char ch) /* determine if "ch" is a separator character */
beyond existing terminator. beyond existing terminator.
*/ */
static void static void
reduce(char *dir) reduce(wchar_t *dir)
{ {
size_t i = strlen(dir); size_t i = wcslen(dir);
while (i > 0 && !is_sep(dir[i])) while (i > 0 && !is_sep(dir[i]))
--i; --i;
dir[i] = '\0'; dir[i] = '\0';
@ -115,24 +115,24 @@ reduce(char *dir)
static int static int
exists(char *filename) exists(wchar_t *filename)
{ {
struct stat buf; struct _stat64 buf;
return stat(filename, &buf) == 0; return _wstat64(filename, &buf) == 0;
} }
/* Assumes 'filename' MAXPATHLEN+1 bytes long - /* Assumes 'filename' MAXPATHLEN+1 bytes long -
may extend 'filename' by one character. may extend 'filename' by one character.
*/ */
static int static int
ismodule(char *filename) /* Is module -- check for .pyc/.pyo too */ ismodule(wchar_t *filename) /* Is module -- check for .pyc/.pyo too */
{ {
if (exists(filename)) if (exists(filename))
return 1; return 1;
/* Check for the compiled version of prefix. */ /* Check for the compiled version of prefix. */
if (strlen(filename) < MAXPATHLEN) { if (wcslen(filename) < MAXPATHLEN) {
strcat(filename, Py_OptimizeFlag ? "o" : "c"); wcscat(filename, Py_OptimizeFlag ? L"o" : L"c");
if (exists(filename)) if (exists(filename))
return 1; return 1;
} }
@ -149,22 +149,22 @@ ismodule(char *filename) /* Is module -- check for .pyc/.pyo too */
stuff as fits will be appended. stuff as fits will be appended.
*/ */
static void static void
join(char *buffer, char *stuff) join(wchar_t *buffer, wchar_t *stuff)
{ {
size_t n, k; size_t n, k;
if (is_sep(stuff[0])) if (is_sep(stuff[0]))
n = 0; n = 0;
else { else {
n = strlen(buffer); n = wcslen(buffer);
if (n > 0 && !is_sep(buffer[n-1]) && n < MAXPATHLEN) if (n > 0 && !is_sep(buffer[n-1]) && n < MAXPATHLEN)
buffer[n++] = SEP; buffer[n++] = SEP;
} }
if (n > MAXPATHLEN) if (n > MAXPATHLEN)
Py_FatalError("buffer overflow in getpathp.c's joinpath()"); Py_FatalError("buffer overflow in getpathp.c's joinpath()");
k = strlen(stuff); k = wcslen(stuff);
if (n + k > MAXPATHLEN) if (n + k > MAXPATHLEN)
k = MAXPATHLEN - n; k = MAXPATHLEN - n;
strncpy(buffer+n, stuff, k); wcsncpy(buffer+n, stuff, k);
buffer[n+k] = '\0'; buffer[n+k] = '\0';
} }
@ -173,12 +173,12 @@ join(char *buffer, char *stuff)
'landmark' can not overflow prefix if too long. 'landmark' can not overflow prefix if too long.
*/ */
static int static int
gotlandmark(char *landmark) gotlandmark(wchar_t *landmark)
{ {
int ok; int ok;
Py_ssize_t n; Py_ssize_t n;
n = strlen(prefix); n = wcslen(prefix);
join(prefix, landmark); join(prefix, landmark);
ok = ismodule(prefix); ok = ismodule(prefix);
prefix[n] = '\0'; prefix[n] = '\0';
@ -188,10 +188,10 @@ gotlandmark(char *landmark)
/* assumes argv0_path is MAXPATHLEN+1 bytes long, already \0 term'd. /* assumes argv0_path is MAXPATHLEN+1 bytes long, already \0 term'd.
assumption provided by only caller, calculate_path() */ assumption provided by only caller, calculate_path() */
static int static int
search_for_prefix(char *argv0_path, char *landmark) search_for_prefix(wchar_t *argv0_path, wchar_t *landmark)
{ {
/* Search from argv0_path, until landmark is found */ /* Search from argv0_path, until landmark is found */
strcpy(prefix, argv0_path); wcscpy(prefix, argv0_path);
do { do {
if (gotlandmark(landmark)) if (gotlandmark(landmark))
return 1; return 1;
@ -219,39 +219,39 @@ extern const char *PyWin_DLLVersionString;
in advance. It could be simplied now Win16/Win32s is dead! in advance. It could be simplied now Win16/Win32s is dead!
*/ */
static char * static wchar_t *
getpythonregpath(HKEY keyBase, int skipcore) getpythonregpath(HKEY keyBase, int skipcore)
{ {
HKEY newKey = 0; HKEY newKey = 0;
DWORD dataSize = 0; DWORD dataSize = 0;
DWORD numKeys = 0; DWORD numKeys = 0;
LONG rc; LONG rc;
char *retval = NULL; wchar_t *retval = NULL;
TCHAR *dataBuf = NULL; WCHAR *dataBuf = NULL;
static const TCHAR keyPrefix[] = _T("Software\\Python\\PythonCore\\"); static const WCHAR keyPrefix[] = L"Software\\Python\\PythonCore\\";
static const TCHAR keySuffix[] = _T("\\PythonPath"); static const WCHAR keySuffix[] = L"\\PythonPath";
size_t versionLen; size_t versionLen;
DWORD index; DWORD index;
TCHAR *keyBuf = NULL; WCHAR *keyBuf = NULL;
TCHAR *keyBufPtr; WCHAR *keyBufPtr;
TCHAR **ppPaths = NULL; WCHAR **ppPaths = NULL;
/* Tried to use sysget("winver") but here is too early :-( */ /* Tried to use sysget("winver") but here is too early :-( */
versionLen = _tcslen(PyWin_DLLVersionString); versionLen = strlen(PyWin_DLLVersionString);
/* Space for all the chars, plus one \0 */ /* Space for all the chars, plus one \0 */
keyBuf = keyBufPtr = malloc(sizeof(keyPrefix) + keyBuf = keyBufPtr = malloc(sizeof(keyPrefix) +
sizeof(TCHAR)*(versionLen-1) + sizeof(WCHAR)*(versionLen-1) +
sizeof(keySuffix)); sizeof(keySuffix));
if (keyBuf==NULL) goto done; if (keyBuf==NULL) goto done;
memcpy(keyBufPtr, keyPrefix, sizeof(keyPrefix)-sizeof(TCHAR)); memcpy(keyBufPtr, keyPrefix, sizeof(keyPrefix)-sizeof(WCHAR));
keyBufPtr += sizeof(keyPrefix)/sizeof(TCHAR) - 1; keyBufPtr += sizeof(keyPrefix)/sizeof(WCHAR) - 1;
memcpy(keyBufPtr, PyWin_DLLVersionString, versionLen * sizeof(TCHAR)); mbstowcs(keyBufPtr, PyWin_DLLVersionString, versionLen);
keyBufPtr += versionLen; keyBufPtr += versionLen;
/* NULL comes with this one! */ /* NULL comes with this one! */
memcpy(keyBufPtr, keySuffix, sizeof(keySuffix)); memcpy(keyBufPtr, keySuffix, sizeof(keySuffix));
/* Open the root Python key */ /* Open the root Python key */
rc=RegOpenKeyEx(keyBase, rc=RegOpenKeyExW(keyBase,
keyBuf, /* subkey */ keyBuf, /* subkey */
0, /* reserved */ 0, /* reserved */
KEY_READ, KEY_READ,
@ -265,31 +265,31 @@ getpythonregpath(HKEY keyBase, int skipcore)
/* Allocate a temp array of char buffers, so we only need to loop /* Allocate a temp array of char buffers, so we only need to loop
reading the registry once reading the registry once
*/ */
ppPaths = malloc( sizeof(TCHAR *) * numKeys ); ppPaths = malloc( sizeof(WCHAR *) * numKeys );
if (ppPaths==NULL) goto done; if (ppPaths==NULL) goto done;
memset(ppPaths, 0, sizeof(TCHAR *) * numKeys); memset(ppPaths, 0, sizeof(WCHAR *) * numKeys);
/* Loop over all subkeys, allocating a temp sub-buffer. */ /* Loop over all subkeys, allocating a temp sub-buffer. */
for(index=0;index<numKeys;index++) { for(index=0;index<numKeys;index++) {
TCHAR keyBuf[MAX_PATH+1]; WCHAR keyBuf[MAX_PATH+1];
HKEY subKey = 0; HKEY subKey = 0;
DWORD reqdSize = MAX_PATH+1; DWORD reqdSize = MAX_PATH+1;
/* Get the sub-key name */ /* Get the sub-key name */
DWORD rc = RegEnumKeyEx(newKey, index, keyBuf, &reqdSize, DWORD rc = RegEnumKeyExW(newKey, index, keyBuf, &reqdSize,
NULL, NULL, NULL, NULL ); NULL, NULL, NULL, NULL );
if (rc!=ERROR_SUCCESS) goto done; if (rc!=ERROR_SUCCESS) goto done;
/* Open the sub-key */ /* Open the sub-key */
rc=RegOpenKeyEx(newKey, rc=RegOpenKeyExW(newKey,
keyBuf, /* subkey */ keyBuf, /* subkey */
0, /* reserved */ 0, /* reserved */
KEY_READ, KEY_READ,
&subKey); &subKey);
if (rc!=ERROR_SUCCESS) goto done; if (rc!=ERROR_SUCCESS) goto done;
/* Find the value of the buffer size, malloc, then read it */ /* Find the value of the buffer size, malloc, then read it */
RegQueryValueEx(subKey, NULL, 0, NULL, NULL, &reqdSize); RegQueryValueExW(subKey, NULL, 0, NULL, NULL, &reqdSize);
if (reqdSize) { if (reqdSize) {
ppPaths[index] = malloc(reqdSize); ppPaths[index] = malloc(reqdSize);
if (ppPaths[index]) { if (ppPaths[index]) {
RegQueryValueEx(subKey, NULL, 0, NULL, RegQueryValueExW(subKey, NULL, 0, NULL,
(LPBYTE)ppPaths[index], (LPBYTE)ppPaths[index],
&reqdSize); &reqdSize);
dataSize += reqdSize + 1; /* 1 for the ";" */ dataSize += reqdSize + 1; /* 1 for the ";" */
@ -302,19 +302,19 @@ getpythonregpath(HKEY keyBase, int skipcore)
if (dataSize == 0) goto done; if (dataSize == 0) goto done;
/* original datasize from RegQueryInfo doesn't include the \0 */ /* original datasize from RegQueryInfo doesn't include the \0 */
dataBuf = malloc((dataSize+1) * sizeof(TCHAR)); dataBuf = malloc((dataSize+1) * sizeof(WCHAR));
if (dataBuf) { if (dataBuf) {
TCHAR *szCur = dataBuf; WCHAR *szCur = dataBuf;
DWORD reqdSize = dataSize; DWORD reqdSize = dataSize;
/* Copy our collected strings */ /* Copy our collected strings */
for (index=0;index<numKeys;index++) { for (index=0;index<numKeys;index++) {
if (index > 0) { if (index > 0) {
*(szCur++) = _T(';'); *(szCur++) = L';';
dataSize--; dataSize--;
} }
if (ppPaths[index]) { if (ppPaths[index]) {
Py_ssize_t len = _tcslen(ppPaths[index]); Py_ssize_t len = wcslen(ppPaths[index]);
_tcsncpy(szCur, ppPaths[index], len); wcsncpy(szCur, ppPaths[index], len);
szCur += len; szCur += len;
assert(dataSize > (DWORD)len); assert(dataSize > (DWORD)len);
dataSize -= (DWORD)len; dataSize -= (DWORD)len;
@ -325,30 +325,17 @@ getpythonregpath(HKEY keyBase, int skipcore)
else { else {
/* If we have no values, we dont need a ';' */ /* If we have no values, we dont need a ';' */
if (numKeys) { if (numKeys) {
*(szCur++) = _T(';'); *(szCur++) = L';';
dataSize--; dataSize--;
} }
/* Now append the core path entries - /* Now append the core path entries -
this will include the NULL this will include the NULL
*/ */
rc = RegQueryValueEx(newKey, NULL, 0, NULL, rc = RegQueryValueExW(newKey, NULL, 0, NULL,
(LPBYTE)szCur, &dataSize); (LPBYTE)szCur, &dataSize);
} }
/* And set the result - caller must free /* And set the result - caller must free */
If MBCS, it is fine as is. If Unicode, allocate new
buffer and convert.
*/
#ifdef UNICODE
retval = (char *)malloc(reqdSize+1);
if (retval)
WideCharToMultiByte(CP_ACP, 0,
dataBuf, -1, /* source */
retval, reqdSize+1, /* dest */
NULL, NULL);
free(dataBuf);
#else
retval = dataBuf; retval = dataBuf;
#endif
} }
done: done:
/* Loop freeing my temp buffers */ /* Loop freeing my temp buffers */
@ -368,45 +355,21 @@ done:
static void static void
get_progpath(void) get_progpath(void)
{ {
extern char *Py_GetProgramName(void); extern wchar_t *Py_GetProgramName(void);
char *path = getenv("PATH"); wchar_t *path = _wgetenv(L"PATH");
char *prog = Py_GetProgramName(); wchar_t *prog = Py_GetProgramName();
#ifdef MS_WINDOWS #ifdef MS_WINDOWS
extern HANDLE PyWin_DLLhModule; extern HANDLE PyWin_DLLhModule;
#ifdef UNICODE
WCHAR wprogpath[MAXPATHLEN+1];
/* Windows documents that GetModuleFileName() will "truncate",
but makes no mention of the null terminator. Play it safe.
PLUS Windows itself defines MAX_PATH as the same, but anyway...
*/
wprogpath[MAXPATHLEN]=_T('\0');
if (PyWin_DLLhModule &&
GetModuleFileName(PyWin_DLLhModule, wprogpath, MAXPATHLEN)) {
WideCharToMultiByte(CP_ACP, 0,
wprogpath, -1,
dllpath, MAXPATHLEN+1,
NULL, NULL);
}
wprogpath[MAXPATHLEN]=_T('\0');
if (GetModuleFileName(NULL, wprogpath, MAXPATHLEN)) {
WideCharToMultiByte(CP_ACP, 0,
wprogpath, -1,
progpath, MAXPATHLEN+1,
NULL, NULL);
return;
}
#else
/* static init of progpath ensures final char remains \0 */ /* static init of progpath ensures final char remains \0 */
if (PyWin_DLLhModule) if (PyWin_DLLhModule)
if (!GetModuleFileName(PyWin_DLLhModule, dllpath, MAXPATHLEN)) if (!GetModuleFileNameW(PyWin_DLLhModule, dllpath, MAXPATHLEN))
dllpath[0] = 0; dllpath[0] = 0;
if (GetModuleFileName(NULL, progpath, MAXPATHLEN)) if (GetModuleFileNameW(NULL, progpath, MAXPATHLEN))
return; return;
#endif
#endif #endif
if (prog == NULL || *prog == '\0') if (prog == NULL || *prog == '\0')
prog = "python"; prog = L"python";
/* If there is no slash in the argv0 path, then we have to /* If there is no slash in the argv0 path, then we have to
* assume python is on the user's $PATH, since there's no * assume python is on the user's $PATH, since there's no
@ -414,24 +377,24 @@ get_progpath(void)
* $PATH isn't exported, you lose. * $PATH isn't exported, you lose.
*/ */
#ifdef ALTSEP #ifdef ALTSEP
if (strchr(prog, SEP) || strchr(prog, ALTSEP)) if (wcschr(prog, SEP) || wcschr(prog, ALTSEP))
#else #else
if (strchr(prog, SEP)) if (wcschr(prog, SEP))
#endif #endif
strncpy(progpath, prog, MAXPATHLEN); wcsncpy(progpath, prog, MAXPATHLEN);
else if (path) { else if (path) {
while (1) { while (1) {
char *delim = strchr(path, DELIM); wchar_t *delim = wcschr(path, DELIM);
if (delim) { if (delim) {
size_t len = delim - path; size_t len = delim - path;
/* ensure we can't overwrite buffer */ /* ensure we can't overwrite buffer */
len = min(MAXPATHLEN,len); len = min(MAXPATHLEN,len);
strncpy(progpath, path, len); wcsncpy(progpath, path, len);
*(progpath + len) = '\0'; *(progpath + len) = '\0';
} }
else else
strncpy(progpath, path, MAXPATHLEN); wcsncpy(progpath, path, MAXPATHLEN);
/* join() is safe for MAXPATHLEN+1 size buffer */ /* join() is safe for MAXPATHLEN+1 size buffer */
join(progpath, prog); join(progpath, prog);
@ -452,23 +415,31 @@ get_progpath(void)
static void static void
calculate_path(void) calculate_path(void)
{ {
char argv0_path[MAXPATHLEN+1]; wchar_t argv0_path[MAXPATHLEN+1];
char *buf; wchar_t *buf;
size_t bufsz; size_t bufsz;
char *pythonhome = Py_GetPythonHome(); wchar_t *pythonhome = Py_GetPythonHome();
char *envpath = Py_GETENV("PYTHONPATH"); char *_envpath = Py_GETENV("PYTHONPATH");
wchar_t wenvpath[MAXPATHLEN+1];
wchar_t *envpath = NULL;
#ifdef MS_WINDOWS #ifdef MS_WINDOWS
int skiphome, skipdefault; int skiphome, skipdefault;
char *machinepath = NULL; wchar_t *machinepath = NULL;
char *userpath = NULL; wchar_t *userpath = NULL;
char zip_path[MAXPATHLEN+1]; wchar_t zip_path[MAXPATHLEN+1];
size_t len; size_t len;
#endif #endif
if (_envpath) {
size_t r = mbstowcs(wenvpath, _envpath, MAXPATHLEN+1);
envpath = wenvpath;
if (r == (size_t)-1 || r >= MAXPATHLEN)
envpath = NULL;
}
get_progpath(); get_progpath();
/* progpath guaranteed \0 terminated in MAXPATH+1 bytes. */ /* progpath guaranteed \0 terminated in MAXPATH+1 bytes. */
strcpy(argv0_path, progpath); wcscpy(argv0_path, progpath);
reduce(argv0_path); reduce(argv0_path);
if (pythonhome == NULL || *pythonhome == '\0') { if (pythonhome == NULL || *pythonhome == '\0') {
if (search_for_prefix(argv0_path, LANDMARK)) if (search_for_prefix(argv0_path, LANDMARK))
@ -477,7 +448,7 @@ calculate_path(void)
pythonhome = NULL; pythonhome = NULL;
} }
else else
strncpy(prefix, pythonhome, MAXPATHLEN); wcsncpy(prefix, pythonhome, MAXPATHLEN);
if (envpath && *envpath == '\0') if (envpath && *envpath == '\0')
envpath = NULL; envpath = NULL;
@ -486,11 +457,11 @@ calculate_path(void)
#ifdef MS_WINDOWS #ifdef MS_WINDOWS
/* Calculate zip archive path */ /* Calculate zip archive path */
if (dllpath[0]) /* use name of python DLL */ if (dllpath[0]) /* use name of python DLL */
strncpy(zip_path, dllpath, MAXPATHLEN); wcsncpy(zip_path, dllpath, MAXPATHLEN);
else /* use name of executable program */ else /* use name of executable program */
strncpy(zip_path, progpath, MAXPATHLEN); wcsncpy(zip_path, progpath, MAXPATHLEN);
zip_path[MAXPATHLEN] = '\0'; zip_path[MAXPATHLEN] = '\0';
len = strlen(zip_path); len = wcslen(zip_path);
if (len > 4) { if (len > 4) {
zip_path[len-3] = 'z'; /* change ending to "zip" */ zip_path[len-3] = 'z'; /* change ending to "zip" */
zip_path[len-2] = 'i'; zip_path[len-2] = 'i';
@ -524,29 +495,29 @@ calculate_path(void)
/* Calculate size of return buffer */ /* Calculate size of return buffer */
if (pythonhome != NULL) { if (pythonhome != NULL) {
char *p; wchar_t *p;
bufsz = 1; bufsz = 1;
for (p = PYTHONPATH; *p; p++) { for (p = PYTHONPATH; *p; p++) {
if (*p == DELIM) if (*p == DELIM)
bufsz++; /* number of DELIM plus one */ bufsz++; /* number of DELIM plus one */
} }
bufsz *= strlen(pythonhome); bufsz *= wcslen(pythonhome);
} }
else else
bufsz = 0; bufsz = 0;
bufsz += strlen(PYTHONPATH) + 1; bufsz += wcslen(PYTHONPATH) + 1;
bufsz += strlen(argv0_path) + 1; bufsz += wcslen(argv0_path) + 1;
#ifdef MS_WINDOWS #ifdef MS_WINDOWS
if (userpath) if (userpath)
bufsz += strlen(userpath) + 1; bufsz += wcslen(userpath) + 1;
if (machinepath) if (machinepath)
bufsz += strlen(machinepath) + 1; bufsz += wcslen(machinepath) + 1;
bufsz += strlen(zip_path) + 1; bufsz += wcslen(zip_path) + 1;
#endif #endif
if (envpath != NULL) if (envpath != NULL)
bufsz += strlen(envpath) + 1; bufsz += wcslen(envpath) + 1;
module_search_path = buf = malloc(bufsz); module_search_path = buf = malloc(bufsz*sizeof(wchar_t));
if (buf == NULL) { if (buf == NULL) {
/* We can't exit, so print a warning and limp along */ /* We can't exit, so print a warning and limp along */
fprintf(stderr, "Can't malloc dynamic PYTHONPATH.\n"); fprintf(stderr, "Can't malloc dynamic PYTHONPATH.\n");
@ -568,57 +539,57 @@ calculate_path(void)
} }
if (envpath) { if (envpath) {
strcpy(buf, envpath); wcscpy(buf, envpath);
buf = strchr(buf, '\0'); buf = wcschr(buf, L'\0');
*buf++ = DELIM; *buf++ = DELIM;
} }
#ifdef MS_WINDOWS #ifdef MS_WINDOWS
if (zip_path[0]) { if (zip_path[0]) {
strcpy(buf, zip_path); wcscpy(buf, zip_path);
buf = strchr(buf, '\0'); buf = wcschr(buf, L'\0');
*buf++ = DELIM; *buf++ = DELIM;
} }
if (userpath) { if (userpath) {
strcpy(buf, userpath); wcscpy(buf, userpath);
buf = strchr(buf, '\0'); buf = wcschr(buf, L'\0');
*buf++ = DELIM; *buf++ = DELIM;
free(userpath); free(userpath);
} }
if (machinepath) { if (machinepath) {
strcpy(buf, machinepath); wcscpy(buf, machinepath);
buf = strchr(buf, '\0'); buf = wcschr(buf, L'\0');
*buf++ = DELIM; *buf++ = DELIM;
free(machinepath); free(machinepath);
} }
if (pythonhome == NULL) { if (pythonhome == NULL) {
if (!skipdefault) { if (!skipdefault) {
strcpy(buf, PYTHONPATH); wcscpy(buf, PYTHONPATH);
buf = strchr(buf, '\0'); buf = wcschr(buf, L'\0');
} }
} }
#else #else
if (pythonhome == NULL) { if (pythonhome == NULL) {
strcpy(buf, PYTHONPATH); wcscpy(buf, PYTHONPATH);
buf = strchr(buf, '\0'); buf = wcschr(buf, L'\0');
} }
#endif /* MS_WINDOWS */ #endif /* MS_WINDOWS */
else { else {
char *p = PYTHONPATH; wchar_t *p = PYTHONPATH;
char *q; wchar_t *q;
size_t n; size_t n;
for (;;) { for (;;) {
q = strchr(p, DELIM); q = wcschr(p, DELIM);
if (q == NULL) if (q == NULL)
n = strlen(p); n = wcslen(p);
else else
n = q-p; n = q-p;
if (p[0] == '.' && is_sep(p[1])) { if (p[0] == '.' && is_sep(p[1])) {
strcpy(buf, pythonhome); wcscpy(buf, pythonhome);
buf = strchr(buf, '\0'); buf = wcschr(buf, L'\0');
p++; p++;
n--; n--;
} }
strncpy(buf, p, n); wcsncpy(buf, p, n);
buf += n; buf += n;
if (q == NULL) if (q == NULL)
break; break;
@ -628,10 +599,10 @@ calculate_path(void)
} }
if (argv0_path) { if (argv0_path) {
*buf++ = DELIM; *buf++ = DELIM;
strcpy(buf, argv0_path); wcscpy(buf, argv0_path);
buf = strchr(buf, '\0'); buf = wcschr(buf, L'\0');
} }
*buf = '\0'; *buf = L'\0';
/* Now to pull one last hack/trick. If sys.prefix is /* Now to pull one last hack/trick. If sys.prefix is
empty, then try and find it somewhere on the paths empty, then try and find it somewhere on the paths
we calculated. We scan backwards, as our general policy we calculated. We scan backwards, as our general policy
@ -640,12 +611,12 @@ calculate_path(void)
on the path, and that our 'prefix' directory is on the path, and that our 'prefix' directory is
the parent of that. the parent of that.
*/ */
if (*prefix=='\0') { if (*prefix==L'\0') {
char lookBuf[MAXPATHLEN+1]; wchar_t lookBuf[MAXPATHLEN+1];
char *look = buf - 1; /* 'buf' is at the end of the buffer */ wchar_t *look = buf - 1; /* 'buf' is at the end of the buffer */
while (1) { while (1) {
Py_ssize_t nchars; Py_ssize_t nchars;
char *lookEnd = look; wchar_t *lookEnd = look;
/* 'look' will end up one character before the /* 'look' will end up one character before the
start of the path in question - even if this start of the path in question - even if this
is one character before the start of the buffer is one character before the start of the buffer
@ -653,8 +624,8 @@ calculate_path(void)
while (look >= module_search_path && *look != DELIM) while (look >= module_search_path && *look != DELIM)
look--; look--;
nchars = lookEnd-look; nchars = lookEnd-look;
strncpy(lookBuf, look+1, nchars); wcsncpy(lookBuf, look+1, nchars);
lookBuf[nchars] = '\0'; lookBuf[nchars] = L'\0';
/* Up one level to the parent */ /* Up one level to the parent */
reduce(lookBuf); reduce(lookBuf);
if (search_for_prefix(lookBuf, LANDMARK)) { if (search_for_prefix(lookBuf, LANDMARK)) {
@ -671,7 +642,7 @@ calculate_path(void)
/* External interface */ /* External interface */
char * wchar_t *
Py_GetPath(void) Py_GetPath(void)
{ {
if (!module_search_path) if (!module_search_path)
@ -679,7 +650,7 @@ Py_GetPath(void)
return module_search_path; return module_search_path;
} }
char * wchar_t *
Py_GetPrefix(void) Py_GetPrefix(void)
{ {
if (!module_search_path) if (!module_search_path)
@ -687,13 +658,13 @@ Py_GetPrefix(void)
return prefix; return prefix;
} }
char * wchar_t *
Py_GetExecPrefix(void) Py_GetExecPrefix(void)
{ {
return Py_GetPrefix(); return Py_GetPrefix();
} }
char * wchar_t *
Py_GetProgramFullPath(void) Py_GetProgramFullPath(void)
{ {
if (!module_search_path) if (!module_search_path)

View file

@ -80,7 +80,7 @@ WIN32 is still required for the locale module.
#define MS_WIN32 /* only support win32 and greater. */ #define MS_WIN32 /* only support win32 and greater. */
#define MS_WINDOWS #define MS_WINDOWS
#ifndef PYTHONPATH #ifndef PYTHONPATH
# define PYTHONPATH ".\\DLLs;.\\lib;.\\lib\\plat-win;.\\lib\\lib-tk" # define PYTHONPATH L".\\DLLs;.\\lib;.\\lib\\plat-win;.\\lib\\lib-tk"
#endif #endif
#define NT_THREADS #define NT_THREADS
#define WITH_THREAD #define WITH_THREAD

View file

@ -2,6 +2,7 @@
/* Python interpreter main program for frozen scripts */ /* Python interpreter main program for frozen scripts */
#include "Python.h" #include "Python.h"
#include <locale.h>
#ifdef MS_WINDOWS #ifdef MS_WINDOWS
extern void PyWinFreeze_ExeInit(void); extern void PyWinFreeze_ExeInit(void);
@ -15,9 +16,13 @@ int
Py_FrozenMain(int argc, char **argv) Py_FrozenMain(int argc, char **argv)
{ {
char *p; char *p;
int n, sts; int i, n, sts;
int inspect = 0; int inspect = 0;
int unbuffered = 0; int unbuffered = 0;
char *oldloc;
wchar_t **argv_copy = PyMem_Malloc(sizeof(wchar_t*)*argc);
/* We need a second copies, as Python might modify the first one. */
wchar_t **argv_copy2 = PyMem_Malloc(sizeof(wchar_t*)*argc);
Py_FrozenFlag = 1; /* Suppress errors from getpath.c */ Py_FrozenFlag = 1; /* Suppress errors from getpath.c */
@ -32,10 +37,33 @@ Py_FrozenMain(int argc, char **argv)
setbuf(stderr, (char *)NULL); setbuf(stderr, (char *)NULL);
} }
if (!argv_copy) {
fprintf(stderr, "out of memory");
return 1;
}
oldloc = setlocale(LC_ALL, NULL);
setlocale(LC_ALL, "");
for (i = 0; i < argc; i++) {
size_t argsize = mbstowcs(NULL, argv[i], 0);
if (argsize == (size_t)-1) {
fprintf(stderr, "Could not convert argument %d to string", i);
return 1;
}
argv_copy[i] = PyMem_Malloc((argsize+1)*sizeof(wchar_t));
argv_copy2[i] = argv_copy[i];
if (!argv_copy[i]) {
fprintf(stderr, "out of memory");
return 1;
}
mbstowcs(argv_copy[i], argv[i], argsize+1);
}
setlocale(LC_ALL, oldloc);
#ifdef MS_WINDOWS #ifdef MS_WINDOWS
PyInitFrozenExtensions(); PyInitFrozenExtensions();
#endif /* MS_WINDOWS */ #endif /* MS_WINDOWS */
Py_SetProgramName(argv[0]); Py_SetProgramName(argv_copy[0]);
Py_Initialize(); Py_Initialize();
#ifdef MS_WINDOWS #ifdef MS_WINDOWS
PyWinFreeze_ExeInit(); PyWinFreeze_ExeInit();
@ -45,7 +73,7 @@ Py_FrozenMain(int argc, char **argv)
fprintf(stderr, "Python %s\n%s\n", fprintf(stderr, "Python %s\n%s\n",
Py_GetVersion(), Py_GetCopyright()); Py_GetVersion(), Py_GetCopyright());
PySys_SetArgv(argc, argv); PySys_SetArgv(argc, argv_copy);
n = PyImport_ImportFrozenModule("__main__"); n = PyImport_ImportFrozenModule("__main__");
if (n == 0) if (n == 0)
@ -64,5 +92,10 @@ Py_FrozenMain(int argc, char **argv)
PyWinFreeze_ExeTerm(); PyWinFreeze_ExeTerm();
#endif #endif
Py_Finalize(); Py_Finalize();
for (i = 0; i < argc; i++) {
PyMem_Free(argv_copy2[i]);
}
PyMem_Free(argv_copy);
PyMem_Free(argv_copy2);
return sts; return sts;
} }

View file

@ -27,8 +27,11 @@
/* Modified to support --help and --version, as well as /? on Windows /* Modified to support --help and --version, as well as /? on Windows
* by Georg Brandl. */ * by Georg Brandl. */
#include <Python.h>
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <wchar.h>
#include <pygetopt.h>
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
@ -36,40 +39,40 @@ extern "C" {
int _PyOS_opterr = 1; /* generate error messages */ int _PyOS_opterr = 1; /* generate error messages */
int _PyOS_optind = 1; /* index into argv array */ int _PyOS_optind = 1; /* index into argv array */
char *_PyOS_optarg = NULL; /* optional argument */ wchar_t *_PyOS_optarg = NULL; /* optional argument */
int _PyOS_GetOpt(int argc, char **argv, char *optstring) int _PyOS_GetOpt(int argc, wchar_t **argv, wchar_t *optstring)
{ {
static char *opt_ptr = ""; static wchar_t *opt_ptr = L"";
char *ptr; wchar_t *ptr;
int option; wchar_t option;
if (*opt_ptr == '\0') { if (*opt_ptr == '\0') {
if (_PyOS_optind >= argc) if (_PyOS_optind >= argc)
return -1; return -1;
#ifdef MS_WINDOWS #ifdef MS_WINDOWS
else if (strcmp(argv[_PyOS_optind], "/?") == 0) { else if (wcscmp(argv[_PyOS_optind], L"/?") == 0) {
++_PyOS_optind; ++_PyOS_optind;
return 'h'; return 'h';
} }
#endif #endif
else if (argv[_PyOS_optind][0] != '-' || else if (argv[_PyOS_optind][0] != L'-' ||
argv[_PyOS_optind][1] == '\0' /* lone dash */ ) argv[_PyOS_optind][1] == L'\0' /* lone dash */ )
return -1; return -1;
else if (strcmp(argv[_PyOS_optind], "--") == 0) { else if (wcscmp(argv[_PyOS_optind], L"--") == 0) {
++_PyOS_optind; ++_PyOS_optind;
return -1; return -1;
} }
else if (strcmp(argv[_PyOS_optind], "--help") == 0) { else if (wcscmp(argv[_PyOS_optind], L"--help") == 0) {
++_PyOS_optind; ++_PyOS_optind;
return 'h'; return 'h';
} }
else if (strcmp(argv[_PyOS_optind], "--version") == 0) { else if (wcscmp(argv[_PyOS_optind], L"--version") == 0) {
++_PyOS_optind; ++_PyOS_optind;
return 'V'; return 'V';
} }
@ -78,27 +81,27 @@ int _PyOS_GetOpt(int argc, char **argv, char *optstring)
opt_ptr = &argv[_PyOS_optind++][1]; opt_ptr = &argv[_PyOS_optind++][1];
} }
if ( (option = *opt_ptr++) == '\0') if ( (option = *opt_ptr++) == L'\0')
return -1; return -1;
if ((ptr = strchr(optstring, option)) == NULL) { if ((ptr = wcschr(optstring, option)) == NULL) {
if (_PyOS_opterr) if (_PyOS_opterr)
fprintf(stderr, "Unknown option: -%c\n", option); fprintf(stderr, "Unknown option: -%c\n", (char)option);
return '_'; return '_';
} }
if (*(ptr + 1) == ':') { if (*(ptr + 1) == L':') {
if (*opt_ptr != '\0') { if (*opt_ptr != L'\0') {
_PyOS_optarg = opt_ptr; _PyOS_optarg = opt_ptr;
opt_ptr = ""; opt_ptr = L"";
} }
else { else {
if (_PyOS_optind >= argc) { if (_PyOS_optind >= argc) {
if (_PyOS_opterr) if (_PyOS_opterr)
fprintf(stderr, fprintf(stderr,
"Argument expected for the -%c option\n", option); "Argument expected for the -%c option\n", (char)option);
return '_'; return '_';
} }

View file

@ -17,6 +17,7 @@
#include "ast.h" #include "ast.h"
#include "eval.h" #include "eval.h"
#include "marshal.h" #include "marshal.h"
#include "osdefs.h"
#ifdef HAVE_SIGNAL_H #ifdef HAVE_SIGNAL_H
#include <signal.h> #include <signal.h>
@ -30,6 +31,7 @@
#ifdef MS_WINDOWS #ifdef MS_WINDOWS
#undef BYTE #undef BYTE
#include "windows.h" #include "windows.h"
#define PATH_MAX MAXPATHLEN
#endif #endif
#ifndef Py_REF_DEBUG #ifndef Py_REF_DEBUG
@ -44,7 +46,7 @@
extern "C" { extern "C" {
#endif #endif
extern char *Py_GetPath(void); extern wchar_t *Py_GetPath(void);
extern grammar _PyParser_Grammar; /* From graminit.c */ extern grammar _PyParser_Grammar; /* From graminit.c */
@ -646,35 +648,43 @@ Py_EndInterpreter(PyThreadState *tstate)
PyInterpreterState_Delete(interp); PyInterpreterState_Delete(interp);
} }
static char *progname = "python"; static wchar_t *progname = L"python";
void void
Py_SetProgramName(char *pn) Py_SetProgramName(wchar_t *pn)
{ {
if (pn && *pn) if (pn && *pn)
progname = pn; progname = pn;
} }
char * wchar_t *
Py_GetProgramName(void) Py_GetProgramName(void)
{ {
return progname; return progname;
} }
static char *default_home = NULL; static wchar_t *default_home = NULL;
static wchar_t env_home[PATH_MAX+1];
void void
Py_SetPythonHome(char *home) Py_SetPythonHome(wchar_t *home)
{ {
default_home = home; default_home = home;
} }
char * wchar_t *
Py_GetPythonHome(void) Py_GetPythonHome(void)
{ {
char *home = default_home; wchar_t *home = default_home;
if (home == NULL && !Py_IgnoreEnvironmentFlag) if (home == NULL && !Py_IgnoreEnvironmentFlag) {
home = Py_GETENV("PYTHONHOME"); char* chome = Py_GETENV("PYTHONHOME");
if (chome) {
size_t r = mbstowcs(env_home, chome, PATH_MAX+1);
if (r != (size_t)-1 && r <= PATH_MAX)
home = env_home;
}
}
return home; return home;
} }

View file

@ -882,7 +882,7 @@ PySys_ResetWarnOptions(void)
} }
void void
PySys_AddWarnOption(const char *s) PySys_AddWarnOption(const wchar_t *s)
{ {
PyObject *str; PyObject *str;
@ -892,7 +892,7 @@ PySys_AddWarnOption(const char *s)
if (warnoptions == NULL) if (warnoptions == NULL)
return; return;
} }
str = PyUnicode_FromString(s); str = PyUnicode_FromWideChar(s, -1);
if (str != NULL) { if (str != NULL) {
PyList_Append(warnoptions, str); PyList_Append(warnoptions, str);
Py_DECREF(str); Py_DECREF(str);
@ -1222,12 +1222,12 @@ _PySys_Init(void)
SET_SYS_FROM_STRING("platform", SET_SYS_FROM_STRING("platform",
PyUnicode_FromString(Py_GetPlatform())); PyUnicode_FromString(Py_GetPlatform()));
SET_SYS_FROM_STRING("executable", SET_SYS_FROM_STRING("executable",
PyUnicode_DecodeFSDefault( PyUnicode_FromWideChar(
Py_GetProgramFullPath())); Py_GetProgramFullPath(), -1));
SET_SYS_FROM_STRING("prefix", SET_SYS_FROM_STRING("prefix",
PyUnicode_DecodeFSDefault(Py_GetPrefix())); PyUnicode_FromWideChar(Py_GetPrefix(), -1));
SET_SYS_FROM_STRING("exec_prefix", SET_SYS_FROM_STRING("exec_prefix",
PyUnicode_DecodeFSDefault(Py_GetExecPrefix())); PyUnicode_FromWideChar(Py_GetExecPrefix(), -1));
SET_SYS_FROM_STRING("maxsize", SET_SYS_FROM_STRING("maxsize",
PyLong_FromSsize_t(PY_SSIZE_T_MAX)); PyLong_FromSsize_t(PY_SSIZE_T_MAX));
SET_SYS_FROM_STRING("float_info", SET_SYS_FROM_STRING("float_info",
@ -1280,15 +1280,15 @@ _PySys_Init(void)
} }
static PyObject * static PyObject *
makepathobject(const char *path, int delim) makepathobject(const wchar_t *path, wchar_t delim)
{ {
int i, n; int i, n;
const char *p; const wchar_t *p;
PyObject *v, *w; PyObject *v, *w;
n = 1; n = 1;
p = path; p = path;
while ((p = strchr(p, delim)) != NULL) { while ((p = wcschr(p, delim)) != NULL) {
n++; n++;
p++; p++;
} }
@ -1296,10 +1296,10 @@ makepathobject(const char *path, int delim)
if (v == NULL) if (v == NULL)
return NULL; return NULL;
for (i = 0; ; i++) { for (i = 0; ; i++) {
p = strchr(path, delim); p = wcschr(path, delim);
if (p == NULL) if (p == NULL)
p = strchr(path, '\0'); /* End of string */ p = wcschr(path, L'\0'); /* End of string */
w = PyUnicode_DecodeFSDefaultAndSize(path, (Py_ssize_t) (p - path)); w = PyUnicode_FromWideChar(path, (Py_ssize_t)(p - path));
if (w == NULL) { if (w == NULL) {
Py_DECREF(v); Py_DECREF(v);
return NULL; return NULL;
@ -1313,7 +1313,7 @@ makepathobject(const char *path, int delim)
} }
void void
PySys_SetPath(const char *path) PySys_SetPath(const wchar_t *path)
{ {
PyObject *v; PyObject *v;
if ((v = makepathobject(path, DELIM)) == NULL) if ((v = makepathobject(path, DELIM)) == NULL)
@ -1324,12 +1324,12 @@ PySys_SetPath(const char *path)
} }
static PyObject * static PyObject *
makeargvobject(int argc, char **argv) makeargvobject(int argc, wchar_t **argv)
{ {
PyObject *av; PyObject *av;
if (argc <= 0 || argv == NULL) { if (argc <= 0 || argv == NULL) {
/* Ensure at least one (empty) argument is seen */ /* Ensure at least one (empty) argument is seen */
static char *empty_argv[1] = {""}; static wchar_t *empty_argv[1] = {L""};
argv = empty_argv; argv = empty_argv;
argc = 1; argc = 1;
} }
@ -1351,7 +1351,7 @@ makeargvobject(int argc, char **argv)
} else } else
v = PyUnicode_FromString(argv[i]); v = PyUnicode_FromString(argv[i]);
#else #else
PyObject *v = PyUnicode_FromString(argv[i]); PyObject *v = PyUnicode_FromWideChar(argv[i], -1);
#endif #endif
if (v == NULL) { if (v == NULL) {
Py_DECREF(av); Py_DECREF(av);
@ -1364,13 +1364,38 @@ makeargvobject(int argc, char **argv)
return av; return av;
} }
#ifdef HAVE_REALPATH
static wchar_t*
_wrealpath(const wchar_t *path, wchar_t *resolved_path)
{
char cpath[PATH_MAX];
char cresolved_path[PATH_MAX];
char *res;
size_t r;
r = wcstombs(cpath, path, PATH_MAX);
if (r == (size_t)-1 || r >= PATH_MAX) {
errno = EINVAL;
return NULL;
}
res = realpath(cpath, cresolved_path);
if (res == NULL)
return NULL;
r = mbstowcs(resolved_path, cresolved_path, PATH_MAX);
if (r == (size_t)-1 || r >= PATH_MAX) {
errno = EINVAL;
return NULL;
}
return resolved_path;
}
#endif
void void
PySys_SetArgv(int argc, char **argv) PySys_SetArgv(int argc, wchar_t **argv)
{ {
#if defined(HAVE_REALPATH) #if defined(HAVE_REALPATH)
char fullpath[MAXPATHLEN]; wchar_t fullpath[MAXPATHLEN];
#elif defined(MS_WINDOWS) #elif defined(MS_WINDOWS)
char fullpath[MAX_PATH]; wchar_t fullpath[MAX_PATH];
#endif #endif
PyObject *av = makeargvobject(argc, argv); PyObject *av = makeargvobject(argc, argv);
PyObject *path = PySys_GetObject("path"); PyObject *path = PySys_GetObject("path");
@ -1379,53 +1404,54 @@ PySys_SetArgv(int argc, char **argv)
if (PySys_SetObject("argv", av) != 0) if (PySys_SetObject("argv", av) != 0)
Py_FatalError("can't assign sys.argv"); Py_FatalError("can't assign sys.argv");
if (path != NULL) { if (path != NULL) {
char *argv0 = argv[0]; wchar_t *argv0 = argv[0];
char *p = NULL; wchar_t *p = NULL;
Py_ssize_t n = 0; Py_ssize_t n = 0;
PyObject *a; PyObject *a;
extern int _Py_wreadlink(const wchar_t *, wchar_t *, size_t);
#ifdef HAVE_READLINK #ifdef HAVE_READLINK
char link[MAXPATHLEN+1]; wchar_t link[MAXPATHLEN+1];
char argv0copy[2*MAXPATHLEN+1]; wchar_t argv0copy[2*MAXPATHLEN+1];
int nr = 0; int nr = 0;
if (argc > 0 && argv0 != NULL && strcmp(argv0, "-c") != 0) if (argc > 0 && argv0 != NULL && wcscmp(argv0, L"-c") != 0)
nr = readlink(argv0, link, MAXPATHLEN); nr = _Py_wreadlink(argv0, link, MAXPATHLEN);
if (nr > 0) { if (nr > 0) {
/* It's a symlink */ /* It's a symlink */
link[nr] = '\0'; link[nr] = '\0';
if (link[0] == SEP) if (link[0] == SEP)
argv0 = link; /* Link to absolute path */ argv0 = link; /* Link to absolute path */
else if (strchr(link, SEP) == NULL) else if (wcschr(link, SEP) == NULL)
; /* Link without path */ ; /* Link without path */
else { else {
/* Must join(dirname(argv0), link) */ /* Must join(dirname(argv0), link) */
char *q = strrchr(argv0, SEP); wchar_t *q = wcsrchr(argv0, SEP);
if (q == NULL) if (q == NULL)
argv0 = link; /* argv0 without path */ argv0 = link; /* argv0 without path */
else { else {
/* Must make a copy */ /* Must make a copy */
strcpy(argv0copy, argv0); wcscpy(argv0copy, argv0);
q = strrchr(argv0copy, SEP); q = wcsrchr(argv0copy, SEP);
strcpy(q+1, link); wcscpy(q+1, link);
argv0 = argv0copy; argv0 = argv0copy;
} }
} }
} }
#endif /* HAVE_READLINK */ #endif /* HAVE_READLINK */
#if SEP == '\\' /* Special case for MS filename syntax */ #if SEP == '\\' /* Special case for MS filename syntax */
if (argc > 0 && argv0 != NULL && strcmp(argv0, "-c") != 0) { if (argc > 0 && argv0 != NULL && wcscmp(argv0, L"-c") != 0) {
char *q; wchar_t *q;
#ifdef MS_WINDOWS #ifdef MS_WINDOWS
char *ptemp; wchar_t *ptemp;
if (GetFullPathName(argv0, if (GetFullPathNameW(argv0,
sizeof(fullpath), sizeof(fullpath)/sizeof(fullpath[0]),
fullpath, fullpath,
&ptemp)) { &ptemp)) {
argv0 = fullpath; argv0 = fullpath;
} }
#endif #endif
p = strrchr(argv0, SEP); p = wcsrchr(argv0, SEP);
/* Test for alternate separator */ /* Test for alternate separator */
q = strrchr(p ? p : argv0, '/'); q = wcsrchr(p ? p : argv0, '/');
if (q != NULL) if (q != NULL)
p = q; p = q;
if (p != NULL) { if (p != NULL) {
@ -1435,13 +1461,13 @@ PySys_SetArgv(int argc, char **argv)
} }
} }
#else /* All other filename syntaxes */ #else /* All other filename syntaxes */
if (argc > 0 && argv0 != NULL && strcmp(argv0, "-c") != 0) { if (argc > 0 && argv0 != NULL && wcscmp(argv0, L"-c") != 0) {
#if defined(HAVE_REALPATH) #if defined(HAVE_REALPATH)
if (realpath(argv0, fullpath)) { if (_wrealpath(argv0, fullpath)) {
argv0 = fullpath; argv0 = fullpath;
} }
#endif #endif
p = strrchr(argv0, SEP); p = wcsrchr(argv0, SEP);
} }
if (p != NULL) { if (p != NULL) {
n = p + 1 - argv0; n = p + 1 - argv0;
@ -1451,7 +1477,7 @@ PySys_SetArgv(int argc, char **argv)
#endif /* Unix */ #endif /* Unix */
} }
#endif /* All others */ #endif /* All others */
a = PyUnicode_FromStringAndSize(argv0, n); a = PyUnicode_FromWideChar(argv0, n);
if (a == NULL) if (a == NULL)
Py_FatalError("no mem for sys.path insertion"); Py_FatalError("no mem for sys.path insertion");
if (PyList_Insert(path, 0, a) < 0) if (PyList_Insert(path, 0, a) < 0)