* NOTE: Do not edit this for the love of god unless you have * read the test cases and understand the code behind each one. * While I don't guarantee there aren't mistakes, I do guarantee * that plugins will end up relying on tiny idiosyncrasies of this * function, just like they did with AMX Mod X. * * There are explicitly more cases than the AMX Mod X version because * we're not d
| 115 | * string in a way that pushes old data out. |
| 116 | */ |
| 117 | char *UTIL_ReplaceEx(char *subject, size_t maxLen, const char *search, size_t searchLen, const char *replace, size_t replaceLen, bool caseSensitive) |
| 118 | { |
| 119 | char *ptr = subject; |
| 120 | size_t browsed = 0; |
| 121 | size_t textLen = strlen(subject); |
| 122 | |
| 123 | /* It's not possible to search or replace */ |
| 124 | if (searchLen > textLen) |
| 125 | { |
| 126 | return NULL; |
| 127 | } |
| 128 | |
| 129 | /* Handle the case of one byte replacement. |
| 130 | * It's only valid in one case. |
| 131 | */ |
| 132 | if (maxLen == 1) |
| 133 | { |
| 134 | /* If the search matches and the replace length is 0, |
| 135 | * we can just terminate the string and be done. |
| 136 | */ |
| 137 | if ((caseSensitive ? strcmp(subject, search) : strcasecmp(subject, search)) == 0 && replaceLen == 0) |
| 138 | { |
| 139 | *subject = '\0'; |
| 140 | return subject; |
| 141 | } |
| 142 | else |
| 143 | { |
| 144 | return NULL; |
| 145 | } |
| 146 | } |
| 147 | |
| 148 | /* Subtract one off the maxlength so we can include the null terminator */ |
| 149 | maxLen--; |
| 150 | |
| 151 | while (*ptr != '\0' && (browsed <= textLen - searchLen)) |
| 152 | { |
| 153 | /* See if we get a comparison */ |
| 154 | if ((caseSensitive ? strncmp(ptr, search, searchLen) : strncasecmp(ptr, search, searchLen)) == 0) |
| 155 | { |
| 156 | if (replaceLen > searchLen) |
| 157 | { |
| 158 | /* First, see if we have enough space to do this operation */ |
| 159 | if (maxLen - textLen < replaceLen - searchLen) |
| 160 | { |
| 161 | /* First, see if the replacement length goes out of bounds. */ |
| 162 | if (browsed + replaceLen >= maxLen) |
| 163 | { |
| 164 | /* EXAMPLE CASE: |
| 165 | * Subject: AABBBCCC |
| 166 | * Buffer : 12 bytes |
| 167 | * Search : BBB |
| 168 | * Replace: DDDDDDDDDD |
| 169 | * OUTPUT : AADDDDDDDDD |
| 170 | * POSITION: ^ |
| 171 | */ |
| 172 | /* If it does, we'll just bound the length and do a strcpy. */ |
| 173 | replaceLen = maxLen - browsed; |
| 174 | /* Note, we add one to the final result for the null terminator */ |
no test coverage detected