this repo has no description
1// Copyright (c) Facebook, Inc. and its affiliates. (http://www.facebook.com)
2#include <cerrno>
3
4#include "cpython-data.h"
5#include "cpython-func.h"
6#include "cpython-types.h"
7
8#include "api-handle.h"
9#include "runtime.h"
10
11namespace py {
12
13PY_EXPORT PyObject* PyFile_GetLine(PyObject* /* f */, int /* n */) {
14 UNIMPLEMENTED("PyFile_GetLine");
15}
16
17PY_EXPORT int PyFile_SetOpenCodeHook(Py_OpenCodeHookFunction, void*) {
18 // TODO(T87346777): add hook to io.open_code()
19 UNIMPLEMENTED("PyFile_SetOpenCodeHook");
20}
21
22PY_EXPORT int PyFile_WriteObject(PyObject* pyobj, PyObject* pyfile, int flags) {
23 Thread* thread = Thread::current();
24 HandleScope scope(thread);
25
26 if (pyfile == nullptr) {
27 thread->raiseWithFmt(LayoutId::kTypeError, "writeobject with NULL file");
28 return -1;
29 }
30
31 Object file(&scope, ApiHandle::asObject(ApiHandle::fromPyObject(pyfile)));
32 Runtime* runtime = thread->runtime();
33 Object obj(&scope, NoneType::object());
34 if (pyobj != nullptr) {
35 obj = ApiHandle::asObject(ApiHandle::fromPyObject(pyobj));
36 obj = thread->invokeFunction1(
37 ID(builtins), flags & Py_PRINT_RAW ? ID(str) : ID(repr), obj);
38 if (obj.isError()) return -1;
39 DCHECK(runtime->isInstanceOfStr(*obj), "str() and repr() must return str");
40 } else {
41 obj = SmallStr::fromCStr("<NULL>");
42 }
43
44 Object result(&scope, thread->invokeMethod2(file, ID(write), obj));
45 return result.isError() ? -1 : 0;
46}
47
48PY_EXPORT int PyFile_WriteString(const char* str, PyObject* pyfile) {
49 Thread* thread = Thread::current();
50 HandleScope scope(thread);
51
52 if (thread->hasPendingException()) return -1;
53 if (pyfile == nullptr) {
54 thread->raiseWithFmt(LayoutId::kSystemError,
55 "null file for PyFile_WriteString");
56 return -1;
57 }
58
59 Object file(&scope, ApiHandle::asObject(ApiHandle::fromPyObject(pyfile)));
60 Object str_obj(&scope, thread->runtime()->newStrFromCStr(str));
61 Object result(&scope, thread->invokeMethod2(file, ID(write), str_obj));
62 return result.isError() ? -1 : 0;
63}
64
65PY_EXPORT int PyObject_AsFileDescriptor(PyObject* obj) {
66 DCHECK(obj != nullptr, "obj must not be null");
67 Thread* thread = Thread::current();
68 HandleScope scope(thread);
69 Object object(&scope, ApiHandle::asObject(ApiHandle::fromPyObject(obj)));
70 Runtime* runtime = thread->runtime();
71 if (!runtime->isInstanceOfInt(*object)) {
72 object = thread->invokeMethod1(object, ID(fileno));
73 if (object.isError()) {
74 if (object.isErrorNotFound()) {
75 thread->raiseWithFmt(
76 LayoutId::kTypeError,
77 "argument must be an int, or have a fileno() method.");
78 }
79 return -1;
80 }
81 if (!runtime->isInstanceOfInt(*object)) {
82 thread->raiseWithFmt(LayoutId::kTypeError,
83 "fileno() returned a non-integer");
84 return -1;
85 }
86 }
87 Int result(&scope, intUnderlying(*object));
88 auto const optint = result.asInt<int>();
89 if (optint.error != CastError::None) {
90 thread->raiseWithFmt(LayoutId::kOverflowError,
91 "Python int too big to convert to C int");
92 return -1;
93 }
94 int fd = optint.value;
95 if (fd < 0) {
96 thread->raiseWithFmt(LayoutId::kValueError,
97 "file descriptor cannot be a negative integer (%d)",
98 fd);
99 return -1;
100 }
101 return fd;
102}
103
104PY_EXPORT char* Py_UniversalNewlineFgets(char* buf, int buf_size, FILE* stream,
105 PyObject* fobj) {
106 if (fobj != nullptr) {
107 errno = ENXIO;
108 return nullptr;
109 }
110
111 enum Newline {
112 CR = 0x1,
113 LF = 0x2,
114 CRLF = 0x4,
115 };
116 char* ptr = buf;
117 bool skipnextlf = false;
118 for (char ch; --buf_size > 0 && (ch = std::getc(stream)) != EOF;) {
119 if (skipnextlf) {
120 skipnextlf = false;
121 if (ch == '\n') {
122 // Seeing a \n here with skipnextlf true means we saw a \r before.
123 ch = std::getc(stream);
124 if (ch == EOF) break;
125 } else {
126 // Note that c == EOF also brings us here, so we're okay
127 // if the last char in the file is a CR.
128 }
129 }
130 if (ch == '\r') {
131 // A \r is translated into a \n, and we skip an adjacent \n, if any.
132 skipnextlf = true;
133 ch = '\n';
134 }
135 *ptr++ = ch;
136 if (ch == '\n') {
137 break;
138 }
139 }
140 *ptr = '\0';
141 if (skipnextlf) {
142 // If we have no file object we cannot save the skipnextlf flag.
143 // We have to readahead, which will cause a pause if we're reading
144 // from an interactive stream, but that is very unlikely unless we're
145 // doing something silly like exec(open("/dev/tty").read()).
146 char ch = std::getc(stream);
147 if (ch != '\n') std::ungetc(ch, stream);
148 }
149 if (ptr == buf) return nullptr;
150 return buf;
151}
152
153} // namespace py