Files
firestorm/Gameleap/code/mw4/Code/MW4GameEd2/Cstr.cpp
T
Cyd 2b8ca921cb Initial full mirror of c:\VWE (source + assets + toolchain + outputs) via Git LFS
Complete disaster-recovery snapshot: engine/game source, game data assets,
VC6 toolchain + DX SDKs, build outputs, deployed game, and _UNUSED archive.
Large binaries in Git LFS; text preserved byte-for-byte (core.autocrlf=false,
no eol attributes). See RECOVERY.md for the one-clone rebuild procedure.
2026-06-24 21:28:16 -05:00

1295 lines
26 KiB
C++

#define __INTERNAL__
#include "stdafx.h"
#include "malloc.h"
#ifdef _DEBUG
#undef THIS_FILE
static CHAR THIS_FILE[] = __FILE__;
#define new DEBUG_NEW
#define delete DEBUG_DELETE
#endif
#ifdef WIN32
#pragma pack(push, 1)
#endif // WIN32
struct
#ifdef WIN32
__declspec(novtable)
#endif // WIN32
SStrDummy
{
#ifdef USE_STRLOCK
WORD m_wRefCount;
#endif // USE_STRLOCK
CHAR m_sz[1];
};
#ifdef WIN32
#pragma pack(pop)
#endif // WIN32
#define NIL_LOCKCOUNT 0x8000
#ifdef WIN32
#pragma data_seg(".SHARED_DATA")
#endif // WIN32
// all data in this section must be INITIALIZED!!!!!!!!!!!!!
static SStrDummy l_sz =
{
#ifdef USE_STRLOCK
NIL_LOCKCOUNT, // WORD m_wRefCount;
#endif // USE_STRLOCK
{ 0, }, // CHAR m_sz;
};
#ifdef WIN32
#pragma data_seg()
#pragma comment(linker, "/section:.SHARED_DATA,RWS")
#endif // WIN32
#ifdef _DEBUG
void CStrTestMain();
class s_CAutoRun
{
public:
s_CAutoRun()
{
CStrTestMain();
}
} s_a;
#endif // _DEBUG
#define l_SZ (&l_sz.m_sz[0])
#ifdef USE_STRLOCK
#define STR_LOCKCOUNT STR_LOCKCOUNT2(m_psz)
#define STR_LOCKCOUNT2(psz) ((WORD*)psz)[-1]
static inline CHAR* str_alloc(int nMax)
{
CHAR* psz = (CHAR*)malloc(sizeof(WORD) + sizeof(CHAR) * nMax);
*(WORD*)psz = 0;
CHAR* p = (CHAR*)&((BYTE*)psz)[sizeof(WORD)];
p[0] = '\0';
return p;
}
static inline CHAR* str_realloc(CHAR* psz, int nMax)
{
return (CHAR*)&((BYTE*)realloc(&STR_LOCKCOUNT2(psz), sizeof(WORD) + sizeof(CHAR) * nMax))[sizeof(WORD)];
}
static inline void str_free(CHAR* psz)
{
free(&STR_LOCKCOUNT2(psz));
}
#else // !USE_STRLOCK
#define STR_LOCKCOUNT ASSERT(FALSE)
#define STR_LOCKCOUNT2(psz) ASSERT(FALSE)
//#define str_alloc(nMax) ((CHAR*)malloc(sizeof(CHAR)*nMax))
static inline CHAR* str_alloc(int nMax)
{
CHAR* p = (CHAR*)malloc(sizeof(CHAR) * nMax);
p[0] = '\0';
return p;
}
#define str_realloc(psz, nMax) ((CHAR*)realloc(psz,sizeof(CHAR)*nMax))
#define str_free(psz) (free(psz))
#endif // USE_STRLOCK
#ifdef USE_STRLOCK
#define IS_NIL(psz) (((const WORD*)psz)[-1] == NIL_LOCKCOUNT) // check m_wRefCount
#else // !USE_STRLOCK
#define IS_NIL(psz) ((psz) == l_SZ) // check pointer...
#endif // USE_STRLOCK
static BOOL LSTRS_IsValid(int c, const char* pcszVals);
static BOOL LSTRS_IsValid(int c, const char* pcszVals)
{
if (pcszVals) {
if (strchr(pcszVals, c)) {
return TRUE;
}
} else {
if ((' ' < c) && (c != 0x7f) && (c != 0xff)) {
return TRUE;
}
}
return FALSE;
}
int __cdecl str_memcmp(const void* elem1, const void* elem2)
{
const char* s1 = ((const CStr*)elem1)->String();
const char* s2 = ((const CStr*)elem2)->String();
int n1 = strlen(s1);
int n2 = strlen(s2);
if (n1 > n2) {
n2 = n1;
}
return memcmp(s1, s2, n2);
}
#if !defined(WIN32)
char* _strupr(char *string)
{
char c, *p = string;
while((c = *p) != '\0') {
if (('a' <= c) && (c <= 'z')) {
c -= ('a' - 'A');
*p = c;
}
p++;
}
return string;
}
char* _strlwr(char *string)
{
char c, *p = string;
while((c = *p) != '\0') {
if (('A' <= c) && (c <= 'Z')) {
c += ('a' - 'A');
*p = c;
}
p++;
}
return string;
}
#endif // !defined(WIN32)
int __cdecl str_Compare(const void* elem1, const void* elem2)
{
return lstrcmp(((const CStr*)elem1)->String(), ((const CStr*)elem2)->String());
}
int __cdecl str_CompareReverse(const void* elem1, const void* elem2)
{
return -lstrcmp(((const CStr*)elem1)->String(), ((const CStr*)elem2)->String());
}
int __cdecl str_CompareIC(const void* elem1, const void* elem2)
{
return lstrcmpi(((const CStr*)elem1)->String(), ((const CStr*)elem2)->String());
}
int __cdecl str_CompareICReverse(const void* elem1, const void* elem2)
{
return -lstrcmpi(((const CStr*)elem1)->String(), ((const CStr*)elem2)->String());
}
CStr::CStr()
{
m_psz = l_SZ;
}
CStr::CStr(const CHAR* pcsz)
{
#ifdef _DEBUG
m_psz = (CHAR*)l_SZ;
#endif // _DEBUG
AssignNoCheck(pcsz);
}
CStr::CStr(const CHAR* pcsz, int nLen)
{
#ifdef _DEBUG
m_psz = (CHAR*)l_SZ;
#endif // _DEBUG
AssignNoCheck(pcsz, nLen);
}
CStr::CStr(CHAR c, int nLen)
{
ASSERT((c != '\0') && (nLen >= 0));
if ((c != '\0') && (nLen > 0)) {
CHAR* psz = str_alloc(nLen + 1);
memset(psz, c, nLen);
psz[nLen] = '\0';
m_psz = psz;
} else {
m_psz = l_SZ;
}
}
CStr::CStr(const CStr& that)
{
#ifdef _DEBUG
m_psz = l_SZ;
#endif // _DEBUG
AssignNoCheck(that.m_psz);
}
CStr::CStr(int nMax)
{
ASSERT(nMax > 0);
m_psz = str_alloc(nMax);
}
CStr::~CStr()
{
#ifdef USE_STRLOCK
#ifdef _DEBUG
if (!IS_NIL(m_psz) && (STR_LOCKCOUNT != 0)) {
TRACE("CStr::~CStr() called for CStr Locked: %d times\n", (int)STR_LOCKCOUNT);
}
#endif // _DEBUG
#endif // USE_STRLOCK
if (!IS_NIL(m_psz)) {
str_free(m_psz);
}
#ifdef _DEBUG
m_psz = NULL;
#endif
}
const CHAR* CStr::Empty()
{
if (!IS_NIL(m_psz)) {
#ifdef USE_STRLOCK
if (STR_LOCKCOUNT) {
m_psz[0] = '\0';
return m_psz;
}
#endif // USE_STRLOCK
str_free(m_psz);
m_psz = l_SZ;
}
return l_SZ;
}
void CStr::Swap(CStr& that)
{
#ifdef _DEBUG
#ifdef USE_STRLOCK
if (IsLocked() || that.IsLocked())
TRACE("CStr::Swap() called for Locked CStr(s)\n");
#endif // USE_STRLOCK
#endif // _DEBUG
CHAR* psz = m_psz;
m_psz = that.m_psz;
that.m_psz = psz;
}
#ifdef USE_STRLOCK
WORD CStr::IsLocked() const
{
ASSERT_VALIDSTRING(m_psz);
if (!IS_NIL(m_psz))
return STR_LOCKCOUNT;
return 0;
}
CHAR* CStr::LockBuffer()
{
ASSERT_VALIDSTRING(m_psz);
if (!IS_NIL(m_psz)) {
++STR_LOCKCOUNT;
} else {
TRACE("Trying To Lock Empty String...\n");
}
return m_psz;
}
WORD CStr::UnlockBuffer()
{
ASSERT_VALIDSTRING(m_psz);
if (!IS_NIL(m_psz)) {
ASSERT(STR_LOCKCOUNT != 0);
WORD wRefCount = --STR_LOCKCOUNT;
if (wRefCount == 0) {
if (m_psz[0] == '\0') {
Reset();
}
}
return wRefCount;
} else {
TRACE("Trying To Unlock Empty String...\n");
return 0;
}
}
#endif // USE_STRLOCK
const CHAR* CStr::Assign(const CHAR* pcsz, int nLen/* = -1*/)
{
ASSERT(this);
ASSERT_VALIDSTRING(m_psz);
#ifdef USE_STRLOCK
if (IsLocked()) {
if (nLen < 0) {
if (!pcsz || ((nLen = strlen(pcsz)) <= 0)) {
return ResetLocked();
}
nLen++;
memcpy(m_psz, pcsz, nLen);
} else {
if (nLen <= 0) {
return ResetLocked();
}
ASSERT(pcsz);
ASSERT((UINT)nLen <= strlen(pcsz));
memcpy(m_psz, pcsz, nLen);
m_psz[nLen] = '\0';
}
} else {
#endif // USE_STRLOCK
if (IS_NIL(m_psz)) {
return AssignNoCheck(pcsz, nLen);
}
if (nLen < 0) {
if (!pcsz || ((nLen = strlen(pcsz)) <= 0)) {
return Reset();
}
nLen++;
memcpy(m_psz = str_realloc(m_psz, nLen), pcsz, nLen);
} else {
if (nLen <= 0) {
return Reset();
}
ASSERT(pcsz);
ASSERT((UINT)nLen <= strlen(pcsz));
int nAlloc = nLen + 1;
memcpy(m_psz = str_realloc(m_psz, nAlloc), pcsz, nLen);
m_psz[nLen] = '\0';
}
#ifdef USE_STRLOCK
}
#endif // USE_STRLOCK
return m_psz;
}
CStr CStr::operator + (const CHAR* pcsz) const
{
int nLen;
if (pcsz && ((nLen = strlen(pcsz)) > 0)) {
CHAR* psz = m_psz;
if (psz[0] == '\0') {
return CStr(pcsz, nLen);
} else {
int n = strlen(psz);
CStr str(n + ++nLen);
CHAR* p = str.m_psz;
memcpy(p, psz, n);
memcpy(&p[n], pcsz, nLen);
return str;
}
}
return *this;
}
CStr& CStr::operator += (const CHAR* pcsz)
{
int nLen;
#ifdef USE_STRLOCK
if (IsLocked()) {
if (pcsz && ((nLen = strlen(pcsz)) > 0)) {
CHAR* psz = m_psz;
memcpy(&psz[strlen(psz)], pcsz, nLen + 1);
}
} else {
#endif // USE_STRLOCK
if (pcsz && ((nLen = strlen(pcsz)) > 0)) {
CHAR* psz = m_psz;
if (IS_NIL(psz)) {
AssignNoCheck(pcsz, nLen);
} else {
nLen++;
int n = strlen(psz);
psz = str_realloc(psz, n + nLen);
memcpy(&psz[n], pcsz, nLen);
m_psz = psz;
}
}
#ifdef USE_STRLOCK
}
#endif // USE_STRLOCK
return *this;
}
CStr CStr::operator + (CHAR c) const
{
CHAR ca[2];
ca[0] = c;
ca[1] = '\0';
return *this + ca;
}
CStr& CStr::operator += (CHAR c)
{
CHAR ca[2];
ca[0] = c;
ca[1] = '\0';
return *this += ca;
}
void CStr::MakeReverse()
{
int nLen = strlen(m_psz);
if (nLen >= 2) {
CHAR* pszStart = m_psz;
CHAR* pszEnd = &pszStart[nLen - 1];
nLen /= 2;
while(nLen-- > 0) {
CHAR c;
c = *pszStart;
*pszStart = *pszEnd;
*pszEnd = c;
pszStart++;
pszEnd--;
}
}
}
const CHAR* CStr::Prune(const CHAR* pcszDELs/* = NULL*/)
{
if (!pcszDELs) {
pcszDELs = "\t ";
}
ASSERT_VALIDSTRING(pcszDELs);
ASSERT(pcszDELs[0]);
CHAR* pszHead = m_psz;
CHAR c;
while((c = *pszHead) != '\0') {
if (strchr(pcszDELs, c)) {
CHAR* pszStart = pszHead;
while((c = *++pszHead) != '\0') {
if (!strchr(pcszDELs, c)) {
strcpy(pszStart, pszHead);
goto no_DELs;
}
}
ASSERT(c == '\0');
pszStart[0] = '\0';
break;
} else {
no_DELs:
pszHead++;
}
}
ReleaseBuffer();
return m_psz;
}
const CHAR* CStr::TrimLeft()
{
CHAR* pszHead = m_psz;
CHAR c;
while((c = *pszHead) != '\0') {
if ((c != ' ') && (c != '\t')) {
if (m_psz != pszHead)
strcpy(m_psz, pszHead);
return m_psz;
}
pszHead++;
}
return Empty();
}
const CHAR* CStr::TrimRight()
{
CHAR* pszHead = m_psz;
CHAR c;
CHAR* pszTail = &pszHead[strlen(pszHead)];
while(pszTail != pszHead) {
c = *--pszTail;
if ((c != ' ') && (c != '\t')) {
pszTail[1] = '\0';
return m_psz;
}
}
return Empty();
}
const CHAR* CStr::TrimAll()
{
TrimLeft();
return TrimRight();
}
void __cdecl CStr::Format(LPCTSTR lpszFormat, ...)
{
va_list marker;
va_start(marker, lpszFormat);
vFormat(lpszFormat, marker);
va_end(marker);
}
void CStr::vFormat(LPCTSTR lpszFormat, va_list marker)
{
CHAR szBuf[512];
#ifdef _DEBUG
int n = vsprintf(szBuf, lpszFormat, marker);
ASSERT((0 <= n) && (n + 1 <= NOFA(szBuf)));
#else // !_DEBUG
vsprintf(szBuf, lpszFormat, marker);
#endif // _DEBUG
Assign(szBuf);
}
CHAR* CStr::GetBuffer(int nLen)
{
ASSERT(nLen >= 0);
ASSERT_VALIDSTRING(m_psz);
CHAR* psz = m_psz;
#ifdef USE_STRLOCK
if (!IsLocked()) {
#endif // USE_STRLOCK
int n = strlen(psz);
if ((n -= nLen) < 0) {
nLen++;
psz = (IS_NIL(psz)) ? str_alloc(nLen): str_realloc(psz, nLen);
m_psz = psz;
}
#ifdef USE_STRLOCK
}
#endif // USE_STRLOCK
return psz;
}
const CHAR* CStr::ReleaseBuffer(int nLen/* = -1*/)
{
ASSERT_VALIDSTRING(m_psz);
CHAR* psz = m_psz;
#ifdef USE_STRLOCK
if (IsLocked()) {
if (nLen >= 0) {
psz[nLen] = '\0';
}
return psz;
} else {
#endif // USE_STRLOCK
if (nLen >= 0) {
#ifdef _DEBUG
if (psz[nLen] != '\0') // when _DEBUG, (pcsz == const l_SZ) is possible
#endif // _DEBUG
psz[nLen] = '\0';
} else {
nLen = strlen(psz);
}
if (nLen == 0) {
return Reset();
} else {
return m_psz = str_realloc(psz, nLen + 1);
}
#ifdef USE_STRLOCK
}
#endif // USE_STRLOCK
}
CHAR* CStr::GetBufferSetLength(int nLen)
{
ASSERT(nLen >= 0);
#ifdef _DEBUG
CHAR* p1 = GetBuffer(nLen);
if (!IS_NIL(p1)) // when _DEBUG, (pcsz == const l_SZ) is possible
m_psz[nLen] = '\0';
#else // !_DEBUG
GetBuffer(nLen);
#endif // _DEBUG
return m_psz;
}
void CStr::ChangeChars(CHAR cBefore, CHAR cAfter)
{
ASSERT(cBefore && cAfter);
CHAR* psz = m_psz;
CHAR c;
while((c = *psz) != '\0') {
if (c == cBefore) {
*psz = cAfter;
}
psz++;
}
}
BOOL CStr::AsDirectory(BOOL bRemoveLastDEL/* = FALSE*/)
{
int nPos = rFindSet("/\\");
if (nPos != -1) {
if (!bRemoveLastDEL)
nPos++;
ReleaseBuffer(nPos);
return TRUE;
}
return FALSE;
}
BOOL CStr::AddDirDEL()
{
int nLen = GetLength();
if (nLen > 0) {
CHAR c = m_psz[nLen - 1];
if ((c != '\\') && (c != '/')) {
#ifdef _WINDOWS
*this += '\\';
#else // !_WINDOWS
*this += '/';
#endif // _WINDOWS
return TRUE;
}
}
return FALSE;
}
int CStr::FindExtPos() const
{
int nPos = rFind('.');
if (nPos != -1) {
const CHAR* pcsz = &m_psz[nPos + 1];
if (strchr(pcsz, '\\') || strchr(pcsz, '/')) {
return -1;
}
}
return nPos;
}
const char* CStr::FindExt() const
{
int nPos = FindExtPos();
if (nPos != -1) {
return &m_psz[nPos];
}
return NULL;
}
BOOL CStr::ChangeExt(const char* pcszExt, BOOL bForce/* = TRUE*/)
{
ASSERT_VALIDSTRING(pcszExt);
int nPos = FindExtPos();
if (nPos != -1) {
if (bForce && strcmp(&m_psz[nPos], pcszExt)) {
int nLen = nPos + strlen(pcszExt);
CHAR* psz = GetBuffer(nLen);
strcpy(&psz[nPos], pcszExt);
return TRUE;
}
} else {
if (*pcszExt) {
*this += pcszExt;
return TRUE;
}
}
return FALSE;
}
const CHAR* CStr::Left(CStr& strLeft, int nCount) const
{
ASSERT(&strLeft);
ASSERT(nCount >= 0);
ASSERT_VALIDSTRING(strLeft);
ASSERT_VALIDSTRING(m_psz);
CHAR* psz = m_psz;
int n = strlen(psz);
if ((n -= nCount) < 0) {
nCount += n;
return strLeft.Assign(psz, nCount);
} else {
CHAR* p = strLeft.GetBuffer(nCount);
memcpy(p, psz, nCount);
return strLeft.ReleaseBuffer(nCount);
}
}
const CHAR* CStr::Right(CStr& strRight, int nCount) const
{
ASSERT(&strRight);
ASSERT(nCount >= 0);
ASSERT_VALIDSTRING(strRight);
ASSERT_VALIDSTRING(m_psz);
CHAR* psz = m_psz;
int n = strlen(psz);
if ((n -= nCount) < 0) {
nCount += n;
} else {
psz += n;
}
return strRight.Assign(psz, nCount);
}
const CHAR* CStr::Mid(CStr& strMid, int nFirst) const
{
ASSERT(&strMid);
ASSERT(nFirst >= 0);
ASSERT_VALIDSTRING(strMid);
ASSERT_VALIDSTRING(m_psz);
CHAR* psz = m_psz;
int n = strlen(psz);
if (nFirst > 0) {
if ((n -= nFirst) <= 0) {
strMid.Empty();
return l_SZ;
}
psz += nFirst;
}
return strMid.Assign(psz, n);
}
const CHAR* CStr::Mid(CStr& strMid, int nFirst, int nCount) const
{
ASSERT(&strMid);
ASSERT(nFirst >= 0);
ASSERT(nCount >= 0);
ASSERT_VALIDSTRING(strMid);
ASSERT_VALIDSTRING(m_psz);
if (nCount <= 0) {
return strMid.Empty();
}
CHAR* psz = m_psz;
int n = strlen(psz);
if (nFirst > 0) {
if ((n -= nFirst) <= 0) {
return strMid.Empty();
}
psz += nFirst;
}
if ((n -= nCount) <= 0) {
nCount += n;
return strMid.Assign(psz, nCount);
} else {
CHAR* p = strMid.GetBuffer(nCount);
memcpy(p, psz, nCount);
return strMid.ReleaseBuffer(nCount);
}
}
CStr CStr::Left(int nCount) const
{
CStr str;
Left(str, nCount);
return str;
}
CStr CStr::Right(int nCount) const
{
CStr str;
Right(str, nCount);
return str;
}
CStr CStr::Mid(int nFirst) const
{
CStr str;
Mid(str, nFirst);
return str;
}
CStr CStr::Mid(int nFirst, int nCount) const
{
CStr str;
Mid(str, nFirst, nCount);
return str;
}
int CStr::FindNext(CHAR c, int nStart) const
{
ASSERT(c != '\0');
const CHAR* pcsz = m_psz;
if (nStart < 0)
nStart = 0;
else {
ASSERT(strlen(pcsz) >= nStart);
pcsz = &pcsz[nStart];
if (*pcsz == '\0')
return -1;
pcsz++;
nStart++;
}
const char* pcsz2 = strchr(pcsz, c);
if (pcsz2) {
return nStart + (pcsz2 - pcsz);
}
return -1;
}
int CStr::Find(CHAR c) const
{
ASSERT(c != '\0');
const CHAR* pcsz = strchr(m_psz, c);
if (pcsz) {
return pcsz - m_psz;
}
return -1;
}
int CStr::rFindNext(CHAR c, int nStart) const
{
ASSERT(c != '\0');
const CHAR* pcsz = m_psz;
const CHAR* pcsz2 = pcsz;
if (nStart < 0) {
nStart = strlen(pcsz2);
} else {
ASSERT(strlen(pcsz2) >= nStart);
}
pcsz2 = &pcsz2[nStart];
while(--pcsz2 >= pcsz) {
nStart--;
if (*pcsz2 == c) {
return nStart;
}
}
return -1;
}
int CStr::rFind(CHAR c) const
{
ASSERT(c != '\0');
const CHAR* pcsz = strrchr(m_psz, c);
if (pcsz) {
return pcsz - m_psz;
}
return -1;
}
int CStr::Find(const CHAR* pcsz, int nStart) const
{
ASSERT_VALIDSTRING(pcsz);
if (nStart < 0)
nStart = 0;
const CHAR* pcsz2 = m_psz;
while(nStart > 0) {
if (*pcsz2++ == '\0')
return -1;
nStart--;
}
pcsz = strstr(pcsz2, pcsz);
if (pcsz) {
return pcsz - m_psz;
}
return -1;
}
int CStr::Find(const CHAR* pcsz) const
{
ASSERT_VALIDSTRING(pcsz);
pcsz = strstr(m_psz, pcsz);
if (pcsz) {
return pcsz - m_psz;
}
return -1;
}
int CStr::FindSet(const CHAR* pcszSet) const
{
ASSERT_VALIDSTRING(pcszSet);
CHAR* psz = m_psz;
CHAR c;
while((c = *psz) != '\0') {
if (strchr(pcszSet, c)) {
return psz - m_psz;
}
psz++;
}
return -1;
}
int CStr::rFindSet(const CHAR* pcszSet) const
{
ASSERT_VALIDSTRING(pcszSet);
CHAR* pszStart = m_psz;
CHAR* psz = &pszStart[strlen(pszStart)];
while(psz-- > pszStart) {
if (strchr(pcszSet, *psz)) {
return psz - m_psz;
}
}
return -1;
}
#if defined(WIN32)
BOOL CStr::GetWindowText(HWND hWnd)
{
Empty();
if (IsWindow(hWnd)) {
int nSize = SendMessage(hWnd, WM_GETTEXTLENGTH, 0, 0);
if (nSize > 0) {
nSize += 10; // for safety...
char* p = GetBuffer(nSize + 1/*'\0'*/);
SendMessage(hWnd, WM_GETTEXT, (WPARAM)nSize, (LPARAM)p);
}
return TRUE;
}
return FALSE;
}
#endif // defined(WIN32)
const CHAR* CStr::AssignNoCheck(const CHAR* pcsz, int nLen/* = -1*/)
{
ASSERT(IS_NIL(m_psz)); // when !_DEBUG then m_psz is !initialized...
CHAR* psz;
if (nLen < 0) {
if (!pcsz || ((nLen = strlen(pcsz)) <= 0)) {
return m_psz = l_SZ;
}
nLen++;
psz = str_alloc(nLen);
memcpy(psz, pcsz, nLen);
} else {
if (nLen <= 0) {
return m_psz = l_SZ;
}
ASSERT(pcsz);
ASSERT((UINT)nLen <= strlen(pcsz));
int nAlloc = nLen + 1;
psz = str_alloc(nAlloc);
memcpy(psz, pcsz, nLen);
psz[nLen] = '\0';
}
return m_psz = psz;
}
CHAR* CStr::Reset()
{
#ifdef USE_STRLOCK
ASSERT(!IsLocked());
#endif // USE_STRLOCK
if (!IS_NIL(m_psz)) {
str_free(m_psz);
m_psz = l_SZ;
}
return l_SZ;
}
#ifdef USE_STRLOCK
CHAR* CStr::ResetLocked()
{
ASSERT(IsLocked());
ASSERT(!IS_NIL(m_psz));
m_psz[0] = '\0';
return m_psz;
}
#endif // USE_STRLOCK
#ifdef USE_CSTR_ISTREAM
istream& operator >> (istream& s, CStr& str)
{
str.Empty();
int c;
while((c = s.get()) != EOF) {
if (!isspace(c)) {
do {
str += (char)c;
if ((c = s.get()) == EOF)
break;
} while(!isspace(c));
break;
}
}
return s;
}
#endif // USE_CSTR_ISTREAM
int CStrArray::GetTotalLength() const
{
int nTotalLength;
int i, nSize = GetSize();
nTotalLength = nSize; // nSize '\0'
for(i = 0; i < nSize; i++) {
nTotalLength += strlen(GetAt(i));
}
return nTotalLength;
}
int CStrArray::Find(const char* pcsz) const
{
ASSERT(pcsz);
int i, nSize = GetSize();
for(i = 0; i < nSize; i++) {
if (strcmp(GetAt(i), pcsz) == 0)
return i;
}
return -1;
}
int CStrArray::AddIfNotFound(const char* pcsz)
{
int nFound = Find(pcsz);
if (nFound == -1) {
Add() = pcsz;
}
return nFound;
}
int CStrArray::AddIfNotFound(const CStr astrs[], int nCount)
{
int nAdded = 0;
for(int i = 0; i < nCount; i++) {
if (AddIfNotFound(astrs[i]) == -1)
nAdded++;
}
return nAdded;
}
void CStrArray::Sort(QSortCompareProc pQSortCompareProc/* = (QSortCompareProc)NULL*/)
{
int nSize = GetSize();
if (nSize > 0) {
if (!pQSortCompareProc)
pQSortCompareProc = str_Compare;
qsort(&GetAt(0), nSize, sizeof(CStr), pQSortCompareProc);
}
}
BOOL CStrArray::LoadStrs(const char* pcszFile, const char* pcszVals/* = NULL*/, UINT uFlags/* = 0*/)
{
BOOL bRet = FALSE;
FILE* pFile = fopen(pcszFile, "rt");
if (pFile) {
bRet = LoadStrs(pFile, pcszVals, uFlags);
fclose(pFile);
}
return bRet;
}
BOOL CStrArray::LoadStrs(FILE* pFile, const char* pcszVals/* = NULL*/, UINT uFlags/* = 0*/)
{
if (pFile) {
int c;
CStr str;
while((c = getc(pFile)) != EOF) {
if (LSTRS_IsValid(c, pcszVals)) {
str += (char)c;
} else {
LSTRS_CheckAdd(str, uFlags);
}
}
LSTRS_CheckAdd(str, uFlags);
if (uFlags & LSTRS_DOSORT)
Sort();
return TRUE;
}
return FALSE;
}
void CStrArray::LSTRS_CheckAdd(CStr& str, UINT uFlags)
{
if (!str.IsEmpty()) {
UINT uFlagsCase = uFlags & (LSTRS_TOLOWER | LSTRS_TOUPPER);
if (uFlagsCase) {
if (uFlagsCase & LSTRS_TOLOWER) {
str.MakeLower();
if (uFlagsCase & LSTRS_TOUPPER) {
str.SetAt(0, (CHAR)toupper(str.GetAt(0)));
}
} else { // LSTRS_TOUPPER
str.MakeUpper();
}
}
if (uFlags & LSTRS_ALLOWDUP)
Add() = str;
else
AddIfNotFound(str);
str.Empty();
}
}
#ifdef _DEBUG
BOOL IsValidString(const CHAR* pcszStr, int nLen/* = -1*/)
{
// nLen: maximum size of string
return pcszStr && !::IsBadStringPtr(pcszStr, (UINT)nLen);
}
BOOL IsValidStringSafe(const CHAR* pcszStr, int nLen/* = -1*/)
{
// nLen: maximum size of string
return !pcszStr || !::IsBadStringPtr(pcszStr, (UINT)nLen);
}
BOOL IsValidMemory(const void* pMem, UINT uBytes, BOOL bWriteCheck/* = TRUE*/)
{
return pMem && !(::IsBadReadPtr(pMem, uBytes) || (bWriteCheck && ::IsBadWritePtr((void*)pMem, uBytes)));
}
BOOL IsValidMemorySafe(const void* pMem, UINT uBytes, BOOL bWriteCheck/* = TRUE*/)
{
return !pMem || !(::IsBadReadPtr(pMem, uBytes) || (bWriteCheck && ::IsBadWritePtr((void*)pMem, uBytes)));
}
#endif // _DEBUG
#ifdef _DEBUG
void CStrTestMain()
{
const CHAR* g_pcsza[] = {
(const CHAR*)NULL,
"",
"a",
"abc ",
" 123456789",
" abCABD ",
};
int i, nStrs = NOFA(g_pcsza);
CStr k;
TARRAYREF(CStr) aStrs;
aStrs.Add(nStrs);
for(i = 0; i < nStrs; i++) {
BOOL bLocked = FALSE;
if (rand() % 2) {
aStrs.GetAt(i).GetBuffer(256);
aStrs.GetAt(i).LockBuffer();
bLocked = TRUE;
}
CStr a(g_pcsza[i]);
CStr b(a, a.GetLength());
CStr c((CHAR)(rand() % 254 + 1), rand() % 3);
a += b;
a += c;
b = a;
c = a;
a += (const CHAR*)NULL;
b += "";
c += "sl123KDFklsd ";
a = c;
b = c;
a.MakeLower();
b.MakeUpper();
c.MakeReverse();
a += b;
c = a + b;
a.TrimLeft();
a.TrimRight();
b.TrimLeft();
b.TrimRight();
c.TrimLeft();
c.TrimRight();
aStrs[i] = c;
a.Left(k, 1000);
a.Right(k, 1000);
a.Mid(k, 1);
a.Mid(k, 100);
a.Mid(k, 1, a.GetLength() / 2);
b.Left(k, 1000);
b.Right(k, 1000);
b.Mid(k, 1);
b.Mid(k, 100);
b.Mid(k, 1, a.GetLength() / 2);
c.Left(k, 1000);
c.Right(k, 1000);
c.Mid(k, 1);
c.Mid(k, 100);
c.Mid(k, 1, a.GetLength() / 2);
if (bLocked)
aStrs.GetAt(i).UnlockBuffer();
}
}
#endif // _DEBUG