Several changes:

- split_whitespace(): slightly better memory ref handling when errors
  occur.

- strop_joinfields(): First argument can now be any sequence-protocol
  conformant object.

- strop_find(), strop_rfind(): Use PyArg_ParseTuple for optional
  arguments

- strop_lower(), strop_upper(): Factor logic into a common function
  do_casechange().

- strop_atoi(), strop_atol(): Use PyArg_ParseTuple.

- strop_maketrans(): arguments used to be optional, although the
  documentation doesn't reflect this.  Make the source conform to the
  docs.  Arguments are required, but two empty strings will return the
  identity translation table.

- General pass fixing up formatting, and checking for return values.
This commit is contained in:
Barry Warsaw 1997-01-03 22:45:34 +00:00
parent 9d1a02ce33
commit e8fc29cde7
1 changed files with 106 additions and 142 deletions

View File

@ -52,17 +52,14 @@ split_whitespace(s, len, maxsplit)
int len; int len;
int maxsplit; int maxsplit;
{ {
int i, j, err; int i = 0, j, err;
int countsplit; int countsplit = 0;
PyObject *list, *item; PyObject* item;
PyObject *list = PyList_New(0);
list = PyList_New(0);
if (list == NULL) if (list == NULL)
return NULL; return NULL;
i = 0;
countsplit = 0;
while (i < len) { while (i < len) {
while (i < len && isspace(Py_CHARMASK(s[i]))) { while (i < len && isspace(Py_CHARMASK(s[i]))) {
i = i+1; i = i+1;
@ -73,38 +70,35 @@ split_whitespace(s, len, maxsplit)
} }
if (j < i) { if (j < i) {
item = PyString_FromStringAndSize(s+j, (int)(i-j)); item = PyString_FromStringAndSize(s+j, (int)(i-j));
if (item == NULL) { if (item == NULL)
Py_DECREF(list); goto finally;
return NULL;
}
err = PyList_Append(list, item); err = PyList_Append(list, item);
Py_DECREF(item); Py_DECREF(item);
if (err < 0) { if (err < 0)
Py_DECREF(list); goto finally;
return NULL;
}
countsplit++; countsplit++;
if (maxsplit && (countsplit >= maxsplit)) { if (maxsplit && (countsplit >= maxsplit)) {
item = PyString_FromStringAndSize( item = PyString_FromStringAndSize(
s+i, (int)(len - i)); s+i, (int)(len - i));
if (item == NULL) { if (item == NULL)
Py_DECREF(list); goto finally;
return NULL;
}
err = PyList_Append(list, item); err = PyList_Append(list, item);
Py_DECREF(item); Py_DECREF(item);
if (err < 0) { if (err < 0)
Py_DECREF(list); goto finally;
return NULL;
}
i = len; i = len;
} }
} }
} }
return list; return list;
finally:
Py_DECREF(list);
return NULL;
} }
@ -175,7 +169,6 @@ strop_joinfields(self, args)
PyObject *args; PyObject *args;
{ {
PyObject *seq, *item, *res; PyObject *seq, *item, *res;
PyObject * (*getitem) Py_FPROTO((PyObject *, int));
char *sep, *p; char *sep, *p;
int seplen, seqlen, reslen, itemlen, i; int seplen, seqlen, reslen, itemlen, i;
@ -187,43 +180,44 @@ strop_joinfields(self, args)
sep = " "; sep = " ";
seplen = 1; seplen = 1;
} }
if (PyList_Check(seq)) { if (!PySequence_Check(seq)) {
getitem = PyList_GetItem;
seqlen = PyList_Size(seq);
}
else if (PyTuple_Check(seq)) {
getitem = PyTuple_GetItem;
seqlen = PyTuple_Size(seq);
}
else {
PyErr_SetString(PyExc_TypeError, PyErr_SetString(PyExc_TypeError,
"first argument must be list/tuple"); "first argument must be a sequence");
return NULL; return NULL;
} }
seqlen = PySequence_Length(seq);
if (seqlen < 0 && PyErr_Occurred())
return NULL;
reslen = 0; reslen = 0;
for (i = 0; i < seqlen; i++) { for (i = 0; i < seqlen; i++) {
item = getitem(seq, i); if (!(item = PySequence_GetItem(seq, i)))
return NULL;
if (!PyString_Check(item)) { if (!PyString_Check(item)) {
PyErr_SetString(PyExc_TypeError, PyErr_SetString(PyExc_TypeError,
"first argument must be list/tuple of strings"); "first argument must be sequence of strings");
Py_DECREF(item);
return NULL; return NULL;
} }
if (i > 0) if (i > 0)
reslen = reslen + seplen; reslen += seplen;
reslen = reslen + PyString_Size(item); reslen += PyString_Size(item);
Py_DECREF(item);
} }
if (seqlen == 1) { if (seqlen == 1)
/* Optimization if there's only one item */ /* Optimization if there's only one item */
item = getitem(seq, 0); return PySequence_GetItem(seq, 0);
Py_INCREF(item);
return item;
}
res = PyString_FromStringAndSize((char *)NULL, reslen); res = PyString_FromStringAndSize((char *)NULL, reslen);
if (res == NULL) if (res == NULL)
return NULL; return NULL;
p = PyString_AsString(res); p = PyString_AsString(res);
for (i = 0; i < seqlen; i++) { for (i = 0; i < seqlen; i++) {
item = getitem(seq, i); if (!(item = PySequence_GetItem(seq, i))) {
Py_DECREF(res);
return NULL;
}
if (i > 0) { if (i > 0) {
memcpy(p, sep, seplen); memcpy(p, sep, seplen);
p += seplen; p += seplen;
@ -231,6 +225,7 @@ strop_joinfields(self, args)
itemlen = PyString_Size(item); itemlen = PyString_Size(item);
memcpy(p, PyString_AsString(item), itemlen); memcpy(p, PyString_AsString(item), itemlen);
p += itemlen; p += itemlen;
Py_DECREF(item);
} }
if (p != PyString_AsString(res) + reslen) { if (p != PyString_AsString(res) + reslen) {
PyErr_SetString(PyExc_SystemError, PyErr_SetString(PyExc_SystemError,
@ -247,20 +242,15 @@ strop_find(self, args)
PyObject *args; PyObject *args;
{ {
char *s, *sub; char *s, *sub;
int len, n, i; int len, n, i = 0;
if (PyArg_Parse(args, "(s#s#i)", &s, &len, &sub, &n, &i)) { if (!PyArg_ParseTuple(args, "s#s#|i", &s, &len, &sub, &n, &i))
if (i < 0) return NULL;
i += len;
if (i < 0) if (i < 0)
i = 0; i += len;
} if (i < 0)
else {
PyErr_Clear();
if (!PyArg_Parse(args, "(s#s#)", &s, &len, &sub, &n))
return NULL;
i = 0; i = 0;
}
if (n == 0) if (n == 0)
return PyInt_FromLong((long)i); return PyInt_FromLong((long)i);
@ -281,20 +271,16 @@ strop_rfind(self, args)
PyObject *args; PyObject *args;
{ {
char *s, *sub; char *s, *sub;
int len, n, i, j; int len, n, j;
int i = 0;
if (PyArg_Parse(args, "(s#s#i)", &s, &len, &sub, &n, &i)) { if (!PyArg_ParseTuple(args, "s#s#|i", &s, &len, &sub, &n, &i))
if (i < 0) return NULL;
i += len;
if (i < 0) if (i < 0)
i = 0; i += len;
} if (i < 0)
else {
PyErr_Clear();
if (!PyArg_Parse(args, "(s#s#)", &s, &len, &sub, &n))
return NULL;
i = 0; i = 0;
}
if (n == 0) if (n == 0)
return PyInt_FromLong((long)len); return PyInt_FromLong((long)len);
@ -370,9 +356,11 @@ strop_rstrip(self, args)
static PyObject * static PyObject *
strop_lower(self, args) do_casechange(self, args, test, conv)
PyObject *self; /* Not used */ PyObject *self; /* Not used */
PyObject *args; PyObject *args;
int (*test) Py_PROTO((int));
int (*conv) Py_PROTO((int));
{ {
char *s, *s_new; char *s, *s_new;
int i, n; int i, n;
@ -388,9 +376,9 @@ strop_lower(self, args)
changed = 0; changed = 0;
for (i = 0; i < n; i++) { for (i = 0; i < n; i++) {
int c = Py_CHARMASK(*s++); int c = Py_CHARMASK(*s++);
if (isupper(c)) { if (test(c)) {
changed = 1; changed = 1;
*s_new = tolower(c); *s_new = conv(c);
} else } else
*s_new = c; *s_new = c;
s_new++; s_new++;
@ -403,39 +391,21 @@ strop_lower(self, args)
return new; return new;
} }
static PyObject *
strop_lower(self, args)
PyObject *self; /* Not used */
PyObject *args;
{
return do_casechange(self, args, isupper, tolower);
}
static PyObject * static PyObject *
strop_upper(self, args) strop_upper(self, args)
PyObject *self; /* Not used */ PyObject *self; /* Not used */
PyObject *args; PyObject *args;
{ {
char *s, *s_new; return do_casechange(self, args, islower, toupper);
int i, n;
PyObject *new;
int changed;
if (!PyArg_Parse(args, "s#", &s, &n))
return NULL;
new = PyString_FromStringAndSize(NULL, n);
if (new == NULL)
return NULL;
s_new = PyString_AsString(new);
changed = 0;
for (i = 0; i < n; i++) {
int c = Py_CHARMASK(*s++);
if (islower(c)) {
changed = 1;
*s_new = toupper(c);
} else
*s_new = c;
s_new++;
}
if (!changed) {
Py_DECREF(new);
Py_INCREF(args);
return args;
}
return new;
} }
@ -536,17 +506,14 @@ strop_atoi(self, args)
long x; long x;
char buffer[256]; /* For errors */ char buffer[256]; /* For errors */
if (args != NULL && PyTuple_Check(args)) { if (!PyArg_ParseTuple(args, "s|i", &s, &base))
if (!PyArg_Parse(args, "(si)", &s, &base))
return NULL;
if ((base != 0 && base < 2) || base > 36) {
PyErr_SetString(PyExc_ValueError,
"invalid base for atoi()");
return NULL;
}
}
else if (!PyArg_Parse(args, "s", &s))
return NULL; return NULL;
if ((base != 0 && base < 2) || base > 36) {
PyErr_SetString(PyExc_ValueError, "invalid base for atoi()");
return NULL;
}
while (*s && isspace(Py_CHARMASK(*s))) while (*s && isspace(Py_CHARMASK(*s)))
s++; s++;
if (s[0] == '\0') { if (s[0] == '\0') {
@ -584,17 +551,14 @@ strop_atol(self, args)
PyObject *x; PyObject *x;
char buffer[256]; /* For errors */ char buffer[256]; /* For errors */
if (args != NULL && PyTuple_Check(args)) { if (!PyArg_ParseTuple(args, "s|i", &s, &base))
if (!PyArg_Parse(args, "(si)", &s, &base))
return NULL;
if ((base != 0 && base < 2) || base > 36) {
PyErr_SetString(PyExc_ValueError,
"invalid base for atol()");
return NULL;
}
}
else if (!PyArg_Parse(args, "s", &s))
return NULL; return NULL;
if ((base != 0 && base < 2) || base > 36) {
PyErr_SetString(PyExc_ValueError, "invalid base for atol()");
return NULL;
}
while (*s && isspace(Py_CHARMASK(*s))) while (*s && isspace(Py_CHARMASK(*s)))
s++; s++;
if (s[0] == '\0') { if (s[0] == '\0') {
@ -662,22 +626,19 @@ strop_maketrans(self, args)
unsigned char c[256], *from=NULL, *to=NULL; unsigned char c[256], *from=NULL, *to=NULL;
int i, fromlen=0, tolen=0; int i, fromlen=0, tolen=0;
if (PyTuple_Size(args)!=0) { if (!PyArg_ParseTuple(args, "s#s#", &from, &fromlen, &to, &tolen))
if (!PyArg_ParseTuple(args, "s#s#", &from, &fromlen, return NULL;
&to, &tolen))
return NULL;
}
if (fromlen!=tolen) { if (fromlen != tolen) {
PyErr_SetString(PyExc_ValueError, PyErr_SetString(PyExc_ValueError,
"maketrans arguments must have same length"); "maketrans arguments must have same length");
return NULL; return NULL;
} }
for(i=0; i<256; i++) for (i = 0; i < 256; i++)
c[i]=(unsigned char)i; c[i]=(unsigned char)i;
for(i=0; i<fromlen; i++) { for (i = 0; i < fromlen; i++)
c[from[i]]=to[i]; c[from[i]]=to[i];
}
return PyString_FromStringAndSize((char *)c, 256); return PyString_FromStringAndSize((char *)c, 256);
} }
@ -688,7 +649,7 @@ strop_translate(self, args)
PyObject *args; PyObject *args;
{ {
char *input, *table, *output, *output_start, *delete=NULL; char *input, *table, *output, *output_start, *delete=NULL;
int inlen, tablen, dellen; int inlen, tablen, dellen = 0;
PyObject *result; PyObject *result;
int i, trans_table[256]; int i, trans_table[256];
@ -697,24 +658,26 @@ strop_translate(self, args)
return NULL; return NULL;
if (tablen != 256) { if (tablen != 256) {
PyErr_SetString(PyExc_ValueError, PyErr_SetString(PyExc_ValueError,
"translation table must be 256 characters long"); "translation table must be 256 characters long");
return NULL; return NULL;
} }
for(i=0; i<256; i++) for (i = 0; i < 256; i++)
trans_table[i]=Py_CHARMASK(table[i]); trans_table[i] = Py_CHARMASK(table[i]);
if (delete!=NULL) {
for(i=0; i<dellen; i++) if (delete != NULL) {
trans_table[(int)delete[i]]=-1; for (i = 0; i < dellen; i++)
trans_table[(int)delete[i]] = -1;
} }
result = PyString_FromStringAndSize((char *)NULL, inlen); result = PyString_FromStringAndSize((char *)NULL, inlen);
if (result == NULL) if (result == NULL)
return NULL; return NULL;
output_start = output = PyString_AsString(result); output_start = output = PyString_AsString(result);
if (delete!=NULL && dellen!=0) {
if (delete != NULL && dellen != 0) {
for (i = 0; i < inlen; i++) { for (i = 0; i < inlen; i++) {
int c = Py_CHARMASK(*input++); int c = Py_CHARMASK(*input++);
if (trans_table[c]!=-1) if (trans_table[c] != -1)
*output++ = (char)trans_table[c]; *output++ = (char)trans_table[c];
} }
/* Fix the size of the resulting string */ /* Fix the size of the resulting string */
@ -733,17 +696,18 @@ strop_translate(self, args)
/* List of functions defined in the module */ /* List of functions defined in the module */
static PyMethodDef strop_methods[] = { static PyMethodDef
strop_methods[] = {
{"atof", strop_atof}, {"atof", strop_atof},
{"atoi", strop_atoi}, {"atoi", strop_atoi, 1},
{"atol", strop_atol}, {"atol", strop_atol, 1},
{"capitalize", strop_capitalize}, {"capitalize", strop_capitalize},
{"find", strop_find}, {"find", strop_find, 1},
{"join", strop_joinfields, 1}, {"join", strop_joinfields, 1},
{"joinfields", strop_joinfields, 1}, {"joinfields", strop_joinfields, 1},
{"lstrip", strop_lstrip}, {"lstrip", strop_lstrip},
{"lower", strop_lower}, {"lower", strop_lower},
{"rfind", strop_rfind}, {"rfind", strop_rfind, 1},
{"rstrip", strop_rstrip}, {"rstrip", strop_rstrip},
{"split", strop_splitfields, 1}, {"split", strop_splitfields, 1},
{"splitfields", strop_splitfields, 1}, {"splitfields", strop_splitfields, 1},