EAString implements an extensive suite of C string functionality from <string.h> in a portable way. Much of this functionality is the same as what is present in the C standard and in common (but non-portable) extensions to the C standard. EAString presents a consistent portable interface to its functionality in both 8 bit and 16 bit string form.
The C language provides various functions which work with non-portable data types, such as long. EAString defines all significant data types in terms of portable types such as int32_t and int64_t. Additionally, the EAString versions of functions are usually faster than the C runtime library versions, usually because the EAString versions minimize cache misses and branching, whereas typical C runtime libraries optimize for the smallest memory footprint with little or no regard to other performance characteristics. Also, the EAString functions do not implement locale-specific functionality and thus save time and space as a result. Other packages within EA implement localization functionality in a way that is better suited to high performance game development.
C-style printf functionality is separate from EAString and is found in EASprintf. Memcpy functionality (which comes from the <string.h> header file) is present in EAMemory.
EAString provides extended functionality that isn't found in conventional C libraries, but it useful nevertheless.
| Function | Description | Signature |
| Strlcat | Safe variation of strncat | char_t* Strlcat(char_t* pDestination, const char_t* pSource, size_t n); |
| Strlcpy | Safe variation of strcpy | char_t* Strlcpy(char_t* pDestination, const char_t* pSource, size_t n); |
| Stristr | Case insensitive version of strstr (find string within string) | char_t* Stristr(const char_t* pString, const char_t* pSubString); |
| FtoaEnglish |
Float to ascii; always use English numeric format, regardless of the current locale. |
char_t* FtoaEnglish(double dValue, char_t* pResult, int nInputLength, int nPrecision, bool bExponentEnabled); |
| AtofEnglish | Ascii to float; always use English numeric format, regardless of the current locale. | double AtofEnglish(const char_t* pString); |
| StrtodEnglish | Same as strtod, but always use English numeric format, regardless of the current locale. | double StrtodEnglish(const char_t* pString, char_t** ppStringEnd); |
| Memset16 | Sets 16 bit values in memory (as opposed to memset's 8 bit values) | uint16_t* Memset16(void* pDestination, uint16_t c, size_t count); |
| Memset32 | Sets 32 bit values in memory (as opposed to memset's 8 bit values) | uint32_t* Memset32(void* pDestination, uint32_t c, size_t count); |
| Memset64 | Sets 64 bit values in memory (as opposed to memset's 8 bit values) | uint64_t* Memset64(void* pDestination, uint64_t c, size_t count); |
| MemsetN | Sets arbitrarily sized values in memory. | void* MemsetN (void* pDestination, const void* pSource, size_t sourceBytes, size_t count); |
| EcvtBuf | Base function for converting a float to a %e string. |
char_t* EcvtBuf(double dValue, int nDigitCount, int* decimalPos, int* sign, char_t* buffer); |
| FcvtBuf | Base function for converting a float to a %f string. | char_t* FcvtBuf(double dValue, int nDigitCountAfterDecimal, int* decimalPos, int* sign, char_t* buffer); |
We provide a random smattering of example code here.
char16_t buffer[32] = L"hello "; Strcat(buffer, L"world");
Strlcpy, Strlcat:
char8_t buffer[32]; Strlcpy(buffer, "Hello ", sizeof(buffer));
Strlcat(buffer, "world", sizeof(buffer));
Strlcpy, used to translate UTF8 to UTF16:
char8_t buffer8[64]; char16_t buffer16[64]; int length16 = Strlcpy(buffer16, buffer8, 64);
U64toa:
char buffer[32]; U64toa(UINT64_C(12345678901234567890), buffer, 16);
AtoI32:
int32_t x = AtoI32("1234567890");
Strtod:
const char16_t* pString = L"12345.678 123.456 1.23456";
while(*pString)
{
double value = Strtod(pString, &pString);
printf("Field = %f\n, value);
}
In each of the functions below, there is an char8_t and char16_t version. So for Strcat there are the following:
char8_t* Strcat(char8_t* pDestination, const char8_t* pSource)
char16_t* Strcat(char16_t* pDestination, const char16_t* pSource)
The list below may be out of date as you read this, so see EAString.h for a definitive list of supported functionality.
char_t* Strcat(char_t* pDestination, const char_t* pSource); char_t* Strncat(char_t* pDestination, const char_t* pSource, size_t n); char_t* Strlcat(char_t* pDestination, const char_t* pSource, size_t n); char_t* Strcpy(char_t* pDestination, const char_t* pSource); char_t* Strncpy(char_t* pDestination, const char_t* pSource, size_t n); char_t* Strlcpy(char_t* pDestination, const char_t* pSource, size_t n); int Strlcpy(char16_t* pDestination, const char8_t* pSource, size_t nDestCapacity, size_t nSourceLength = (size_t)~0); int Strlcpy(char32_t* pDestination, const char8_t* pSource, size_t nDestCapacity, size_t nSourceLength = (size_t)~0); int Strlcpy(char8_t* pDestination, const char16_t* pSource, size_t nDestCapacity, size_t nSourceLength = (size_t)~0); int Strlcpy(char32_t* pDestination, const char16_t* pSource, size_t nDestCapacity, size_t nSourceLength = (size_t)~0); int Strlcpy(char8_t* pDestination, const char32_t* pSource, size_t nDestCapacity, size_t nSourceLength = (size_t)~0); int Strlcpy(char16_t* pDestination, const char32_t* pSource, size_t nDestCapacity, size_t nSourceLength = (size_t)~0); int Strlcpy(char8_t* pDestination, const wchar_t* pSource, size_t nDestCapacity, size_t nSourceLength = (size_t)~0); int Strlcpy(char16_t* pDestination, const wchar_t* pSource, size_t nDestCapacity, size_t nSourceLength = (size_t)~0); int Strlcpy(char32_t* pDestination, const wchar_t* pSource, size_t nDestCapacity, size_t nSourceLength = (size_t)~0); int Strlcpy(wchar_t* pDestination, const char8_t* pSource, size_t nDestCapacity, size_t nSourceLength = (size_t)~0); int Strlcpy(wchar_t* pDestination, const char16_t* pSource, size_t nDestCapacity, size_t nSourceLength = (size_t)~0); int Strlcpy(wchar_t* pDestination, const char32_t* pSource, size_t nDestCapacity, size_t nSourceLength = (size_t)~0); bool Strlcpy(char16_t* pDestination, const char8_t* pSource, size_t nDestCapacity, size_t nSourceLength, size_t& nDestUsed, size_t& nSourceUsed); bool Strlcpy(char32_t* pDestination, const char8_t* pSource, size_t nDestCapacity, size_t nSourceLength, size_t& nDestUsed, size_t& nSourceUsed); bool Strlcpy(char8_t* pDestination, const char16_t* pSource, size_t nDestCapacity, size_t nSourceLength, size_t& nDestUsed, size_t& nSourceUsed); bool Strlcpy(char32_t* pDestination, const char16_t* pSource, size_t nDestCapacity, size_t nSourceLength, size_t& nDestUsed, size_t& nSourceUsed); bool Strlcpy(char8_t* pDestination, const char32_t* pSource, size_t nDestCapacity, size_t nSourceLength, size_t& nDestUsed, size_t& nSourceUsed); bool Strlcpy(char16_t* pDestination, const char32_t* pSource, size_t nDestCapacity, size_t nSourceLength, size_t& nDestUsed, size_t& nSourceUsed); bool Strlcpy(char8_t* pDestination, const wchar_t* pSource, size_t nDestCapacity, size_t nSourceLength, size_t& nDestUsed, size_t& nSourceUsed); bool Strlcpy(char16_t* pDestination, const wchar_t* pSource, size_t nDestCapacity, size_t nSourceLength, size_t& nDestUsed, size_t& nSourceUsed); bool Strlcpy(char32_t* pDestination, const wchar_t* pSource, size_t nDestCapacity, size_t nSourceLength, size_t& nDestUsed, size_t& nSourceUsed); bool Strlcpy(wchar_t* pDestination, const char8_t* pSource, size_t nDestCapacity, size_t nSourceLength, size_t& nDestUsed, size_t& nSourceUsed); bool Strlcpy(wchar_t* pDestination, const char16_t* pSource, size_t nDestCapacity, size_t nSourceLength, size_t& nDestUsed, size_t& nSourceUsed); bool Strlcpy(wchar_t* pDestination, const char32_t* pSource, size_t nDestCapacity, size_t nSourceLength, size_t& nDestUsed, size_t& nSourceUsed); size_t Strlen(const char_t* pString); size_t Strxfrm(char_t* pDest, const char_t* pSource, size_t n); char_t* Strdup(const char_t* pString); char_t* Strlwr(char_t* pString); char_t* Strupr(char_t* pString); char_t* Strchr(const char_t* pString, char_t c); size_t Strcspn(const char_t* pString1, const char_t* pString2); char_t* Strpbrk(const char_t* pString1, const char_t* pString2); char_t* Strrchr(const char_t* pString, char_t c); size_t Strspn(const char_t* pString, const char_t* pSubString); char_t* Strstr(const char_t* pString, const char_t* pSubString); char_t* Stristr(const char_t* pString, const char_t* pSubString); char_t* Strtok(char_t* pString, const char_t* pTokens, char_t** pContext); char_t* Strset(char_t* pString, char_t c); char_t* Strnset(char_t* pString, char_t c, size_t n); char_t* Strrev(char_t* pString); int Strcmp(const char_t* pString1, const char_t* pString2); int Strncmp(const char_t* pString1, const char_t* pString2, size_t n); int Stricmp(const char_t* pString1, const char_t* pString2); int Strnicmp(const char_t* pString1, const char_t* pString2, size_t n); int Strcoll(const char_t* pString1, const char_t* pString2); int Strncoll(const char_t* pString1, const char_t* pString2, size_t n); int Stricoll(const char_t* pString1, const char_t* pString2); int Strnicoll(const char_t* pString1, const char_t* pString1, size_t n); char_t* EcvtBuf(double dValue, int nDigitCount, int* decimalPos, int* sign, char_t* buffer); char_t* FcvtBuf(double dValue, int nDigitCountAfterDecimal, int* decimalPos, int* sign, char_t* buffer); char_t* I32toa(int32_t nValue, char_t* pResult, int nBase); char_t* U32toa(uint32_t nValue, char_t* pResult, int nBase); char_t* I64toa(int64_t nValue, char_t* pBuffer, int nBase); char_t* U64toa(uint64_t nValue, char_t* pBuffer, int nBase); double Strtod(const char_t* pString, char_t** ppStringEnd); double StrtodEnglish(const char_t* pString, char_t** ppStringEnd); int64_t StrtoI64(const char_t* pString, char_t** ppStringEnd, int nBase); uint64_t StrtoU64(const char_t* pString, char_t** ppStringEnd, int nBase); int32_t StrtoI32(const char_t* pString, char_t** ppStringEnd, int nBase); uint32_t StrtoU32(const char_t* pString, char_t** ppStringEnd, int nBase); int32_t AtoI32(const char_t* pString); uint32_t AtoU32(const char_t* pString); int64_t AtoI64(const char_t* pString); uint64_t AtoU64(const char_t* pString); double Atof(const char_t* pString); double AtofEnglish(const char_t* pString); char_t* Ftoa(double dValue, char_t* pResult, int nInputLength, int nPrecision, bool bExponentEnabled); char_t* FtoaEnglish(double dValue, char_t* pResult, int nInputLength, int nPrecision, bool bExponentEnabled);
The Strlcpy function size_t Strlcpy(char16_t* pDestination, const char8_t* pSource, size_t nDestCapacity, size_t nSourceLength) converts UTF8 text (char8_t) to UCS2 (char16_t). It doesn't work if your pSource string isn't truly UTF8-encoded. Typically this would happen because the source string is using Windows code page 1252 or HTML's ISO 8859-1. All 8 bit strings in EAStdC are assumed to be UTF8 unless specifically documented otherwise.
Any 8 bit text that's not UTF8 has to be defined within the context of a code page; otherwise any chars above 127 have an arbitrary meaning, and may include multi-byte characters for some code pages. If you need to convert code page 1252 to UCS2, you need to implement a function which uses a table that maps the high byte values into their proper Unicode values. It's not so simple to just cast the byte value to char16_t, as some of the code page 1252 characters don't map directly to their numerical values in Unicode, though ISO 8859-1 characters to completely map to their equivalent Unicode values.
The following is an implementation of Strcpy and Strlcpy for ISO 8859-1 char8_t text which isn't currently part of EAStdC:
char16_t* StrcpyISO8859_1(char16_t* pDestination, const char8_t* pSource)
{
char16_t* pDestSaved = pDestination;
while(*pSource)
*(pDestination++) = (uint8_t)*pSource++;
*pDestination = 0;
return pDestSaved;
}
size_t StrlcpyISO8859_1(char16_t* pDestination, const char8_t* pSource, size_t nDestCapacity)
{
const char8_t* s = pSource;
size_t n = nDestCapacity;
if(n && --n)
{
do{
if((*pDestination++ = (uint8_t)*s++) == 0)
break;
} while(--n);
}
if(!n)
{
if(nDestCapacity)
*pDestination = 0;
while(*s)
++s;
}
return (s - pSource - 1);
}