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