A bunch of functions are now properly implemented in abstract.c, and
the code here becomes much simpler. In particular: abs(), divmod(), pow(), int(), long(), float(), len(), tuple(), list(). Also make sure that no use of a function pointer gotten from a tp_as_sequence or tp_as_mapping structure is made without checking it for NULL first. A few other cosmetic things, such as properly reindenting slice().
This commit is contained in:
parent
44e4d5a6fd
commit
09df08a105
|
@ -48,9 +48,6 @@ PERFORMANCE OF THIS SOFTWARE.
|
|||
/* Forward */
|
||||
static PyObject *filterstring Py_PROTO((PyObject *, PyObject *));
|
||||
static PyObject *filtertuple Py_PROTO((PyObject *, PyObject *));
|
||||
static PyObject *int_from_string Py_PROTO((PyObject *));
|
||||
static PyObject *long_from_string Py_PROTO((PyObject *));
|
||||
static PyObject *float_from_string Py_PROTO((PyObject *));
|
||||
|
||||
static PyObject *
|
||||
builtin___import__(self, args)
|
||||
|
@ -75,16 +72,10 @@ builtin_abs(self, args)
|
|||
PyObject *args;
|
||||
{
|
||||
PyObject *v;
|
||||
PyNumberMethods *nm;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "O:abs", &v))
|
||||
return NULL;
|
||||
if ((nm = v->ob_type->tp_as_number) == NULL) {
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"abs() requires numeric argument");
|
||||
return NULL;
|
||||
}
|
||||
return (*nm->nb_absolute)(v);
|
||||
return PyNumber_Absolute(v);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
|
@ -144,7 +135,8 @@ builtin_filter(self, args)
|
|||
return r;
|
||||
}
|
||||
|
||||
if ((sqf = seq->ob_type->tp_as_sequence) == NULL) {
|
||||
sqf = seq->ob_type->tp_as_sequence;
|
||||
if (sqf == NULL || sqf->sq_length == NULL || sqf->sq_item == NULL) {
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"argument 2 to filter() must be a sequence type");
|
||||
goto Fail_2;
|
||||
|
@ -245,14 +237,13 @@ builtin_cmp(self, args)
|
|||
PyObject *args;
|
||||
{
|
||||
PyObject *a, *b;
|
||||
long c;
|
||||
int c;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "OO:cmp", &a, &b))
|
||||
return NULL;
|
||||
c = PyObject_Compare(a, b);
|
||||
if (c && PyErr_Occurred())
|
||||
if (PyObject_Cmp(a, b, &c) < 0)
|
||||
return NULL;
|
||||
return PyInt_FromLong(c);
|
||||
return PyInt_FromLong((long)c);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
|
@ -450,29 +441,6 @@ builtin_dir(self, args)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
do_divmod(v, w)
|
||||
PyObject *v, *w;
|
||||
{
|
||||
PyObject *res;
|
||||
|
||||
if (PyInstance_Check(v) || PyInstance_Check(w))
|
||||
return PyInstance_DoBinOp(v, w, "__divmod__", "__rdivmod__",
|
||||
do_divmod);
|
||||
if (v->ob_type->tp_as_number == NULL ||
|
||||
w->ob_type->tp_as_number == NULL) {
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"divmod() requires numeric or class instance arguments");
|
||||
return NULL;
|
||||
}
|
||||
if (PyNumber_Coerce(&v, &w) != 0)
|
||||
return NULL;
|
||||
res = (*v->ob_type->tp_as_number->nb_divmod)(v, w);
|
||||
Py_DECREF(v);
|
||||
Py_DECREF(w);
|
||||
return res;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
builtin_divmod(self, args)
|
||||
PyObject *self;
|
||||
|
@ -482,7 +450,7 @@ builtin_divmod(self, args)
|
|||
|
||||
if (!PyArg_ParseTuple(args, "OO:divmod", &v, &w))
|
||||
return NULL;
|
||||
return do_divmod(v, w);
|
||||
return PyNumber_Divmod(v, w);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
|
@ -576,19 +544,10 @@ builtin_float(self, args)
|
|||
PyObject *args;
|
||||
{
|
||||
PyObject *v;
|
||||
PyNumberMethods *nb;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "O:float", &v))
|
||||
return NULL;
|
||||
if (PyString_Check(v))
|
||||
return float_from_string(v);
|
||||
if ((nb = v->ob_type->tp_as_number) == NULL ||
|
||||
nb->nb_float == NULL) {
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"float() argument can't be converted to float");
|
||||
return NULL;
|
||||
}
|
||||
return (*nb->nb_float)(v);
|
||||
return PyNumber_Float(v);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
|
@ -631,10 +590,12 @@ builtin_hasattr(self, args)
|
|||
v = PyObject_GetAttr(v, name);
|
||||
if (v == NULL) {
|
||||
PyErr_Clear();
|
||||
return PyInt_FromLong(0L);
|
||||
Py_INCREF(Py_False);
|
||||
return Py_False;
|
||||
}
|
||||
Py_DECREF(v);
|
||||
return PyInt_FromLong(1L);
|
||||
Py_INCREF(Py_True);
|
||||
return Py_True;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
|
@ -682,11 +643,16 @@ builtin_map(self, args)
|
|||
|
||||
for (len = 0, i = 0, sqp = seqs; i < n; ++i, ++sqp) {
|
||||
int curlen;
|
||||
PySequenceMethods *sqf;
|
||||
|
||||
if ((sqp->seq = PyTuple_GetItem(args, i + 1)) == NULL)
|
||||
goto Fail_2;
|
||||
|
||||
if (! (sqp->sqf = sqp->seq->ob_type->tp_as_sequence)) {
|
||||
sqp->sqf = sqf = sqp->seq->ob_type->tp_as_sequence;
|
||||
if (sqf == NULL ||
|
||||
sqf->sq_length == NULL ||
|
||||
sqf->sq_item == NULL)
|
||||
{
|
||||
static char errmsg[] =
|
||||
"argument %d to map() must be a sequence object";
|
||||
char errbuf[sizeof(errmsg) + 25];
|
||||
|
@ -916,15 +882,7 @@ builtin_int(self, args)
|
|||
|
||||
if (!PyArg_ParseTuple(args, "O:int", &v))
|
||||
return NULL;
|
||||
if (PyString_Check(v))
|
||||
return int_from_string(v);
|
||||
if ((nb = v->ob_type->tp_as_number) == NULL ||
|
||||
nb->nb_int == NULL) {
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"int() argument can't be converted to int");
|
||||
return NULL;
|
||||
}
|
||||
return (*nb->nb_int)(v);
|
||||
return PyNumber_Int(v);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
|
@ -933,26 +891,10 @@ builtin_len(self, args)
|
|||
PyObject *args;
|
||||
{
|
||||
PyObject *v;
|
||||
long len;
|
||||
PyTypeObject *tp;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "O:len", &v))
|
||||
return NULL;
|
||||
tp = v->ob_type;
|
||||
if (tp->tp_as_sequence != NULL) {
|
||||
len = (*tp->tp_as_sequence->sq_length)(v);
|
||||
}
|
||||
else if (tp->tp_as_mapping != NULL) {
|
||||
len = (*tp->tp_as_mapping->mp_length)(v);
|
||||
}
|
||||
else {
|
||||
PyErr_SetString(PyExc_TypeError, "len() of unsized object");
|
||||
return NULL;
|
||||
}
|
||||
if (len < 0)
|
||||
return NULL;
|
||||
else
|
||||
return PyInt_FromLong(len);
|
||||
return PyInt_FromLong((long)PyObject_Length(v));
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
|
@ -961,33 +903,10 @@ builtin_list(self, args)
|
|||
PyObject *args;
|
||||
{
|
||||
PyObject *v;
|
||||
PySequenceMethods *sqf;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "O:list", &v))
|
||||
return NULL;
|
||||
if ((sqf = v->ob_type->tp_as_sequence) != NULL) {
|
||||
int n = (*sqf->sq_length)(v);
|
||||
int i;
|
||||
PyObject *l;
|
||||
if (n < 0)
|
||||
return NULL;
|
||||
l = PyList_New(n);
|
||||
if (l == NULL)
|
||||
return NULL;
|
||||
for (i = 0; i < n; i++) {
|
||||
PyObject *item = (*sqf->sq_item)(v, i);
|
||||
if (item == NULL) {
|
||||
Py_DECREF(l);
|
||||
l = NULL;
|
||||
break;
|
||||
}
|
||||
PyList_SetItem(l, i, item);
|
||||
}
|
||||
/* XXX Should support indefinite-length sequences */
|
||||
return l;
|
||||
}
|
||||
PyErr_SetString(PyExc_TypeError, "list() argument must be a sequence");
|
||||
return NULL;
|
||||
return PySequence_List(v);
|
||||
}
|
||||
|
||||
|
||||
|
@ -996,20 +915,20 @@ builtin_slice(self, args)
|
|||
PyObject *self;
|
||||
PyObject *args;
|
||||
{
|
||||
PyObject *start, *stop, *step;
|
||||
PyObject *start, *stop, *step;
|
||||
|
||||
start = stop = step = NULL;
|
||||
start = stop = step = NULL;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "O|OO:slice", &start, &stop, &step))
|
||||
return NULL;
|
||||
if (!PyArg_ParseTuple(args, "O|OO:slice", &start, &stop, &step))
|
||||
return NULL;
|
||||
|
||||
/*This swapping of stop and start is to maintain compatibility with
|
||||
the range builtin.*/
|
||||
if (stop == NULL) {
|
||||
stop = start;
|
||||
start = NULL;
|
||||
}
|
||||
return PySlice_New(start, stop, step);
|
||||
/* This swapping of stop and start is to maintain similarity with
|
||||
range(). */
|
||||
if (stop == NULL) {
|
||||
stop = start;
|
||||
start = NULL;
|
||||
}
|
||||
return PySlice_New(start, stop, step);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
|
@ -1032,19 +951,10 @@ builtin_long(self, args)
|
|||
PyObject *args;
|
||||
{
|
||||
PyObject *v;
|
||||
PyNumberMethods *nb;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "O:long", &v))
|
||||
return NULL;
|
||||
if (PyString_Check(v))
|
||||
return long_from_string(v);
|
||||
if ((nb = v->ob_type->tp_as_number) == NULL ||
|
||||
nb->nb_long == NULL) {
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"long() argument can't be converted to long");
|
||||
return NULL;
|
||||
}
|
||||
return (*nb->nb_long)(v);
|
||||
return PyNumber_Long(v);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
|
@ -1061,7 +971,7 @@ min_max(args, sign)
|
|||
else if (!PyArg_ParseTuple(args, "O:min/max", &v))
|
||||
return NULL;
|
||||
sq = v->ob_type->tp_as_sequence;
|
||||
if (sq == NULL) {
|
||||
if (sq == NULL || sq->sq_item == NULL) {
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"min() or max() of non-sequence");
|
||||
return NULL;
|
||||
|
@ -1165,80 +1075,16 @@ builtin_ord(self, args)
|
|||
return PyInt_FromLong((long)(c & 0xff));
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
do_pow(v, w)
|
||||
PyObject *v, *w;
|
||||
{
|
||||
PyObject *res;
|
||||
if (PyInstance_Check(v) || PyInstance_Check(w))
|
||||
return PyInstance_DoBinOp(v, w, "__pow__", "__rpow__", do_pow);
|
||||
if (v->ob_type->tp_as_number == NULL ||
|
||||
w->ob_type->tp_as_number == NULL) {
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"pow() requires numeric arguments");
|
||||
return NULL;
|
||||
}
|
||||
if (
|
||||
#ifndef WITHOUT_COMPLEX
|
||||
!PyComplex_Check(v) &&
|
||||
#endif
|
||||
PyFloat_Check(w) && PyFloat_AsDouble(v) < 0.0) {
|
||||
if (!PyErr_Occurred())
|
||||
PyErr_SetString(PyExc_ValueError,
|
||||
"negative number to float power");
|
||||
return NULL;
|
||||
}
|
||||
if (PyNumber_Coerce(&v, &w) != 0)
|
||||
return NULL;
|
||||
res = (*v->ob_type->tp_as_number->nb_power)(v, w, Py_None);
|
||||
Py_DECREF(v);
|
||||
Py_DECREF(w);
|
||||
return res;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
builtin_pow(self, args)
|
||||
PyObject *self;
|
||||
PyObject *args;
|
||||
{
|
||||
PyObject *v, *w, *z = Py_None, *res;
|
||||
PyObject *v1, *z1, *w2, *z2;
|
||||
PyObject *v, *w, *z = Py_None;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "OO|O:pow", &v, &w, &z))
|
||||
return NULL;
|
||||
if (z == Py_None)
|
||||
return do_pow(v, w);
|
||||
/* XXX The ternary version doesn't do class instance coercions */
|
||||
if (PyInstance_Check(v))
|
||||
return v->ob_type->tp_as_number->nb_power(v, w, z);
|
||||
if (v->ob_type->tp_as_number == NULL ||
|
||||
z->ob_type->tp_as_number == NULL ||
|
||||
w->ob_type->tp_as_number == NULL) {
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"pow() requires numeric arguments");
|
||||
return NULL;
|
||||
}
|
||||
if (PyNumber_Coerce(&v, &w) != 0)
|
||||
return NULL;
|
||||
res = NULL;
|
||||
v1 = v;
|
||||
z1 = z;
|
||||
if (PyNumber_Coerce(&v1, &z1) != 0)
|
||||
goto error2;
|
||||
w2 = w;
|
||||
z2 = z1;
|
||||
if (PyNumber_Coerce(&w2, &z2) != 0)
|
||||
goto error1;
|
||||
res = (*v1->ob_type->tp_as_number->nb_power)(v1, w2, z2);
|
||||
Py_DECREF(w2);
|
||||
Py_DECREF(z2);
|
||||
error1:
|
||||
Py_DECREF(v1);
|
||||
Py_DECREF(z1);
|
||||
error2:
|
||||
Py_DECREF(v);
|
||||
Py_DECREF(w);
|
||||
return res;
|
||||
return PyNumber_Power(v, w, z);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
|
@ -1401,7 +1247,8 @@ builtin_reduce(self, args)
|
|||
if (result != NULL)
|
||||
Py_INCREF(result);
|
||||
|
||||
if ((sqf = seq->ob_type->tp_as_sequence) == NULL) {
|
||||
sqf = seq->ob_type->tp_as_sequence;
|
||||
if (sqf == NULL || sqf->sq_item == NULL) {
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"2nd argument to reduce() must be a sequence object");
|
||||
return NULL;
|
||||
|
@ -1528,57 +1375,7 @@ builtin_tuple(self, args)
|
|||
|
||||
if (!PyArg_ParseTuple(args, "O:tuple", &v))
|
||||
return NULL;
|
||||
if (PyTuple_Check(v)) {
|
||||
Py_INCREF(v);
|
||||
return v;
|
||||
}
|
||||
if (PyList_Check(v))
|
||||
return PyList_AsTuple(v);
|
||||
if (PyString_Check(v)) {
|
||||
int n = PyString_Size(v);
|
||||
PyObject *t = PyTuple_New(n);
|
||||
if (t != NULL) {
|
||||
int i;
|
||||
char *p = PyString_AsString(v);
|
||||
for (i = 0; i < n; i++) {
|
||||
PyObject *item =
|
||||
PyString_FromStringAndSize(p+i, 1);
|
||||
if (item == NULL) {
|
||||
Py_DECREF(t);
|
||||
t = NULL;
|
||||
break;
|
||||
}
|
||||
PyTuple_SetItem(t, i, item);
|
||||
}
|
||||
}
|
||||
return t;
|
||||
}
|
||||
/* Generic sequence object */
|
||||
if ((sqf = v->ob_type->tp_as_sequence) != NULL) {
|
||||
int n = (*sqf->sq_length)(v);
|
||||
int i;
|
||||
PyObject *t;
|
||||
if (n < 0)
|
||||
return NULL;
|
||||
t = PyTuple_New(n);
|
||||
if (t == NULL)
|
||||
return NULL;
|
||||
for (i = 0; i < n; i++) {
|
||||
PyObject *item = (*sqf->sq_item)(v, i);
|
||||
if (item == NULL) {
|
||||
Py_DECREF(t);
|
||||
t = NULL;
|
||||
break;
|
||||
}
|
||||
PyTuple_SetItem(t, i, item);
|
||||
}
|
||||
/* XXX Should support indefinite-length sequences */
|
||||
return t;
|
||||
}
|
||||
/* None of the above */
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"tuple() argument must be a sequence");
|
||||
return NULL;
|
||||
return PySequence_Tuple(v);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
|
@ -1815,6 +1612,7 @@ init_class_exc(dict)
|
|||
if (m == NULL ||
|
||||
(d = PyModule_GetDict(m)) == NULL)
|
||||
{
|
||||
/* XXX Should use PySys_WriteStderr here */
|
||||
PyObject *f = PySys_GetObject("stderr");
|
||||
if (Py_VerboseFlag) {
|
||||
PyFile_WriteString(
|
||||
|
@ -2093,117 +1891,3 @@ Fail_1:
|
|||
Py_DECREF(result);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Copied with modifications from stropmodule.c: atoi,atof.atol */
|
||||
|
||||
static PyObject *
|
||||
int_from_string(v)
|
||||
PyObject *v;
|
||||
{
|
||||
extern long PyOS_strtol Py_PROTO((const char *, char **, int));
|
||||
char *s, *end;
|
||||
long x;
|
||||
char buffer[256]; /* For errors */
|
||||
|
||||
s = PyString_AS_STRING(v);
|
||||
while (*s && isspace(Py_CHARMASK(*s)))
|
||||
s++;
|
||||
if (s[0] == '\0') {
|
||||
PyErr_SetString(PyExc_ValueError, "empty string for int()");
|
||||
return NULL;
|
||||
}
|
||||
errno = 0;
|
||||
x = PyOS_strtol(s, &end, 10);
|
||||
while (*end && isspace(Py_CHARMASK(*end)))
|
||||
end++;
|
||||
if (*end != '\0') {
|
||||
sprintf(buffer, "invalid literal for int(): %.200s", s);
|
||||
PyErr_SetString(PyExc_ValueError, buffer);
|
||||
return NULL;
|
||||
}
|
||||
else if (end-s != PyString_GET_SIZE(v)) {
|
||||
PyErr_SetString(PyExc_ValueError,
|
||||
"null byte in argument for int()");
|
||||
return NULL;
|
||||
}
|
||||
else if (errno != 0) {
|
||||
sprintf(buffer, "int() literal too large: %.200s", s);
|
||||
PyErr_SetString(PyExc_ValueError, buffer);
|
||||
return NULL;
|
||||
}
|
||||
return PyInt_FromLong(x);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
long_from_string(v)
|
||||
PyObject *v;
|
||||
{
|
||||
char *s, *end;
|
||||
PyObject *x;
|
||||
char buffer[256]; /* For errors */
|
||||
|
||||
s = PyString_AS_STRING(v);
|
||||
while (*s && isspace(Py_CHARMASK(*s)))
|
||||
s++;
|
||||
if (s[0] == '\0') {
|
||||
PyErr_SetString(PyExc_ValueError, "empty string for long()");
|
||||
return NULL;
|
||||
}
|
||||
x = PyLong_FromString(s, &end, 10);
|
||||
if (x == NULL)
|
||||
return NULL;
|
||||
while (*end && isspace(Py_CHARMASK(*end)))
|
||||
end++;
|
||||
if (*end != '\0') {
|
||||
sprintf(buffer, "invalid literal for long(): %.200s", s);
|
||||
PyErr_SetString(PyExc_ValueError, buffer);
|
||||
Py_DECREF(x);
|
||||
return NULL;
|
||||
}
|
||||
else if (end-s != PyString_GET_SIZE(v)) {
|
||||
PyErr_SetString(PyExc_ValueError,
|
||||
"null byte in argument for float()");
|
||||
return NULL;
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
float_from_string(v)
|
||||
PyObject *v;
|
||||
{
|
||||
extern double strtod Py_PROTO((const char *, char **));
|
||||
char *s, *end;
|
||||
double x;
|
||||
char buffer[256]; /* For errors */
|
||||
|
||||
s = PyString_AS_STRING(v);
|
||||
while (*s && isspace(Py_CHARMASK(*s)))
|
||||
s++;
|
||||
if (s[0] == '\0') {
|
||||
PyErr_SetString(PyExc_ValueError, "empty string for float()");
|
||||
return NULL;
|
||||
}
|
||||
errno = 0;
|
||||
PyFPE_START_PROTECT("float_from_string", return 0)
|
||||
x = strtod(s, &end);
|
||||
PyFPE_END_PROTECT(x)
|
||||
while (*end && isspace(Py_CHARMASK(*end)))
|
||||
end++;
|
||||
if (*end != '\0') {
|
||||
sprintf(buffer, "invalid literal for float(): %.200s", s);
|
||||
PyErr_SetString(PyExc_ValueError, buffer);
|
||||
return NULL;
|
||||
}
|
||||
else if (end-s != PyString_GET_SIZE(v)) {
|
||||
PyErr_SetString(PyExc_ValueError,
|
||||
"null byte in argument for float()");
|
||||
return NULL;
|
||||
}
|
||||
else if (errno != 0) {
|
||||
sprintf(buffer, "float() literal too large: %.200s", s);
|
||||
PyErr_SetString(PyExc_ValueError, buffer);
|
||||
return NULL;
|
||||
}
|
||||
return PyFloat_FromDouble(x);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue