Commit b1e0937b authored by Kevin Modzelewski's avatar Kevin Modzelewski

Migrate to the CPython file object format

Trying to patch up our file support so that we match CPython's behavior and
functionality more closely; this is the first step.
parent ee548408
...@@ -42,7 +42,8 @@ extern "C" void* gc_compat_realloc(void* ptr, size_t sz) noexcept { ...@@ -42,7 +42,8 @@ extern "C" void* gc_compat_realloc(void* ptr, size_t sz) noexcept {
} }
extern "C" void gc_compat_free(void* ptr) noexcept { extern "C" void gc_compat_free(void* ptr) noexcept {
gc_free(ptr); if (ptr)
gc_free(ptr);
} }
// We may need to hook malloc as well. For now, these definitions serve // We may need to hook malloc as well. For now, these definitions serve
......
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
#include "gc/collector.h" #include "gc/collector.h"
#include "runtime/capi.h" #include "runtime/capi.h"
#include "runtime/classobj.h" #include "runtime/classobj.h"
#include "runtime/file.h"
#include "runtime/ics.h" #include "runtime/ics.h"
#include "runtime/import.h" #include "runtime/import.h"
#include "runtime/inline/xrange.h" #include "runtime/inline/xrange.h"
...@@ -329,27 +330,8 @@ extern "C" Box* id(Box* arg) { ...@@ -329,27 +330,8 @@ extern "C" Box* id(Box* arg) {
Box* open(Box* arg1, Box* arg2) { Box* open(Box* arg1, Box* arg2) {
assert(arg2); assert(arg2);
// This could be optimized quite a bit if it ends up being important:
if (arg1->cls != str_cls) { return runtimeCall(file_cls, ArgPassSpec(2), arg1, arg2, NULL, NULL, NULL);
fprintf(stderr, "TypeError: coercing to Unicode: need string of buffer, %s found\n", getTypeName(arg1));
raiseExcHelper(TypeError, "");
}
if (arg2->cls != str_cls) {
fprintf(stderr, "TypeError: coercing to Unicode: need string of buffer, %s found\n", getTypeName(arg2));
raiseExcHelper(TypeError, "");
}
const std::string& fn = static_cast<BoxedString*>(arg1)->s;
const std::string& mode = static_cast<BoxedString*>(arg2)->s;
FILE* f = fopen(fn.c_str(), mode.c_str());
if (!f) {
PyErr_SetFromErrnoWithFilename(IOError, fn.c_str());
checkAndThrowCAPIException();
abort(); // unreachable;
}
return new BoxedFile(f, fn, mode);
} }
extern "C" Box* chr(Box* arg) { extern "C" Box* chr(Box* arg) {
...@@ -872,6 +854,9 @@ public: ...@@ -872,6 +854,9 @@ public:
static Box* __init__(BoxedEnvironmentError* self, Box* errno_, Box* strerror, Box** _args) { static Box* __init__(BoxedEnvironmentError* self, Box* errno_, Box* strerror, Box** _args) {
Box* filename = _args[0]; Box* filename = _args[0];
if (!errno_)
return None;
RELEASE_ASSERT(isSubclass(self->cls, EnvironmentError), ""); RELEASE_ASSERT(isSubclass(self->cls, EnvironmentError), "");
self->myerrno = errno_; self->myerrno = errno_;
...@@ -1038,8 +1023,8 @@ void setupBuiltins() { ...@@ -1038,8 +1023,8 @@ void setupBuiltins() {
EnvironmentError->gc_visit = BoxedEnvironmentError::gcHandler; EnvironmentError->gc_visit = BoxedEnvironmentError::gcHandler;
EnvironmentError->giveAttr( EnvironmentError->giveAttr(
"__init__", "__init__", new BoxedFunction(boxRTFunction((void*)BoxedEnvironmentError::__init__, NONE, 4, 3, false, false),
new BoxedFunction(boxRTFunction((void*)BoxedEnvironmentError::__init__, NONE, 4, 1, false, false), { NULL })); { NULL, NULL, NULL }));
EnvironmentError->giveAttr( EnvironmentError->giveAttr(
"errno", new BoxedMemberDescriptor(BoxedMemberDescriptor::OBJECT, offsetof(BoxedEnvironmentError, myerrno))); "errno", new BoxedMemberDescriptor(BoxedMemberDescriptor::OBJECT, offsetof(BoxedEnvironmentError, myerrno)));
EnvironmentError->giveAttr("strerror", new BoxedMemberDescriptor(BoxedMemberDescriptor::OBJECT, EnvironmentError->giveAttr("strerror", new BoxedMemberDescriptor(BoxedMemberDescriptor::OBJECT,
......
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
#include "codegen/unwinding.h" #include "codegen/unwinding.h"
#include "core/types.h" #include "core/types.h"
#include "gc/collector.h" #include "gc/collector.h"
#include "runtime/file.h"
#include "runtime/inline/boxing.h" #include "runtime/inline/boxing.h"
#include "runtime/int.h" #include "runtime/int.h"
#include "runtime/types.h" #include "runtime/types.h"
......
...@@ -12,6 +12,8 @@ ...@@ -12,6 +12,8 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
#include "runtime/file.h"
#include <cstdio> #include <cstdio>
#include <cstring> #include <cstring>
#include <sstream> #include <sstream>
...@@ -26,18 +28,122 @@ ...@@ -26,18 +28,122 @@
namespace pyston { namespace pyston {
/* Bits in f_newlinetypes */
#define NEWLINE_UNKNOWN 0 /* No newline seen, yet */
#define NEWLINE_CR 1 /* \r newline seen */
#define NEWLINE_LF 2 /* \n newline seen */
#define NEWLINE_CRLF 4 /* \r\n newline seen */
#define FILE_BEGIN_ALLOW_THREADS(fobj) \
{ \
/*fobj->unlocked_count++;*/ \
Py_BEGIN_ALLOW_THREADS
#define FILE_END_ALLOW_THREADS(fobj) \
Py_END_ALLOW_THREADS \
/*fobj->unlocked_count--;*/ \
/*assert(fobj->unlocked_count >= 0);*/ \
}
static BoxedFile* dircheck(BoxedFile* f) {
#if defined(HAVE_FSTAT) && defined(S_IFDIR) && defined(EISDIR)
struct stat buf;
if (f->f_fp == NULL)
return f;
if (fstat(fileno(f->f_fp), &buf) == 0 && S_ISDIR(buf.st_mode)) {
char* msg = strerror(EISDIR);
PyObject* exc = PyObject_CallFunction(PyExc_IOError, "(isO)", EISDIR, msg, f->f_name);
PyErr_SetObject(PyExc_IOError, exc);
Py_XDECREF(exc);
return NULL;
}
#endif
return f;
}
static PyObject* fill_file_fields(BoxedFile* f, FILE* fp, PyObject* name, const char* mode, int (*close)(FILE*)) {
assert(name != NULL);
assert(f != NULL);
assert(PyFile_Check(f));
assert(f->f_fp == NULL);
Py_DECREF(f->f_name);
Py_DECREF(f->f_mode);
Py_DECREF(f->f_encoding);
Py_DECREF(f->f_errors);
Py_INCREF(name);
f->f_name = name;
f->f_mode = PyString_FromString(mode);
f->f_close = close;
f->f_softspace = 0;
f->f_binary = strchr(mode, 'b') != NULL;
f->f_buf = NULL;
f->f_univ_newline = (strchr(mode, 'U') != NULL);
f->f_newlinetypes = NEWLINE_UNKNOWN;
f->f_skipnextlf = 0;
Py_INCREF(Py_None);
f->f_encoding = Py_None;
Py_INCREF(Py_None);
f->f_errors = Py_None;
f->readable = f->writable = 0;
if (strchr(mode, 'r') != NULL || f->f_univ_newline)
f->readable = 1;
if (strchr(mode, 'w') != NULL || strchr(mode, 'a') != NULL)
f->writable = 1;
if (strchr(mode, '+') != NULL)
f->readable = f->writable = 1;
if (f->f_mode == NULL)
return NULL;
f->f_fp = fp;
f = dircheck(f);
return (PyObject*)f;
}
BoxedFile::BoxedFile(FILE* f, std::string fname, const char* fmode, int (*close)(FILE*))
// Zero out fields not set by fill_file_fields:
: f_fp(NULL),
f_bufend(NULL),
f_bufptr(0),
f_setbuf(0),
unlocked_count(0) {
Box* r = fill_file_fields(this, f, new BoxedString(fname), fmode, close);
checkAndThrowCAPIException();
assert(r == this);
}
Box* fileRepr(BoxedFile* self) { Box* fileRepr(BoxedFile* self) {
assert(self->cls == file_cls); assert(self->cls == file_cls);
void* addr = static_cast<void*>(self->f); void* addr = static_cast<void*>(self->f_fp);
std::ostringstream repr; std::ostringstream repr;
repr << "<" << (self->closed ? "closed" : "open") << " file '" << self->fname << "', "; repr << "<" << (self->f_fp ? "open" : "closed") << " file '" << PyString_AsString(self->f_name) << "', ";
repr << "mode '" << self->fmode << "' at " << addr << ">"; repr << "mode '" << PyString_AsString(self->f_mode) << "' at " << addr << ">";
return boxString(repr.str()); return boxString(repr.str());
} }
static void checkOpen(BoxedFile* self) {
if (!self->f_fp)
raiseExcHelper(IOError, "I/O operation on closed file");
}
static void checkReadable(BoxedFile* self) {
checkOpen(self);
if (!self->readable)
raiseExcHelper(IOError, "File not open for reading");
}
static void checkWritable(BoxedFile* self) {
checkOpen(self);
if (!self->writable)
raiseExcHelper(IOError, "File not open for writing");
}
Box* fileRead(BoxedFile* self, Box* _size) { Box* fileRead(BoxedFile* self, Box* _size) {
assert(self->cls == file_cls); assert(self->cls == file_cls);
if (_size->cls != int_cls) { if (_size->cls != int_cls) {
...@@ -46,10 +152,7 @@ Box* fileRead(BoxedFile* self, Box* _size) { ...@@ -46,10 +152,7 @@ Box* fileRead(BoxedFile* self, Box* _size) {
} }
int64_t size = static_cast<BoxedInt*>(_size)->n; int64_t size = static_cast<BoxedInt*>(_size)->n;
if (self->closed) { checkReadable(self);
fprintf(stderr, "IOError: file not open for reading\n");
raiseExcHelper(IOError, "");
}
std::ostringstream os(""); std::ostringstream os("");
...@@ -60,9 +163,9 @@ Box* fileRead(BoxedFile* self, Box* _size) { ...@@ -60,9 +163,9 @@ Box* fileRead(BoxedFile* self, Box* _size) {
while (read < size) { while (read < size) {
const int BUF_SIZE = 1024; const int BUF_SIZE = 1024;
char buf[BUF_SIZE]; char buf[BUF_SIZE];
size_t more_read = fread(buf, 1, std::min((i64)BUF_SIZE, size - read), self->f); size_t more_read = fread(buf, 1, std::min((i64)BUF_SIZE, size - read), self->f_fp);
if (more_read == 0) { if (more_read == 0) {
ASSERT(!ferror(self->f), "%d", ferror(self->f)); ASSERT(!ferror(self->f_fp), "%d", ferror(self->f_fp));
break; break;
} }
...@@ -76,11 +179,13 @@ Box* fileRead(BoxedFile* self, Box* _size) { ...@@ -76,11 +179,13 @@ Box* fileRead(BoxedFile* self, Box* _size) {
Box* fileReadline1(BoxedFile* self) { Box* fileReadline1(BoxedFile* self) {
assert(self->cls == file_cls); assert(self->cls == file_cls);
checkReadable(self);
std::ostringstream os(""); std::ostringstream os("");
while (true) { while (true) {
char c; char c;
int nread = fread(&c, 1, 1, self->f); int nread = fread(&c, 1, 1, self->f_fp);
if (nread == 0) if (nread == 0)
break; break;
os << c; os << c;
...@@ -94,10 +199,7 @@ Box* fileReadline1(BoxedFile* self) { ...@@ -94,10 +199,7 @@ Box* fileReadline1(BoxedFile* self) {
Box* fileWrite(BoxedFile* self, Box* val) { Box* fileWrite(BoxedFile* self, Box* val) {
assert(self->cls == file_cls); assert(self->cls == file_cls);
if (self->closed) { checkWritable(self);
raiseExcHelper(IOError, "file is closed");
}
if (val->cls == str_cls) { if (val->cls == str_cls) {
const std::string& s = static_cast<BoxedString*>(val)->s; const std::string& s = static_cast<BoxedString*>(val)->s;
...@@ -109,12 +211,12 @@ Box* fileWrite(BoxedFile* self, Box* val) { ...@@ -109,12 +211,12 @@ Box* fileWrite(BoxedFile* self, Box* val) {
// char buf[BUF_SIZE]; // char buf[BUF_SIZE];
// int to_write = std::min(BUF_SIZE, size - written); // int to_write = std::min(BUF_SIZE, size - written);
// memcpy(buf, s.c_str() + written, to_write); // memcpy(buf, s.c_str() + written, to_write);
// size_t new_written = fwrite(buf, 1, to_write, self->f); // size_t new_written = fwrite(buf, 1, to_write, self->f_fp);
size_t new_written = fwrite(s.c_str() + written, 1, size - written, self->f); size_t new_written = fwrite(s.c_str() + written, 1, size - written, self->f_fp);
if (!new_written) { if (!new_written) {
int error = ferror(self->f); int error = ferror(self->f_fp);
fprintf(stderr, "IOError %d\n", error); fprintf(stderr, "IOError %d\n", error);
raiseExcHelper(IOError, ""); raiseExcHelper(IOError, "");
} }
...@@ -132,24 +234,66 @@ Box* fileWrite(BoxedFile* self, Box* val) { ...@@ -132,24 +234,66 @@ Box* fileWrite(BoxedFile* self, Box* val) {
Box* fileFlush(BoxedFile* self) { Box* fileFlush(BoxedFile* self) {
RELEASE_ASSERT(self->cls == file_cls, ""); RELEASE_ASSERT(self->cls == file_cls, "");
if (self->closed) checkOpen(self);
raiseExcHelper(IOError, "file is closed"); int res;
fflush(self->f); FILE_BEGIN_ALLOW_THREADS(self);
errno = 0;
res = fflush(self->f_fp);
FILE_END_ALLOW_THREADS(self);
if (res != 0) {
PyErr_SetFromErrno(IOError);
clearerr(self->f_fp);
throwCAPIException();
}
return None; return None;
} }
Box* fileClose(BoxedFile* self) { static PyObject* close_the_file(BoxedFile* f) {
assert(self->cls == file_cls); int sts = 0;
if (self->closed) { int (*local_close)(FILE*);
fprintf(stderr, "IOError: file is closed\n"); FILE* local_fp = f->f_fp;
raiseExcHelper(IOError, ""); char* local_setbuf = f->f_setbuf;
if (local_fp != NULL) {
local_close = f->f_close;
if (local_close != NULL && f->unlocked_count > 0) {
PyErr_SetString(PyExc_IOError, "close() called during concurrent "
"operation on the same file object.");
return NULL;
}
/* NULL out the FILE pointer before releasing the GIL, because
* it will not be valid anymore after the close() function is
* called. */
f->f_fp = NULL;
if (local_close != NULL) {
/* Issue #9295: must temporarily reset f_setbuf so that another
thread doesn't free it when running file_close() concurrently.
Otherwise this close() will crash when flushing the buffer. */
f->f_setbuf = NULL;
Py_BEGIN_ALLOW_THREADS errno = 0;
sts = (*local_close)(local_fp);
Py_END_ALLOW_THREADS f->f_setbuf = local_setbuf;
if (sts == EOF)
return PyErr_SetFromErrno(PyExc_IOError);
if (sts != 0)
return PyInt_FromLong((long)sts);
}
} }
Py_RETURN_NONE;
}
fclose(self->f); Box* fileClose(BoxedFile* self) {
self->closed = true; assert(self->cls == file_cls);
return None; PyObject* sts = close_the_file(self);
if (sts) {
PyMem_Free(self->f_setbuf);
self->f_setbuf = NULL;
} else {
throwCAPIException();
}
return sts;
} }
Box* fileEnter(BoxedFile* self) { Box* fileEnter(BoxedFile* self) {
...@@ -169,7 +313,27 @@ Box* fileExit(BoxedFile* self, Box* exc_type, Box* exc_val, Box** args) { ...@@ -169,7 +313,27 @@ Box* fileExit(BoxedFile* self, Box* exc_type, Box* exc_val, Box** args) {
Box* fileNew(BoxedClass* cls, Box* s, Box* m) { Box* fileNew(BoxedClass* cls, Box* s, Box* m) {
assert(cls == file_cls); assert(cls == file_cls);
return open(s, m);
if (s->cls != str_cls) {
fprintf(stderr, "TypeError: coercing to Unicode: need string of buffer, %s found\n", getTypeName(s));
raiseExcHelper(TypeError, "");
}
if (m->cls != str_cls) {
fprintf(stderr, "TypeError: coercing to Unicode: need string of buffer, %s found\n", getTypeName(m));
raiseExcHelper(TypeError, "");
}
const std::string& fn = static_cast<BoxedString*>(s)->s;
const std::string& mode = static_cast<BoxedString*>(m)->s;
FILE* f = fopen(fn.c_str(), mode.c_str());
if (!f) {
PyErr_SetFromErrnoWithFilename(IOError, fn.c_str());
throwCAPIException();
abort(); // unreachable;
}
return new BoxedFile(f, fn, PyString_AsString(m));
} }
Box* fileIterNext(BoxedFile* s) { Box* fileIterNext(BoxedFile* s) {
...@@ -177,9 +341,9 @@ Box* fileIterNext(BoxedFile* s) { ...@@ -177,9 +341,9 @@ Box* fileIterNext(BoxedFile* s) {
} }
bool fileEof(BoxedFile* self) { bool fileEof(BoxedFile* self) {
char ch = fgetc(self->f); char ch = fgetc(self->f_fp);
ungetc(ch, self->f); ungetc(ch, self->f_fp);
return feof(self->f); return feof(self->f_fp);
} }
Box* fileIterHasNext(Box* s) { Box* fileIterHasNext(Box* s) {
...@@ -191,8 +355,8 @@ Box* fileIterHasNext(Box* s) { ...@@ -191,8 +355,8 @@ Box* fileIterHasNext(Box* s) {
extern "C" void PyFile_SetFP(PyObject* _f, FILE* fp) noexcept { extern "C" void PyFile_SetFP(PyObject* _f, FILE* fp) noexcept {
assert(_f->cls == file_cls); assert(_f->cls == file_cls);
BoxedFile* f = static_cast<BoxedFile*>(_f); BoxedFile* f = static_cast<BoxedFile*>(_f);
assert(f->f == NULL); assert(f->f_fp == NULL);
f->f = fp; f->f_fp = fp;
} }
extern "C" PyObject* PyFile_FromFile(FILE* fp, char* name, char* mode, int (*close)(FILE*)) noexcept { extern "C" PyObject* PyFile_FromFile(FILE* fp, char* name, char* mode, int (*close)(FILE*)) noexcept {
...@@ -204,7 +368,7 @@ extern "C" FILE* PyFile_AsFile(PyObject* f) noexcept { ...@@ -204,7 +368,7 @@ extern "C" FILE* PyFile_AsFile(PyObject* f) noexcept {
if (!f || !PyFile_Check(f)) if (!f || !PyFile_Check(f))
return NULL; return NULL;
return static_cast<BoxedFile*>(f)->f; return static_cast<BoxedFile*>(f)->f_fp;
} }
extern "C" int PyFile_WriteObject(PyObject* v, PyObject* f, int flags) noexcept { extern "C" int PyFile_WriteObject(PyObject* v, PyObject* f, int flags) noexcept {
...@@ -220,17 +384,6 @@ extern "C" int PyFile_WriteObject(PyObject* v, PyObject* f, int flags) noexcept ...@@ -220,17 +384,6 @@ extern "C" int PyFile_WriteObject(PyObject* v, PyObject* f, int flags) noexcept
} }
} }
#define FILE_BEGIN_ALLOW_THREADS(fobj) \
{ \
/*fobj->unlocked_count++;*/ \
Py_BEGIN_ALLOW_THREADS
#define FILE_END_ALLOW_THREADS(fobj) \
Py_END_ALLOW_THREADS \
/*fobj->unlocked_count--;*/ \
/*assert(fobj->unlocked_count >= 0);*/ \
}
static PyObject* err_closed(void) noexcept { static PyObject* err_closed(void) noexcept {
PyErr_SetString(PyExc_ValueError, "I/O operation on closed file"); PyErr_SetString(PyExc_ValueError, "I/O operation on closed file");
return NULL; return NULL;
...@@ -269,7 +422,7 @@ extern "C" void PyFile_SetBufSize(PyObject* f, int bufsize) noexcept { ...@@ -269,7 +422,7 @@ extern "C" void PyFile_SetBufSize(PyObject* f, int bufsize) noexcept {
assert(f->cls == file_cls); assert(f->cls == file_cls);
if (bufsize >= 0) { if (bufsize >= 0) {
if (bufsize == 0) { if (bufsize == 0) {
setvbuf(static_cast<BoxedFile*>(f)->f, NULL, _IONBF, 0); setvbuf(static_cast<BoxedFile*>(f)->f_fp, NULL, _IONBF, 0);
} else { } else {
Py_FatalError("unimplemented"); Py_FatalError("unimplemented");
} }
...@@ -387,7 +540,7 @@ void setupFile() { ...@@ -387,7 +540,7 @@ void setupFile() {
file_cls->giveAttr("next", new BoxedFunction(boxRTFunction((void*)fileIterNext, STR, 1))); file_cls->giveAttr("next", new BoxedFunction(boxRTFunction((void*)fileIterNext, STR, 1)));
file_cls->giveAttr("softspace", file_cls->giveAttr("softspace",
new BoxedMemberDescriptor(BoxedMemberDescriptor::BYTE, offsetof(BoxedFile, softspace))); new BoxedMemberDescriptor(BoxedMemberDescriptor::INT, offsetof(BoxedFile, f_softspace)));
file_cls->giveAttr("__new__", new BoxedFunction(boxRTFunction((void*)fileNew, UNKNOWN, 3, 1, false, false), file_cls->giveAttr("__new__", new BoxedFunction(boxRTFunction((void*)fileNew, UNKNOWN, 3, 1, false, false),
{ boxStrConstant("r") })); { boxStrConstant("r") }));
......
// Copyright (c) 2014-2015 Dropbox, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef PYSTON_RUNTIME_FILE_H
#define PYSTON_RUNTIME_FILE_H
#include "core/types.h"
#include "runtime/types.h"
namespace pyston {
class BoxedFile : public Box {
public:
PyObject_HEAD FILE* f_fp;
PyObject* f_name;
PyObject* f_mode;
int (*f_close)(FILE*);
int f_softspace; /* Flag used by 'print' command */
int f_binary; /* Flag which indicates whether the file is
open in binary (1) or text (0) mode */
char* f_buf; /* Allocated readahead buffer */
char* f_bufend; /* Points after last occupied position */
char* f_bufptr; /* Current buffer position */
char* f_setbuf; /* Buffer for setbuf(3) and setvbuf(3) */
int f_univ_newline; /* Handle any newline convention */
int f_newlinetypes; /* Types of newlines seen */
int f_skipnextlf; /* Skip next \n */
PyObject* f_encoding;
PyObject* f_errors;
#if 0
PyObject* weakreflist; /* List of weak references */
#endif
int unlocked_count; /* Num. currently running sections of code
using f_fp with the GIL released. */
int readable;
int writable;
BoxedFile(FILE* f, std::string fname, const char* fmode, int (*close)(FILE*) = fclose)
__attribute__((visibility("default")));
DEFAULT_CLASS(file_cls);
};
}
#endif
...@@ -41,6 +41,7 @@ ...@@ -41,6 +41,7 @@
#include "gc/heap.h" #include "gc/heap.h"
#include "runtime/capi.h" #include "runtime/capi.h"
#include "runtime/classobj.h" #include "runtime/classobj.h"
#include "runtime/file.h"
#include "runtime/float.h" #include "runtime/float.h"
#include "runtime/generator.h" #include "runtime/generator.h"
#include "runtime/ics.h" #include "runtime/ics.h"
...@@ -173,10 +174,11 @@ extern "C" bool softspace(Box* b, bool newval) { ...@@ -173,10 +174,11 @@ extern "C" bool softspace(Box* b, bool newval) {
assert(b); assert(b);
if (isSubclass(b->cls, file_cls)) { if (isSubclass(b->cls, file_cls)) {
bool& ss = static_cast<BoxedFile*>(b)->softspace; int& ss = static_cast<BoxedFile*>(b)->f_softspace;
bool r = ss; int r = ss;
ss = newval; ss = newval;
return r; assert(r == 0 || r == 1);
return (bool)r;
} }
bool r; bool r;
......
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
#include "gc/collector.h" #include "gc/collector.h"
#include "runtime/capi.h" #include "runtime/capi.h"
#include "runtime/classobj.h" #include "runtime/classobj.h"
#include "runtime/file.h"
#include "runtime/ics.h" #include "runtime/ics.h"
#include "runtime/iterobject.h" #include "runtime/iterobject.h"
#include "runtime/list.h" #include "runtime/list.h"
......
...@@ -404,19 +404,6 @@ public: ...@@ -404,19 +404,6 @@ public:
}; };
extern "C" BoxedTuple* EmptyTuple; extern "C" BoxedTuple* EmptyTuple;
class BoxedFile : public Box {
public:
FILE* f;
std::string fname;
std::string fmode;
bool closed;
bool softspace;
BoxedFile(FILE* f, std::string fname, std::string fmode) __attribute__((visibility("default")))
: f(f), fname(fname), fmode(fmode), closed(false), softspace(false) {}
DEFAULT_CLASS(file_cls);
};
struct PyHasher { struct PyHasher {
size_t operator()(Box*) const; size_t operator()(Box*) const;
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment