/* * 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 #include #include //Map is filled with id-string pars that are needed for CBot language parsing const std::map 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]; 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]; 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]; 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]; 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(i) <= m_lg-l; ++i) { for (size_t j = 0; static_cast(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 (start >= m_lg) return res; if ( lg < 0 ) lg = m_lg - start; 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(i) < m_lg && static_cast(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(i) < m_lg && static_cast(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(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(m_pData); m_pData = NULL; m_nSize = m_nMaxSize = 0; } else if (m_pData == NULL) { // create one with exact size m_pData = reinterpret_cast (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 (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(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]; }