/src/Python-3.8.3/Objects/fileobject.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* File object implementation (what's left of it -- see io.py) */ |
2 | | |
3 | | #define PY_SSIZE_T_CLEAN |
4 | | #include "Python.h" |
5 | | #include "pycore_pystate.h" |
6 | | |
7 | | #if defined(HAVE_GETC_UNLOCKED) && !defined(_Py_MEMORY_SANITIZER) |
8 | | /* clang MemorySanitizer doesn't yet understand getc_unlocked. */ |
9 | | #define GETC(f) getc_unlocked(f) |
10 | | #define FLOCKFILE(f) flockfile(f) |
11 | | #define FUNLOCKFILE(f) funlockfile(f) |
12 | | #else |
13 | 0 | #define GETC(f) getc(f) |
14 | | #define FLOCKFILE(f) |
15 | | #define FUNLOCKFILE(f) |
16 | | #endif |
17 | | |
18 | | /* Newline flags */ |
19 | | #define NEWLINE_UNKNOWN 0 /* No newline seen, yet */ |
20 | 0 | #define NEWLINE_CR 1 /* \r newline seen */ |
21 | 0 | #define NEWLINE_LF 2 /* \n newline seen */ |
22 | 0 | #define NEWLINE_CRLF 4 /* \r\n newline seen */ |
23 | | |
24 | | #ifdef __cplusplus |
25 | | extern "C" { |
26 | | #endif |
27 | | |
28 | | /* External C interface */ |
29 | | |
30 | | PyObject * |
31 | | PyFile_FromFd(int fd, const char *name, const char *mode, int buffering, const char *encoding, |
32 | | const char *errors, const char *newline, int closefd) |
33 | 0 | { |
34 | 0 | PyObject *io, *stream; |
35 | 0 | _Py_IDENTIFIER(open); |
36 | | |
37 | | /* import _io in case we are being used to open io.py */ |
38 | 0 | io = PyImport_ImportModule("_io"); |
39 | 0 | if (io == NULL) |
40 | 0 | return NULL; |
41 | 0 | stream = _PyObject_CallMethodId(io, &PyId_open, "isisssi", fd, mode, |
42 | 0 | buffering, encoding, errors, |
43 | 0 | newline, closefd); |
44 | 0 | Py_DECREF(io); |
45 | 0 | if (stream == NULL) |
46 | 0 | return NULL; |
47 | | /* ignore name attribute because the name attribute of _BufferedIOMixin |
48 | | and TextIOWrapper is read only */ |
49 | 0 | return stream; |
50 | 0 | } |
51 | | |
52 | | PyObject * |
53 | | PyFile_GetLine(PyObject *f, int n) |
54 | 0 | { |
55 | 0 | _Py_IDENTIFIER(readline); |
56 | 0 | PyObject *result; |
57 | |
|
58 | 0 | if (f == NULL) { |
59 | 0 | PyErr_BadInternalCall(); |
60 | 0 | return NULL; |
61 | 0 | } |
62 | | |
63 | 0 | if (n <= 0) { |
64 | 0 | result = _PyObject_CallMethodIdObjArgs(f, &PyId_readline, NULL); |
65 | 0 | } |
66 | 0 | else { |
67 | 0 | result = _PyObject_CallMethodId(f, &PyId_readline, "i", n); |
68 | 0 | } |
69 | 0 | if (result != NULL && !PyBytes_Check(result) && |
70 | 0 | !PyUnicode_Check(result)) { |
71 | 0 | Py_DECREF(result); |
72 | 0 | result = NULL; |
73 | 0 | PyErr_SetString(PyExc_TypeError, |
74 | 0 | "object.readline() returned non-string"); |
75 | 0 | } |
76 | |
|
77 | 0 | if (n < 0 && result != NULL && PyBytes_Check(result)) { |
78 | 0 | char *s = PyBytes_AS_STRING(result); |
79 | 0 | Py_ssize_t len = PyBytes_GET_SIZE(result); |
80 | 0 | if (len == 0) { |
81 | 0 | Py_DECREF(result); |
82 | 0 | result = NULL; |
83 | 0 | PyErr_SetString(PyExc_EOFError, |
84 | 0 | "EOF when reading a line"); |
85 | 0 | } |
86 | 0 | else if (s[len-1] == '\n') { |
87 | 0 | if (result->ob_refcnt == 1) |
88 | 0 | _PyBytes_Resize(&result, len-1); |
89 | 0 | else { |
90 | 0 | PyObject *v; |
91 | 0 | v = PyBytes_FromStringAndSize(s, len-1); |
92 | 0 | Py_DECREF(result); |
93 | 0 | result = v; |
94 | 0 | } |
95 | 0 | } |
96 | 0 | } |
97 | 0 | if (n < 0 && result != NULL && PyUnicode_Check(result)) { |
98 | 0 | Py_ssize_t len = PyUnicode_GET_LENGTH(result); |
99 | 0 | if (len == 0) { |
100 | 0 | Py_DECREF(result); |
101 | 0 | result = NULL; |
102 | 0 | PyErr_SetString(PyExc_EOFError, |
103 | 0 | "EOF when reading a line"); |
104 | 0 | } |
105 | 0 | else if (PyUnicode_READ_CHAR(result, len-1) == '\n') { |
106 | 0 | PyObject *v; |
107 | 0 | v = PyUnicode_Substring(result, 0, len-1); |
108 | 0 | Py_DECREF(result); |
109 | 0 | result = v; |
110 | 0 | } |
111 | 0 | } |
112 | 0 | return result; |
113 | 0 | } |
114 | | |
115 | | /* Interfaces to write objects/strings to file-like objects */ |
116 | | |
117 | | int |
118 | | PyFile_WriteObject(PyObject *v, PyObject *f, int flags) |
119 | 112 | { |
120 | 112 | PyObject *writer, *value, *result; |
121 | 112 | _Py_IDENTIFIER(write); |
122 | | |
123 | 112 | if (f == NULL) { |
124 | 0 | PyErr_SetString(PyExc_TypeError, "writeobject with NULL file"); |
125 | 0 | return -1; |
126 | 0 | } |
127 | 112 | writer = _PyObject_GetAttrId(f, &PyId_write); |
128 | 112 | if (writer == NULL) |
129 | 0 | return -1; |
130 | 112 | if (flags & Py_PRINT_RAW) { |
131 | 112 | value = PyObject_Str(v); |
132 | 112 | } |
133 | 0 | else |
134 | 0 | value = PyObject_Repr(v); |
135 | 112 | if (value == NULL) { |
136 | 0 | Py_DECREF(writer); |
137 | 0 | return -1; |
138 | 0 | } |
139 | 112 | result = PyObject_CallFunctionObjArgs(writer, value, NULL); |
140 | 112 | Py_DECREF(value); |
141 | 112 | Py_DECREF(writer); |
142 | 112 | if (result == NULL) |
143 | 0 | return -1; |
144 | 112 | Py_DECREF(result); |
145 | 112 | return 0; |
146 | 112 | } |
147 | | |
148 | | int |
149 | | PyFile_WriteString(const char *s, PyObject *f) |
150 | 0 | { |
151 | 0 | if (f == NULL) { |
152 | | /* Should be caused by a pre-existing error */ |
153 | 0 | if (!PyErr_Occurred()) |
154 | 0 | PyErr_SetString(PyExc_SystemError, |
155 | 0 | "null file for PyFile_WriteString"); |
156 | 0 | return -1; |
157 | 0 | } |
158 | 0 | else if (!PyErr_Occurred()) { |
159 | 0 | PyObject *v = PyUnicode_FromString(s); |
160 | 0 | int err; |
161 | 0 | if (v == NULL) |
162 | 0 | return -1; |
163 | 0 | err = PyFile_WriteObject(v, f, Py_PRINT_RAW); |
164 | 0 | Py_DECREF(v); |
165 | 0 | return err; |
166 | 0 | } |
167 | 0 | else |
168 | 0 | return -1; |
169 | 0 | } |
170 | | |
171 | | /* Try to get a file-descriptor from a Python object. If the object |
172 | | is an integer, its value is returned. If not, the |
173 | | object's fileno() method is called if it exists; the method must return |
174 | | an integer, which is returned as the file descriptor value. |
175 | | -1 is returned on failure. |
176 | | */ |
177 | | |
178 | | int |
179 | | PyObject_AsFileDescriptor(PyObject *o) |
180 | 0 | { |
181 | 0 | int fd; |
182 | 0 | PyObject *meth; |
183 | 0 | _Py_IDENTIFIER(fileno); |
184 | |
|
185 | 0 | if (PyLong_Check(o)) { |
186 | 0 | fd = _PyLong_AsInt(o); |
187 | 0 | } |
188 | 0 | else if (_PyObject_LookupAttrId(o, &PyId_fileno, &meth) < 0) { |
189 | 0 | return -1; |
190 | 0 | } |
191 | 0 | else if (meth != NULL) { |
192 | 0 | PyObject *fno = _PyObject_CallNoArg(meth); |
193 | 0 | Py_DECREF(meth); |
194 | 0 | if (fno == NULL) |
195 | 0 | return -1; |
196 | | |
197 | 0 | if (PyLong_Check(fno)) { |
198 | 0 | fd = _PyLong_AsInt(fno); |
199 | 0 | Py_DECREF(fno); |
200 | 0 | } |
201 | 0 | else { |
202 | 0 | PyErr_SetString(PyExc_TypeError, |
203 | 0 | "fileno() returned a non-integer"); |
204 | 0 | Py_DECREF(fno); |
205 | 0 | return -1; |
206 | 0 | } |
207 | 0 | } |
208 | 0 | else { |
209 | 0 | PyErr_SetString(PyExc_TypeError, |
210 | 0 | "argument must be an int, or have a fileno() method."); |
211 | 0 | return -1; |
212 | 0 | } |
213 | | |
214 | 0 | if (fd == -1 && PyErr_Occurred()) |
215 | 0 | return -1; |
216 | 0 | if (fd < 0) { |
217 | 0 | PyErr_Format(PyExc_ValueError, |
218 | 0 | "file descriptor cannot be a negative integer (%i)", |
219 | 0 | fd); |
220 | 0 | return -1; |
221 | 0 | } |
222 | 0 | return fd; |
223 | 0 | } |
224 | | |
225 | | /* |
226 | | ** Py_UniversalNewlineFgets is an fgets variation that understands |
227 | | ** all of \r, \n and \r\n conventions. |
228 | | ** The stream should be opened in binary mode. |
229 | | ** If fobj is NULL the routine always does newline conversion, and |
230 | | ** it may peek one char ahead to gobble the second char in \r\n. |
231 | | ** If fobj is non-NULL it must be a PyFileObject. In this case there |
232 | | ** is no readahead but in stead a flag is used to skip a following |
233 | | ** \n on the next read. Also, if the file is open in binary mode |
234 | | ** the whole conversion is skipped. Finally, the routine keeps track of |
235 | | ** the different types of newlines seen. |
236 | | ** Note that we need no error handling: fgets() treats error and eof |
237 | | ** identically. |
238 | | */ |
239 | | char * |
240 | | Py_UniversalNewlineFgets(char *buf, int n, FILE *stream, PyObject *fobj) |
241 | 0 | { |
242 | 0 | char *p = buf; |
243 | 0 | int c; |
244 | 0 | int newlinetypes = 0; |
245 | 0 | int skipnextlf = 0; |
246 | |
|
247 | 0 | if (fobj) { |
248 | 0 | errno = ENXIO; /* What can you do... */ |
249 | 0 | return NULL; |
250 | 0 | } |
251 | 0 | FLOCKFILE(stream); |
252 | 0 | c = 'x'; /* Shut up gcc warning */ |
253 | 0 | while (--n > 0 && (c = GETC(stream)) != EOF ) { |
254 | 0 | if (skipnextlf ) { |
255 | 0 | skipnextlf = 0; |
256 | 0 | if (c == '\n') { |
257 | | /* Seeing a \n here with skipnextlf true |
258 | | ** means we saw a \r before. |
259 | | */ |
260 | 0 | newlinetypes |= NEWLINE_CRLF; |
261 | 0 | c = GETC(stream); |
262 | 0 | if (c == EOF) break; |
263 | 0 | } else { |
264 | | /* |
265 | | ** Note that c == EOF also brings us here, |
266 | | ** so we're okay if the last char in the file |
267 | | ** is a CR. |
268 | | */ |
269 | 0 | newlinetypes |= NEWLINE_CR; |
270 | 0 | } |
271 | 0 | } |
272 | 0 | if (c == '\r') { |
273 | | /* A \r is translated into a \n, and we skip |
274 | | ** an adjacent \n, if any. We don't set the |
275 | | ** newlinetypes flag until we've seen the next char. |
276 | | */ |
277 | 0 | skipnextlf = 1; |
278 | 0 | c = '\n'; |
279 | 0 | } else if ( c == '\n') { |
280 | 0 | newlinetypes |= NEWLINE_LF; |
281 | 0 | } |
282 | 0 | *p++ = c; |
283 | 0 | if (c == '\n') break; |
284 | 0 | } |
285 | | /* if ( c == EOF && skipnextlf ) |
286 | | newlinetypes |= NEWLINE_CR; */ |
287 | 0 | FUNLOCKFILE(stream); |
288 | 0 | *p = '\0'; |
289 | 0 | if ( skipnextlf ) { |
290 | | /* If we have no file object we cannot save the |
291 | | ** skipnextlf flag. We have to readahead, which |
292 | | ** will cause a pause if we're reading from an |
293 | | ** interactive stream, but that is very unlikely |
294 | | ** unless we're doing something silly like |
295 | | ** exec(open("/dev/tty").read()). |
296 | | */ |
297 | 0 | c = GETC(stream); |
298 | 0 | if ( c != '\n' ) |
299 | 0 | ungetc(c, stream); |
300 | 0 | } |
301 | 0 | if (p == buf) |
302 | 0 | return NULL; |
303 | 0 | return buf; |
304 | 0 | } |
305 | | |
306 | | /* **************************** std printer **************************** |
307 | | * The stdprinter is used during the boot strapping phase as a preliminary |
308 | | * file like object for sys.stderr. |
309 | | */ |
310 | | |
311 | | typedef struct { |
312 | | PyObject_HEAD |
313 | | int fd; |
314 | | } PyStdPrinter_Object; |
315 | | |
316 | | static PyObject * |
317 | | stdprinter_new(PyTypeObject *type, PyObject *args, PyObject *kews) |
318 | 0 | { |
319 | 0 | PyStdPrinter_Object *self; |
320 | |
|
321 | 0 | assert(type != NULL && type->tp_alloc != NULL); |
322 | |
|
323 | 0 | self = (PyStdPrinter_Object *) type->tp_alloc(type, 0); |
324 | 0 | if (self != NULL) { |
325 | 0 | self->fd = -1; |
326 | 0 | } |
327 | |
|
328 | 0 | return (PyObject *) self; |
329 | 0 | } |
330 | | |
331 | | static int |
332 | | stdprinter_init(PyObject *self, PyObject *args, PyObject *kwds) |
333 | 0 | { |
334 | 0 | PyErr_SetString(PyExc_TypeError, |
335 | 0 | "cannot create 'stderrprinter' instances"); |
336 | 0 | return -1; |
337 | 0 | } |
338 | | |
339 | | PyObject * |
340 | | PyFile_NewStdPrinter(int fd) |
341 | 14 | { |
342 | 14 | PyStdPrinter_Object *self; |
343 | | |
344 | 14 | if (fd != fileno(stdout) && fd != fileno(stderr)) { |
345 | | /* not enough infrastructure for PyErr_BadInternalCall() */ |
346 | 0 | return NULL; |
347 | 0 | } |
348 | | |
349 | 14 | self = PyObject_New(PyStdPrinter_Object, |
350 | 14 | &PyStdPrinter_Type); |
351 | 14 | if (self != NULL) { |
352 | 14 | self->fd = fd; |
353 | 14 | } |
354 | 14 | return (PyObject*)self; |
355 | 14 | } |
356 | | |
357 | | static PyObject * |
358 | | stdprinter_write(PyStdPrinter_Object *self, PyObject *args) |
359 | 0 | { |
360 | 0 | PyObject *unicode; |
361 | 0 | PyObject *bytes = NULL; |
362 | 0 | const char *str; |
363 | 0 | Py_ssize_t n; |
364 | 0 | int err; |
365 | | |
366 | | /* The function can clear the current exception */ |
367 | 0 | assert(!PyErr_Occurred()); |
368 | |
|
369 | 0 | if (self->fd < 0) { |
370 | | /* fd might be invalid on Windows |
371 | | * I can't raise an exception here. It may lead to an |
372 | | * unlimited recursion in the case stderr is invalid. |
373 | | */ |
374 | 0 | Py_RETURN_NONE; |
375 | 0 | } |
376 | | |
377 | 0 | if (!PyArg_ParseTuple(args, "U", &unicode)) { |
378 | 0 | return NULL; |
379 | 0 | } |
380 | | |
381 | | /* Encode Unicode to UTF-8/surrogateescape */ |
382 | 0 | str = PyUnicode_AsUTF8AndSize(unicode, &n); |
383 | 0 | if (str == NULL) { |
384 | 0 | PyErr_Clear(); |
385 | 0 | bytes = _PyUnicode_AsUTF8String(unicode, "backslashreplace"); |
386 | 0 | if (bytes == NULL) |
387 | 0 | return NULL; |
388 | 0 | str = PyBytes_AS_STRING(bytes); |
389 | 0 | n = PyBytes_GET_SIZE(bytes); |
390 | 0 | } |
391 | | |
392 | 0 | n = _Py_write(self->fd, str, n); |
393 | | /* save errno, it can be modified indirectly by Py_XDECREF() */ |
394 | 0 | err = errno; |
395 | |
|
396 | 0 | Py_XDECREF(bytes); |
397 | |
|
398 | 0 | if (n == -1) { |
399 | 0 | if (err == EAGAIN) { |
400 | 0 | PyErr_Clear(); |
401 | 0 | Py_RETURN_NONE; |
402 | 0 | } |
403 | 0 | return NULL; |
404 | 0 | } |
405 | | |
406 | 0 | return PyLong_FromSsize_t(n); |
407 | 0 | } |
408 | | |
409 | | static PyObject * |
410 | | stdprinter_fileno(PyStdPrinter_Object *self, PyObject *Py_UNUSED(ignored)) |
411 | 0 | { |
412 | 0 | return PyLong_FromLong((long) self->fd); |
413 | 0 | } |
414 | | |
415 | | static PyObject * |
416 | | stdprinter_repr(PyStdPrinter_Object *self) |
417 | 0 | { |
418 | 0 | return PyUnicode_FromFormat("<stdprinter(fd=%d) object at %p>", |
419 | 0 | self->fd, self); |
420 | 0 | } |
421 | | |
422 | | static PyObject * |
423 | | stdprinter_noop(PyStdPrinter_Object *self, PyObject *Py_UNUSED(ignored)) |
424 | 0 | { |
425 | 0 | Py_RETURN_NONE; |
426 | 0 | } |
427 | | |
428 | | static PyObject * |
429 | | stdprinter_isatty(PyStdPrinter_Object *self, PyObject *Py_UNUSED(ignored)) |
430 | 0 | { |
431 | 0 | long res; |
432 | 0 | if (self->fd < 0) { |
433 | 0 | Py_RETURN_FALSE; |
434 | 0 | } |
435 | | |
436 | 0 | Py_BEGIN_ALLOW_THREADS |
437 | 0 | res = isatty(self->fd); |
438 | 0 | Py_END_ALLOW_THREADS |
439 | |
|
440 | 0 | return PyBool_FromLong(res); |
441 | 0 | } |
442 | | |
443 | | static PyMethodDef stdprinter_methods[] = { |
444 | | {"close", (PyCFunction)stdprinter_noop, METH_NOARGS, ""}, |
445 | | {"flush", (PyCFunction)stdprinter_noop, METH_NOARGS, ""}, |
446 | | {"fileno", (PyCFunction)stdprinter_fileno, METH_NOARGS, ""}, |
447 | | {"isatty", (PyCFunction)stdprinter_isatty, METH_NOARGS, ""}, |
448 | | {"write", (PyCFunction)stdprinter_write, METH_VARARGS, ""}, |
449 | | {NULL, NULL} /*sentinel */ |
450 | | }; |
451 | | |
452 | | static PyObject * |
453 | | get_closed(PyStdPrinter_Object *self, void *closure) |
454 | 0 | { |
455 | 0 | Py_RETURN_FALSE; |
456 | 0 | } |
457 | | |
458 | | static PyObject * |
459 | | get_mode(PyStdPrinter_Object *self, void *closure) |
460 | 0 | { |
461 | 0 | return PyUnicode_FromString("w"); |
462 | 0 | } |
463 | | |
464 | | static PyObject * |
465 | | get_encoding(PyStdPrinter_Object *self, void *closure) |
466 | 0 | { |
467 | 0 | Py_RETURN_NONE; |
468 | 0 | } |
469 | | |
470 | | static PyGetSetDef stdprinter_getsetlist[] = { |
471 | | {"closed", (getter)get_closed, NULL, "True if the file is closed"}, |
472 | | {"encoding", (getter)get_encoding, NULL, "Encoding of the file"}, |
473 | | {"mode", (getter)get_mode, NULL, "String giving the file mode"}, |
474 | | {0}, |
475 | | }; |
476 | | |
477 | | PyTypeObject PyStdPrinter_Type = { |
478 | | PyVarObject_HEAD_INIT(&PyType_Type, 0) |
479 | | "stderrprinter", /* tp_name */ |
480 | | sizeof(PyStdPrinter_Object), /* tp_basicsize */ |
481 | | 0, /* tp_itemsize */ |
482 | | /* methods */ |
483 | | 0, /* tp_dealloc */ |
484 | | 0, /* tp_vectorcall_offset */ |
485 | | 0, /* tp_getattr */ |
486 | | 0, /* tp_setattr */ |
487 | | 0, /* tp_as_async */ |
488 | | (reprfunc)stdprinter_repr, /* tp_repr */ |
489 | | 0, /* tp_as_number */ |
490 | | 0, /* tp_as_sequence */ |
491 | | 0, /* tp_as_mapping */ |
492 | | 0, /* tp_hash */ |
493 | | 0, /* tp_call */ |
494 | | 0, /* tp_str */ |
495 | | PyObject_GenericGetAttr, /* tp_getattro */ |
496 | | 0, /* tp_setattro */ |
497 | | 0, /* tp_as_buffer */ |
498 | | Py_TPFLAGS_DEFAULT, /* tp_flags */ |
499 | | 0, /* tp_doc */ |
500 | | 0, /* tp_traverse */ |
501 | | 0, /* tp_clear */ |
502 | | 0, /* tp_richcompare */ |
503 | | 0, /* tp_weaklistoffset */ |
504 | | 0, /* tp_iter */ |
505 | | 0, /* tp_iternext */ |
506 | | stdprinter_methods, /* tp_methods */ |
507 | | 0, /* tp_members */ |
508 | | stdprinter_getsetlist, /* tp_getset */ |
509 | | 0, /* tp_base */ |
510 | | 0, /* tp_dict */ |
511 | | 0, /* tp_descr_get */ |
512 | | 0, /* tp_descr_set */ |
513 | | 0, /* tp_dictoffset */ |
514 | | stdprinter_init, /* tp_init */ |
515 | | PyType_GenericAlloc, /* tp_alloc */ |
516 | | stdprinter_new, /* tp_new */ |
517 | | PyObject_Del, /* tp_free */ |
518 | | }; |
519 | | |
520 | | |
521 | | /* ************************** open_code hook *************************** |
522 | | * The open_code hook allows embedders to override the method used to |
523 | | * open files that are going to be used by the runtime to execute code |
524 | | */ |
525 | | |
526 | | int |
527 | 0 | PyFile_SetOpenCodeHook(Py_OpenCodeHookFunction hook, void *userData) { |
528 | 0 | if (Py_IsInitialized() && |
529 | 0 | PySys_Audit("setopencodehook", NULL) < 0) { |
530 | 0 | return -1; |
531 | 0 | } |
532 | | |
533 | 0 | if (_PyRuntime.open_code_hook) { |
534 | 0 | if (Py_IsInitialized()) { |
535 | 0 | PyErr_SetString(PyExc_SystemError, |
536 | 0 | "failed to change existing open_code hook"); |
537 | 0 | } |
538 | 0 | return -1; |
539 | 0 | } |
540 | | |
541 | 0 | _PyRuntime.open_code_hook = hook; |
542 | 0 | _PyRuntime.open_code_userdata = userData; |
543 | 0 | return 0; |
544 | 0 | } |
545 | | |
546 | | PyObject * |
547 | | PyFile_OpenCodeObject(PyObject *path) |
548 | 235 | { |
549 | 235 | PyObject *iomod, *f = NULL; |
550 | 235 | _Py_IDENTIFIER(open); |
551 | | |
552 | 235 | if (!PyUnicode_Check(path)) { |
553 | 0 | PyErr_Format(PyExc_TypeError, "'path' must be 'str', not '%.200s'", |
554 | 0 | Py_TYPE(path)->tp_name); |
555 | 0 | return NULL; |
556 | 0 | } |
557 | | |
558 | 235 | Py_OpenCodeHookFunction hook = _PyRuntime.open_code_hook; |
559 | 235 | if (hook) { |
560 | 0 | f = hook(path, _PyRuntime.open_code_userdata); |
561 | 235 | } else { |
562 | 235 | iomod = PyImport_ImportModule("_io"); |
563 | 235 | if (iomod) { |
564 | 235 | f = _PyObject_CallMethodId(iomod, &PyId_open, "Os", |
565 | 235 | path, "rb"); |
566 | 235 | Py_DECREF(iomod); |
567 | 235 | } |
568 | 235 | } |
569 | | |
570 | 235 | return f; |
571 | 235 | } |
572 | | |
573 | | PyObject * |
574 | | PyFile_OpenCode(const char *utf8path) |
575 | 0 | { |
576 | 0 | PyObject *pathobj = PyUnicode_FromString(utf8path); |
577 | 0 | PyObject *f; |
578 | 0 | if (!pathobj) { |
579 | 0 | return NULL; |
580 | 0 | } |
581 | 0 | f = PyFile_OpenCodeObject(pathobj); |
582 | 0 | Py_DECREF(pathobj); |
583 | 0 | return f; |
584 | 0 | } |
585 | | |
586 | | |
587 | | #ifdef __cplusplus |
588 | | } |
589 | | #endif |