A different approach to the problem reported in
Patch #419651: Metrowerks on Mac adds 0x itself C std says %#x and %#X conversion of 0 do not add the 0x/0X base marker. Metrowerks apparently does. Mark Favas reported the same bug under a Compaq compiler on Tru64 Unix, but no other libc broken in this respect is known (known to be OK under MSVC and gcc). So just try the damn thing at runtime and see what the platform does. Note that we've always had bugs here, but never knew it before because a relevant test case didn't exist before 2.1.
This commit is contained in:
parent
3a80c4a29c
commit
b3d8d1f76c
|
@ -141,8 +141,8 @@ PyObject *PyString_Decode(const char *s,
|
||||||
const char *errors)
|
const char *errors)
|
||||||
{
|
{
|
||||||
PyObject *buffer = NULL, *str;
|
PyObject *buffer = NULL, *str;
|
||||||
|
|
||||||
if (encoding == NULL)
|
if (encoding == NULL)
|
||||||
encoding = PyUnicode_GetDefaultEncoding();
|
encoding = PyUnicode_GetDefaultEncoding();
|
||||||
|
|
||||||
/* Decode via the codec registry */
|
/* Decode via the codec registry */
|
||||||
|
@ -169,7 +169,7 @@ PyObject *PyString_Decode(const char *s,
|
||||||
}
|
}
|
||||||
Py_DECREF(buffer);
|
Py_DECREF(buffer);
|
||||||
return str;
|
return str;
|
||||||
|
|
||||||
onError:
|
onError:
|
||||||
Py_XDECREF(buffer);
|
Py_XDECREF(buffer);
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -181,7 +181,7 @@ PyObject *PyString_Encode(const char *s,
|
||||||
const char *errors)
|
const char *errors)
|
||||||
{
|
{
|
||||||
PyObject *v, *str;
|
PyObject *v, *str;
|
||||||
|
|
||||||
str = PyString_FromStringAndSize(s, size);
|
str = PyString_FromStringAndSize(s, size);
|
||||||
if (str == NULL)
|
if (str == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -195,13 +195,13 @@ PyObject *PyString_AsEncodedString(PyObject *str,
|
||||||
const char *errors)
|
const char *errors)
|
||||||
{
|
{
|
||||||
PyObject *v;
|
PyObject *v;
|
||||||
|
|
||||||
if (!PyString_Check(str)) {
|
if (!PyString_Check(str)) {
|
||||||
PyErr_BadArgument();
|
PyErr_BadArgument();
|
||||||
goto onError;
|
goto onError;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (encoding == NULL)
|
if (encoding == NULL)
|
||||||
encoding = PyUnicode_GetDefaultEncoding();
|
encoding = PyUnicode_GetDefaultEncoding();
|
||||||
|
|
||||||
/* Encode via the codec registry */
|
/* Encode via the codec registry */
|
||||||
|
@ -224,7 +224,7 @@ PyObject *PyString_AsEncodedString(PyObject *str,
|
||||||
goto onError;
|
goto onError;
|
||||||
}
|
}
|
||||||
return v;
|
return v;
|
||||||
|
|
||||||
onError:
|
onError:
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -272,7 +272,7 @@ PyString_AsString(register PyObject *op)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Internal API needed by PyString_AsStringAndSize(): */
|
/* Internal API needed by PyString_AsStringAndSize(): */
|
||||||
extern
|
extern
|
||||||
PyObject *_PyUnicode_AsDefaultEncodedString(PyObject *unicode,
|
PyObject *_PyUnicode_AsDefaultEncodedString(PyObject *unicode,
|
||||||
const char *errors);
|
const char *errors);
|
||||||
|
|
||||||
|
@ -415,7 +415,7 @@ string_concat(register PyStringObject *a, register PyObject *bb)
|
||||||
if (!PyString_Check(bb)) {
|
if (!PyString_Check(bb)) {
|
||||||
if (PyUnicode_Check(bb))
|
if (PyUnicode_Check(bb))
|
||||||
return PyUnicode_Concat((PyObject *)a, bb);
|
return PyUnicode_Concat((PyObject *)a, bb);
|
||||||
PyErr_Format(PyExc_TypeError,
|
PyErr_Format(PyExc_TypeError,
|
||||||
"cannot add type \"%.200s\" to string",
|
"cannot add type \"%.200s\" to string",
|
||||||
bb->ob_type->tp_name);
|
bb->ob_type->tp_name);
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -908,7 +908,7 @@ string_find_internal(PyStringObject *self, PyObject *args, int dir)
|
||||||
int n, i = 0, last = INT_MAX;
|
int n, i = 0, last = INT_MAX;
|
||||||
PyObject *subobj;
|
PyObject *subobj;
|
||||||
|
|
||||||
if (!PyArg_ParseTuple(args, "O|O&O&:find/rfind/index/rindex",
|
if (!PyArg_ParseTuple(args, "O|O&O&:find/rfind/index/rindex",
|
||||||
&subobj, _PyEval_SliceIndex, &i, _PyEval_SliceIndex, &last))
|
&subobj, _PyEval_SliceIndex, &i, _PyEval_SliceIndex, &last))
|
||||||
return -2;
|
return -2;
|
||||||
if (PyString_Check(subobj)) {
|
if (PyString_Check(subobj)) {
|
||||||
|
@ -941,14 +941,14 @@ string_find_internal(PyStringObject *self, PyObject *args, int dir)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
int j;
|
int j;
|
||||||
|
|
||||||
if (n == 0 && i <= last)
|
if (n == 0 && i <= last)
|
||||||
return (long)last;
|
return (long)last;
|
||||||
for (j = last-n; j >= i; --j)
|
for (j = last-n; j >= i; --j)
|
||||||
if (s[j] == sub[0] && memcmp(&s[j], sub, n) == 0)
|
if (s[j] == sub[0] && memcmp(&s[j], sub, n) == 0)
|
||||||
return (long)j;
|
return (long)j;
|
||||||
}
|
}
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1364,7 +1364,7 @@ string_translate(PyStringObject *self, PyObject *args)
|
||||||
tablen = PyString_GET_SIZE(tableobj);
|
tablen = PyString_GET_SIZE(tableobj);
|
||||||
}
|
}
|
||||||
else if (PyUnicode_Check(tableobj)) {
|
else if (PyUnicode_Check(tableobj)) {
|
||||||
/* Unicode .translate() does not support the deletechars
|
/* Unicode .translate() does not support the deletechars
|
||||||
parameter; instead a mapping to None will cause characters
|
parameter; instead a mapping to None will cause characters
|
||||||
to be deleted. */
|
to be deleted. */
|
||||||
if (delobj != NULL) {
|
if (delobj != NULL) {
|
||||||
|
@ -1460,7 +1460,7 @@ string_translate(PyStringObject *self, PyObject *args)
|
||||||
found, or -1 if not found. If len of PAT is greater than length of
|
found, or -1 if not found. If len of PAT is greater than length of
|
||||||
MEM, the function returns -1.
|
MEM, the function returns -1.
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
mymemfind(const char *mem, int len, const char *pat, int pat_len)
|
mymemfind(const char *mem, int len, const char *pat, int pat_len)
|
||||||
{
|
{
|
||||||
register int ii;
|
register int ii;
|
||||||
|
@ -1483,7 +1483,7 @@ mymemfind(const char *mem, int len, const char *pat, int pat_len)
|
||||||
meaning mem=1111 and pat==11 returns 2.
|
meaning mem=1111 and pat==11 returns 2.
|
||||||
mem=11111 and pat==11 also return 2.
|
mem=11111 and pat==11 also return 2.
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
mymemcnt(const char *mem, int len, const char *pat, int pat_len)
|
mymemcnt(const char *mem, int len, const char *pat, int pat_len)
|
||||||
{
|
{
|
||||||
register int offset = 0;
|
register int offset = 0;
|
||||||
|
@ -1605,7 +1605,7 @@ string_replace(PyStringObject *self, PyObject *args)
|
||||||
sub_len = PyString_GET_SIZE(subobj);
|
sub_len = PyString_GET_SIZE(subobj);
|
||||||
}
|
}
|
||||||
else if (PyUnicode_Check(subobj))
|
else if (PyUnicode_Check(subobj))
|
||||||
return PyUnicode_Replace((PyObject *)self,
|
return PyUnicode_Replace((PyObject *)self,
|
||||||
subobj, replobj, count);
|
subobj, replobj, count);
|
||||||
else if (PyObject_AsCharBuffer(subobj, &sub, &sub_len))
|
else if (PyObject_AsCharBuffer(subobj, &sub, &sub_len))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -1615,7 +1615,7 @@ string_replace(PyStringObject *self, PyObject *args)
|
||||||
repl_len = PyString_GET_SIZE(replobj);
|
repl_len = PyString_GET_SIZE(replobj);
|
||||||
}
|
}
|
||||||
else if (PyUnicode_Check(replobj))
|
else if (PyUnicode_Check(replobj))
|
||||||
return PyUnicode_Replace((PyObject *)self,
|
return PyUnicode_Replace((PyObject *)self,
|
||||||
subobj, replobj, count);
|
subobj, replobj, count);
|
||||||
else if (PyObject_AsCharBuffer(replobj, &repl, &repl_len))
|
else if (PyObject_AsCharBuffer(replobj, &repl, &repl_len))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -1669,7 +1669,7 @@ string_startswith(PyStringObject *self, PyObject *args)
|
||||||
}
|
}
|
||||||
else if (PyUnicode_Check(subobj)) {
|
else if (PyUnicode_Check(subobj)) {
|
||||||
int rc;
|
int rc;
|
||||||
rc = PyUnicode_Tailmatch((PyObject *)self,
|
rc = PyUnicode_Tailmatch((PyObject *)self,
|
||||||
subobj, start, end, -1);
|
subobj, start, end, -1);
|
||||||
if (rc == -1)
|
if (rc == -1)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -1727,7 +1727,7 @@ string_endswith(PyStringObject *self, PyObject *args)
|
||||||
}
|
}
|
||||||
else if (PyUnicode_Check(subobj)) {
|
else if (PyUnicode_Check(subobj)) {
|
||||||
int rc;
|
int rc;
|
||||||
rc = PyUnicode_Tailmatch((PyObject *)self,
|
rc = PyUnicode_Tailmatch((PyObject *)self,
|
||||||
subobj, start, end, +1);
|
subobj, start, end, +1);
|
||||||
if (rc == -1)
|
if (rc == -1)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -1829,9 +1829,9 @@ string_expandtabs(PyStringObject *self, PyObject *args)
|
||||||
return u;
|
return u;
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
PyObject *pad(PyStringObject *self,
|
PyObject *pad(PyStringObject *self,
|
||||||
int left,
|
int left,
|
||||||
int right,
|
int right,
|
||||||
char fill)
|
char fill)
|
||||||
{
|
{
|
||||||
|
@ -1847,13 +1847,13 @@ PyObject *pad(PyStringObject *self,
|
||||||
return (PyObject *)self;
|
return (PyObject *)self;
|
||||||
}
|
}
|
||||||
|
|
||||||
u = PyString_FromStringAndSize(NULL,
|
u = PyString_FromStringAndSize(NULL,
|
||||||
left + PyString_GET_SIZE(self) + right);
|
left + PyString_GET_SIZE(self) + right);
|
||||||
if (u) {
|
if (u) {
|
||||||
if (left)
|
if (left)
|
||||||
memset(PyString_AS_STRING(u), fill, left);
|
memset(PyString_AS_STRING(u), fill, left);
|
||||||
memcpy(PyString_AS_STRING(u) + left,
|
memcpy(PyString_AS_STRING(u) + left,
|
||||||
PyString_AS_STRING(self),
|
PyString_AS_STRING(self),
|
||||||
PyString_GET_SIZE(self));
|
PyString_GET_SIZE(self));
|
||||||
if (right)
|
if (right)
|
||||||
memset(PyString_AS_STRING(u) + left + PyString_GET_SIZE(self),
|
memset(PyString_AS_STRING(u) + left + PyString_GET_SIZE(self),
|
||||||
|
@ -2308,7 +2308,7 @@ string_splitlines(PyStringObject *self, PyObject *args)
|
||||||
#undef SPLIT_APPEND
|
#undef SPLIT_APPEND
|
||||||
|
|
||||||
|
|
||||||
static PyMethodDef
|
static PyMethodDef
|
||||||
string_methods[] = {
|
string_methods[] = {
|
||||||
/* Counterparts of the obsolete stropmodule functions; except
|
/* Counterparts of the obsolete stropmodule functions; except
|
||||||
string.maketrans(). */
|
string.maketrans(). */
|
||||||
|
@ -2494,7 +2494,7 @@ formatfloat(char *buf, size_t buflen, int flags,
|
||||||
/* worst case length calc to ensure no buffer overrun:
|
/* worst case length calc to ensure no buffer overrun:
|
||||||
fmt = %#.<prec>g
|
fmt = %#.<prec>g
|
||||||
buf = '-' + [0-9]*prec + '.' + 'e+' + (longest exp
|
buf = '-' + [0-9]*prec + '.' + 'e+' + (longest exp
|
||||||
for any double rep.)
|
for any double rep.)
|
||||||
len = 1 + prec + 1 + 2 + 5 = 9 + prec
|
len = 1 + prec + 1 + 2 + 5 = 9 + prec
|
||||||
If prec=0 the effective precision is 1 (the leading digit is
|
If prec=0 the effective precision is 1 (the leading digit is
|
||||||
always given), therefore increase by one to 10+prec. */
|
always given), therefore increase by one to 10+prec. */
|
||||||
|
@ -2517,7 +2517,7 @@ formatfloat(char *buf, size_t buflen, int flags,
|
||||||
* The string starting at *pbuf is of the form
|
* The string starting at *pbuf is of the form
|
||||||
* "-"? ("0x" | "0X")? digit+
|
* "-"? ("0x" | "0X")? digit+
|
||||||
* "0x"/"0X" are present only for x and X conversions, with F_ALT
|
* "0x"/"0X" are present only for x and X conversions, with F_ALT
|
||||||
* set in flags. The case of hex digits will be correct,
|
* set in flags. The case of hex digits will be correct,
|
||||||
* There will be at least prec digits, zero-filled on the left if
|
* There will be at least prec digits, zero-filled on the left if
|
||||||
* necessary to get that many.
|
* necessary to get that many.
|
||||||
* val object to be converted
|
* val object to be converted
|
||||||
|
@ -2673,9 +2673,15 @@ formatint(char *buf, size_t buflen, int flags,
|
||||||
/* When converting 0 under %#x or %#X, C leaves off the base marker,
|
/* When converting 0 under %#x or %#X, C leaves off the base marker,
|
||||||
* but we want it (for consistency with other %#x conversions, and
|
* but we want it (for consistency with other %#x conversions, and
|
||||||
* for consistency with Python's hex() function).
|
* for consistency with Python's hex() function).
|
||||||
|
* BUG 28-Apr-2001 tim: At least two platform Cs (Metrowerks &
|
||||||
|
* Compaq Tru64) violate the std by converting 0 w/ leading 0x anyway.
|
||||||
|
* So add it only if the platform didn't already.
|
||||||
*/
|
*/
|
||||||
if (x == 0 && (flags & F_ALT) && (type == 'x' || type == 'X')) {
|
if (x == 0 &&
|
||||||
assert(buf[1] != type); /* else this C *is* adding 0x/0X */
|
(flags & F_ALT) &&
|
||||||
|
(type == 'x' || type == 'X') &&
|
||||||
|
buf[1] != (char)type) /* this last always true under std C */
|
||||||
|
{
|
||||||
memmove(buf+2, buf, strlen(buf) + 1);
|
memmove(buf+2, buf, strlen(buf) + 1);
|
||||||
buf[0] = '0';
|
buf[0] = '0';
|
||||||
buf[1] = (char)type;
|
buf[1] = (char)type;
|
||||||
|
@ -2768,7 +2774,7 @@ PyString_Format(PyObject *format, PyObject *args)
|
||||||
int len;
|
int len;
|
||||||
char formatbuf[FORMATBUFLEN]; /* For format{float,int,char}() */
|
char formatbuf[FORMATBUFLEN]; /* For format{float,int,char}() */
|
||||||
char *fmt_start = fmt;
|
char *fmt_start = fmt;
|
||||||
|
|
||||||
fmt++;
|
fmt++;
|
||||||
if (*fmt == '(') {
|
if (*fmt == '(') {
|
||||||
char *keystart;
|
char *keystart;
|
||||||
|
@ -2778,7 +2784,7 @@ PyString_Format(PyObject *format, PyObject *args)
|
||||||
|
|
||||||
if (dict == NULL) {
|
if (dict == NULL) {
|
||||||
PyErr_SetString(PyExc_TypeError,
|
PyErr_SetString(PyExc_TypeError,
|
||||||
"format requires a mapping");
|
"format requires a mapping");
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
++fmt;
|
++fmt;
|
||||||
|
@ -3125,7 +3131,7 @@ PyString_Format(PyObject *format, PyObject *args)
|
||||||
Py_DECREF(v);
|
Py_DECREF(v);
|
||||||
Py_DECREF(args);
|
Py_DECREF(args);
|
||||||
return w;
|
return w;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
Py_DECREF(result);
|
Py_DECREF(result);
|
||||||
if (args_owned) {
|
if (args_owned) {
|
||||||
|
|
|
@ -4737,6 +4737,7 @@ formatint(Py_UNICODE *buf,
|
||||||
+ 1 + 1 = 24*/
|
+ 1 + 1 = 24*/
|
||||||
char fmt[64]; /* plenty big enough! */
|
char fmt[64]; /* plenty big enough! */
|
||||||
long x;
|
long x;
|
||||||
|
int use_native_c_format = 1;
|
||||||
|
|
||||||
x = PyInt_AsLong(v);
|
x = PyInt_AsLong(v);
|
||||||
if (x == -1 && PyErr_Occurred())
|
if (x == -1 && PyErr_Occurred())
|
||||||
|
@ -4753,11 +4754,21 @@ formatint(Py_UNICODE *buf,
|
||||||
/* When converting 0 under %#x or %#X, C leaves off the base marker,
|
/* When converting 0 under %#x or %#X, C leaves off the base marker,
|
||||||
* but we want it (for consistency with other %#x conversions, and
|
* but we want it (for consistency with other %#x conversions, and
|
||||||
* for consistency with Python's hex() function).
|
* for consistency with Python's hex() function).
|
||||||
|
* BUG 28-Apr-2001 tim: At least two platform Cs (Metrowerks &
|
||||||
|
* Compaq Tru64) violate the std by converting 0 w/ leading 0x anyway.
|
||||||
|
* So add it only if the platform doesn't already.
|
||||||
*/
|
*/
|
||||||
if (x == 0 && (flags & F_ALT) && (type == 'x' || type == 'X'))
|
if (x == 0 && (flags & F_ALT) && (type == 'x' || type == 'X')) {
|
||||||
sprintf(fmt, "0%c%%%s.%dl%c", type, "#", prec, type);
|
/* Only way to know what the platform does is to try it. */
|
||||||
else
|
sprintf(fmt, type == 'x' ? "%#x" : "%#X", 0);
|
||||||
sprintf(fmt, "%%%s.%dl%c", (flags & F_ALT) ? "#" : "", prec, type);
|
if (fmt[1] != (char)type) {
|
||||||
|
/* Supply our own leading 0x/0X -- needed under std C */
|
||||||
|
use_native_c_format = 0;
|
||||||
|
sprintf(fmt, "0%c%%#.%dl%c", type, prec, type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (use_native_c_format)
|
||||||
|
sprintf(fmt, "%%%s.%dl%c", (flags & F_ALT) ? "#" : "", prec, type);
|
||||||
return usprintf(buf, fmt, x);
|
return usprintf(buf, fmt, x);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue