Commit dc914e07 authored by Kevin Modzelewski's avatar Kevin Modzelewski

Copied over CPython's str.__mod__

parent c3a27c8b
...@@ -271,6 +271,21 @@ typedef ssize_t Py_ssize_t; ...@@ -271,6 +271,21 @@ typedef ssize_t Py_ssize_t;
#endif #endif
#endif #endif
#if defined(_MSC_VER)
#define Py_MEMCPY(target, source, length) do { \
size_t i_, n_ = (length); \
char *t_ = (void*) (target); \
const char *s_ = (void*) (source); \
if (n_ >= 16) \
memcpy(t_, s_, n_); \
else \
for (i_ = 0; i_ < n_; i_++) \
t_[i_] = s_[i_]; \
} while (0)
#else
#define Py_MEMCPY memcpy
#endif
#endif /* Py_PYPORT_H */ #endif /* Py_PYPORT_H */
...@@ -86,8 +86,9 @@ PyAPI_FUNC(void) PyString_ConcatAndDel(PyObject **, PyObject *); ...@@ -86,8 +86,9 @@ PyAPI_FUNC(void) PyString_ConcatAndDel(PyObject **, PyObject *);
PyAPI_FUNC(int) _PyString_Resize(PyObject **, Py_ssize_t); PyAPI_FUNC(int) _PyString_Resize(PyObject **, Py_ssize_t);
PyAPI_FUNC(int) _PyString_Eq(PyObject *, PyObject*); PyAPI_FUNC(int) _PyString_Eq(PyObject *, PyObject*);
PyAPI_FUNC(PyObject *) PyString_Format(PyObject *, PyObject *); PyAPI_FUNC(PyObject *) PyString_Format(PyObject *, PyObject *);
// Pyston change: added const
PyAPI_FUNC(PyObject *) _PyString_FormatLong(PyObject*, int, int, PyAPI_FUNC(PyObject *) _PyString_FormatLong(PyObject*, int, int,
int, char**, int*); int, const char**, int*);
PyAPI_FUNC(PyObject *) PyString_DecodeEscape(const char *, Py_ssize_t, PyAPI_FUNC(PyObject *) PyString_DecodeEscape(const char *, Py_ssize_t,
const char *, Py_ssize_t, const char *, Py_ssize_t,
const char *); const char *);
......
...@@ -725,8 +725,15 @@ extern "C" void PyMem_Free(void* ptr) { ...@@ -725,8 +725,15 @@ extern "C" void PyMem_Free(void* ptr) {
gc_compat_free(ptr); gc_compat_free(ptr);
} }
extern "C" int PyNumber_Check(PyObject*) { extern "C" int PyNumber_Check(PyObject* obj) {
Py_FatalError("unimplemented"); assert(obj && obj->cls);
// Our check, since we don't currently fill in tp_as_number:
if (isSubclass(obj->cls, int_cls) || isSubclass(obj->cls, long_cls))
return true;
// The CPython check:
return obj->cls->tp_as_number && (obj->cls->tp_as_number->nb_int || obj->cls->tp_as_number->nb_float);
} }
extern "C" PyObject* PyNumber_Add(PyObject* lhs, PyObject* rhs) { extern "C" PyObject* PyNumber_Add(PyObject* lhs, PyObject* rhs) {
......
...@@ -62,6 +62,10 @@ extern "C" PyAPI_FUNC(PyObject*) _PyInt_Format(PyIntObject* v, int base, int new ...@@ -62,6 +62,10 @@ extern "C" PyAPI_FUNC(PyObject*) _PyInt_Format(PyIntObject* v, int base, int new
Py_FatalError("unimplemented"); Py_FatalError("unimplemented");
} }
extern "C" int _PyInt_AsInt(PyObject*) {
Py_FatalError("unimplemented");
}
BoxedInt* interned_ints[NUM_INTERNED_INTS]; BoxedInt* interned_ints[NUM_INTERNED_INTS];
// If we don't have fast overflow-checking builtins, provide some slow variants: // If we don't have fast overflow-checking builtins, provide some slow variants:
......
...@@ -47,203 +47,621 @@ extern "C" BoxedString* strAdd(BoxedString* lhs, Box* _rhs) { ...@@ -47,203 +47,621 @@ extern "C" BoxedString* strAdd(BoxedString* lhs, Box* _rhs) {
return new BoxedString(lhs->s + rhs->s); return new BoxedString(lhs->s + rhs->s);
} }
extern "C" Box* strMod(BoxedString* lhs, Box* rhs) { /* Format codes
assert(lhs->cls == str_cls); * F_LJUST '-'
* F_SIGN '+'
const BoxedTuple::GCVector* elts; * F_BLANK ' '
BoxedTuple::GCVector _elts; * F_ALT '#'
if (rhs->cls == tuple_cls) { * F_ZERO '0'
elts = &static_cast<BoxedTuple*>(rhs)->elts; */
} else { #define F_LJUST (1 << 0)
elts = &_elts; #define F_SIGN (1 << 1)
_elts.push_back(rhs); #define F_BLANK (1 << 2)
#define F_ALT (1 << 3)
#define F_ZERO (1 << 4)
Py_LOCAL_INLINE(PyObject*) getnextarg(PyObject* args, Py_ssize_t arglen, Py_ssize_t* p_argidx) {
Py_ssize_t argidx = *p_argidx;
if (argidx < arglen) {
(*p_argidx)++;
if (arglen < 0)
return args;
else
return PyTuple_GetItem(args, argidx);
} }
PyErr_SetString(PyExc_TypeError, "not enough arguments for format string");
return NULL;
}
BoxedDict* dict = NULL; extern "C" PyObject* _PyString_FormatLong(PyObject*, int, int, int, const char**, int*) {
if (rhs->cls == dict_cls) Py_FatalError("unimplemented");
dict = static_cast<BoxedDict*>(rhs); }
const char* fmt = lhs->s.c_str(); static PyObject* formatfloat(PyObject* v, int flags, int prec, int type) {
const char* fmt_end = fmt + lhs->s.size(); char* p;
PyObject* result;
double x;
int elt_num = 0; x = PyFloat_AsDouble(v);
int num_elts = elts->size(); if (x == -1.0 && PyErr_Occurred()) {
PyErr_Format(PyExc_TypeError, "float argument required, "
"not %.200s",
Py_TYPE(v)->tp_name);
return NULL;
}
std::ostringstream os(""); if (prec < 0)
while (fmt < fmt_end) { prec = 6;
if (*fmt != '%') {
os << (*fmt);
fmt++;
} else {
fmt++;
int nspace = 0; p = PyOS_double_to_string(x, type, prec, (flags & F_ALT) ? Py_DTSF_ALT : 0, NULL);
int ndot = 0;
int nzero = 0;
int mode = 0;
while (true) {
RELEASE_ASSERT(fmt < fmt_end, "");
Box* val_to_use = NULL; if (p == NULL)
if (*fmt == '(') { return NULL;
if (dict == NULL) result = PyString_FromStringAndSize(p, strlen(p));
raiseExcHelper(TypeError, "format requires a mapping"); PyMem_Free(p);
return result;
}
int pcount = 1; Py_LOCAL_INLINE(int) formatint(char* buf, size_t buflen, int flags, int prec, int type, PyObject* v) {
fmt++; /* fmt = '%#.' + `prec` + 'l' + `type`
const char* keystart = fmt; worst case length = 3 + 19 (worst len of INT_MAX on 64-bit machine)
+ 1 + 1 = 24 */
while (pcount > 0 && fmt < fmt_end) { char fmt[64]; /* plenty big enough! */
char c = *fmt; const char* sign;
if (c == ')') long x;
pcount--;
else if (c == '(') x = PyInt_AsLong(v);
pcount++; if (x == -1 && PyErr_Occurred()) {
fmt++; PyErr_Format(PyExc_TypeError, "int argument required, not %.200s", Py_TYPE(v)->tp_name);
return -1;
}
if (x < 0 && type == 'u') {
type = 'd';
}
if (x < 0 && (type == 'x' || type == 'X' || type == 'o'))
sign = "-";
else
sign = "";
if (prec < 0)
prec = 1;
if ((flags & F_ALT) && (type == 'x' || type == 'X')) {
/* When converting under %#x or %#X, there are a number
* of issues that cause pain:
* - when 0 is being converted, the C standard leaves off
* the '0x' or '0X', which is inconsistent with other
* %#x/%#X conversions and inconsistent with Python's
* hex() function
* - there are platforms that violate the standard and
* convert 0 with the '0x' or '0X'
* (Metrowerks, Compaq Tru64)
* - there are platforms that give '0x' when converting
* under %#X, but convert 0 in accordance with the
* standard (OS/2 EMX)
*
* We can achieve the desired consistency by inserting our
* own '0x' or '0X' prefix, and substituting %x/%X in place
* of %#x/%#X.
*
* Note that this is the same approach as used in
* formatint() in unicodeobject.c
*/
PyOS_snprintf(fmt, sizeof(fmt), "%s0%c%%.%dl%c", sign, type, prec, type);
} else {
PyOS_snprintf(fmt, sizeof(fmt), "%s%%%s.%dl%c", sign, (flags & F_ALT) ? "#" : "", prec, type);
} }
if (pcount > 0) /* buf = '+'/'-'/'' + '0'/'0x'/'' + '[0-9]'*max(prec, len(x in octal))
raiseExcHelper(ValueError, "incomplete format key"); * worst case buf = '-0x' + [0-9]*prec, where prec >= 11
*/
if (buflen <= 14 || buflen <= (size_t)3 + (size_t)prec) {
PyErr_SetString(PyExc_OverflowError, "formatted integer is too long (precision too large?)");
return -1;
}
if (sign[0])
PyOS_snprintf(buf, buflen, fmt, -x);
else
PyOS_snprintf(buf, buflen, fmt, x);
return (int)strlen(buf);
}
Py_LOCAL_INLINE(int) formatchar(char* buf, size_t buflen, PyObject* v) {
/* presume that the buffer is at least 2 characters long */
if (PyString_Check(v)) {
if (!PyArg_Parse(v, "c;%c requires int or char", &buf[0]))
return -1;
} else {
if (!PyArg_Parse(v, "b;%c requires int or char", &buf[0]))
return -1;
}
buf[1] = '\0';
return 1;
}
BoxedString* key = boxStrConstantSize(keystart, fmt - keystart - 1); #define FORMATBUFLEN (size_t)120
val_to_use = dictGetitem(dict, key); extern "C" PyObject* PyString_Format(PyObject* format, PyObject* args) {
char* fmt, *res;
Py_ssize_t arglen, argidx;
Py_ssize_t reslen, rescnt, fmtcnt;
int args_owned = 0;
PyObject* result, *orig_args;
#ifdef Py_USING_UNICODE
PyObject* v, *w;
#endif
PyObject* dict = NULL;
if (format == NULL || !PyString_Check(format) || args == NULL) {
PyErr_BadInternalCall();
return NULL;
}
orig_args = args;
fmt = PyString_AS_STRING(format);
fmtcnt = PyString_GET_SIZE(format);
reslen = rescnt = fmtcnt + 100;
result = PyString_FromStringAndSize((char*)NULL, reslen);
if (result == NULL)
return NULL;
res = PyString_AsString(result);
if (PyTuple_Check(args)) {
arglen = PyTuple_GET_SIZE(args);
argidx = 0;
} else {
arglen = -1;
argidx = -2;
} }
if (Py_TYPE(args)->tp_as_mapping && Py_TYPE(args)->tp_as_mapping->mp_subscript && !PyTuple_Check(args)
&& !PyObject_TypeCheck(args, &PyBaseString_Type))
dict = args;
while (--fmtcnt >= 0) {
if (*fmt != '%') {
if (--rescnt < 0) {
rescnt = fmtcnt + 100;
reslen += rescnt;
if (_PyString_Resize(&result, reslen))
return NULL;
res = PyString_AS_STRING(result) + reslen - rescnt;
--rescnt;
}
*res++ = *fmt++;
} else {
/* Got a format specifier */
int flags = 0;
Py_ssize_t width = -1;
int prec = -1;
int c = '\0';
int fill;
int isnumok;
PyObject* v = NULL;
PyObject* temp = NULL;
const char* pbuf;
int sign;
Py_ssize_t len;
char formatbuf[FORMATBUFLEN];
/* For format{int,char}() */
#ifdef Py_USING_UNICODE
char* fmt_start = fmt;
Py_ssize_t argidx_start = argidx;
#endif
char c = *fmt;
fmt++; fmt++;
if (*fmt == '(') {
char* keystart;
Py_ssize_t keylen;
PyObject* key;
int pcount = 1;
if (c == ' ') { if (dict == NULL) {
assert(mode == 0); PyErr_SetString(PyExc_TypeError, "format requires a mapping");
mode = 1; goto error;
} else if (c == '.') { }
assert(mode == 0); ++fmt;
mode = 2; --fmtcnt;
} else if (mode == 0 && c == '0') { keystart = fmt;
mode = 3; /* Skip over balanced parentheses */
} else if ('0' <= c && c <= '9') { while (pcount > 0 && --fmtcnt >= 0) {
assert(mode == 1 || mode == 2 || mode == 3); if (*fmt == ')')
if (mode == 1) { --pcount;
nspace = nspace * 10 + c - '0'; else if (*fmt == '(')
} else if (mode == 2) { ++pcount;
ndot = ndot * 10 + c - '0'; fmt++;
} else if (mode == 3) {
nzero = nzero * 10 + c - '0';
} else {
assert(0);
} }
} else if (c == '%') { keylen = fmt - keystart - 1;
for (int i = 1; i < nspace; i++) { if (fmtcnt < 0 || pcount > 0) {
os << ' '; PyErr_SetString(PyExc_ValueError, "incomplete format key");
goto error;
}
key = PyString_FromStringAndSize(keystart, keylen);
if (key == NULL)
goto error;
if (args_owned) {
Py_DECREF(args);
args_owned = 0;
}
args = PyObject_GetItem(dict, key);
Py_DECREF(key);
if (args == NULL) {
goto error;
}
args_owned = 1;
arglen = -1;
argidx = -2;
}
while (--fmtcnt >= 0) {
switch (c = *fmt++) {
case '-':
flags |= F_LJUST;
continue;
case '+':
flags |= F_SIGN;
continue;
case ' ':
flags |= F_BLANK;
continue;
case '#':
flags |= F_ALT;
continue;
case '0':
flags |= F_ZERO;
continue;
} }
os << '%';
break; break;
} else if (c == 's' || c == 'r') {
RELEASE_ASSERT(ndot == 0, "");
RELEASE_ASSERT(nzero == 0, "");
RELEASE_ASSERT(nspace == 0, "");
if (!val_to_use) {
if (elt_num >= num_elts)
raiseExcHelper(TypeError, "not enough arguments for format string");
val_to_use = (*elts)[elt_num];
elt_num++;
} }
if (c == '*') {
BoxedString* s; v = getnextarg(args, arglen, &argidx);
if (c == 's') if (v == NULL)
s = str(val_to_use); goto error;
else if (!PyInt_Check(v)) {
s = repr(val_to_use); PyErr_SetString(PyExc_TypeError, "* wants int");
os << s->s; goto error;
}
width = PyInt_AsSsize_t(v);
if (width == -1 && PyErr_Occurred())
goto error;
if (width < 0) {
flags |= F_LJUST;
width = -width;
}
if (--fmtcnt >= 0)
c = *fmt++;
} else if (c >= 0 && isdigit(c)) {
width = c - '0';
while (--fmtcnt >= 0) {
c = Py_CHARMASK(*fmt++);
if (!isdigit(c))
break;
if (width > (PY_SSIZE_T_MAX - ((int)c - '0')) / 10) {
PyErr_SetString(PyExc_ValueError, "width too big");
goto error;
}
width = width * 10 + (c - '0');
}
}
if (c == '.') {
prec = 0;
if (--fmtcnt >= 0)
c = *fmt++;
if (c == '*') {
v = getnextarg(args, arglen, &argidx);
if (v == NULL)
goto error;
if (!PyInt_Check(v)) {
PyErr_SetString(PyExc_TypeError, "* wants int");
goto error;
}
prec = _PyInt_AsInt(v);
if (prec == -1 && PyErr_Occurred())
goto error;
if (prec < 0)
prec = 0;
if (--fmtcnt >= 0)
c = *fmt++;
} else if (c >= 0 && isdigit(c)) {
prec = c - '0';
while (--fmtcnt >= 0) {
c = Py_CHARMASK(*fmt++);
if (!isdigit(c))
break; break;
} else if (c == 'c') { if (prec > (INT_MAX - ((int)c - '0')) / 10) {
if (!val_to_use) { PyErr_SetString(PyExc_ValueError, "prec too big");
if (elt_num >= num_elts) goto error;
raiseExcHelper(TypeError, "not enough arguments for format string");
val_to_use = (*elts)[elt_num];
elt_num++;
} }
prec = prec * 10 + (c - '0');
RELEASE_ASSERT(isSubclass(val_to_use->cls, int_cls), "unsupported"); }
RELEASE_ASSERT(nspace == 0, "unsupported"); }
RELEASE_ASSERT(ndot == 0, "unsupported"); } /* prec */
RELEASE_ASSERT(nzero == 0, "unsupported"); if (fmtcnt >= 0) {
if (c == 'h' || c == 'l' || c == 'L') {
int64_t n = static_cast<BoxedInt*>(val_to_use)->n; if (--fmtcnt >= 0)
if (n < 0) c = *fmt++;
raiseExcHelper(OverflowError, "unsigned byte integer is less than minimum"); }
if (n >= 256) }
raiseExcHelper(OverflowError, "unsigned byte integer is greater than maximum"); if (fmtcnt < 0) {
os << (char)n; PyErr_SetString(PyExc_ValueError, "incomplete format");
goto error;
}
if (c != '%') {
v = getnextarg(args, arglen, &argidx);
if (v == NULL)
goto error;
}
sign = 0;
fill = ' ';
switch (c) {
case '%':
pbuf = "%";
len = 1;
break; break;
} else if (c == 'd' || c == 'i') { case 's':
if (!val_to_use) { #ifdef Py_USING_UNICODE
if (elt_num >= num_elts) if (PyUnicode_Check(v)) {
raiseExcHelper(TypeError, "not enough arguments for format string"); fmt = fmt_start;
val_to_use = (*elts)[elt_num]; argidx = argidx_start;
elt_num++; goto unicode;
} }
#endif
RELEASE_ASSERT(isSubclass(val_to_use->cls, int_cls), "unsupported"); temp = _PyObject_Str(v);
#ifdef Py_USING_UNICODE
std::ostringstream fmt(""); if (temp != NULL && PyUnicode_Check(temp)) {
fmt << '%'; Py_DECREF(temp);
if (nspace) fmt = fmt_start;
fmt << ' ' << nspace; argidx = argidx_start;
else if (ndot) goto unicode;
fmt << '.' << ndot; }
else if (nzero) #endif
fmt << '0' << nzero; /* Fall through */
fmt << "ld"; case 'r':
if (c == 'r')
char buf[20]; temp = PyObject_Repr(v);
snprintf(buf, 20, fmt.str().c_str(), static_cast<BoxedInt*>(val_to_use)->n); if (temp == NULL)
os << std::string(buf); goto error;
if (!PyString_Check(temp)) {
PyErr_SetString(PyExc_TypeError, "%s argument has non-string str()");
Py_DECREF(temp);
goto error;
}
pbuf = PyString_AS_STRING(temp);
len = PyString_GET_SIZE(temp);
if (prec >= 0 && len > prec)
len = prec;
break; break;
} else if (c == 'f') { case 'i':
if (!val_to_use) { case 'd':
if (elt_num >= num_elts) case 'u':
raiseExcHelper(TypeError, "not enough arguments for format string"); case 'o':
val_to_use = (*elts)[elt_num]; case 'x':
elt_num++; case 'X':
} if (c == 'i')
c = 'd';
double d; isnumok = 0;
if (val_to_use->cls == float_cls) { if (PyNumber_Check(v)) {
d = static_cast<BoxedFloat*>(val_to_use)->d; PyObject* iobj = NULL;
} else if (isSubclass(val_to_use->cls, int_cls)) {
d = static_cast<BoxedInt*>(val_to_use)->n; if (PyInt_Check(v) || (PyLong_Check(v))) {
iobj = v;
Py_INCREF(iobj);
} else { } else {
RELEASE_ASSERT(0, "unsupported"); iobj = PyNumber_Int(v);
} if (iobj == NULL) {
PyErr_Clear();
std::ostringstream fmt(""); iobj = PyNumber_Long(v);
fmt << '%'; }
if (nspace) }
fmt << ' ' << nspace; if (iobj != NULL) {
else if (ndot) if (PyInt_Check(iobj)) {
fmt << '.' << ndot; isnumok = 1;
else if (nzero) pbuf = formatbuf;
fmt << '0' << nzero; // Pyston change:
fmt << "f"; len = formatint(formatbuf /* pbuf */, sizeof(formatbuf), flags, prec, c, iobj);
Py_DECREF(iobj);
char buf[20]; if (len < 0)
snprintf(buf, 20, fmt.str().c_str(), d); goto error;
os << std::string(buf); sign = 1;
break; } else if (PyLong_Check(iobj)) {
int ilen;
isnumok = 1;
temp = _PyString_FormatLong(iobj, flags, prec, c, &pbuf, &ilen);
Py_DECREF(iobj);
len = ilen;
if (!temp)
goto error;
sign = 1;
} else { } else {
RELEASE_ASSERT(0, "unsupported format character '%c'", c); Py_DECREF(iobj);
} }
} }
} }
if (!isnumok) {
PyErr_Format(PyExc_TypeError, "%%%c format: a number is required, "
"not %.200s",
c, Py_TYPE(v)->tp_name);
goto error;
} }
assert(fmt == fmt_end && "incomplete format"); if (flags & F_ZERO)
fill = '0';
if (dict == NULL && elt_num < num_elts) { break;
raiseExcHelper(TypeError, "not all arguments converted during string formatting"); case 'e':
} case 'E':
case 'f':
return boxString(os.str()); case 'F':
case 'g':
case 'G':
temp = formatfloat(v, flags, prec, c);
if (temp == NULL)
goto error;
pbuf = PyString_AS_STRING(temp);
len = PyString_GET_SIZE(temp);
sign = 1;
if (flags & F_ZERO)
fill = '0';
break;
case 'c':
#ifdef Py_USING_UNICODE
if (PyUnicode_Check(v)) {
fmt = fmt_start;
argidx = argidx_start;
goto unicode;
}
#endif
pbuf = formatbuf;
// Pyston change:
len = formatchar(formatbuf /* was pbuf */, sizeof(formatbuf), v);
if (len < 0)
goto error;
break;
default:
PyErr_Format(PyExc_ValueError, "unsupported format character '%c' (0x%x) "
"at index %zd",
c, c, (Py_ssize_t)(fmt - 1 - PyString_AsString(format)));
goto error;
}
if (sign) {
if (*pbuf == '-' || *pbuf == '+') {
sign = *pbuf++;
len--;
} else if (flags & F_SIGN)
sign = '+';
else if (flags & F_BLANK)
sign = ' ';
else
sign = 0;
}
if (width < len)
width = len;
if (rescnt - (sign != 0) < width) {
reslen -= rescnt;
rescnt = width + fmtcnt + 100;
reslen += rescnt;
if (reslen < 0) {
Py_DECREF(result);
Py_XDECREF(temp);
return PyErr_NoMemory();
}
if (_PyString_Resize(&result, reslen)) {
Py_XDECREF(temp);
return NULL;
}
res = PyString_AS_STRING(result) + reslen - rescnt;
}
if (sign) {
if (fill != ' ')
*res++ = sign;
rescnt--;
if (width > len)
width--;
}
if ((flags & F_ALT) && (c == 'x' || c == 'X')) {
assert(pbuf[0] == '0');
assert(pbuf[1] == c);
if (fill != ' ') {
*res++ = *pbuf++;
*res++ = *pbuf++;
}
rescnt -= 2;
width -= 2;
if (width < 0)
width = 0;
len -= 2;
}
if (width > len && !(flags & F_LJUST)) {
do {
--rescnt;
*res++ = fill;
} while (--width > len);
}
if (fill == ' ') {
if (sign)
*res++ = sign;
if ((flags & F_ALT) && (c == 'x' || c == 'X')) {
assert(pbuf[0] == '0');
assert(pbuf[1] == c);
*res++ = *pbuf++;
*res++ = *pbuf++;
}
}
Py_MEMCPY(res, pbuf, len);
res += len;
rescnt -= len;
while (--width >= len) {
--rescnt;
*res++ = ' ';
}
if (dict && (argidx < arglen) && c != '%') {
PyErr_SetString(PyExc_TypeError, "not all arguments converted during string formatting");
Py_XDECREF(temp);
goto error;
}
Py_XDECREF(temp);
} /* '%' */
} /* until end */
if (argidx < arglen && !dict) {
PyErr_SetString(PyExc_TypeError, "not all arguments converted during string formatting");
goto error;
}
if (args_owned) {
Py_DECREF(args);
}
if (_PyString_Resize(&result, reslen - rescnt))
return NULL;
return result;
#ifdef Py_USING_UNICODE
unicode:
if (args_owned) {
Py_DECREF(args);
args_owned = 0;
}
/* Fiddle args right (remove the first argidx arguments) */
if (PyTuple_Check(orig_args) && argidx > 0) {
PyObject* v;
Py_ssize_t n = PyTuple_GET_SIZE(orig_args) - argidx;
v = PyTuple_New(n);
if (v == NULL)
goto error;
while (--n >= 0) {
PyObject* w = PyTuple_GET_ITEM(orig_args, n + argidx);
Py_INCREF(w);
PyTuple_SET_ITEM(v, n, w);
}
args = v;
} else {
Py_INCREF(orig_args);
args = orig_args;
}
args_owned = 1;
/* Take what we have of the result and let the Unicode formatting
function format the rest of the input. */
rescnt = res - PyString_AS_STRING(result);
if (_PyString_Resize(&result, rescnt))
goto error;
fmtcnt = PyString_GET_SIZE(format) - (fmt - PyString_AS_STRING(format));
format = PyUnicode_Decode(fmt, fmtcnt, NULL, NULL);
if (format == NULL)
goto error;
v = PyUnicode_Format(format, args);
Py_DECREF(format);
if (v == NULL)
goto error;
/* Paste what we have (result) to what the Unicode formatting
function returned (v) and return the result (or error) */
w = PyUnicode_Concat(result, v);
Py_DECREF(result);
Py_DECREF(v);
Py_DECREF(args);
return w;
#endif /* Py_USING_UNICODE */
error:
Py_DECREF(result);
if (args_owned) {
Py_DECREF(args);
}
return NULL;
}
extern "C" Box* strMod(BoxedString* lhs, Box* rhs) {
Box* rtn = PyString_Format(lhs, rhs);
checkAndThrowCAPIException();
assert(rtn);
return rtn;
} }
extern "C" Box* strMul(BoxedString* lhs, Box* rhs) { extern "C" Box* strMul(BoxedString* lhs, Box* rhs) {
...@@ -1021,7 +1439,8 @@ BoxedString* createUninitializedString(ssize_t n) { ...@@ -1021,7 +1439,8 @@ BoxedString* createUninitializedString(ssize_t n) {
} }
char* getWriteableStringContents(BoxedString* s) { char* getWriteableStringContents(BoxedString* s) {
ASSERT(s->s.size() > 0, "not sure whether this is valid for strings with zero size"); if (s->s.size() == 0)
return NULL;
// After doing some reading, I think this is ok: // After doing some reading, I think this is ok:
// http://stackoverflow.com/questions/14290795/why-is-modifying-a-string-through-a-retrieved-pointer-to-its-data-not-allowed // http://stackoverflow.com/questions/14290795/why-is-modifying-a-string-through-a-retrieved-pointer-to-its-data-not-allowed
......
...@@ -80,3 +80,4 @@ print "hello world".partition("o") ...@@ -80,3 +80,4 @@ print "hello world".partition("o")
print "hello world"[False:True:True] print "hello world"[False:True:True]
print "{hello}".format(hello="world") print "{hello}".format(hello="world")
print "%.3s" % "hello world"
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