Skip to content

Commit 1648e53

Browse files
committed
Net result of Tim's checkins to stropmodule.c (2.78, 2.79, 2.80, 2.81),
stringobject.c (2.114, 2.115) and test_strop.py (1.11, 1.12). Fixes 'replace' behaviour on systems on which 'malloc(0)' returns NULL (together with previous checkins) and re-synchs the string-operation code in stringobject.c and stropmodule.c, with the exception of 'replace', which has the old semantics in stropmodule but the new semantics in stringobjects.
1 parent 49a8bec commit 1648e53

3 files changed

Lines changed: 65 additions & 41 deletions

File tree

‎Lib/test/test_strop.py‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,8 @@ def __getitem__(self, i): return self.seq[i]
7777
test('replace', 'one!two!three!', 'one@two@three!', '!', '@', 2)
7878
test('replace', 'one!two!three!', 'one@two@three@', '!', '@', 3)
7979
test('replace', 'one!two!three!', 'one@two@three@', '!', '@', 4)
80+
# CAUTION: a replace count of 0 means infinity only to strop, not to the
81+
# string .replace() method or to the string.replace() function.
8082
test('replace', 'one!two!three!', 'one@two@three@', '!', '@', 0)
8183
test('replace', 'one!two!three!', 'one@two@three@', '!', '@')
8284
test('replace', 'one!two!three!', 'one!two!three!', 'x', '@')

‎Modules/stropmodule.c‎

Lines changed: 28 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -982,7 +982,8 @@ strop_translate(PyObject *self, PyObject *args)
982982
found, or -1 if not found. If len of PAT is greater than length of
983983
MEM, the function returns -1.
984984
*/
985-
static int mymemfind(char *mem, int len, char *pat, int pat_len)
985+
static int
986+
mymemfind(const char *mem, int len, const char *pat, int pat_len)
986987
{
987988
register int ii;
988989

@@ -1006,7 +1007,8 @@ static int mymemfind(char *mem, int len, char *pat, int pat_len)
10061007
meaning mem=1111 and pat==11 returns 2.
10071008
mem=11111 and pat==11 also return 2.
10081009
*/
1009-
static int mymemcnt(char *mem, int len, char *pat, int pat_len)
1010+
static int
1011+
mymemcnt(const char *mem, int len, const char *pat, int pat_len)
10101012
{
10111013
register int offset = 0;
10121014
int nfound = 0;
@@ -1041,7 +1043,12 @@ static int mymemcnt(char *mem, int len, char *pat, int pat_len)
10411043
the new string allocated locally, or
10421044
NULL if an error occurred.
10431045
*/
1044-
static char *mymemreplace(char *str, int len, char *pat, int pat_len, char *sub, int sub_len, int count, int *out_len)
1046+
static char *
1047+
mymemreplace(const char *str, int len, /* input string */
1048+
const char *pat, int pat_len, /* pattern string to find */
1049+
const char *sub, int sub_len, /* substitution string */
1050+
int count, /* number of replacements */
1051+
int *out_len)
10451052
{
10461053
char *out_s;
10471054
char *new_s;
@@ -1052,14 +1059,20 @@ static char *mymemreplace(char *str, int len, char *pat, int pat_len, char *sub,
10521059

10531060
/* find length of output string */
10541061
nfound = mymemcnt(str, len, pat, pat_len);
1055-
if (count > 0)
1056-
nfound = nfound > count ? count : nfound;
1062+
if (count < 0)
1063+
count = INT_MAX;
1064+
else if (nfound > count)
1065+
nfound = count;
10571066
if (nfound == 0)
10581067
goto return_same;
10591068

10601069
new_len = len + nfound*(sub_len - pat_len);
10611070
if (new_len == 0) {
1062-
out_s = "";
1071+
/* Have to allocate something for the caller to free(). */
1072+
out_s = (char *)PyMem_MALLOC(1);
1073+
if (out_s == NULL)
1074+
return NULL;
1075+
out_s[0] = '\0';
10631076
}
10641077
else {
10651078
assert(new_len > 0);
@@ -1068,7 +1081,7 @@ static char *mymemreplace(char *str, int len, char *pat, int pat_len, char *sub,
10681081
return NULL;
10691082
out_s = new_s;
10701083

1071-
while (len > 0) {
1084+
for (; count > 0 && len > 0; --count) {
10721085
/* find index of next instance of pattern */
10731086
offset = mymemfind(str, len, pat, pat_len);
10741087
if (offset == -1)
@@ -1083,10 +1096,6 @@ static char *mymemreplace(char *str, int len, char *pat, int pat_len, char *sub,
10831096
new_s += offset;
10841097
memcpy(new_s, sub, sub_len);
10851098
new_s += sub_len;
1086-
1087-
/* note count==0 is effectively infinity */
1088-
if (--count == 0)
1089-
break;
10901099
}
10911100
/* copy any remaining values into output string */
10921101
if (len > 0)
@@ -1097,7 +1106,7 @@ static char *mymemreplace(char *str, int len, char *pat, int pat_len, char *sub,
10971106

10981107
return_same:
10991108
*out_len = -1;
1100-
return str;
1109+
return (char *)str; /* cast away const */
11011110
}
11021111

11031112

@@ -1113,7 +1122,7 @@ strop_replace(PyObject *self, PyObject *args)
11131122
{
11141123
char *str, *pat,*sub,*new_s;
11151124
int len,pat_len,sub_len,out_len;
1116-
int count = 0;
1125+
int count = -1;
11171126
PyObject *new;
11181127

11191128
if (!PyArg_ParseTuple(args, "t#t#t#|i:replace",
@@ -1124,6 +1133,12 @@ strop_replace(PyObject *self, PyObject *args)
11241133
PyErr_SetString(PyExc_ValueError, "empty pattern string");
11251134
return NULL;
11261135
}
1136+
/* CAUTION: strop treats a replace count of 0 as infinity, unlke
1137+
* current (2.1) string.py and string methods. Preserve this for
1138+
* ... well, hard to say for what <wink>.
1139+
*/
1140+
if (count == 0)
1141+
count = -1;
11271142
new_s = mymemreplace(str,len,pat,pat_len,sub,sub_len,count,&out_len);
11281143
if (new_s == NULL) {
11291144
PyErr_NoMemory();

‎Objects/stringobject.c‎

Lines changed: 35 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1531,7 +1531,7 @@ mymemreplace(const char *str, int len, /* input string */
15311531
const char *pat, int pat_len, /* pattern string to find */
15321532
const char *sub, int sub_len, /* substitution string */
15331533
int count, /* number of replacements */
1534-
int *out_len)
1534+
int *out_len)
15351535
{
15361536
char *out_s;
15371537
char *new_s;
@@ -1548,41 +1548,48 @@ mymemreplace(const char *str, int len, /* input string */
15481548
nfound = count;
15491549
if (nfound == 0)
15501550
goto return_same;
1551+
15511552
new_len = len + nfound*(sub_len - pat_len);
1553+
if (new_len == 0) {
1554+
/* Have to allocate something for the caller to free(). */
1555+
out_s = (char *)PyMem_MALLOC(1);
1556+
if (out_s == NULL)
1557+
return NULL;
1558+
out_s[0] = '\0';
1559+
}
1560+
else {
1561+
assert(new_len > 0);
1562+
new_s = (char *)PyMem_MALLOC(new_len);
1563+
if (new_s == NULL)
1564+
return NULL;
1565+
out_s = new_s;
15521566

1553-
new_s = (char *)PyMem_MALLOC(new_len);
1554-
if (new_s == NULL) return NULL;
1567+
for (; count > 0 && len > 0; --count) {
1568+
/* find index of next instance of pattern */
1569+
offset = mymemfind(str, len, pat, pat_len);
1570+
if (offset == -1)
1571+
break;
1572+
1573+
/* copy non matching part of input string */
1574+
memcpy(new_s, str, offset);
1575+
str += offset + pat_len;
1576+
len -= offset + pat_len;
15551577

1578+
/* copy substitute into the output string */
1579+
new_s += offset;
1580+
memcpy(new_s, sub, sub_len);
1581+
new_s += sub_len;
1582+
}
1583+
/* copy any remaining values into output string */
1584+
if (len > 0)
1585+
memcpy(new_s, str, len);
1586+
}
15561587
*out_len = new_len;
1557-
out_s = new_s;
1558-
1559-
while (len > 0) {
1560-
/* find index of next instance of pattern */
1561-
offset = mymemfind(str, len, pat, pat_len);
1562-
/* if not found, break out of loop */
1563-
if (offset == -1) break;
1564-
1565-
/* copy non matching part of input string */
1566-
memcpy(new_s, str, offset); /* copy part of str before pat */
1567-
str += offset + pat_len; /* move str past pattern */
1568-
len -= offset + pat_len; /* reduce length of str remaining */
1569-
1570-
/* copy substitute into the output string */
1571-
new_s += offset; /* move new_s to dest for sub string */
1572-
memcpy(new_s, sub, sub_len); /* copy substring into new_s */
1573-
new_s += sub_len; /* offset new_s past sub string */
1574-
1575-
/* break when we've done count replacements */
1576-
if (--count == 0) break;
1577-
}
1578-
/* copy any remaining values into output string */
1579-
if (len > 0)
1580-
memcpy(new_s, str, len);
15811588
return out_s;
15821589

15831590
return_same:
15841591
*out_len = -1;
1585-
return (char*)str; /* have to cast away constness here */
1592+
return (char *)str; /* cast away const */
15861593
}
15871594

15881595

0 commit comments

Comments
 (0)