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