colobot/src/CBot/CBotString.cpp

713 lines
14 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

/*
* This file is part of the Colobot: Gold Edition source code
* Copyright (C) 2001-2014, Daniel Roux, EPSITEC SA & TerranovaTeam
* http://epsiteс.ch; http://colobot.info; http://github.com/colobot
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see http://gnu.org/licenses
*/
/////////////////////////////////////////////////////
//strings management
#include "CBot.h"
#include <cstdlib>
#include <cstring>
#include <algorithm>
//Map is filled with id-string pars that are needed for CBot language parsing
const std::map<EID,const char *> CBotString::s_keywordString =
{
{ID_IF, "if"},
{ID_ELSE, "else"},
{ID_WHILE, "while"},
{ID_DO, "do"},
{ID_FOR, "for"},
{ID_BREAK, "break"},
{ID_CONTINUE, "continue"},
{ID_SWITCH, "switch"},
{ID_CASE, "case"},
{ID_DEFAULT, "default"},
{ID_TRY, "try"},
{ID_THROW, "throw"},
{ID_CATCH, "catch"},
{ID_FINALLY, "finally"},
{ID_TXT_AND, "and"},
{ID_TXT_OR, "or"},
{ID_TXT_NOT, "not"},
{ID_RETURN, "return"},
{ID_CLASS, "class"},
{ID_EXTENDS, "extends"},
{ID_SYNCHO, "synchronized"},
{ID_NEW, "new"},
{ID_PUBLIC, "public"},
{ID_EXTERN, "extern"},
{ID_FINAL, "final"},
{ID_STATIC, "static"},
{ID_PROTECTED, "protected"},
{ID_PRIVATE, "private"},
{ID_DEBUGDD, "STARTDEBUGDD"},
{ID_INT, "int"},
{ID_FLOAT, "float"},
{ID_BOOLEAN, "boolean"},
{ID_STRING, "string"},
{ID_VOID, "void"},
{ID_BOOL, "bool"},
{ID_TRUE, "true"},
{ID_FALSE, "false"},
{ID_NULL, "null"},
{ID_NAN, "nan"},
{ID_OPENPAR, "("},
{ID_CLOSEPAR, ")"},
{ID_OPBLK, "{"},
{ID_CLBLK, "}"},
{ID_SEP, ";"},
{ID_COMMA, ","},
{ID_DOTS, ":"},
{ID_DOT, "."},
{ID_OPBRK, "["},
{ID_CLBRK, "]"},
{ID_DBLDOTS, "::"},
{ID_LOGIC, "?"},
{ID_ADD, "+"},
{ID_SUB, "-"},
{ID_MUL, "*"},
{ID_DIV, "/"},
{ID_ASS, "="},
{ID_ASSADD, "+="},
{ID_ASSSUB, "-="},
{ID_ASSMUL, "*="},
{ID_ASSDIV, "/="},
{ID_ASSOR, "|="},
{ID_ASSAND, "&="},
{ID_ASSXOR, "^="},
{ID_ASSSL, "<<="},
{ID_ASSSR, ">>>="},
{ID_ASSASR, ">>="},
{ID_SL, "<<"},
{ID_SR, ">>"},
{ID_ASR, ">>"},
{ID_INC, "++"},
{ID_DEC, "--"},
{ID_LO, "<"},
{ID_HI, ">"},
{ID_LS, "<="},
{ID_HS, ">="},
{ID_EQ, "=="},
{ID_NE, "!="},
{ID_AND, "&"},
{ID_XOR, "^"},
{ID_OR, "|"},
{ID_LOG_AND, "&&"},
{ID_LOG_OR, "||"},
{ID_LOG_NOT, "!"},
{ID_NOT, "~"},
{ID_MODULO, "%"},
{ID_POWER, "**"},
{ID_ASSMODULO, "%="},
{ID_SUPER, "super"},
{TX_UNDEF, "undefined"},
{TX_NAN, "not a number"}
};
CBotString::CBotString()
{
m_ptr = NULL;
m_lg = 0;
}
CBotString::~CBotString()
{
delete[] m_ptr;
m_ptr = nullptr;
}
CBotString::CBotString(const char* p)
{
m_lg = strlen(p);
m_ptr = NULL;
if (m_lg>0)
{
m_ptr = new char[m_lg+1];
strcpy(m_ptr, p);
}
}
CBotString::CBotString(const CBotString& srcString)
{
m_lg = srcString.m_lg;
m_ptr = NULL;
if (m_lg>0)
{
m_ptr = new char[m_lg+1];
strcpy(m_ptr, srcString.m_ptr);
}
}
int CBotString::GetLength()
{
if (m_ptr == NULL) return 0;
return strlen( m_ptr );
}
CBotString CBotString::Left(int nCount) const
{
char chain[2000];
// clamp nCount to correct value
if(nCount < 0) nCount = 0;
if(nCount > m_lg) nCount = m_lg;
int i;
for (i = 0; i < m_lg && i < nCount && i < 1999; ++i)
{
chain[i] = m_ptr[i];
}
chain[i] = 0 ;
return CBotString(chain);
}
CBotString CBotString::Right(int nCount) const
{
char chain[2000];
// clamp nCount to correct value
if(nCount < 0) nCount = 0;
if(nCount > m_lg) nCount = m_lg;
int i = m_lg - nCount;
if ( i < 0 ) i = 0;
int j;
for (j = 0 ; i < m_lg && i < 1999; ++i)
{
chain[j++] = m_ptr[i];
}
chain[j] = 0 ;
return CBotString(chain);
}
CBotString CBotString::Mid(int nFirst, int nCount) const
{
char chain[2000];
// clamps nFirst to correct value
if(nFirst < 0) nFirst = 0;
if(nFirst > m_lg) nFirst = m_lg;
// clamp nCount to correct value
int remaining = m_lg - nFirst;
if(nCount > remaining) nCount = remaining;
if(nCount < 0) nCount = 0;
int i;
for (i = nFirst; i < m_lg && i < 1999 && i <= nFirst + nCount; ++i)
{
chain[i] = m_ptr[i];
}
chain[i] = 0 ;
return CBotString(chain);
}
CBotString CBotString::Mid(int nFirst) const
{
char chain[2000];
// clamp nFirst to correct value
if(nFirst < 0) nFirst = 0;
if(nFirst > m_lg) nFirst = m_lg;
int i;
for (i = nFirst; i < m_lg && i < 1999 ; ++i)
{
chain[i] = m_ptr[i];
}
chain[i] = 0 ;
return CBotString(chain);
}
int CBotString::Find(const char c)
{
for (int i = 0; i < m_lg; ++i)
{
if (m_ptr[i] == c) return i;
}
return -1;
}
int CBotString::Find(const char * lpsz)
{
int l = strlen(lpsz);
for (size_t i = 0; static_cast<int>(i) <= m_lg-l; ++i)
{
for (size_t j = 0; static_cast<int>(j) < l; ++j)
{
if (m_ptr[i+j] != lpsz[j]) goto bad;
}
return i;
bad:;
}
return -1;
}
int CBotString::ReverseFind(const char c)
{
int i;
for (i = m_lg-1; i >= 0; --i)
{
if (m_ptr[i] == c) return i;
}
return -1;
}
int CBotString::ReverseFind(const char * lpsz)
{
int i, j;
int l = strlen(lpsz);
for (i = m_lg-l; i >= 0; --i)
{
for (j = 0; j < l; ++j)
{
if (m_ptr[i+j] != lpsz[j]) goto bad;
}
return i;
bad:;
}
return -1;
}
CBotString CBotString::Mid(int start, int lg)
{
CBotString res;
if (lg == -1) lg = 2000;
// clamp start to correct value
if (start < 0) start = 0;
if (start >= m_lg) return res;
int remaining = m_lg - start;
if (lg > remaining) lg = remaining;
if (lg < 0) lg = 0;
char* p = new char[m_lg+1];
strcpy(p, m_ptr+start);
p[lg] = 0;
res = p;
delete[] p;
return res;
}
void CBotString::MakeUpper()
{
for (size_t i = 0; static_cast<int>(i) < m_lg && static_cast<int>(i) < 1999 ; ++i)
{
char c = m_ptr[i];
if ( c >= 'a' && c <= 'z' ) m_ptr[i] = c - 'a' + 'A';
}
}
void CBotString::MakeLower()
{
for (size_t i = 0; static_cast<int>(i) < m_lg && static_cast<int>(i) < 1999 ; ++i)
{
char c = m_ptr[i];
if ( c >= 'A' && c <= 'Z' ) m_ptr[i] = c - 'A' + 'a';
}
}
bool CBotString::LoadString(unsigned int id)
{
const char * str = nullptr;
str = MapIdToString(static_cast<EID>(id));
if (m_ptr != nullptr)
delete[] m_ptr;
m_lg = strlen(str);
m_ptr = NULL;
if (m_lg > 0)
{
m_ptr = new char[m_lg+1];
strcpy(m_ptr, str);
return true;
}
return false;
}
const CBotString& CBotString::operator=(const CBotString& stringSrc)
{
delete[] m_ptr;
m_ptr = nullptr;
m_lg = stringSrc.m_lg;
if (m_lg > 0)
{
m_ptr = new char[m_lg+1];
strcpy(m_ptr, stringSrc.m_ptr);
}
return *this;
}
CBotString operator+(const CBotString& string, const char * lpsz)
{
CBotString s(string);
s += lpsz;
return s;
}
const CBotString& CBotString::operator+(const CBotString& stringSrc)
{
char* p = new char[m_lg+stringSrc.m_lg+1];
if (m_ptr!=NULL) strcpy(p, m_ptr);
char* pp = p + m_lg;
if (stringSrc.m_ptr!=NULL) strcpy(pp, stringSrc.m_ptr);
delete[] m_ptr;
m_ptr = p;
m_lg += stringSrc.m_lg;
return *this;
}
const CBotString& CBotString::operator=(const char ch)
{
delete[] m_ptr;
m_lg = 1;
m_ptr = new char[2];
m_ptr[0] = ch;
m_ptr[1] = 0;
return *this;
}
const CBotString& CBotString::operator=(const char* pString)
{
delete[] m_ptr;
m_ptr = nullptr;
if (pString != nullptr)
{
m_lg = strlen(pString);
if (m_lg != 0)
{
m_ptr = new char[m_lg+1];
strcpy(m_ptr, pString);
}
}
return *this;
}
const CBotString& CBotString::operator+=(const char ch)
{
char* p = new char[m_lg+2];
if (m_ptr != nullptr) strcpy(p, m_ptr);
p[m_lg++] = ch;
p[m_lg] = 0;
delete[] m_ptr;
m_ptr = p;
return *this;
}
const CBotString& CBotString::operator+=(const CBotString& str)
{
char* p = new char[m_lg+str.m_lg+1];
strcpy(p, m_ptr);
char* pp = p + m_lg;
strcpy(pp, str.m_ptr);
m_lg = m_lg + str.m_lg;
delete[] m_ptr;
m_ptr = p;
return *this;
}
bool CBotString::operator==(const CBotString& str)
{
return Compare(str) == 0;
}
bool CBotString::operator==(const char* p)
{
return Compare(p) == 0;
}
bool CBotString::operator!=(const CBotString& str)
{
return Compare(str) != 0;
}
bool CBotString::operator!=(const char* p)
{
return Compare(p) != 0;
}
bool CBotString::operator>(const CBotString& str)
{
return Compare(str) > 0;
}
bool CBotString::operator>(const char* p)
{
return Compare(p) > 0;
}
bool CBotString::operator>=(const CBotString& str)
{
return Compare(str) >= 0;
}
bool CBotString::operator>=(const char* p)
{
return Compare(p) >= 0;
}
bool CBotString::operator<(const CBotString& str)
{
return Compare(str) < 0;
}
bool CBotString::operator<(const char* p)
{
return Compare(p) < 0;
}
bool CBotString::operator<=(const CBotString& str)
{
return Compare(str) <= 0;
}
bool CBotString::operator<=(const char* p)
{
return Compare(p) <= 0;
}
bool CBotString::IsEmpty() const
{
return (m_lg == 0);
}
void CBotString::Empty()
{
delete[] m_ptr;
m_ptr = nullptr;
m_lg = 0;
}
static char emptyString[] = {0};
CBotString::operator const char * () const
{
if (this == NULL || m_ptr == NULL) return emptyString;
return m_ptr;
}
int CBotString::Compare(const char * lpsz) const
{
char* p = m_ptr;
if (lpsz == NULL) lpsz = emptyString;
if (m_ptr == NULL) p = emptyString;
return strcmp(p, lpsz); // wcscmp
}
const char * CBotString::MapIdToString(EID id)
{
if (s_keywordString.find(id) != s_keywordString.end())
{
return s_keywordString.at(id);
}
else
{
return emptyString;
}
}
///////////////////////////////////////////////////////////////////////////////////////////
// arrays of strings
CBotStringArray::CBotStringArray()
{
m_pData = NULL;
m_nSize = m_nMaxSize = 0;
}
CBotStringArray::~CBotStringArray()
{
SetSize(0); // destroys data !
}
int CBotStringArray::GetSize()
{
return m_nSize;
}
void CBotStringArray::Add(const CBotString& str)
{
SetSize(m_nSize+1);
m_pData[m_nSize-1] = str;
}
///////////////////////////////////////////////////////////////////////
// utility routines
static inline void ConstructElement(CBotString* pNewData)
{
memset(pNewData, 0, sizeof(CBotString));
}
static inline void DestructElement(CBotString* pOldData)
{
pOldData->~CBotString();
}
static inline void CopyElement(CBotString* pSrc, CBotString* pDest)
{
*pSrc = *pDest;
}
static void ConstructElements(CBotString* pNewData, int nCount)
{
while (nCount--)
{
ConstructElement(pNewData);
pNewData++;
}
}
static void DestructElements(CBotString* pOldData, int nCount)
{
while (nCount--)
{
DestructElement(pOldData);
pOldData++;
}
}
// set the array size
void CBotStringArray::SetSize(int nNewSize)
{
if (nNewSize == 0)
{
// shrink to nothing
DestructElements(m_pData, m_nSize);
delete[] reinterpret_cast<unsigned char *>(m_pData);
m_pData = NULL;
m_nSize = m_nMaxSize = 0;
}
else if (m_pData == NULL)
{
// create one with exact size
m_pData = reinterpret_cast<CBotString*> (new unsigned char[nNewSize * sizeof(CBotString)]);
ConstructElements(m_pData, nNewSize);
m_nSize = m_nMaxSize = nNewSize;
}
else if (nNewSize <= m_nMaxSize)
{
// it fits
if (nNewSize > m_nSize)
{
// initialize the new elements
ConstructElements(&m_pData[m_nSize], nNewSize-m_nSize);
}
else if (m_nSize > nNewSize) // destroy the old elements
DestructElements(&m_pData[nNewSize], m_nSize-nNewSize);
m_nSize = nNewSize;
}
else
{
// otherwise, grow array
int nGrowBy;
{
// heuristically determine growth when nGrowBy == 0
// (this avoids heap fragmentation in many situations)
nGrowBy = std::min(1024, std::max(4, m_nSize / 8));
}
int nNewMax;
if (nNewSize < m_nMaxSize + nGrowBy)
nNewMax = m_nMaxSize + nGrowBy; // granularity
else
nNewMax = nNewSize; // no slush
CBotString* pNewData = reinterpret_cast<CBotString*> (new unsigned char[nNewMax * sizeof(CBotString)]);
// copy new data from old
memcpy(pNewData, m_pData, m_nSize * sizeof(CBotString));
// construct remaining elements
ConstructElements(&pNewData[m_nSize], nNewSize-m_nSize);
// Get rid of old stuff (note: no destructors called)
delete[] reinterpret_cast<unsigned char *>(m_pData);
m_pData = pNewData;
m_nSize = nNewSize;
m_nMaxSize = nNewMax;
}
}
CBotString& CBotStringArray::operator[](int nIndex)
{
return ElementAt(nIndex);
}
CBotString& CBotStringArray::ElementAt(int nIndex)
{
return m_pData[nIndex];
}