diff options
| author | pepper <peppersclothescult@gmail.com> | 2015-01-10 21:32:32 -0800 |
|---|---|---|
| committer | pepper <peppersclothescult@gmail.com> | 2015-01-10 21:32:32 -0800 |
| commit | d53fa8a169832563c62262078b8d2ffe5cab8473 (patch) | |
| tree | b911d06d357d009c976709780f10e92ce915228a /source/base/CharString.c | |
first
Diffstat (limited to 'source/base/CharString.c')
| -rw-r--r-- | source/base/CharString.c | 298 |
1 files changed, 298 insertions, 0 deletions
diff --git a/source/base/CharString.c b/source/base/CharString.c new file mode 100644 index 0000000..e44e4dd --- /dev/null +++ b/source/base/CharString.c @@ -0,0 +1,298 @@ +// +// CharString.c - MrsWatson +// Created by Nik Reiman on 1/2/12. +// Copyright (c) 2012 Teragon Audio. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "logging/EventLogger.h" + +CharString newCharString(void) +{ + return newCharStringWithCapacity(kCharStringLengthDefault); +} + +CharString newCharStringWithCapacity(size_t length) +{ + CharString charString = (CharString)malloc(sizeof(CharStringMembers)); + charString->capacity = length; + charString->data = (char *)malloc(sizeof(char) * length); + charStringClear(charString); + return charString; +} + +CharString newCharStringWithCString(const char *string) +{ + size_t length; + CharString result = NULL; + + length = string != NULL ? strlen(string) : 0; + + if (length > kCharStringLengthLong) { + logError("Can't create string with length %d", length); + } else if (length == 0) { + result = newCharString(); + } else { + // Add 1 to compensate for trailing null character + result = newCharStringWithCapacity(length + 1); + strncpy(result->data, string, length); + } + + return result; +} + +void charStringAppend(CharString self, const CharString string) +{ + charStringAppendCString(self, string->data); +} + +void charStringAppendCString(CharString self, const char *string) +{ + size_t stringLength = strlen(string); + size_t selfLength = strlen(self->data); + + if (stringLength + selfLength >= self->capacity) { + self->capacity = stringLength + selfLength + 1; // don't forget the null! + self->data = (char *)realloc(self->data, self->capacity); + strcat(self->data, string); + } else { + strcat(self->data, string); + } +} + +void charStringClear(CharString self) +{ + memset(self->data, 0, self->capacity); +} + +void charStringCopyCString(CharString self, const char *string) +{ + strncpy(self->data, string, self->capacity); +} + +void charStringCopy(CharString self, const CharString string) +{ + strncpy(self->data, string->data, self->capacity); +} + +boolByte charStringIsEmpty(const CharString self) +{ + return (boolByte)(self == NULL || self->data == NULL || self->data[0] == '\0'); +} + +boolByte charStringIsEqualTo(const CharString self, const CharString string, boolByte caseInsensitive) +{ + size_t comparisonSize; + + if (self == NULL || string == NULL) { + return false; + } + + // Only compare to the length of the smaller of the two strings + comparisonSize = self->capacity < string->capacity ? self->capacity : string->capacity; + + if (caseInsensitive) { + return (boolByte)(strncasecmp(self->data, string->data, comparisonSize) == 0); + } else { + return (boolByte)(strncmp(self->data, string->data, comparisonSize) == 0); + } +} + +boolByte charStringIsEqualToCString(const CharString self, const char *string, boolByte caseInsensitive) +{ + if (self == NULL || string == NULL) { + return false; + } else if (caseInsensitive) { + return (boolByte)(strncasecmp(self->data, string, self->capacity) == 0); + } else { + return (boolByte)(strncmp(self->data, string, self->capacity) == 0); + } +} + +boolByte charStringIsLetter(const CharString self, const size_t index) +{ + const char ch = self->data[index]; + return (boolByte)((ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z')); +} + +boolByte charStringIsNumber(const CharString self, const size_t index) +{ + const char ch = self->data[index]; + return (boolByte)(ch >= '0' && ch <= '9'); +} + +LinkedList charStringSplit(const CharString self, const char delimiter) +{ + LinkedList result = NULL; + char *delimiterPtr = NULL; + char *selfIndex = self->data; + CharString item = NULL; + size_t charsToCopy = 0; + boolByte done = false; + + if (delimiter == '\0') { + logError("Cannot split string with NULL delimiter"); + return NULL; + } + + result = newLinkedList(); + + while (!done) { + delimiterPtr = strchr(selfIndex, delimiter); + + if (delimiterPtr == NULL) { + done = true; + charsToCopy = self->data + strlen(self->data) - selfIndex; + } else { + charsToCopy = delimiterPtr - selfIndex; + } + + if (charsToCopy > 0) { + item = newCharStringWithCapacity(charsToCopy + 1); + strncpy(item->data, selfIndex, charsToCopy); + linkedListAppend(result, item); + } + + selfIndex = delimiterPtr + 1; + } + + return result; +} + +void _charStringWrap(const char *srcString, char *destString, size_t destStringSize, int indentSize, int lineLength); +void _charStringWrap(const char *srcString, char *destString, size_t destStringSize, int indentSize, int lineLength) +{ + char *lineBuffer = NULL; + unsigned long destStringIndex = 0; + unsigned long srcStringIndex = 0; + size_t lineIndex = 0; + int indentIndex = 0; + size_t bufferLength; + char *newlinePosition; + char *lastSpacePosition; + + // Sanity checks + if (srcString == NULL) { + return; + } else if (indentSize < 0 || indentSize > lineLength) { + return; + } else if (lineLength <= 0) { + return; + } + + lineBuffer = (char *)malloc(sizeof(char) * lineLength); + + while (srcStringIndex < strlen(srcString)) { + if (lineIndex == 0) { + for (indentIndex = 0; indentIndex < indentSize; indentIndex++) { + destString[destStringIndex++] = ' '; + lineIndex++; + } + } + + // Clear out the line buffer, and copy a full line into it + memset(lineBuffer, 0, lineLength); + bufferLength = lineLength - lineIndex - 1; // don't forget the null! + + if (bufferLength <= 0) { + break; + } + + strncpy(lineBuffer, srcString + srcStringIndex, bufferLength); + + // Check to see if we have copied the last line of the source string. If so, append that to + // the destination string and break. + if (bufferLength + srcStringIndex >= strlen(srcString)) { + strncpy(destString + destStringIndex, lineBuffer, destStringSize - destStringIndex - 1); + break; + } + + // Look for any newlines in the buffer, and stop there if we find any + newlinePosition = strchr(lineBuffer, '\n'); + + if (newlinePosition != NULL) { + bufferLength = newlinePosition - lineBuffer + 1; + strncpy(destString + destStringIndex, lineBuffer, destStringSize - destStringIndex - 1); + destStringIndex += bufferLength; + srcStringIndex += bufferLength; + lineIndex = 0; + continue; + } + + // If no newlines were found, then find the last space in this line and copy to that point + lastSpacePosition = strrchr(lineBuffer, ' '); + + if (lastSpacePosition == NULL) { + // If NULL is returned here, then there are no spaces in this line. In this case, insert + // a hyphen at the end of the line and start a new line. Also, we need to leave room + // for the newline, so subtract 2 from the total buffer length. + bufferLength = lineLength - lineIndex - 1; + strncpy(destString + destStringIndex, lineBuffer, bufferLength); + destString[lineLength - 1] = '-'; + // Move the destination string index ahead 1 to account for the hyphen, and the source + // string index back one to copy the last character from the previous line. + destStringIndex++; + srcStringIndex--; + } else { + bufferLength = lastSpacePosition - lineBuffer; + strncpy(destString + destStringIndex, lineBuffer, bufferLength); + } + + // Increase string indexes and continue looping + destStringIndex += bufferLength; + destString[destStringIndex++] = '\n'; + srcStringIndex += bufferLength + 1; + lineIndex = 0; + } + + free(lineBuffer); +} + +CharString charStringWrap(const CharString srcString, unsigned int indentSize) +{ + CharString destString; + + if (srcString == NULL) { + return NULL; + } + + // Allocate 2x as many characters as needed to avoid buffer overflows. + // Since this method is only used in "user-friendly" cases, it's ok to be + // a bit wasteful in the name of avoiding memory corruption. Therefore this + // function should *not* used for regular logging or text output. + destString = newCharStringWithCapacity(srcString->capacity * 2); + _charStringWrap(srcString->data, destString->data, destString->capacity, indentSize, TERMINAL_LINE_LENGTH); + return destString; +} + +void freeCharString(CharString self) +{ + if (self != NULL) { + free(self->data); + free(self); + } +} |
