154 stdout = sys.stdout.buffer |
153 stdout = sys.stdout.buffer |
155 stderr = sys.stderr.buffer |
154 stderr = sys.stderr.buffer |
156 |
155 |
157 if getattr(sys, 'argv', None) is not None: |
156 if getattr(sys, 'argv', None) is not None: |
158 # On POSIX, the char** argv array is converted to Python str using |
157 # On POSIX, the char** argv array is converted to Python str using |
159 # Py_DecodeLocale(). The inverse of this is Py_EncodeLocale(), which isn't |
158 # Py_DecodeLocale(). The inverse of this is Py_EncodeLocale(), which |
160 # directly callable from Python code. So, we need to emulate it. |
159 # isn't directly callable from Python code. In practice, os.fsencode() |
161 # Py_DecodeLocale() calls mbstowcs() and falls back to mbrtowc() with |
160 # can be used instead (this is recommended by Python's documentation |
162 # surrogateescape error handling on failure. These functions take the |
161 # for sys.argv). |
163 # current system locale into account. So, the inverse operation is to |
|
164 # .encode() using the system locale's encoding and using the |
|
165 # surrogateescape error handler. The only tricky part here is getting |
|
166 # the system encoding correct, since `locale.getlocale()` can return |
|
167 # None. We fall back to the filesystem encoding if lookups via `locale` |
|
168 # fail, as this seems like a reasonable thing to do. |
|
169 # |
162 # |
170 # On Windows, the wchar_t **argv is passed into the interpreter as-is. |
163 # On Windows, the wchar_t **argv is passed into the interpreter as-is. |
171 # Like POSIX, we need to emulate what Py_EncodeLocale() would do. But |
164 # Like POSIX, we need to emulate what Py_EncodeLocale() would do. But |
172 # there's an additional wrinkle. What we really want to access is the |
165 # there's an additional wrinkle. What we really want to access is the |
173 # ANSI codepage representation of the arguments, as this is what |
166 # ANSI codepage representation of the arguments, as this is what |
176 # encoding, which will pass CP_ACP to the underlying Windows API to |
169 # encoding, which will pass CP_ACP to the underlying Windows API to |
177 # produce bytes. |
170 # produce bytes. |
178 if os.name == r'nt': |
171 if os.name == r'nt': |
179 sysargv = [a.encode("mbcs", "ignore") for a in sys.argv] |
172 sysargv = [a.encode("mbcs", "ignore") for a in sys.argv] |
180 else: |
173 else: |
181 |
174 sysargv = [fsencode(a) for a in sys.argv] |
182 def getdefaultlocale_if_known(): |
|
183 try: |
|
184 return locale.getdefaultlocale() |
|
185 except ValueError: |
|
186 return None, None |
|
187 |
|
188 encoding = ( |
|
189 locale.getlocale()[1] |
|
190 or getdefaultlocale_if_known()[1] |
|
191 or sys.getfilesystemencoding() |
|
192 ) |
|
193 sysargv = [a.encode(encoding, "surrogateescape") for a in sys.argv] |
|
194 |
175 |
195 bytechr = struct.Struct('>B').pack |
176 bytechr = struct.Struct('>B').pack |
196 byterepr = b'%r'.__mod__ |
177 byterepr = b'%r'.__mod__ |
197 |
178 |
198 class bytestr(bytes): |
179 class bytestr(bytes): |