diff -r bd78b90bee84 Doc/c-api/init.rst --- a/Doc/c-api/init.rst Wed Sep 18 07:36:12 2013 -0400 +++ b/Doc/c-api/init.rst Mon Oct 07 16:40:35 2013 +0200 @@ -86,6 +86,26 @@ ======================= +.. c:function:: int Py_SetStandardStreamEncoding(char *encoding, char *errors) + + .. index:: + single: Py_Initialize() + single: main() + triple: stdin; stdout; sdterr + + This function should be called before :c:func:`Py_Initialize`. It specifies + which encoding and error handling to use with standard io, with the same + meanings as in :func:`str.encode`. + + It overrides :envvar:`PYTHONIOENCODING` values, and allows embedding code to + control io encoding when the environment variable does not work. + + ``encoding`` and/or ``errors`` may be NULL to use :envvar:`PYTHONIOENCODING` + and/or default values. + + Returns 0 if successful. + + .. c:function:: void Py_SetProgramName(wchar_t *name) .. index:: diff -r bd78b90bee84 Include/pythonrun.h --- a/Include/pythonrun.h Wed Sep 18 07:36:12 2013 -0400 +++ b/Include/pythonrun.h Mon Oct 07 16:40:35 2013 +0200 @@ -38,6 +38,8 @@ PyAPI_FUNC(PyThreadState *) Py_NewInterpreter(void); PyAPI_FUNC(void) Py_EndInterpreter(PyThreadState *); +PyAPI_FUNC(int) Py_SetStandardStreamEncoding(const char *encoding, const char *errors); + #ifndef Py_LIMITED_API PyAPI_FUNC(int) PyRun_SimpleStringFlags(const char *, PyCompilerFlags *); PyAPI_FUNC(int) PyRun_AnyFileFlags(FILE *, const char *, PyCompilerFlags *); diff -r bd78b90bee84 Python/pythonrun.c --- a/Python/pythonrun.c Wed Sep 18 07:36:12 2013 -0400 +++ b/Python/pythonrun.c Mon Oct 07 16:40:35 2013 +0200 @@ -146,6 +146,35 @@ */ +static char *Py_StandardStreamEncoding = NULL; +static char *Py_StandardStreamErrors = NULL; + +int +Py_SetStandardStreamEncoding(const char *encoding, const char *errors) +{ + if (Py_IsInitialized()) { + return -1; + } + if (encoding) { + Py_StandardStreamEncoding = _PyMem_RawStrdup(encoding); + if (!Py_StandardStreamEncoding) { + PyErr_NoMemory(); + return -1; + } + } + if (errors) { + Py_StandardStreamErrors = _PyMem_RawStrdup(errors); + if (!Py_StandardStreamErrors) { + if (Py_StandardStreamEncoding) { + PyMem_RawFree(Py_StandardStreamEncoding); + } + PyErr_NoMemory(); + return -1; + } + } + return 0; +} + static int add_flag(int flag, const char *envs) { @@ -1088,23 +1117,27 @@ } Py_DECREF(wrapper); - pythonioencoding = Py_GETENV("PYTHONIOENCODING"); - encoding = errors = NULL; - if (pythonioencoding) { - pythonioencoding = _PyMem_Strdup(pythonioencoding); - if (pythonioencoding == NULL) { - PyErr_NoMemory(); - goto error; + encoding = Py_StandardStreamEncoding; + errors = Py_StandardStreamErrors; + if (!encoding || !errors) { + pythonioencoding = Py_GETENV("PYTHONIOENCODING"); + if (pythonioencoding) { + char *err; + pythonioencoding = _PyMem_Strdup(pythonioencoding); + if (pythonioencoding == NULL) { + PyErr_NoMemory(); + goto error; + } + err = strchr(pythonioencoding, ':'); + if (err) { + *err = '\0'; + err++; + } + if (*pythonioencoding && !encoding) + encoding = pythonioencoding; + if (*err && !errors) + errors = err; } - errors = strchr(pythonioencoding, ':'); - if (errors) { - *errors = '\0'; - errors++; - if (!*errors) - errors = NULL; - } - if (*pythonioencoding) - encoding = pythonioencoding; } /* Set sys.stdin */ @@ -1184,6 +1217,15 @@ status = -1; } + /* We won't need them anymore. */ + if (Py_StandardStreamEncoding) { + PyMem_RawFree(Py_StandardStreamEncoding); + Py_StandardStreamEncoding = NULL; + } + if (Py_StandardStreamErrors) { + PyMem_RawFree(Py_StandardStreamErrors); + Py_StandardStreamErrors = NULL; + } PyMem_Free(pythonioencoding); Py_XDECREF(bimod); Py_XDECREF(iomod);