183 lines
5.8 KiB
C
183 lines
5.8 KiB
C
#include <Lib/String.h>
|
|
#include <Lib/VAArgs.h>
|
|
|
|
static void BufferAdd(ASCII* buffer, Size bufferSize, Size* written, ASCII character) {
|
|
if (*written + 1 < bufferSize) {
|
|
buffer[*written] = character;
|
|
}
|
|
(*written)++;
|
|
}
|
|
|
|
void* StringSet(BytePointer destination, ASCII value, Size count) {
|
|
BytePointer savedDestination = destination;
|
|
while (count--) {
|
|
*destination++ = (UInt8) value;
|
|
}
|
|
return savedDestination;
|
|
}
|
|
|
|
void* MemoryCopy(void* destination, const void* source, Size count) {
|
|
BytePointer destinationBuffer = (BytePointer) destination;
|
|
const UInt8* sourceBuffer = (const UInt8*) source;
|
|
|
|
while (count >= 8) {
|
|
*(UInt64*) destinationBuffer = *(const UInt64*) sourceBuffer;
|
|
destinationBuffer += 8;
|
|
sourceBuffer += 8;
|
|
count -= 8;
|
|
}
|
|
|
|
while (count > 0) {
|
|
*destinationBuffer++ = *sourceBuffer++;
|
|
count--;
|
|
}
|
|
|
|
return destination;
|
|
}
|
|
|
|
Int32 StringCompare(const ASCII* firstString, const ASCII* secondString) {
|
|
while (*firstString && (*firstString == *secondString)) {
|
|
firstString++;
|
|
secondString++;
|
|
}
|
|
return *(const UInt8*) firstString - *(const UInt8*) secondString;
|
|
}
|
|
|
|
Int32 StringCompareWithLimit(const ASCII* firstString, const ASCII* secondString, Size limit) {
|
|
while (limit > 0) {
|
|
if (*firstString != *secondString) return *(const UInt8*) firstString - *(const UInt8*) secondString;
|
|
if (*firstString == '\0') return 0;
|
|
firstString++;
|
|
secondString++;
|
|
limit--;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
ASCII* StringCopy(ASCII* destination, const ASCII* source) {
|
|
ASCII* saved = destination;
|
|
while (*source) *destination++ = *source++;
|
|
*destination = 0;
|
|
return saved;
|
|
}
|
|
|
|
ASCII* StringCopyWithLimit(ASCII* destination, const ASCII* source, Size limit) {
|
|
ASCII* saved = destination;
|
|
while (*source && limit > 0) {
|
|
*destination++ = *source++;
|
|
limit--;
|
|
}
|
|
while (limit > 0) {
|
|
*destination++ = 0;
|
|
limit--;
|
|
}
|
|
return saved;
|
|
}
|
|
|
|
Size StringGetLength(const ASCII* string) {
|
|
Size result = 0;
|
|
for (result = 0; string[result]; result++);
|
|
return result;
|
|
}
|
|
|
|
const ASCII* StringFindLastOccurrenceOfCharacter(const ASCII* string, ASCII separator) {
|
|
const ASCII* lastSeparator = 0;
|
|
do {
|
|
if (*string == separator) lastSeparator = string;
|
|
} while (*string++);
|
|
|
|
return lastSeparator;
|
|
}
|
|
|
|
Int32 StringFormatVariadic(ASCII* string, Size size, const ASCII* format, va_list args) {
|
|
Size written = 0;
|
|
for (Size i = 0; format[i] != '\0'; i++) {
|
|
if (format[i] == '%') {
|
|
i++;
|
|
if (format[i] == '\0') break;
|
|
switch (format[i]) {
|
|
case 's': {
|
|
const ASCII* vaArgString = va_arg(args, const ASCII*);
|
|
if (!vaArgString) vaArgString = "(null)";
|
|
while (*vaArgString) BufferAdd(string, size, &written, *vaArgString++);
|
|
break;
|
|
}
|
|
case 'c': {
|
|
ASCII character = (ASCII)va_arg(args, Int);
|
|
BufferAdd(string, size, &written, character);
|
|
break;
|
|
}
|
|
case 'd': {
|
|
Int64 number = va_arg(args, Int);
|
|
if (number < 0) {
|
|
BufferAdd(string, size, &written, '-');
|
|
number = -number;
|
|
}
|
|
|
|
UInt64 unsignedNumber = (UInt64)number;
|
|
ASCII tempBuffer[32];
|
|
Size position = 0;
|
|
|
|
if (unsignedNumber == 0) tempBuffer[position++] = '0';
|
|
while (unsignedNumber > 0) {
|
|
tempBuffer[position++] = (ASCII)((unsignedNumber % 10) + '0');
|
|
unsignedNumber /= 10;
|
|
}
|
|
|
|
while (position > 0) BufferAdd(string, size, &written, tempBuffer[--position]);
|
|
break;
|
|
}
|
|
case 'x':
|
|
case 'X': {
|
|
UInt64 unsignedNumber = va_arg(args, UInt64);
|
|
UInt8 padding = (format[i] == 'X') ? 16 : 0;
|
|
|
|
ASCII tempBuffer[32];
|
|
Size position = 0;
|
|
static const ASCII kHexDigits[] = "0123456789ABCDEF";
|
|
|
|
if (unsignedNumber == 0 && padding == 0) tempBuffer[position++] = '0';
|
|
while (unsignedNumber > 0) {
|
|
tempBuffer[position++] = kHexDigits[unsignedNumber % 16];
|
|
unsignedNumber /= 16;
|
|
}
|
|
|
|
while (position < (Size)padding) tempBuffer[position++] = '0';
|
|
while (position > 0) BufferAdd(string, size, &written, tempBuffer[--position]);
|
|
break;
|
|
}
|
|
case '%': {
|
|
BufferAdd(string, size, &written, '%');
|
|
break;
|
|
}
|
|
default: {
|
|
BufferAdd(string, size, &written, '%');
|
|
BufferAdd(string, size, &written, format[i]);
|
|
break;
|
|
}
|
|
}
|
|
} else {
|
|
BufferAdd(string, size, &written, format[i]);
|
|
}
|
|
}
|
|
|
|
if (size > 0) {
|
|
if (written < size) string[written] = '\0';
|
|
else string[size - 1] = '\0';
|
|
}
|
|
|
|
return (Int32)written;
|
|
}
|
|
|
|
Int32 StringFormat(ASCII* destination, UInt64 size, const ASCII* format, ...) {
|
|
va_list args;
|
|
va_start(args, format);
|
|
Int32 returnValue = StringFormatVariadic(destination, size, format, args);
|
|
va_end(args);
|
|
return returnValue;
|
|
}
|
|
|
|
Boolean StringStartsWith(const ASCII* string, const ASCII* prefix) {
|
|
return StringCompareWithLimit(string, prefix, StringGetLength(prefix)) == 0;
|
|
} |