this repo has no description
at trunk 153 lines 4.7 kB view raw
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