| /* NOTE: this API is -ONLY- for use with single byte character strings. */ | |
| /* Do not use it with Unicode. */ | |
| /* the more complicated methods. parts of these should be pulled out into the | |
| shared code in bytes_methods.c to cut down on duplicate code bloat. */ | |
| PyDoc_STRVAR(expandtabs__doc__, | |
| "B.expandtabs([tabsize]) -> copy of B\n\ | |
| \n\ | |
| Return a copy of B where all tab characters are expanded using spaces.\n\ | |
| If tabsize is not given, a tab size of 8 characters is assumed."); | |
| static PyObject* | |
| stringlib_expandtabs(PyObject *self, PyObject *args) | |
| { | |
| const char *e, *p; | |
| char *q; | |
| size_t i, j; | |
| PyObject *u; | |
| int tabsize = 8; | |
| if (!PyArg_ParseTuple(args, "|i:expandtabs", &tabsize)) | |
| return NULL; | |
| /* First pass: determine size of output string */ | |
| i = j = 0; | |
| e = STRINGLIB_STR(self) + STRINGLIB_LEN(self); | |
| for (p = STRINGLIB_STR(self); p < e; p++) | |
| if (*p == '\t') { | |
| if (tabsize > 0) { | |
| j += tabsize - (j % tabsize); | |
| if (j > PY_SSIZE_T_MAX) { | |
| PyErr_SetString(PyExc_OverflowError, | |
| "result is too long"); | |
| return NULL; | |
| } | |
| } | |
| } | |
| else { | |
| j++; | |
| if (*p == '\n' || *p == '\r') { | |
| i += j; | |
| j = 0; | |
| if (i > PY_SSIZE_T_MAX) { | |
| PyErr_SetString(PyExc_OverflowError, | |
| "result is too long"); | |
| return NULL; | |
| } | |
| } | |
| } | |
| if ((i + j) > PY_SSIZE_T_MAX) { | |
| PyErr_SetString(PyExc_OverflowError, "result is too long"); | |
| return NULL; | |
| } | |
| /* Second pass: create output string and fill it */ | |
| u = STRINGLIB_NEW(NULL, i + j); | |
| if (!u) | |
| return NULL; | |
| j = 0; | |
| q = STRINGLIB_STR(u); | |
| for (p = STRINGLIB_STR(self); p < e; p++) | |
| if (*p == '\t') { | |
| if (tabsize > 0) { | |
| i = tabsize - (j % tabsize); | |
| j += i; | |
| while (i--) | |
| *q++ = ' '; | |
| } | |
| } | |
| else { | |
| j++; | |
| *q++ = *p; | |
| if (*p == '\n' || *p == '\r') | |
| j = 0; | |
| } | |
| return u; | |
| } | |
| Py_LOCAL_INLINE(PyObject *) | |
| pad(PyObject *self, Py_ssize_t left, Py_ssize_t right, char fill) | |
| { | |
| PyObject *u; | |
| if (left < 0) | |
| left = 0; | |
| if (right < 0) | |
| right = 0; | |
| if (left == 0 && right == 0 && STRINGLIB_CHECK_EXACT(self)) { | |
| #if STRINGLIB_MUTABLE | |
| /* We're defined as returning a copy; If the object is mutable | |
| * that means we must make an identical copy. */ | |
| return STRINGLIB_NEW(STRINGLIB_STR(self), STRINGLIB_LEN(self)); | |
| #else | |
| Py_INCREF(self); | |
| return (PyObject *)self; | |
| #endif /* STRINGLIB_MUTABLE */ | |
| } | |
| u = STRINGLIB_NEW(NULL, | |
| left + STRINGLIB_LEN(self) + right); | |
| if (u) { | |
| if (left) | |
| memset(STRINGLIB_STR(u), fill, left); | |
| Py_MEMCPY(STRINGLIB_STR(u) + left, | |
| STRINGLIB_STR(self), | |
| STRINGLIB_LEN(self)); | |
| if (right) | |
| memset(STRINGLIB_STR(u) + left + STRINGLIB_LEN(self), | |
| fill, right); | |
| } | |
| return u; | |
| } | |
| PyDoc_STRVAR(ljust__doc__, | |
| "B.ljust(width[, fillchar]) -> copy of B\n" | |
| "\n" | |
| "Return B left justified in a string of length width. Padding is\n" | |
| "done using the specified fill character (default is a space)."); | |
| static PyObject * | |
| stringlib_ljust(PyObject *self, PyObject *args) | |
| { | |
| Py_ssize_t width; | |
| char fillchar = ' '; | |
| if (!PyArg_ParseTuple(args, "n|c:ljust", &width, &fillchar)) | |
| return NULL; | |
| if (STRINGLIB_LEN(self) >= width && STRINGLIB_CHECK_EXACT(self)) { | |
| #if STRINGLIB_MUTABLE | |
| /* We're defined as returning a copy; If the object is mutable | |
| * that means we must make an identical copy. */ | |
| return STRINGLIB_NEW(STRINGLIB_STR(self), STRINGLIB_LEN(self)); | |
| #else | |
| Py_INCREF(self); | |
| return (PyObject*) self; | |
| #endif | |
| } | |
| return pad(self, 0, width - STRINGLIB_LEN(self), fillchar); | |
| } | |
| PyDoc_STRVAR(rjust__doc__, | |
| "B.rjust(width[, fillchar]) -> copy of B\n" | |
| "\n" | |
| "Return B right justified in a string of length width. Padding is\n" | |
| "done using the specified fill character (default is a space)"); | |
| static PyObject * | |
| stringlib_rjust(PyObject *self, PyObject *args) | |
| { | |
| Py_ssize_t width; | |
| char fillchar = ' '; | |
| if (!PyArg_ParseTuple(args, "n|c:rjust", &width, &fillchar)) | |
| return NULL; | |
| if (STRINGLIB_LEN(self) >= width && STRINGLIB_CHECK_EXACT(self)) { | |
| #if STRINGLIB_MUTABLE | |
| /* We're defined as returning a copy; If the object is mutable | |
| * that means we must make an identical copy. */ | |
| return STRINGLIB_NEW(STRINGLIB_STR(self), STRINGLIB_LEN(self)); | |
| #else | |
| Py_INCREF(self); | |
| return (PyObject*) self; | |
| #endif | |
| } | |
| return pad(self, width - STRINGLIB_LEN(self), 0, fillchar); | |
| } | |
| PyDoc_STRVAR(center__doc__, | |
| "B.center(width[, fillchar]) -> copy of B\n" | |
| "\n" | |
| "Return B centered in a string of length width. Padding is\n" | |
| "done using the specified fill character (default is a space)."); | |
| static PyObject * | |
| stringlib_center(PyObject *self, PyObject *args) | |
| { | |
| Py_ssize_t marg, left; | |
| Py_ssize_t width; | |
| char fillchar = ' '; | |
| if (!PyArg_ParseTuple(args, "n|c:center", &width, &fillchar)) | |
| return NULL; | |
| if (STRINGLIB_LEN(self) >= width && STRINGLIB_CHECK_EXACT(self)) { | |
| #if STRINGLIB_MUTABLE | |
| /* We're defined as returning a copy; If the object is mutable | |
| * that means we must make an identical copy. */ | |
| return STRINGLIB_NEW(STRINGLIB_STR(self), STRINGLIB_LEN(self)); | |
| #else | |
| Py_INCREF(self); | |
| return (PyObject*) self; | |
| #endif | |
| } | |
| marg = width - STRINGLIB_LEN(self); | |
| left = marg / 2 + (marg & width & 1); | |
| return pad(self, left, marg - left, fillchar); | |
| } | |
| PyDoc_STRVAR(zfill__doc__, | |
| "B.zfill(width) -> copy of B\n" | |
| "\n" | |
| "Pad a numeric string B with zeros on the left, to fill a field\n" | |
| "of the specified width. B is never truncated."); | |
| static PyObject * | |
| stringlib_zfill(PyObject *self, PyObject *args) | |
| { | |
| Py_ssize_t fill; | |
| PyObject *s; | |
| char *p; | |
| Py_ssize_t width; | |
| if (!PyArg_ParseTuple(args, "n:zfill", &width)) | |
| return NULL; | |
| if (STRINGLIB_LEN(self) >= width) { | |
| if (STRINGLIB_CHECK_EXACT(self)) { | |
| #if STRINGLIB_MUTABLE | |
| /* We're defined as returning a copy; If the object is mutable | |
| * that means we must make an identical copy. */ | |
| return STRINGLIB_NEW(STRINGLIB_STR(self), STRINGLIB_LEN(self)); | |
| #else | |
| Py_INCREF(self); | |
| return (PyObject*) self; | |
| #endif | |
| } | |
| else | |
| return STRINGLIB_NEW( | |
| STRINGLIB_STR(self), | |
| STRINGLIB_LEN(self) | |
| ); | |
| } | |
| fill = width - STRINGLIB_LEN(self); | |
| s = pad(self, fill, 0, '0'); | |
| if (s == NULL) | |
| return NULL; | |
| p = STRINGLIB_STR(s); | |
| if (p[fill] == '+' || p[fill] == '-') { | |
| /* move sign to beginning of string */ | |
| p[0] = p[fill]; | |
| p[fill] = '0'; | |
| } | |
| return (PyObject*) s; | |
| } |