@@ -85,6 +85,88 @@ _Py_wstrlist_copy(int len, wchar_t **list)
8585}
8686
8787
88+ /* Helper to allow an embedding application to override the normal
89+ * mechanism that attempts to figure out an appropriate IO encoding
90+ */
91+
92+ char * _Py_StandardStreamEncoding = NULL ;
93+ char * _Py_StandardStreamErrors = NULL ;
94+
95+ int
96+ Py_SetStandardStreamEncoding (const char * encoding , const char * errors )
97+ {
98+ if (Py_IsInitialized ()) {
99+ /* This is too late to have any effect */
100+ return -1 ;
101+ }
102+
103+ int res = 0 ;
104+
105+ /* Py_SetStandardStreamEncoding() can be called before Py_Initialize(),
106+ but Py_Initialize() can change the allocator. Use a known allocator
107+ to be able to release the memory later. */
108+ PyMemAllocatorEx old_alloc ;
109+ _PyMem_SetDefaultAllocator (PYMEM_DOMAIN_RAW , & old_alloc );
110+
111+ /* Can't call PyErr_NoMemory() on errors, as Python hasn't been
112+ * initialised yet.
113+ *
114+ * However, the raw memory allocators are initialised appropriately
115+ * as C static variables, so _PyMem_RawStrdup is OK even though
116+ * Py_Initialize hasn't been called yet.
117+ */
118+ if (encoding ) {
119+ _Py_StandardStreamEncoding = _PyMem_RawStrdup (encoding );
120+ if (!_Py_StandardStreamEncoding ) {
121+ res = -2 ;
122+ goto done ;
123+ }
124+ }
125+ if (errors ) {
126+ _Py_StandardStreamErrors = _PyMem_RawStrdup (errors );
127+ if (!_Py_StandardStreamErrors ) {
128+ if (_Py_StandardStreamEncoding ) {
129+ PyMem_RawFree (_Py_StandardStreamEncoding );
130+ }
131+ res = -3 ;
132+ goto done ;
133+ }
134+ }
135+ #ifdef MS_WINDOWS
136+ if (_Py_StandardStreamEncoding ) {
137+ /* Overriding the stream encoding implies legacy streams */
138+ Py_LegacyWindowsStdioFlag = 1 ;
139+ }
140+ #endif
141+
142+ done :
143+ PyMem_SetAllocator (PYMEM_DOMAIN_RAW , & old_alloc );
144+
145+ return res ;
146+ }
147+
148+
149+ void
150+ _Py_ClearStandardStreamEncoding (void )
151+ {
152+ /* Use the same allocator than Py_SetStandardStreamEncoding() */
153+ PyMemAllocatorEx old_alloc ;
154+ _PyMem_SetDefaultAllocator (PYMEM_DOMAIN_RAW , & old_alloc );
155+
156+ /* We won't need them anymore. */
157+ if (_Py_StandardStreamEncoding ) {
158+ PyMem_RawFree (_Py_StandardStreamEncoding );
159+ _Py_StandardStreamEncoding = NULL ;
160+ }
161+ if (_Py_StandardStreamErrors ) {
162+ PyMem_RawFree (_Py_StandardStreamErrors );
163+ _Py_StandardStreamErrors = NULL ;
164+ }
165+
166+ PyMem_SetAllocator (PYMEM_DOMAIN_RAW , & old_alloc );
167+ }
168+
169+
88170/* Free memory allocated in config, but don't clear all attributes */
89171void
90172_PyCoreConfig_Clear (_PyCoreConfig * config )
@@ -134,7 +216,7 @@ _PyCoreConfig_Copy(_PyCoreConfig *config, const _PyCoreConfig *config2)
134216 _PyCoreConfig_Clear (config );
135217
136218#define COPY_ATTR (ATTR ) config->ATTR = config2->ATTR
137- #define COPY_STR_ATTR (ATTR ) \
219+ #define COPY_WSTR_ATTR (ATTR ) \
138220 do { \
139221 if (config2->ATTR != NULL) { \
140222 config->ATTR = _PyMem_RawWcsdup(config2->ATTR); \
@@ -173,25 +255,25 @@ _PyCoreConfig_Copy(_PyCoreConfig *config, const _PyCoreConfig *config2)
173255 COPY_ATTR (coerce_c_locale_warn );
174256 COPY_ATTR (utf8_mode );
175257
176- COPY_STR_ATTR (pycache_prefix );
177- COPY_STR_ATTR (module_search_path_env );
178- COPY_STR_ATTR (home );
179- COPY_STR_ATTR (program_name );
180- COPY_STR_ATTR (program );
258+ COPY_WSTR_ATTR (pycache_prefix );
259+ COPY_WSTR_ATTR (module_search_path_env );
260+ COPY_WSTR_ATTR (home );
261+ COPY_WSTR_ATTR (program_name );
262+ COPY_WSTR_ATTR (program );
181263
182264 COPY_WSTRLIST (argc , argv );
183265 COPY_WSTRLIST (nwarnoption , warnoptions );
184266 COPY_WSTRLIST (nxoption , xoptions );
185267 COPY_WSTRLIST (nmodule_search_path , module_search_paths );
186268
187- COPY_STR_ATTR (executable );
188- COPY_STR_ATTR (prefix );
189- COPY_STR_ATTR (base_prefix );
190- COPY_STR_ATTR (exec_prefix );
269+ COPY_WSTR_ATTR (executable );
270+ COPY_WSTR_ATTR (prefix );
271+ COPY_WSTR_ATTR (base_prefix );
272+ COPY_WSTR_ATTR (exec_prefix );
191273#ifdef MS_WINDOWS
192- COPY_STR_ATTR (dll_path );
274+ COPY_WSTR_ATTR (dll_path );
193275#endif
194- COPY_STR_ATTR (base_exec_prefix );
276+ COPY_WSTR_ATTR (base_exec_prefix );
195277
196278 COPY_ATTR (isolated );
197279 COPY_ATTR (site_import );
@@ -213,7 +295,7 @@ _PyCoreConfig_Copy(_PyCoreConfig *config, const _PyCoreConfig *config2)
213295 COPY_ATTR (_frozen );
214296
215297#undef COPY_ATTR
216- #undef COPY_STR_ATTR
298+ #undef COPY_WSTR_ATTR
217299#undef COPY_WSTRLIST
218300 return 0 ;
219301}
@@ -627,8 +709,6 @@ get_env_flag(_PyCoreConfig *config, int *flag, const char *name)
627709static _PyInitError
628710config_read_env_vars (_PyCoreConfig * config )
629711{
630- assert (config -> use_environment > 0 );
631-
632712 /* Get environment variables */
633713 get_env_flag (config , & config -> parser_debug , "PYTHONDEBUG" );
634714 get_env_flag (config , & config -> verbose , "PYTHONVERBOSE" );
@@ -870,6 +950,7 @@ _PyCoreConfig_Read(_PyCoreConfig *config)
870950 _PyInitError err ;
871951
872952 _PyCoreConfig_GetGlobalConfig (config );
953+ assert (config -> use_environment >= 0 );
873954
874955 if (config -> isolated > 0 ) {
875956 config -> use_environment = 0 ;
@@ -882,7 +963,6 @@ _PyCoreConfig_Read(_PyCoreConfig *config)
882963 }
883964#endif
884965
885- assert (config -> use_environment >= 0 );
886966 if (config -> use_environment ) {
887967 err = config_read_env_vars (config );
888968 if (_Py_INIT_FAILED (err )) {
@@ -960,12 +1040,12 @@ _PyCoreConfig_Read(_PyCoreConfig *config)
9601040 if (config -> utf8_mode < 0 ) {
9611041 config -> utf8_mode = 0 ;
9621042 }
963- if (config -> _frozen < 0 ) {
964- config -> _frozen = 0 ;
965- }
9661043 if (config -> argc < 0 ) {
9671044 config -> argc = 0 ;
9681045 }
9691046
1047+ assert (config -> coerce_c_locale >= 0 );
1048+ assert (config -> use_environment >= 0 );
1049+
9701050 return _Py_INIT_OK ();
9711051}
0 commit comments