#include "arc/std/string.h" #include "arc/std/bool.h" #include "arc/std/errno.h" #include #include #include void ARC_String_Create(ARC_String **string, char *data, uint64_t length){ *string = (ARC_String *)malloc(sizeof(ARC_String)); (*string)->data = (char *)malloc(sizeof(char) * (length + 1)); (*string)->length = length; strncpy((*string)->data, data, length); (*string)->data[length] = '\0'; } void ARC_String_CreateWithStrlen(ARC_String **string, char *data){ *string = (ARC_String *)malloc(sizeof(ARC_String)); (*string)->length = strlen(data); (*string)->data = (char *)malloc(sizeof(char) * ((*string)->length + 1)); strncpy((*string)->data, data, (*string)->length); (*string)->data[(*string)->length] = '\0'; } void ARC_String_Destroy(ARC_String *string){ if(string->data){ free(string->data); } free(string); } void ARC_String_Copy(ARC_String **copy, ARC_String *original){ if(!original){ arc_errno = ARC_ERRNO_NULL; *copy = NULL; return; } ARC_String_Create(copy, original->data, original->length); } void ARC_String_CopySubstring(ARC_String **substring, ARC_String *original, uint64_t start, uint64_t length){ if(!original){ arc_errno = ARC_ERRNO_NULL; *substring = NULL; return; } if(length == 0){ *substring = NULL; return; } if(start + length > original->length){ arc_errno = ARC_ERRNO_DATA; *substring = NULL; return; } char data[length]; for(uint32_t i = 0; i < length; i++){ data[i] = 0; } strncpy(data, original->data + start, length); ARC_String_Create(substring, data, length); } void ARC_String_RemoveSubstring(ARC_String **newString, ARC_String *original, ARC_String *substring){ uint64_t index = ARC_String_Find(original, substring); if(arc_errno){ newString = NULL; return; } ARC_String_RemoveSection(newString, original, index, original->length); } ARC_Bool ARC_String_Equals(ARC_String *first, ARC_String *second){ if(first->length != second->length){ return ARC_False; } if(strncmp(first->data, second->data, first->length)){ return ARC_False; } return ARC_True; } ARC_Bool ARC_String_EqualsCString(ARC_String *string, const char *cstring, uint64_t length){ if(string->length != length){ return ARC_False; } if(strncmp(string->data, cstring, string->length)){ return ARC_False; } return ARC_True; } ARC_Bool ARC_String_EqualsCStringWithStrlen(ARC_String *string, const char *cstring){ return ARC_String_EqualsCString(string, cstring, strlen(cstring)); } 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 ARC_False; } if(strncmp(string->data + offset, cstring, length)){ return ARC_False; } return ARC_True; } uint8_t ARC_String_Alpha(ARC_String *string){ for(uint64_t length = string->length; length; length--){ if(string->data[length - 1] >= 'a' && string->data[length - 1] <= 'z'){ continue; } if(string->data[length - 1] >= 'A' && string->data[length - 1] <= 'Z'){ continue; } return 1; } return 0; } uint64_t ARC_String_ToUint64_t(ARC_String *string){ return (uint64_t) strtoul(string->data, NULL, 10); } int64_t ARC_String_ToInt64_t(ARC_String *string){ return (int64_t) strtol(string->data, NULL, 10); } double ARC_String_ToDouble(ARC_String *string){ return strtod(string->data, NULL); } uint64_t ARC_String_Find(ARC_String *string, ARC_String *substring){ if(!string || !substring){ ARC_DEBUG_ERR("ARC_String_Find(string, substring), string or substring was null"); arc_errno = ARC_ERRNO_NULL; return ~(uint64_t)0; } if(substring->length > string->length){ return ~(uint64_t)0; } uint64_t max = string->length - (substring->length - 1); for(uint64_t i = 0; max; i++, max--){ if(!strncmp(string->data + i, substring->data, substring->length)){ return i; } } return ~(uint64_t)0; } uint64_t ARC_String_FindCString(ARC_String *string, const char *cstring, uint64_t length){ if(!string || !cstring){ arc_errno = ARC_ERRNO_NULL; ARC_DEBUG_ERR("ARC_String_FindCString(string, cstring, length), string or cstring was null"); return ~(uint64_t)0; } if(string->length < length){ return ~(uint64_t)0; } uint64_t max = string->length - (length - 1); for(uint64_t i = 0; i < max; i++){ if(!strncmp(string->data + i, cstring, length)){ return i + 1; } } return ~(uint64_t)0; } uint64_t ARC_String_FindCStringWithStrlen(ARC_String *string, const char *cstring){ return ARC_String_FindCString(string, cstring, strlen(cstring)); } uint64_t ARC_String_FindBack(ARC_String *string, ARC_String *substring){ if(!string || !substring){ arc_errno = ARC_ERRNO_NULL; ARC_DEBUG_ERR("ARC_String_FindBack(string, substring), string or substring was null"); return ~(uint64_t)0; } if(substring->length > string->length){ return ~(uint64_t)0; } uint64_t max = string->length - (substring->length - 1); for(; max; max--){ if(!strncmp(string->data + (max - 1), substring->data, substring->length)){ return max; } } return ~(uint64_t)0; } uint64_t ARC_String_FindBackCString(ARC_String *string, const char *cstring, uint64_t length){ if(!string || !cstring){ arc_errno = ARC_ERRNO_NULL; ARC_DEBUG_ERR("ARC_String_FindBack(string, substring), string or substring was null"); return ~(uint64_t)0; } if(length > string->length){ return ~(uint64_t)0; } uint64_t max = string->length - (length - 1); for(; max; max--){ if(!strncmp(string->data + (max - 1), cstring, length)){ return max; } } return ~(uint64_t)0; } uint64_t ARC_String_FindBackCStringWithStrlen(ARC_String *string, const char *cstring){ return ARC_String_FindBackCString(string, cstring, strlen(cstring)); } void ARC_String_StripEnds(ARC_String **stripped, ARC_String *original, char charToStrip){ if(!original){ arc_errno = ARC_ERRNO_NULL; *stripped = NULL; return; } if(!original->length){ arc_errno = ARC_ERRNO_DATA; *stripped = NULL; return; } uint64_t length = original->length - 1; for(; length; length--){ if(strncmp(original->data + (length - 1), &charToStrip, 1)){ break; } } if(!length){ arc_errno = ARC_ERRNO_DATA; *stripped = NULL; return; } uint64_t start = 0; for(; start <= length; start++){ if(strncmp(original->data + start, &charToStrip, 1)){ break; } } if(start == length){ arc_errno = ARC_ERRNO_DATA; *stripped = NULL; return; } length -= start; ARC_String_Create(stripped, original->data + start, length); } void ARC_String_StripWhitespace(ARC_String **stripped, ARC_String *original){ if(!original){ arc_errno = ARC_ERRNO_NULL; *stripped = NULL; return; } if(!original->length){ arc_errno = ARC_ERRNO_DATA; *stripped = NULL; return; } uint64_t length = 0; for(uint64_t i = 0; i < original->length; i++){ if(original->data[i] == ' '){ continue; } if(original->data[i] == '\n'){ continue; } if(original->data[i] == '\t'){ continue; } if(original->data[i] == '\r'){ continue; } length++; } if(!length){ arc_errno = ARC_ERRNO_DATA; *stripped = NULL; return; } length++; char data[length]; for(uint32_t i = 0; i < length; i++){ data[i] = 0; } uint64_t start = 0; for(uint64_t i = 0; i < length; i++){ if(original->data[i] == ' '){ continue; } if(original->data[i] == '\n'){ continue; } if(original->data[i] == '\t'){ continue; } if(original->data[i] == '\r'){ continue; } data[start] = original->data[i]; start++; } ARC_String_Create(stripped, data, length); } void ARC_String_StripEndsWhitespace(ARC_String **stripped, ARC_String *original){ uint64_t index; for(uint64_t i = 0; i < original->length; i++){ if(original->data[i] == ' '){ continue; } if(original->data[i] == '\n'){ continue; } if(original->data[i] == '\t'){ continue; } if(original->data[i] == '\r'){ continue; } index = i; break; } uint64_t endIndex; for(uint64_t i = original->length;; i--){ if(original->data[i - 1] == ' '){ continue; } if(original->data[i - 1] == '\n'){ continue; } if(original->data[i - 1] == '\t'){ continue; } if(original->data[i - 1] == '\r'){ continue; } endIndex = i; break; } ARC_String_CopySubstring(stripped, original, index, endIndex - index); } void ARC_String_Merge(ARC_String **combined, ARC_String *first, ARC_String *second){ char data[first->length + second->length]; for(uint32_t i = 0; i < first->length; i++){ data[i] = first->data[i]; } for(uint32_t i = 0; i < second->length; i++){ data[i + first->length] = second->data[i]; } ARC_String_Create(combined, data, first->length + second->length); } void ARC_String_RemoveSection(ARC_String **newString, ARC_String *original, uint64_t removeIndex, uint64_t removeLength){ if(removeIndex == 0 && removeIndex + removeLength >= original->length){ ARC_String_Copy(newString, original); return; } if(removeIndex == 0){ ARC_String_CopySubstring(newString, original, removeLength, original->length - removeLength); return; } if(removeIndex + removeLength >= original->length){ ARC_String_CopySubstring(newString, original, 0, removeIndex); return; } ARC_String *first, *second; ARC_String_CopySubstring(&first , original, 0 , removeIndex ); ARC_String_CopySubstring(&second, original, removeIndex + removeLength, original->length - (removeIndex + removeLength)); ARC_String_Merge(newString, first, second); ARC_String_Destroy(first ); ARC_String_Destroy(second); } 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)); }