diff --git a/include/arc/std/string.h b/include/arc/std/string.h index 9cee4b6..a01d97d 100644 --- a/include/arc/std/string.h +++ b/include/arc/std/string.h @@ -6,6 +6,7 @@ extern "C" { #endif #include +#include "bool.h" /** * @brief substring position within a string @@ -72,9 +73,9 @@ void ARC_String_RemoveSubstring(ARC_String **newString, ARC_String *original, AR * @param first string to check against second * @param second string to check against first * - * @return 1 if match, 0 if they don't match + * @return ARC_True if match, ARC_False if they don't match */ -uint8_t ARC_String_Equals(ARC_String *first, ARC_String *second); +ARC_Bool ARC_String_Equals(ARC_String *first, ARC_String *second); /** * @brief check if ARC_String and cstring match @@ -83,9 +84,9 @@ uint8_t ARC_String_Equals(ARC_String *first, ARC_String *second); * @param cstring cstring to check * @param length length of cstring * - * @return 1 if match, 0 if they don't match + * @return ARC_True if match, ARC_False if they don't match */ -uint8_t ARC_String_EqualsCString(ARC_String *string, const char *cstring, uint64_t length); +ARC_Bool ARC_String_EqualsCString(ARC_String *string, const char *cstring, uint64_t length); /** * @brief check if ARC_String and cstring match @@ -95,9 +96,20 @@ uint8_t ARC_String_EqualsCString(ARC_String *string, const char *cstring, uint64 * @param string ARC_string to check * @param cstring cstring to check * - * @return 1 if match, 0 if they don't match + * @return ARC_True if match, ARC_False if they don't match */ -uint8_t ARC_String_EqualsCStringWithStrlen(ARC_String *string, const char *cstring); +ARC_Bool ARC_String_EqualsCStringWithStrlen(ARC_String *string, const char *cstring); + +/** + * @brief check if substring of first equals second string + * + * @param first string to check against second + * @param offset postion based on first to start comparing against second + * @param second string to check against first + * + * @return ARC_True if match, ARC_False if they don't match +*/ +ARC_Bool ARC_String_SubstringEquals(ARC_String *first, uint64_t offset, ARC_String *second); /** * @brief check if ARC_String and cstring match @@ -107,9 +119,9 @@ uint8_t ARC_String_EqualsCStringWithStrlen(ARC_String *string, const char *cstri * @param cstring cstring to check * @param length length of cstring * - * @return 1 if match, 0 if they don't match + * @return ARC_True if match, ARC_False if they don't match */ -uint8_t ARC_String_SubstringEqualsCString(ARC_String *string, uint64_t offset, const char *cstring, uint64_t length); +ARC_Bool ARC_String_SubstringEqualsCString(ARC_String *string, uint64_t offset, const char *cstring, uint64_t length); /** * @brief checks if string is alphabetic @@ -260,6 +272,52 @@ void ARC_String_Merge(ARC_String **combined, ARC_String *first, ARC_String *seco */ void ARC_String_RemoveSection(ARC_String **newString, ARC_String *original, uint64_t removeIndex, uint64_t removeLength); +/** + * @brief replaces characters in string matching the given pattern + * + * @note this uses ARC_String_CopyReplaceMatching, so debug logs will be thrown in that function not this one + * + * @param string the string that will be modified, will discard changes and set arc_errno on fail + * @param pattern the pattern to replace in the string on match + * @param replacement the string that will replace the matched pattern +*/ +void ARC_String_ReplaceMatching(ARC_String **string, ARC_String *pattern, ARC_String *replacement); + +/** + * @brief replaces characters in a copy of a string matching the given pattern + * + * @note original will not be modified + * @note newString will need to be destroyed if it is not set to NULL + * + * @param newString an empty string that this function will fill with a copy with replacements, will be set to NULL and arc_errno set on fail + * @param original the original string that will be copied + * @param pattern the pattern to replace in the string on match + * @param replacement the string that will replace the matched pattern +*/ +void ARC_String_CopyReplaceMatching(ARC_String **newString, ARC_String *original, ARC_String *pattern, ARC_String *replacement); + +/** + * @brief replaces characters in string matching the given pattern + * + * @param string the string that will be modified, will discard changes and set arc_errno on fail + * @param patternCString the cstring pattern to replace in the string on match + * @param patternLength the lenght of the cstring pattern + * @param replacementCstring the cstring that will replace the matched pattern + * @param replacementLength the length of the cstring replacement +*/ +void ARC_String_ReplaceMatchingCString(ARC_String **string, char *patternCString, uint64_t patternLength, char *replacementCString, uint64_t replacementLength); + +/** + * @brief replaces characters in string matching the given pattern + * + * @note this uses ARC_String_ReplaceMatchingCString, so debug logs will be thrown in that function not this one + * + * @param string the string that will be modified, will discard changes and set arc_errno on fail + * @param patternCString the cstring pattern to replace in the string on match + * @param replacementCstring the cstring that will replace the matched pattern +*/ +void ARC_String_ReplaceMatchingCStringWithStrlen(ARC_String **string, char *patternCString, char *replacement); + #ifdef __cplusplus } #endif diff --git a/src/std/string.c b/src/std/string.c index 243d30d..c1fa1da 100644 --- a/src/std/string.c +++ b/src/std/string.c @@ -1,5 +1,6 @@ #include "arc/std/string.h" +#include "arc/std/bool.h" #include "arc/std/errno.h" #include #include @@ -7,7 +8,7 @@ void ARC_String_Create(ARC_String **string, char *data, uint64_t length){ *string = (ARC_String *)malloc(sizeof(ARC_String)); - (*string)->data = (char *)malloc(length + 1); + (*string)->data = (char *)malloc(sizeof(char) * (length + 1)); (*string)->length = length; strncpy((*string)->data, data, length); @@ -17,7 +18,7 @@ void ARC_String_Create(ARC_String **string, char *data, uint64_t length){ void ARC_String_CreateWithStrlen(ARC_String **string, char *data){ *string = (ARC_String *)malloc(sizeof(ARC_String)); (*string)->length = strlen(data); - (*string)->data = (char *)malloc((*string)->length + 1); + (*string)->data = (char *)malloc(sizeof(char) * ((*string)->length + 1)); strncpy((*string)->data, data, (*string)->length); (*string)->data[(*string)->length] = '\0'; @@ -78,44 +79,48 @@ void ARC_String_RemoveSubstring(ARC_String **newString, ARC_String *original, AR ARC_String_RemoveSection(newString, original, index, original->length); } -uint8_t ARC_String_Equals(ARC_String *first, ARC_String *second){ +ARC_Bool ARC_String_Equals(ARC_String *first, ARC_String *second){ if(first->length != second->length){ - return 0; + return ARC_False; } if(strncmp(first->data, second->data, first->length)){ - return 0; + return ARC_False; } - return 1; + return ARC_True; } -uint8_t ARC_String_EqualsCString(ARC_String *string, const char *cstring, uint64_t length){ +ARC_Bool ARC_String_EqualsCString(ARC_String *string, const char *cstring, uint64_t length){ if(string->length != length){ - return 0; + return ARC_False; } if(strncmp(string->data, cstring, string->length)){ - return 0; + return ARC_False; } - return 1; + return ARC_True; } -uint8_t ARC_String_EqualsCStringWithStrlen(ARC_String *string, const char *cstring){ +ARC_Bool ARC_String_EqualsCStringWithStrlen(ARC_String *string, const char *cstring){ return ARC_String_EqualsCString(string, cstring, strlen(cstring)); } -uint8_t ARC_String_SubstringEqualsCString(ARC_String *string, uint64_t offset, const char *cstring, uint64_t length){ +ARC_Bool ARC_String_SubstringEquals(ARC_String *first, uint64_t offset, ARC_String *second){ + return ARC_String_SubstringEqualsCString(first, offset, second->data, second->length); +} + +ARC_Bool ARC_String_SubstringEqualsCString(ARC_String *string, uint64_t offset, const char *cstring, uint64_t length){ if(string->length - offset < length){ - return 0; + return ARC_False; } if(strncmp(string->data + offset, cstring, length)){ - return 0; + return ARC_False; } - return 1; + return ARC_True; } uint8_t ARC_String_Alpha(ARC_String *string){ @@ -439,4 +444,120 @@ void ARC_String_RemoveSection(ARC_String **newString, ARC_String *original, uint ARC_String_Destroy(first ); ARC_String_Destroy(second); -} \ No newline at end of file +} + +void ARC_String_ReplaceMatching(ARC_String **string, ARC_String *pattern, ARC_String *replacement){ + ARC_String *copyReplaced; + ARC_String_CopyReplaceMatching(©Replaced, *string, pattern, replacement); + + if(arc_errno != 0 || copyReplaced == NULL){ + return; + } + + ARC_String_Destroy(*string); + *string = copyReplaced; +} + +void ARC_String_CopyReplaceMatching(ARC_String **newString, ARC_String *original, ARC_String *pattern, ARC_String *replacement){ + //TODO: probs want to check if the replacement goes over a uint64_t size + if(original == NULL || pattern == NULL || replacement == NULL){ + arc_errno = ARC_ERRNO_NULL; + ARC_DEBUG_ERR("ARC_String_CopyReplaceMatching(newString, original, pattern, replacement), original, pattern, or replacement was null"); + return; + } + + uint64_t numberOfMatches = 0; + for(uint64_t originalIndex = 0; originalIndex < original->length; originalIndex++){ + if(ARC_String_SubstringEquals(original, originalIndex, pattern)){ + numberOfMatches++; + originalIndex += pattern->length - 1; + } + } + + //no matches were found, but that isn't an error, so copy and return + if(numberOfMatches == 0){ + ARC_String_Copy(newString, original); + return; + } + + (*newString) = (ARC_String *)malloc(sizeof(ARC_String)); + (*newString)->length = original->length + (replacement->length - pattern->length); + (*newString)->data = (char *)malloc(sizeof(char *) * original->length + 1); + + for(uint64_t originalIndex = 0, newIndex = 0; originalIndex < original->length; originalIndex++, newIndex++){ + if(ARC_String_SubstringEquals(original, originalIndex, pattern)){ + for(uint64_t replacementIndex = 0; replacementIndex < replacement->length; replacementIndex++){ + (*newString)->data[newIndex + replacementIndex] = replacement->data[replacementIndex]; + } + + originalIndex += pattern->length - 1; + newIndex += replacement->length - 1; + continue; + } + + (*newString)->data[newIndex] = original->data[originalIndex]; + } + + (*newString)->data[(*newString)->length] = '\0'; +} + +/** + * @brief replaces characters in string matching the given pattern + * + * @param string the string that will be modified, will discard changes and set arc_errno on fail + * @param patternCString the cstring pattern to replace in the string on match + * @param patternLength the lenght of the cstring pattern + * @param replacementCstring the cstring that will replace the matched pattern + * @param replacementLength the length of the cstring replacement +*/ +void ARC_String_ReplaceMatchingCString(ARC_String **string, char *patternCString, uint64_t patternLength, char *replacementCString, uint64_t replacementLength){ + //TODO: probs want to check if the replacement goes over a uint64_t size + if(*string == NULL || patternCString == NULL || replacementCString == NULL){ + arc_errno = ARC_ERRNO_NULL; + ARC_DEBUG_ERR("ARC_String_ReplaceMatchingCString(string, patternCString, patternLength, replacementCString, replacementLength), *string, patternCString, or replacementCString was null"); + return; + } + + ARC_String *original = *string; + + uint64_t numberOfMatches = 0; + for(uint64_t originalIndex = 0; originalIndex < original->length; originalIndex++){ + if(ARC_String_SubstringEqualsCString(original, originalIndex, patternCString, patternLength)){ + numberOfMatches++; + originalIndex += patternLength - 1; + } + } + + //no matches were found, but that isn't an error, so nothing to do, return + if(numberOfMatches == 0){ + return; + } + + (*string) = (ARC_String *)malloc(sizeof(ARC_String)); + (*string)->length = original->length + (replacementLength - patternLength); + (*string)->data = (char *)malloc(sizeof(char *) * original->length + 1); + + for(uint64_t originalIndex = 0, newIndex = 0; originalIndex < original->length; originalIndex++, newIndex++){ + if(ARC_String_SubstringEqualsCString(original, originalIndex, patternCString, patternLength)){ + for(uint64_t replacementIndex = 0; replacementIndex < replacementLength; replacementIndex++){ + (*string)->data[newIndex + replacementIndex] = replacementCString[replacementIndex]; + } + + originalIndex += patternLength - 1; + newIndex += replacementLength - 1; + continue; + } + + (*string)->data[newIndex] = original->data[originalIndex]; + } + + (*string)->data[(*string)->length] = '\0'; + + //cleanup + ARC_String_Destroy(original); +} + +void ARC_String_ReplaceMatchingCStringWithStrlen(ARC_String **string, char *patternCString, char *replacementCString){ + ARC_String_ReplaceMatchingCString(string, patternCString, strlen(patternCString), replacementCString, strlen(replacementCString)); +} +