static PyObject * io_open(PyObject *self, PyObject *args, PyObject *kwds) { char *kwlist[] = {"file", "mode", "buffering", "encoding", "errors", "newline", "closefd", NULL}; PyObject *file; char *mode = "r"; int buffering = -1, closefd = 1; char *encoding = NULL, *errors = NULL, *newline = NULL; unsigned i; int reading = 0, writing = 0, appending = 0, updating = 0; int text = 0, binary = 0, universal = 0; char rawmode[5], *m; int line_buffering; long isatty; PyObject *raw, *modeobj = NULL, *buffer, *wrapper, *result = NULL; if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|sizzzi:open", kwlist, &file, &mode, &buffering, &encoding, &errors, &newline, &closefd)) { return NULL; } if (!PyUnicode_Check(file) && !PyBytes_Check(file) && !PyNumber_Check(file)) { PyObject *repr = PyObject_Repr(file); if (repr != NULL) { PyErr_Format(PyExc_TypeError, "invalid file: %s", PyString_AS_STRING(repr)); Py_DECREF(repr); } return NULL; } /* Decode mode */ for (i = 0; i < strlen(mode); i++) { char c = mode[i]; switch (c) { case 'r': reading = 1; break; case 'w': writing = 1; break; case 'a': appending = 1; break; case '+': updating = 1; break; case 't': text = 1; break; case 'b': binary = 1; break; case 'U': universal = 1; reading = 1; break; default: goto invalid_mode; } /* c must not be duplicated */ if (strchr(mode+i+1, c)) { invalid_mode: PyErr_Format(PyExc_ValueError, "invalid mode: '%s'", mode); return NULL; } } m = rawmode; if (reading) *(m++) = 'r'; if (writing) *(m++) = 'w'; if (appending) *(m++) = 'a'; if (updating) *(m++) = '+'; *m = '\0'; /* Parameters validation */ if (universal) { if (writing || appending) { PyErr_SetString(PyExc_ValueError, "can't use U and writing mode at once"); return NULL; } reading = 1; } if (text && binary) { PyErr_SetString(PyExc_ValueError, "can't have text and binary mode at once"); return NULL; } if (reading + writing + appending > 1) { PyErr_SetString(PyExc_ValueError, "must have exactly one of read/write/append mode"); return NULL; } if (binary && encoding != NULL) { PyErr_SetString(PyExc_ValueError, "binary mode doesn't take an encoding argument"); return NULL; } if (binary && errors != NULL) { PyErr_SetString(PyExc_ValueError, "binary mode doesn't take an errors argument"); return NULL; } if (binary && newline != NULL) { PyErr_SetString(PyExc_ValueError, "binary mode doesn't take a newline argument"); return NULL; } /* Create the Raw file stream */ raw = PyObject_CallFunction((PyObject *)&PyFileIO_Type, "Osi", file, rawmode, closefd); if (raw == NULL) return NULL; result = raw; modeobj = PyUnicode_FromString(mode); if (modeobj == NULL) goto error; /* buffering */ { PyObject *res = PyObject_CallMethod(raw, "isatty", NULL); if (res == NULL) goto error; isatty = PyLong_AsLong(res); Py_DECREF(res); if (isatty == -1 && PyErr_Occurred()) goto error; } if (buffering == 1 || (buffering < 0 && isatty)) { buffering = -1; line_buffering = 1; } else line_buffering = 0; if (buffering < 0) { buffering = DEFAULT_BUFFER_SIZE; #ifdef HAVE_STRUCT_STAT_ST_BLKSIZE { struct stat st; int fileno; PyObject *res = PyObject_CallMethod(raw, "fileno", NULL); if (res == NULL) goto error; fileno = _PyInt_AsInt(res); Py_DECREF(res); if (fileno == -1 && PyErr_Occurred()) goto error; if (fstat(fileno, &st) >= 0 && st.st_blksize > 1) buffering = st.st_blksize; } #endif } if (buffering < 0) { PyErr_SetString(PyExc_ValueError, "invalid buffering size"); goto error; } /* if not buffering, returns the raw file object */ if (buffering == 0) { if (!binary) { PyErr_SetString(PyExc_ValueError, "can't have unbuffered text I/O"); goto error; } Py_DECREF(modeobj); return result; } /* wraps into a buffered file */ { PyObject *Buffered_class; if (updating) Buffered_class = (PyObject *)&PyBufferedRandom_Type; else if (writing || appending) Buffered_class = (PyObject *)&PyBufferedWriter_Type; else if (reading) Buffered_class = (PyObject *)&PyBufferedReader_Type; else { PyErr_Format(PyExc_ValueError, "unknown mode: '%s'", mode); goto error; } buffer = PyObject_CallFunction(Buffered_class, "Oi", raw, buffering); } if (buffer == NULL) goto error; result = buffer; Py_DECREF(raw); /* if binary, returns the buffered file */ if (binary) { Py_DECREF(modeobj); return result; } /* wraps into a TextIOWrapper */ wrapper = PyObject_CallFunction((PyObject *)&PyTextIOWrapper_Type, "Osssi", buffer, encoding, errors, newline, line_buffering); if (wrapper == NULL) goto error; result = wrapper; Py_DECREF(buffer); if (PyObject_SetAttrString(wrapper, "mode", modeobj) < 0) goto error; Py_DECREF(modeobj); return result; error: if (result != NULL) { PyObject *exc, *val, *tb, *close_result; PyErr_Fetch(&exc, &val, &tb); close_result = PyObject_CallMethod(result, "close", NULL); _PyErr_ReplaceException(exc, val, tb); Py_XDECREF(close_result); Py_DECREF(result); } Py_XDECREF(modeobj); return NULL; }
/* This function is called by the tp_dealloc handler to clear weak references. * * This iterates through the weak references for 'object' and calls callbacks * for those references which have one. It returns when all callbacks have * been attempted. */ void PyObject_ClearWeakRefs(PyObject *object) { PyWeakReference **list; if (object == NULL || !PyType_SUPPORTS_WEAKREFS(Py_TYPE(object)) || object->ob_refcnt != 0) { PyErr_BadInternalCall(); return; } list = GET_WEAKREFS_LISTPTR(object); /* Remove the callback-less basic and proxy references */ if (*list != NULL && (*list)->wr_callback == NULL) { clear_weakref(*list); if (*list != NULL && (*list)->wr_callback == NULL) clear_weakref(*list); } if (*list != NULL) { PyWeakReference *current = *list; Py_ssize_t count = _PyWeakref_GetWeakrefCount(current); PyObject *err_type, *err_value, *err_tb; PyErr_Fetch(&err_type, &err_value, &err_tb); if (count == 1) { PyObject *callback = current->wr_callback; current->wr_callback = NULL; clear_weakref(current); if (callback != NULL) { if (current->ob_refcnt > 0) handle_callback(current, callback); Py_DECREF(callback); } } else { PyObject *tuple; Py_ssize_t i = 0; tuple = PyTuple_New(count * 2); if (tuple == NULL) { _PyErr_ReplaceException(err_type, err_value, err_tb); return; } for (i = 0; i < count; ++i) { PyWeakReference *next = current->wr_next; if (current->ob_refcnt > 0) { Py_INCREF(current); PyTuple_SET_ITEM(tuple, i * 2, (PyObject *) current); PyTuple_SET_ITEM(tuple, i * 2 + 1, current->wr_callback); } else { Py_DECREF(current->wr_callback); } current->wr_callback = NULL; clear_weakref(current); current = next; } for (i = 0; i < count; ++i) { PyObject *callback = PyTuple_GET_ITEM(tuple, i * 2 + 1); /* The tuple may have slots left to NULL */ if (callback != NULL) { PyObject *item = PyTuple_GET_ITEM(tuple, i * 2); handle_callback((PyWeakReference *)item, callback); } } Py_DECREF(tuple); } assert(!PyErr_Occurred()); PyErr_Restore(err_type, err_value, err_tb); } }