improve treatment of multi-line replies, ignore empty lines
[python/dscho.git] / Modules / stropmodule.c
blob326dfb8854a0f4729f0a1db92ad984dc4d62dc6a
1 /***********************************************************
2 Copyright 1991-1995 by Stichting Mathematisch Centrum, Amsterdam,
3 The Netherlands.
5 All Rights Reserved
7 Permission to use, copy, modify, and distribute this software and its
8 documentation for any purpose and without fee is hereby granted,
9 provided that the above copyright notice appear in all copies and that
10 both that copyright notice and this permission notice appear in
11 supporting documentation, and that the names of Stichting Mathematisch
12 Centrum or CWI not be used in advertising or publicity pertaining to
13 distribution of the software without specific, written prior permission.
15 STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO
16 THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
17 FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE
18 FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
20 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
21 OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
23 ******************************************************************/
25 /* strop module */
27 #include "allobjects.h"
28 #include "modsupport.h"
30 #include <ctype.h>
31 /* XXX This file assumes that the <ctype.h> is*() functions
32 XXX are defined for all 8-bit characters! */
34 #include <errno.h>
37 static object *
38 strop_split(self, args)
39 object *self; /* Not used */
40 object *args;
42 int len, i, j, err;
43 char *s;
44 char c;
45 object *list, *item;
47 if (!getargs(args, "s#", &s, &len))
48 return NULL;
49 list = newlistobject(0);
50 if (list == NULL)
51 return NULL;
53 i = 0;
54 while (i < len) {
55 while (i < len &&
56 ((c = s[i]), isspace(c))) {
57 i = i+1;
59 j = i;
60 while (i < len &&
61 !((c = s[i]), isspace(c))) {
62 i = i+1;
64 if (j < i) {
65 item = newsizedstringobject(s+j, (int)(i-j));
66 if (item == NULL) {
67 DECREF(list);
68 return NULL;
70 err = addlistitem(list, item);
71 DECREF(item);
72 if (err < 0) {
73 DECREF(list);
74 return NULL;
79 return list;
83 static object *
84 strop_splitfields(self, args)
85 object *self; /* Not used */
86 object *args;
88 int len, n, i, j, err;
89 char *s, *sub;
90 object *list, *item;
92 if (!getargs(args, "(s#s#)", &s, &len, &sub, &n))
93 return NULL;
94 if (n == 0) {
95 err_setstr(ValueError, "empty separator");
96 return NULL;
99 list = newlistobject(0);
100 if (list == NULL)
101 return NULL;
103 i = j = 0;
104 while (i+n <= len) {
105 if (s[i] == sub[0] && (n == 1 || strncmp(s+i, sub, n) == 0)) {
106 item = newsizedstringobject(s+j, (int)(i-j));
107 if (item == NULL)
108 goto fail;
109 err = addlistitem(list, item);
110 DECREF(item);
111 if (err < 0)
112 goto fail;
113 i = j = i + n;
115 else
116 i++;
118 item = newsizedstringobject(s+j, (int)(len-j));
119 if (item == NULL)
120 goto fail;
121 err = addlistitem(list, item);
122 DECREF(item);
123 if (err < 0)
124 goto fail;
126 return list;
128 fail:
129 DECREF(list);
130 return NULL;
134 static object *
135 strop_joinfields(self, args)
136 object *self; /* Not used */
137 object *args;
139 object *seq, *item, *res;
140 object * (*getitem) FPROTO((object *, int));
141 char *sep, *p;
142 int seplen, seqlen, reslen, itemlen, i;
144 if (!getargs(args, "(Os#)", &seq, &sep, &seplen))
145 return NULL;
146 if (is_listobject(seq)) {
147 getitem = getlistitem;
148 seqlen = getlistsize(seq);
150 else if (is_tupleobject(seq)) {
151 getitem = gettupleitem;
152 seqlen = gettuplesize(seq);
154 else {
155 err_setstr(TypeError, "first argument must be list/tuple");
156 return NULL;
158 reslen = 0;
159 for (i = 0; i < seqlen; i++) {
160 item = getitem(seq, i);
161 if (!is_stringobject(item)) {
162 err_setstr(TypeError,
163 "first argument must be list/tuple of strings");
164 return NULL;
166 if (i > 0)
167 reslen = reslen + seplen;
168 reslen = reslen + getstringsize(item);
170 if (seqlen == 1) {
171 /* Optimization if there's only one item */
172 item = getitem(seq, 0);
173 INCREF(item);
174 return item;
176 res = newsizedstringobject((char *)NULL, reslen);
177 if (res == NULL)
178 return NULL;
179 p = getstringvalue(res);
180 for (i = 0; i < seqlen; i++) {
181 item = getitem(seq, i);
182 if (i > 0) {
183 memcpy(p, sep, seplen);
184 p += seplen;
186 itemlen = getstringsize(item);
187 memcpy(p, getstringvalue(item), itemlen);
188 p += itemlen;
190 if (p != getstringvalue(res) + reslen) {
191 err_setstr(SystemError, "strop.joinfields: assertion failed");
192 return NULL;
194 return res;
198 static object *
199 strop_find(self, args)
200 object *self; /* Not used */
201 object *args;
203 char *s, *sub;
204 int len, n, i;
206 if (getargs(args, "(s#s#i)", &s, &len, &sub, &n, &i)) {
207 if (i < 0)
208 i += len;
209 if (i < 0)
210 i = 0;
212 else {
213 err_clear();
214 if (!getargs(args, "(s#s#)", &s, &len, &sub, &n))
215 return NULL;
216 i = 0;
219 if (n == 0)
220 return newintobject((long)i);
222 len -= n;
223 for (; i <= len; ++i)
224 if (s[i] == sub[0] &&
225 (n == 1 || strncmp(&s[i+1], &sub[1], n-1) == 0))
226 return newintobject((long)i);
228 return newintobject(-1L);
232 static object *
233 strop_rfind(self, args)
234 object *self; /* Not used */
235 object *args;
237 char *s, *sub;
238 int len, n, i, j;
240 if (getargs(args, "(s#s#i)", &s, &len, &sub, &n, &i)) {
241 if (i < 0)
242 i += len;
243 if (i < 0)
244 i = 0;
246 else {
247 err_clear();
248 if (!getargs(args, "(s#s#)", &s, &len, &sub, &n))
249 return NULL;
250 i = 0;
253 if (n == 0)
254 return newintobject((long)len);
256 for (j = len-n; j >= i; --j)
257 if (s[j] == sub[0] &&
258 (n == 1 || strncmp(&s[j+1], &sub[1], n-1) == 0))
259 return newintobject((long)j);
261 return newintobject(-1L);
265 static object *
266 strop_strip(self, args)
267 object *self; /* Not used */
268 object *args;
270 char *s;
271 int len, i, j;
272 char c;
274 if (!getargs(args, "s#", &s, &len))
275 return NULL;
277 i = 0;
278 while (i < len && ((c = s[i]), isspace(c))) {
279 i++;
282 j = len;
283 do {
284 j--;
285 } while (j >= i && ((c = s[j]), isspace(c)));
286 j++;
288 if (i == 0 && j == len) {
289 INCREF(args);
290 return args;
292 else
293 return newsizedstringobject(s+i, j-i);
297 static object *
298 strop_lower(self, args)
299 object *self; /* Not used */
300 object *args;
302 char *s, *s_new;
303 int i, n;
304 object *new;
305 int changed;
307 if (!getargs(args, "s#", &s, &n))
308 return NULL;
309 new = newsizedstringobject(NULL, n);
310 if (new == NULL)
311 return NULL;
312 s_new = getstringvalue(new);
313 changed = 0;
314 for (i = 0; i < n; i++) {
315 char c = *s++;
316 if (isupper(c)) {
317 changed = 1;
318 *s_new = tolower(c);
319 } else
320 *s_new = c;
321 s_new++;
323 if (!changed) {
324 DECREF(new);
325 INCREF(args);
326 return args;
328 return new;
332 static object *
333 strop_upper(self, args)
334 object *self; /* Not used */
335 object *args;
337 char *s, *s_new;
338 int i, n;
339 object *new;
340 int changed;
342 if (!getargs(args, "s#", &s, &n))
343 return NULL;
344 new = newsizedstringobject(NULL, n);
345 if (new == NULL)
346 return NULL;
347 s_new = getstringvalue(new);
348 changed = 0;
349 for (i = 0; i < n; i++) {
350 char c = *s++;
351 if (islower(c)) {
352 changed = 1;
353 *s_new = toupper(c);
354 } else
355 *s_new = c;
356 s_new++;
358 if (!changed) {
359 DECREF(new);
360 INCREF(args);
361 return args;
363 return new;
367 static object *
368 strop_swapcase(self, args)
369 object *self; /* Not used */
370 object *args;
372 char *s, *s_new;
373 int i, n;
374 object *new;
375 int changed;
377 if (!getargs(args, "s#", &s, &n))
378 return NULL;
379 new = newsizedstringobject(NULL, n);
380 if (new == NULL)
381 return NULL;
382 s_new = getstringvalue(new);
383 changed = 0;
384 for (i = 0; i < n; i++) {
385 char c = *s++;
386 if (islower(c)) {
387 changed = 1;
388 *s_new = toupper(c);
390 else if (isupper(c)) {
391 changed = 1;
392 *s_new = tolower(c);
394 else
395 *s_new = c;
396 s_new++;
398 if (!changed) {
399 DECREF(new);
400 INCREF(args);
401 return args;
403 return new;
407 static object *
408 strop_atoi(self, args)
409 object *self; /* Not used */
410 object *args;
412 extern long mystrtol PROTO((const char *, char **, int));
413 extern unsigned long mystrtoul PROTO((const char *, char **, int));
414 char *s, *end;
415 int base = 10;
416 long x;
418 if (args != NULL && is_tupleobject(args)) {
419 if (!getargs(args, "(si)", &s, &base))
420 return NULL;
421 if (base != 0 && base < 2 || base > 36) {
422 err_setstr(ValueError, "invalid base for atoi()");
423 return NULL;
426 else if (!getargs(args, "s", &s))
427 return NULL;
428 errno = 0;
429 if (base == 0 && s[0] == '0')
430 x = (long) mystrtoul(s, &end, base);
431 else
432 x = mystrtol(s, &end, base);
433 if (*end != '\0') {
434 err_setstr(ValueError, "invalid literal for atoi()");
435 return NULL;
437 else if (errno != 0) {
438 err_setstr(OverflowError, "atoi() literal too large");
439 return NULL;
441 return newintobject(x);
445 static object *
446 strop_atol(self, args)
447 object *self; /* Not used */
448 object *args;
450 char *s, *end;
451 int base = 10;
452 object *x;
454 if (args != NULL && is_tupleobject(args)) {
455 if (!getargs(args, "(si)", &s, &base))
456 return NULL;
457 if (base != 0 && base < 2 || base > 36) {
458 err_setstr(ValueError, "invalid base for atol()");
459 return NULL;
462 else if (!getargs(args, "s", &s))
463 return NULL;
464 x = long_escan(s, &end, base);
465 if (x == NULL)
466 return NULL;
467 if (base == 0 && (*end == 'l' || *end == 'L'))
468 end++;
469 if (*end != '\0') {
470 err_setstr(ValueError, "invalid literal for atol()");
471 DECREF(x);
472 return NULL;
474 return x;
478 static object *
479 strop_atof(self, args)
480 object *self; /* Not used */
481 object *args;
483 extern double strtod PROTO((const char *, char **));
484 char *s, *end;
485 double x;
487 if (!getargs(args, "s", &s))
488 return NULL;
489 errno = 0;
490 x = strtod(s, &end);
491 if (*end != '\0') {
492 err_setstr(ValueError, "invalid literal for atof()");
493 return NULL;
495 else if (errno != 0) {
496 err_setstr(OverflowError, "atof() literal too large");
497 return NULL;
499 return newfloatobject(x);
503 /* List of functions defined in the module */
505 static struct methodlist strop_methods[] = {
506 {"atof", strop_atof},
507 {"atoi", strop_atoi},
508 {"atol", strop_atol},
509 {"find", strop_find},
510 {"joinfields", strop_joinfields},
511 {"lower", strop_lower},
512 {"rfind", strop_rfind},
513 {"split", strop_split},
514 {"splitfields", strop_splitfields},
515 {"strip", strop_strip},
516 {"swapcase", strop_swapcase},
517 {"upper", strop_upper},
518 {NULL, NULL} /* sentinel */
522 void
523 initstrop()
525 object *m, *d, *s;
526 char buf[256];
527 int c, n;
528 m = initmodule("strop", strop_methods);
529 d = getmoduledict(m);
531 /* Create 'whitespace' object */
532 n = 0;
533 for (c = 1; c < 256; c++) {
534 if (isspace(c))
535 buf[n++] = c;
537 s = newsizedstringobject(buf, n);
538 if (s) {
539 dictinsert(d, "whitespace", s);
540 DECREF(s);
542 /* Create 'lowercase' object */
543 n = 0;
544 for (c = 1; c < 256; c++) {
545 if (islower(c))
546 buf[n++] = c;
548 s = newsizedstringobject(buf, n);
549 if (s) {
550 dictinsert(d, "lowercase", s);
551 DECREF(s);
554 /* Create 'uppercase' object */
555 n = 0;
556 for (c = 1; c < 256; c++) {
557 if (isupper(c))
558 buf[n++] = c;
560 s = newsizedstringobject(buf, n);
561 if (s) {
562 dictinsert(d, "uppercase", s);
563 DECREF(s);
566 if (err_occurred())
567 fatal("can't initialize module strop");