Mainlining the string_methods branch. See branch revision log

messages for specific changes.
This commit is contained in:
Barry Warsaw 1999-10-12 19:54:53 +00:00
parent 75260275fe
commit 226ae6ca12
9 changed files with 1776 additions and 980 deletions

View file

@ -53,123 +53,6 @@ null_error()
return NULL;
}
/* Copied with modifications from stropmodule.c: atoi, atof, atol */
static PyObject *
int_from_string(v)
PyObject *v;
{
char *s, *end;
long x;
char buffer[256]; /* For errors */
s = PyString_AS_STRING(v);
while (*s && isspace(Py_CHARMASK(*s)))
s++;
errno = 0;
x = PyOS_strtol(s, &end, 10);
if (end == s || !isdigit(end[-1]))
goto bad;
while (*end && isspace(Py_CHARMASK(*end)))
end++;
if (*end != '\0') {
bad:
sprintf(buffer, "invalid literal for int(): %.200s", s);
PyErr_SetString(PyExc_ValueError, buffer);
return NULL;
}
else if (end != PyString_AS_STRING(v) + 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++;
x = PyLong_FromString(s, &end, 10);
if (x == NULL) {
if (PyErr_ExceptionMatches(PyExc_ValueError))
goto bad;
return NULL;
}
while (*end && isspace(Py_CHARMASK(*end)))
end++;
if (*end != '\0') {
bad:
sprintf(buffer, "invalid literal for long(): %.200s", s);
PyErr_SetString(PyExc_ValueError, buffer);
Py_XDECREF(x);
return NULL;
}
else if (end != PyString_AS_STRING(v) + PyString_GET_SIZE(v)) {
PyErr_SetString(PyExc_ValueError,
"null byte in argument for long()");
return NULL;
}
return x;
}
static PyObject *
float_from_string(v)
PyObject *v;
{
extern double strtod Py_PROTO((const char *, char **));
char *s, *last, *end;
double x;
char buffer[256]; /* For errors */
s = PyString_AS_STRING(v);
last = s + PyString_GET_SIZE(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)
/* Believe it or not, Solaris 2.6 can move end *beyond* the null
byte at the end of the string, when the input is inf(inity) */
if (end > last)
end = last;
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 != PyString_AS_STRING(v) + 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);
}
/* Operations on any object */
int
@ -713,7 +596,7 @@ PyNumber_Int(o)
if (o == NULL)
return null_error();
if (PyString_Check(o))
return int_from_string(o);
return PyInt_FromString(PyString_AS_STRING(o), NULL, 10);
m = o->ob_type->tp_as_number;
if (m && m->nb_int)
return m->nb_int(o);
@ -721,6 +604,61 @@ PyNumber_Int(o)
return type_error("object can't be converted to int");
}
/* There are two C API functions for converting a string to a long,
* PyNumber_Long() and PyLong_FromString(). Both are used in builtin_long,
* reachable from Python with the built-in function long().
*
* The difference is this: PyNumber_Long will raise an exception when the
* string cannot be converted to a long. The most common situation is
* where a float string is passed in; this raises a ValueError.
* PyLong_FromString does not raise an exception; it silently truncates the
* float to an integer.
*
* You can see the different behavior from Python with the following:
*
* long('9.5')
* => ValueError: invalid literal for long(): 9.5
*
* long('9.5', 10)
* => 9L
*
* The first example ends up calling PyNumber_Long(), while the second one
* calls PyLong_FromString().
*/
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++;
x = PyLong_FromString(s, &end, 10);
if (x == NULL) {
if (PyErr_ExceptionMatches(PyExc_ValueError))
goto bad;
return NULL;
}
while (*end && isspace(Py_CHARMASK(*end)))
end++;
if (*end != '\0') {
bad:
sprintf(buffer, "invalid literal for long(): %.200s", s);
PyErr_SetString(PyExc_ValueError, buffer);
Py_XDECREF(x);
return NULL;
}
else if (end != PyString_AS_STRING(v) + PyString_GET_SIZE(v)) {
PyErr_SetString(PyExc_ValueError,
"null byte in argument for long()");
return NULL;
}
return x;
}
PyObject *
PyNumber_Long(o)
PyObject *o;
@ -730,6 +668,10 @@ PyNumber_Long(o)
if (o == NULL)
return null_error();
if (PyString_Check(o))
/* need to do extra error checking that PyLong_FromString()
* doesn't do. In particular long('9.5') must raise an
* exception, not truncate the float.
*/
return long_from_string(o);
m = o->ob_type->tp_as_number;
if (m && m->nb_long)
@ -747,7 +689,7 @@ PyNumber_Float(o)
if (o == NULL)
return null_error();
if (PyString_Check(o))
return float_from_string(o);
return PyFloat_FromString(o, NULL);
m = o->ob_type->tp_as_number;
if (m && m->nb_float)
return m->nb_float(o);

View file

@ -149,6 +149,57 @@ PyFloat_FromDouble(fval)
return (PyObject *) op;
}
PyObject *
PyFloat_FromString(v, pend)
PyObject *v;
char **pend;
{
extern double strtod Py_PROTO((const char *, char **));
char *s, *last, *end;
double x;
char buffer[256]; /* For errors */
if (!PyString_Check(v))
return NULL;
s = PyString_AS_STRING(v);
last = s + PyString_GET_SIZE(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("PyFloat_FromString", return 0)
x = strtod(s, &end);
PyFPE_END_PROTECT(x)
/* Believe it or not, Solaris 2.6 can move end *beyond* the null
byte at the end of the string, when the input is inf(inity) */
if (end > last)
end = last;
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 != PyString_AS_STRING(v) + 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;
}
if (pend)
*pend = end;
return PyFloat_FromDouble(x);
}
static void
float_dealloc(op)
PyFloatObject *op;

View file

@ -32,6 +32,7 @@ PERFORMANCE OF THIS SOFTWARE.
/* Integer object implementation */
#include "Python.h"
#include <ctype.h>
#ifdef HAVE_LIMITS_H
#include <limits.h>
@ -218,6 +219,48 @@ PyInt_AsLong(op)
return val;
}
PyObject *
PyInt_FromString(s, pend, base)
char *s;
char **pend;
int base;
{
char *end;
long x;
char buffer[256]; /* For errors */
if ((base != 0 && base < 2) || base > 36) {
PyErr_SetString(PyExc_ValueError, "invalid base for int()");
return NULL;
}
while (*s && isspace(Py_CHARMASK(*s)))
s++;
errno = 0;
if (base == 0 && s[0] == '0')
x = (long) PyOS_strtoul(s, &end, base);
else
x = PyOS_strtol(s, &end, base);
if (end == s || !isalnum(end[-1]))
goto bad;
while (*end && isspace(Py_CHARMASK(*end)))
end++;
if (*end != '\0') {
bad:
sprintf(buffer, "invalid literal for int(): %.200s", s);
PyErr_SetString(PyExc_ValueError, buffer);
return NULL;
}
else if (errno != 0) {
sprintf(buffer, "int() literal too large: %.200s", s);
PyErr_SetString(PyExc_ValueError, buffer);
return NULL;
}
if (pend)
*pend = end;
return PyInt_FromLong(x);
}
/* Methods */
/* ARGSUSED */

File diff suppressed because it is too large Load diff