From 1648e53efce867513ffdbdbdc044b9a8a810b8ad Mon Sep 17 00:00:00 2001 From: Thomas Wouters Date: Wed, 23 May 2001 14:38:53 +0000 Subject: 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. --- Lib/test/test_strop.py | 2 ++ Modules/stropmodule.c | 41 +++++++++++++++++++++----------- Objects/stringobject.c | 63 ++++++++++++++++++++++++++++---------------------- 3 files changed, 65 insertions(+), 41 deletions(-) diff --git a/Lib/test/test_strop.py b/Lib/test/test_strop.py index 5770046..9130088 100644 --- a/Lib/test/test_strop.py +++ b/Lib/test/test_strop.py @@ -77,6 +77,8 @@ test('replace', 'one!two!three!', 'one@two!three!', '!', '@', 1) test('replace', 'one!two!three!', 'one@two@three!', '!', '@', 2) test('replace', 'one!two!three!', 'one@two@three@', '!', '@', 3) test('replace', 'one!two!three!', 'one@two@three@', '!', '@', 4) +# CAUTION: a replace count of 0 means infinity only to strop, not to the +# string .replace() method or to the string.replace() function. test('replace', 'one!two!three!', 'one@two@three@', '!', '@', 0) test('replace', 'one!two!three!', 'one@two@three@', '!', '@') test('replace', 'one!two!three!', 'one!two!three!', 'x', '@') diff --git a/Modules/stropmodule.c b/Modules/stropmodule.c index abd27bc..bec246c 100644 --- a/Modules/stropmodule.c +++ b/Modules/stropmodule.c @@ -982,7 +982,8 @@ strop_translate(PyObject *self, PyObject *args) found, or -1 if not found. If len of PAT is greater than length of MEM, the function returns -1. */ -static int mymemfind(char *mem, int len, char *pat, int pat_len) +static int +mymemfind(const char *mem, int len, const char *pat, int pat_len) { register int ii; @@ -1006,7 +1007,8 @@ static int mymemfind(char *mem, int len, char *pat, int pat_len) meaning mem=1111 and pat==11 returns 2. mem=11111 and pat==11 also return 2. */ -static int mymemcnt(char *mem, int len, char *pat, int pat_len) +static int +mymemcnt(const char *mem, int len, const char *pat, int pat_len) { register int offset = 0; int nfound = 0; @@ -1041,7 +1043,12 @@ static int mymemcnt(char *mem, int len, char *pat, int pat_len) the new string allocated locally, or NULL if an error occurred. */ -static char *mymemreplace(char *str, int len, char *pat, int pat_len, char *sub, int sub_len, int count, int *out_len) +static char * +mymemreplace(const char *str, int len, /* input string */ + const char *pat, int pat_len, /* pattern string to find */ + const char *sub, int sub_len, /* substitution string */ + int count, /* number of replacements */ + int *out_len) { char *out_s; char *new_s; @@ -1052,14 +1059,20 @@ static char *mymemreplace(char *str, int len, char *pat, int pat_len, char *sub, /* find length of output string */ nfound = mymemcnt(str, len, pat, pat_len); - if (count > 0) - nfound = nfound > count ? count : nfound; + if (count < 0) + count = INT_MAX; + else if (nfound > count) + nfound = count; if (nfound == 0) goto return_same; new_len = len + nfound*(sub_len - pat_len); if (new_len == 0) { - out_s = ""; + /* Have to allocate something for the caller to free(). */ + out_s = (char *)PyMem_MALLOC(1); + if (out_s == NULL) + return NULL; + out_s[0] = '\0'; } else { assert(new_len > 0); @@ -1068,7 +1081,7 @@ static char *mymemreplace(char *str, int len, char *pat, int pat_len, char *sub, return NULL; out_s = new_s; - while (len > 0) { + for (; count > 0 && len > 0; --count) { /* find index of next instance of pattern */ offset = mymemfind(str, len, pat, pat_len); if (offset == -1) @@ -1083,10 +1096,6 @@ static char *mymemreplace(char *str, int len, char *pat, int pat_len, char *sub, new_s += offset; memcpy(new_s, sub, sub_len); new_s += sub_len; - - /* note count==0 is effectively infinity */ - if (--count == 0) - break; } /* copy any remaining values into output string */ if (len > 0) @@ -1097,7 +1106,7 @@ static char *mymemreplace(char *str, int len, char *pat, int pat_len, char *sub, return_same: *out_len = -1; - return str; + return (char *)str; /* cast away const */ } @@ -1113,7 +1122,7 @@ strop_replace(PyObject *self, PyObject *args) { char *str, *pat,*sub,*new_s; int len,pat_len,sub_len,out_len; - int count = 0; + int count = -1; PyObject *new; if (!PyArg_ParseTuple(args, "t#t#t#|i:replace", @@ -1124,6 +1133,12 @@ strop_replace(PyObject *self, PyObject *args) PyErr_SetString(PyExc_ValueError, "empty pattern string"); return NULL; } + /* CAUTION: strop treats a replace count of 0 as infinity, unlke + * current (2.1) string.py and string methods. Preserve this for + * ... well, hard to say for what . + */ + if (count == 0) + count = -1; new_s = mymemreplace(str,len,pat,pat_len,sub,sub_len,count,&out_len); if (new_s == NULL) { PyErr_NoMemory(); diff --git a/Objects/stringobject.c b/Objects/stringobject.c index 4de8b1f..25a7c92 100644 --- a/Objects/stringobject.c +++ b/Objects/stringobject.c @@ -1531,7 +1531,7 @@ mymemreplace(const char *str, int len, /* input string */ const char *pat, int pat_len, /* pattern string to find */ const char *sub, int sub_len, /* substitution string */ int count, /* number of replacements */ - int *out_len) + int *out_len) { char *out_s; char *new_s; @@ -1548,41 +1548,48 @@ mymemreplace(const char *str, int len, /* input string */ nfound = count; if (nfound == 0) goto return_same; + new_len = len + nfound*(sub_len - pat_len); + if (new_len == 0) { + /* Have to allocate something for the caller to free(). */ + out_s = (char *)PyMem_MALLOC(1); + if (out_s == NULL) + return NULL; + out_s[0] = '\0'; + } + else { + assert(new_len > 0); + new_s = (char *)PyMem_MALLOC(new_len); + if (new_s == NULL) + return NULL; + out_s = new_s; - new_s = (char *)PyMem_MALLOC(new_len); - if (new_s == NULL) return NULL; + for (; count > 0 && len > 0; --count) { + /* find index of next instance of pattern */ + offset = mymemfind(str, len, pat, pat_len); + if (offset == -1) + break; + + /* copy non matching part of input string */ + memcpy(new_s, str, offset); + str += offset + pat_len; + len -= offset + pat_len; + /* copy substitute into the output string */ + new_s += offset; + memcpy(new_s, sub, sub_len); + new_s += sub_len; + } + /* copy any remaining values into output string */ + if (len > 0) + memcpy(new_s, str, len); + } *out_len = new_len; - out_s = new_s; - - while (len > 0) { - /* find index of next instance of pattern */ - offset = mymemfind(str, len, pat, pat_len); - /* if not found, break out of loop */ - if (offset == -1) break; - - /* copy non matching part of input string */ - memcpy(new_s, str, offset); /* copy part of str before pat */ - str += offset + pat_len; /* move str past pattern */ - len -= offset + pat_len; /* reduce length of str remaining */ - - /* copy substitute into the output string */ - new_s += offset; /* move new_s to dest for sub string */ - memcpy(new_s, sub, sub_len); /* copy substring into new_s */ - new_s += sub_len; /* offset new_s past sub string */ - - /* break when we've done count replacements */ - if (--count == 0) break; - } - /* copy any remaining values into output string */ - if (len > 0) - memcpy(new_s, str, len); return out_s; return_same: *out_len = -1; - return (char*)str; /* have to cast away constness here */ + return (char *)str; /* cast away const */ } -- cgit v0.12