Gregory P. Smith | 60d241f | 2007-10-16 06:31:30 +0000 | [diff] [blame] | 1 | /* NOTE: this API is -ONLY- for use with single byte character strings. */ |
| 2 | /* Do not use it with Unicode. */ |
| 3 | |
Gregory P. Smith | 60d241f | 2007-10-16 06:31:30 +0000 | [diff] [blame] | 4 | /* the more complicated methods. parts of these should be pulled out into the |
| 5 | shared code in bytes_methods.c to cut down on duplicate code bloat. */ |
| 6 | |
| 7 | PyDoc_STRVAR(expandtabs__doc__, |
Ezio Melotti | 745d54d | 2013-11-16 19:10:57 +0200 | [diff] [blame] | 8 | "B.expandtabs(tabsize=8) -> copy of B\n\ |
Gregory P. Smith | 60d241f | 2007-10-16 06:31:30 +0000 | [diff] [blame] | 9 | \n\ |
| 10 | Return a copy of B where all tab characters are expanded using spaces.\n\ |
| 11 | If tabsize is not given, a tab size of 8 characters is assumed."); |
| 12 | |
| 13 | static PyObject* |
Ezio Melotti | 745d54d | 2013-11-16 19:10:57 +0200 | [diff] [blame] | 14 | stringlib_expandtabs(PyObject *self, PyObject *args, PyObject *kwds) |
Gregory P. Smith | 60d241f | 2007-10-16 06:31:30 +0000 | [diff] [blame] | 15 | { |
| 16 | const char *e, *p; |
| 17 | char *q; |
Antoine Pitrou | 8d4e505 | 2009-01-13 22:59:11 +0000 | [diff] [blame] | 18 | size_t i, j; |
Gregory P. Smith | 60d241f | 2007-10-16 06:31:30 +0000 | [diff] [blame] | 19 | PyObject *u; |
Ezio Melotti | 745d54d | 2013-11-16 19:10:57 +0200 | [diff] [blame] | 20 | static char *kwlist[] = {"tabsize", 0}; |
Gregory P. Smith | 60d241f | 2007-10-16 06:31:30 +0000 | [diff] [blame] | 21 | int tabsize = 8; |
Ezio Melotti | 6b02772 | 2013-04-21 04:07:51 +0300 | [diff] [blame] | 22 | |
Ezio Melotti | 745d54d | 2013-11-16 19:10:57 +0200 | [diff] [blame] | 23 | if (!PyArg_ParseTupleAndKeywords(args, kwds, "|i:expandtabs", |
| 24 | kwlist, &tabsize)) |
Antoine Pitrou | 8d4e505 | 2009-01-13 22:59:11 +0000 | [diff] [blame] | 25 | return NULL; |
Ezio Melotti | 6b02772 | 2013-04-21 04:07:51 +0300 | [diff] [blame] | 26 | |
Gregory P. Smith | 60d241f | 2007-10-16 06:31:30 +0000 | [diff] [blame] | 27 | /* First pass: determine size of output string */ |
Antoine Pitrou | 8d4e505 | 2009-01-13 22:59:11 +0000 | [diff] [blame] | 28 | i = j = 0; |
Gregory P. Smith | 60d241f | 2007-10-16 06:31:30 +0000 | [diff] [blame] | 29 | e = STRINGLIB_STR(self) + STRINGLIB_LEN(self); |
| 30 | for (p = STRINGLIB_STR(self); p < e; p++) |
| 31 | if (*p == '\t') { |
Antoine Pitrou | 8d4e505 | 2009-01-13 22:59:11 +0000 | [diff] [blame] | 32 | if (tabsize > 0) { |
| 33 | j += tabsize - (j % tabsize); |
| 34 | if (j > PY_SSIZE_T_MAX) { |
Gregory P. Smith | 60d241f | 2007-10-16 06:31:30 +0000 | [diff] [blame] | 35 | PyErr_SetString(PyExc_OverflowError, |
| 36 | "result is too long"); |
| 37 | return NULL; |
| 38 | } |
| 39 | } |
| 40 | } |
Antoine Pitrou | 8d4e505 | 2009-01-13 22:59:11 +0000 | [diff] [blame] | 41 | else { |
| 42 | j++; |
| 43 | if (*p == '\n' || *p == '\r') { |
| 44 | i += j; |
| 45 | j = 0; |
| 46 | if (i > PY_SSIZE_T_MAX) { |
| 47 | PyErr_SetString(PyExc_OverflowError, |
| 48 | "result is too long"); |
| 49 | return NULL; |
| 50 | } |
| 51 | } |
| 52 | } |
Ezio Melotti | 6b02772 | 2013-04-21 04:07:51 +0300 | [diff] [blame] | 53 | |
Antoine Pitrou | 8d4e505 | 2009-01-13 22:59:11 +0000 | [diff] [blame] | 54 | if ((i + j) > PY_SSIZE_T_MAX) { |
Gregory P. Smith | 60d241f | 2007-10-16 06:31:30 +0000 | [diff] [blame] | 55 | PyErr_SetString(PyExc_OverflowError, "result is too long"); |
| 56 | return NULL; |
| 57 | } |
Ezio Melotti | 6b02772 | 2013-04-21 04:07:51 +0300 | [diff] [blame] | 58 | |
Gregory P. Smith | 60d241f | 2007-10-16 06:31:30 +0000 | [diff] [blame] | 59 | /* Second pass: create output string and fill it */ |
| 60 | u = STRINGLIB_NEW(NULL, i + j); |
| 61 | if (!u) |
| 62 | return NULL; |
Ezio Melotti | 6b02772 | 2013-04-21 04:07:51 +0300 | [diff] [blame] | 63 | |
Gregory P. Smith | 60d241f | 2007-10-16 06:31:30 +0000 | [diff] [blame] | 64 | j = 0; |
| 65 | q = STRINGLIB_STR(u); |
Ezio Melotti | 6b02772 | 2013-04-21 04:07:51 +0300 | [diff] [blame] | 66 | |
Gregory P. Smith | 60d241f | 2007-10-16 06:31:30 +0000 | [diff] [blame] | 67 | for (p = STRINGLIB_STR(self); p < e; p++) |
| 68 | if (*p == '\t') { |
Antoine Pitrou | 8d4e505 | 2009-01-13 22:59:11 +0000 | [diff] [blame] | 69 | if (tabsize > 0) { |
| 70 | i = tabsize - (j % tabsize); |
| 71 | j += i; |
| 72 | while (i--) |
| 73 | *q++ = ' '; |
| 74 | } |
| 75 | } |
| 76 | else { |
Gregory P. Smith | 60d241f | 2007-10-16 06:31:30 +0000 | [diff] [blame] | 77 | j++; |
Antoine Pitrou | 8d4e505 | 2009-01-13 22:59:11 +0000 | [diff] [blame] | 78 | *q++ = *p; |
Gregory P. Smith | 60d241f | 2007-10-16 06:31:30 +0000 | [diff] [blame] | 79 | if (*p == '\n' || *p == '\r') |
| 80 | j = 0; |
| 81 | } |
Ezio Melotti | 6b02772 | 2013-04-21 04:07:51 +0300 | [diff] [blame] | 82 | |
Gregory P. Smith | 60d241f | 2007-10-16 06:31:30 +0000 | [diff] [blame] | 83 | return u; |
| 84 | } |
| 85 | |
| 86 | Py_LOCAL_INLINE(PyObject *) |
| 87 | pad(PyObject *self, Py_ssize_t left, Py_ssize_t right, char fill) |
| 88 | { |
| 89 | PyObject *u; |
| 90 | |
| 91 | if (left < 0) |
| 92 | left = 0; |
| 93 | if (right < 0) |
| 94 | right = 0; |
| 95 | |
| 96 | if (left == 0 && right == 0 && STRINGLIB_CHECK_EXACT(self)) { |
| 97 | #if STRINGLIB_MUTABLE |
| 98 | /* We're defined as returning a copy; If the object is mutable |
| 99 | * that means we must make an identical copy. */ |
| 100 | return STRINGLIB_NEW(STRINGLIB_STR(self), STRINGLIB_LEN(self)); |
| 101 | #else |
| 102 | Py_INCREF(self); |
| 103 | return (PyObject *)self; |
| 104 | #endif /* STRINGLIB_MUTABLE */ |
| 105 | } |
| 106 | |
| 107 | u = STRINGLIB_NEW(NULL, |
| 108 | left + STRINGLIB_LEN(self) + right); |
| 109 | if (u) { |
| 110 | if (left) |
| 111 | memset(STRINGLIB_STR(u), fill, left); |
| 112 | Py_MEMCPY(STRINGLIB_STR(u) + left, |
| 113 | STRINGLIB_STR(self), |
| 114 | STRINGLIB_LEN(self)); |
| 115 | if (right) |
| 116 | memset(STRINGLIB_STR(u) + left + STRINGLIB_LEN(self), |
| 117 | fill, right); |
| 118 | } |
| 119 | |
| 120 | return u; |
| 121 | } |
| 122 | |
| 123 | PyDoc_STRVAR(ljust__doc__, |
Guido van Rossum | 98297ee | 2007-11-06 21:34:58 +0000 | [diff] [blame] | 124 | "B.ljust(width[, fillchar]) -> copy of B\n" |
Gregory P. Smith | 60d241f | 2007-10-16 06:31:30 +0000 | [diff] [blame] | 125 | "\n" |
| 126 | "Return B left justified in a string of length width. Padding is\n" |
| 127 | "done using the specified fill character (default is a space)."); |
| 128 | |
| 129 | static PyObject * |
| 130 | stringlib_ljust(PyObject *self, PyObject *args) |
| 131 | { |
| 132 | Py_ssize_t width; |
| 133 | char fillchar = ' '; |
| 134 | |
| 135 | if (!PyArg_ParseTuple(args, "n|c:ljust", &width, &fillchar)) |
| 136 | return NULL; |
| 137 | |
| 138 | if (STRINGLIB_LEN(self) >= width && STRINGLIB_CHECK_EXACT(self)) { |
| 139 | #if STRINGLIB_MUTABLE |
| 140 | /* We're defined as returning a copy; If the object is mutable |
| 141 | * that means we must make an identical copy. */ |
| 142 | return STRINGLIB_NEW(STRINGLIB_STR(self), STRINGLIB_LEN(self)); |
| 143 | #else |
| 144 | Py_INCREF(self); |
| 145 | return (PyObject*) self; |
| 146 | #endif |
| 147 | } |
| 148 | |
| 149 | return pad(self, 0, width - STRINGLIB_LEN(self), fillchar); |
| 150 | } |
| 151 | |
| 152 | |
| 153 | PyDoc_STRVAR(rjust__doc__, |
Guido van Rossum | 98297ee | 2007-11-06 21:34:58 +0000 | [diff] [blame] | 154 | "B.rjust(width[, fillchar]) -> copy of B\n" |
Gregory P. Smith | 60d241f | 2007-10-16 06:31:30 +0000 | [diff] [blame] | 155 | "\n" |
| 156 | "Return B right justified in a string of length width. Padding is\n" |
| 157 | "done using the specified fill character (default is a space)"); |
| 158 | |
| 159 | static PyObject * |
| 160 | stringlib_rjust(PyObject *self, PyObject *args) |
| 161 | { |
| 162 | Py_ssize_t width; |
| 163 | char fillchar = ' '; |
| 164 | |
| 165 | if (!PyArg_ParseTuple(args, "n|c:rjust", &width, &fillchar)) |
| 166 | return NULL; |
| 167 | |
| 168 | if (STRINGLIB_LEN(self) >= width && STRINGLIB_CHECK_EXACT(self)) { |
| 169 | #if STRINGLIB_MUTABLE |
| 170 | /* We're defined as returning a copy; If the object is mutable |
| 171 | * that means we must make an identical copy. */ |
| 172 | return STRINGLIB_NEW(STRINGLIB_STR(self), STRINGLIB_LEN(self)); |
| 173 | #else |
| 174 | Py_INCREF(self); |
| 175 | return (PyObject*) self; |
| 176 | #endif |
| 177 | } |
| 178 | |
| 179 | return pad(self, width - STRINGLIB_LEN(self), 0, fillchar); |
| 180 | } |
| 181 | |
| 182 | |
| 183 | PyDoc_STRVAR(center__doc__, |
Guido van Rossum | 98297ee | 2007-11-06 21:34:58 +0000 | [diff] [blame] | 184 | "B.center(width[, fillchar]) -> copy of B\n" |
Gregory P. Smith | 60d241f | 2007-10-16 06:31:30 +0000 | [diff] [blame] | 185 | "\n" |
Guido van Rossum | 98297ee | 2007-11-06 21:34:58 +0000 | [diff] [blame] | 186 | "Return B centered in a string of length width. Padding is\n" |
| 187 | "done using the specified fill character (default is a space)."); |
Gregory P. Smith | 60d241f | 2007-10-16 06:31:30 +0000 | [diff] [blame] | 188 | |
| 189 | static PyObject * |
| 190 | stringlib_center(PyObject *self, PyObject *args) |
| 191 | { |
| 192 | Py_ssize_t marg, left; |
| 193 | Py_ssize_t width; |
| 194 | char fillchar = ' '; |
| 195 | |
| 196 | if (!PyArg_ParseTuple(args, "n|c:center", &width, &fillchar)) |
| 197 | return NULL; |
| 198 | |
| 199 | if (STRINGLIB_LEN(self) >= width && STRINGLIB_CHECK_EXACT(self)) { |
| 200 | #if STRINGLIB_MUTABLE |
| 201 | /* We're defined as returning a copy; If the object is mutable |
| 202 | * that means we must make an identical copy. */ |
| 203 | return STRINGLIB_NEW(STRINGLIB_STR(self), STRINGLIB_LEN(self)); |
| 204 | #else |
| 205 | Py_INCREF(self); |
| 206 | return (PyObject*) self; |
| 207 | #endif |
| 208 | } |
| 209 | |
| 210 | marg = width - STRINGLIB_LEN(self); |
| 211 | left = marg / 2 + (marg & width & 1); |
| 212 | |
| 213 | return pad(self, left, marg - left, fillchar); |
| 214 | } |
| 215 | |
| 216 | PyDoc_STRVAR(zfill__doc__, |
Guido van Rossum | 98297ee | 2007-11-06 21:34:58 +0000 | [diff] [blame] | 217 | "B.zfill(width) -> copy of B\n" |
Gregory P. Smith | 60d241f | 2007-10-16 06:31:30 +0000 | [diff] [blame] | 218 | "\n" |
| 219 | "Pad a numeric string B with zeros on the left, to fill a field\n" |
| 220 | "of the specified width. B is never truncated."); |
| 221 | |
| 222 | static PyObject * |
| 223 | stringlib_zfill(PyObject *self, PyObject *args) |
| 224 | { |
| 225 | Py_ssize_t fill; |
| 226 | PyObject *s; |
| 227 | char *p; |
| 228 | Py_ssize_t width; |
| 229 | |
| 230 | if (!PyArg_ParseTuple(args, "n:zfill", &width)) |
| 231 | return NULL; |
| 232 | |
| 233 | if (STRINGLIB_LEN(self) >= width) { |
| 234 | if (STRINGLIB_CHECK_EXACT(self)) { |
| 235 | #if STRINGLIB_MUTABLE |
| 236 | /* We're defined as returning a copy; If the object is mutable |
| 237 | * that means we must make an identical copy. */ |
| 238 | return STRINGLIB_NEW(STRINGLIB_STR(self), STRINGLIB_LEN(self)); |
| 239 | #else |
| 240 | Py_INCREF(self); |
| 241 | return (PyObject*) self; |
| 242 | #endif |
| 243 | } |
| 244 | else |
| 245 | return STRINGLIB_NEW( |
| 246 | STRINGLIB_STR(self), |
| 247 | STRINGLIB_LEN(self) |
| 248 | ); |
| 249 | } |
| 250 | |
| 251 | fill = width - STRINGLIB_LEN(self); |
| 252 | |
| 253 | s = pad(self, fill, 0, '0'); |
| 254 | |
| 255 | if (s == NULL) |
| 256 | return NULL; |
| 257 | |
| 258 | p = STRINGLIB_STR(s); |
| 259 | if (p[fill] == '+' || p[fill] == '-') { |
| 260 | /* move sign to beginning of string */ |
| 261 | p[0] = p[fill]; |
| 262 | p[fill] = '0'; |
| 263 | } |
| 264 | |
| 265 | return (PyObject*) s; |
| 266 | } |