Rework and simplify $remw() implementation
This replaces calls to alloca() followed by two strcpy()s with a single call to memmove(), and removes a confusing for/break structure. The function should behave exactly as it did before.
This commit is contained in:
@@ -2130,46 +2130,54 @@ BUILT_IN_FUNCTION(function_restw, word)
|
|||||||
* returns "string of text" with the word "word" removed
|
* returns "string of text" with the word "word" removed
|
||||||
* EX: $remw(the now is the time for) returns "now is time for"
|
* EX: $remw(the now is the time for) returns "now is time for"
|
||||||
*/
|
*/
|
||||||
BUILT_IN_FUNCTION(function_remw, word)
|
BUILT_IN_FUNCTION(function_remw, text)
|
||||||
{
|
{
|
||||||
char *word_to_remove;
|
char *word_to_remove;
|
||||||
int len;
|
size_t len;
|
||||||
char *str;
|
char *str;
|
||||||
|
|
||||||
GET_STR_ARG(word_to_remove, word);
|
GET_STR_ARG(word_to_remove, text);
|
||||||
len = strlen(word_to_remove);
|
len = strlen(word_to_remove);
|
||||||
|
|
||||||
str = stristr(word, word_to_remove);
|
/* Find the first instance of word_to_remove that's either at the start
|
||||||
for (; str && *str; str = stristr(str + 1, word_to_remove))
|
* of the text or preceded by a space, and is either at the end of the
|
||||||
|
* text or followed by a space. */
|
||||||
|
str = stristr(text, word_to_remove);
|
||||||
|
|
||||||
|
while (str &&
|
||||||
|
((str != text && !isspace((unsigned char)str[-1])) ||
|
||||||
|
(str[len] && !isspace((unsigned char)str[len]))))
|
||||||
{
|
{
|
||||||
if (str == word || isspace((unsigned char)str[-1]))
|
str = stristr(str + 1, word_to_remove);
|
||||||
{
|
|
||||||
if (!str[len] || isspace((unsigned char)str[len]))
|
|
||||||
{
|
|
||||||
if (!str[len])
|
|
||||||
{
|
|
||||||
if (str != word)
|
|
||||||
str--;
|
|
||||||
*str = 0;
|
|
||||||
}
|
|
||||||
else if (str > word)
|
|
||||||
{
|
|
||||||
char *safe = (char *)alloca(strlen(str));
|
|
||||||
strcpy(safe, str + len);
|
|
||||||
strcpy(str - 1, safe);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
char *safe = (char *)alloca(strlen(str));
|
|
||||||
strcpy(safe, str + len + 1);
|
|
||||||
strcpy(str, safe);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
RETURN_STR(word);
|
if (str)
|
||||||
|
{
|
||||||
|
/* Move from the following space (if any) */
|
||||||
|
char *src = str + len;
|
||||||
|
char *dest;
|
||||||
|
|
||||||
|
/* We always discard at least one space around the word (except for the
|
||||||
|
* special case where the text is exactly equal to the word). If the
|
||||||
|
* word was found in the middle or end of text, we discard the space
|
||||||
|
* preceding the word, but if the word was found at the start of text
|
||||||
|
* we have to discard the space following the word, if any.
|
||||||
|
*/
|
||||||
|
if (str == text)
|
||||||
|
{
|
||||||
|
dest = str;
|
||||||
|
if (*src)
|
||||||
|
src++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
dest = str - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
memmove(dest, src, strlen(src) + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
RETURN_STR(text);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* $insertw(num word string of text)
|
/* $insertw(num word string of text)
|
||||||
|
|||||||
Reference in New Issue
Block a user