538 lines
12 KiB
C++
538 lines
12 KiB
C++
// Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
|
|
// Copyright (C) 2010 Winch Gate Property Limited
|
|
//
|
|
// This program is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU Affero 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 Affero General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU Affero General Public License
|
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
|
|
#ifndef PDSLIB_STRING_H
|
|
#define PDSLIB_STRING_H
|
|
|
|
#include <string>
|
|
|
|
|
|
class CSString: public std::string
|
|
{
|
|
public:
|
|
CSString()
|
|
{
|
|
}
|
|
|
|
CSString(const char *s)
|
|
{
|
|
*(std::string *)this=s;
|
|
}
|
|
|
|
CSString(const std::string &s)
|
|
{
|
|
*(std::string *)this=s;
|
|
}
|
|
|
|
CSString(char c)
|
|
{
|
|
*(std::string *)this=c;
|
|
}
|
|
|
|
CSString(int i,const char *fmt="%d")
|
|
{
|
|
char buf[1024];
|
|
sprintf(buf,fmt,i);
|
|
*this=buf;
|
|
}
|
|
|
|
CSString(unsigned u,const char *fmt="%u")
|
|
{
|
|
char buf[1024];
|
|
sprintf(buf,fmt,u);
|
|
*this=buf;
|
|
}
|
|
|
|
CSString(double d,const char *fmt="%f")
|
|
{
|
|
char buf[1024];
|
|
sprintf(buf,fmt,d);
|
|
*this=buf;
|
|
}
|
|
|
|
CSString(const char *s,const char *fmt)
|
|
{
|
|
char buf[1024];
|
|
sprintf(buf,fmt,s);
|
|
*this=buf;
|
|
}
|
|
|
|
CSString(const std::string &s,const char *fmt)
|
|
{
|
|
char buf[1024];
|
|
sprintf(buf,fmt,s.c_str());
|
|
*this=buf;
|
|
}
|
|
|
|
char operator*()
|
|
{
|
|
if (empty())
|
|
return 0;
|
|
return (*this)[0];
|
|
}
|
|
|
|
// return the n right hand most characters of a string
|
|
CSString right(unsigned count) const
|
|
{
|
|
if (count>=size())
|
|
return *this;
|
|
return substr(size()-count);
|
|
}
|
|
|
|
// return the string minus the n right hand most characters of a string
|
|
CSString rightCrop(unsigned count) const
|
|
{
|
|
if (count>=size())
|
|
return CSString();
|
|
return substr(0,size()-count);
|
|
}
|
|
|
|
// return the n left hand most characters of a string
|
|
CSString left(unsigned count) const
|
|
{
|
|
return substr(0,count);
|
|
}
|
|
|
|
// return the string minus the n left hand most characters of a string
|
|
CSString leftCrop(unsigned count) const
|
|
{
|
|
if (count>=size())
|
|
return CSString();
|
|
return substr(count);
|
|
}
|
|
|
|
// return sub string up to but not including first instance of given character
|
|
CSString splitTo(char c,bool truncateThis=false)
|
|
{
|
|
unsigned i;
|
|
CSString result;
|
|
for (i=0;i<size() && (*this)[i]!=c;++i)
|
|
result+=(*this)[i];
|
|
|
|
// remove the result string from the input string if so desired
|
|
if (truncateThis)
|
|
{
|
|
if (i<size()-1)
|
|
(*this)=substr(i+1); // +1 to skip the separator character
|
|
else
|
|
clear();
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
// return sub string up to but not including first instance of given character
|
|
CSString splitTo(const char *s,bool truncateThis=false)
|
|
{
|
|
unsigned i;
|
|
CSString result;
|
|
for (i=0;i<size();++i)
|
|
{
|
|
// perform a quick string compare
|
|
int j;
|
|
for (j=0;s[j]!=0 && s[j]==(&((*this)[i]))[j];++j)
|
|
{
|
|
}
|
|
// if string compare matched then return result so far
|
|
if (s[j]==0)
|
|
{
|
|
// remove the result string from the input string if so desired
|
|
if (truncateThis)
|
|
{
|
|
if (i<size()-1)
|
|
(*this)=substr(i+1); // +1 to skip the separator character
|
|
else
|
|
clear();
|
|
}
|
|
|
|
return result;
|
|
}
|
|
result+=(*this)[i];
|
|
}
|
|
// we didn't find the separator string so we're returning a copy of the whole string
|
|
if (truncateThis)
|
|
clear();
|
|
return result;
|
|
}
|
|
|
|
// return sub string from character following first instance of given character on
|
|
CSString splitFrom(char c) const
|
|
{
|
|
CSString result;
|
|
std::string::const_iterator it;
|
|
for (it=begin();it!=end() && *it!=c;++it)
|
|
{}
|
|
if (it!=end())
|
|
{
|
|
++it;
|
|
for (;it!=end();++it)
|
|
result+=*it;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
// return sub string from character following first instance of given character on
|
|
CSString splitFrom(const char *s) const
|
|
{
|
|
unsigned int i;
|
|
CSString result;
|
|
for (i=0;i<size();++i)
|
|
{
|
|
// perform a quick string compare
|
|
unsigned int j;
|
|
for (j=0;i+j<size() && s[j]!=0 && s[j]==(*this)[i+j];++j)
|
|
{
|
|
}
|
|
// if string compare matched then build and return a result
|
|
if (s[j]==0)
|
|
{
|
|
result=substr(i+j);
|
|
return result;
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
// behave like a s strtok() routine, returning the sun string extracted from (and removed from) *this
|
|
CSString strtok(const char *separators)
|
|
{
|
|
unsigned int i;
|
|
CSString result;
|
|
|
|
// skip leading junk
|
|
for (i=0;i<size();++i)
|
|
{
|
|
// look for the next character in the 'separator' character list supplied
|
|
unsigned j;
|
|
for (j=0;separators[j] && (*this)[i]!=separators[j];++j)
|
|
{}
|
|
// if not found then we're at end of leading junk
|
|
if (!separators[j])
|
|
break;
|
|
}
|
|
|
|
// copy out everything up to the next separator character
|
|
for (;i<size();++i)
|
|
{
|
|
// look for the next character in the 'separator' character list supplied
|
|
unsigned j;
|
|
for (j=0;separators[j] && (*this)[i]!=separators[j];++j)
|
|
{}
|
|
// if not found then we're at end of leading junk
|
|
if (separators[j])
|
|
break;
|
|
result+=(*this)[i];
|
|
}
|
|
|
|
// skip trailing junk
|
|
for (;i<size();++i)
|
|
{
|
|
// look for the next character in the 'separator' character list supplied
|
|
unsigned j;
|
|
for (j=0;separators[j] && (*this)[i]!=separators[j];++j)
|
|
{}
|
|
// if not found then we're at end of leading junk
|
|
if (!separators[j])
|
|
break;
|
|
}
|
|
|
|
// delete the treated bit from this string
|
|
(*this)=substr(i);
|
|
|
|
return result;
|
|
}
|
|
|
|
// return first word (blank separated)
|
|
CSString firstWord(bool truncateThis=false)
|
|
{
|
|
CSString result;
|
|
unsigned i=0;
|
|
// skip white space
|
|
for (i=0;i<size() && isWhiteSpace((*this)[i]);++i)
|
|
{}
|
|
|
|
if ( ((*this)[i]>='A' && (*this)[i]<='Z') || ((*this)[i]>='a' && (*this)[i]<='z') ||
|
|
((*this)[i]>='0' && (*this)[i]<='9') || (*this)[i]=='_')
|
|
{
|
|
// copy out an alpha-numeric string
|
|
for (;i<(*this).size() &&
|
|
( ((*this)[i]>='A' && (*this)[i]<='Z') || ((*this)[i]>='a' && (*this)[i]<='z') ||
|
|
((*this)[i]>='0' && (*this)[i]<='9') || (*this)[i]=='_')
|
|
;++i)
|
|
result+=(*this)[i];
|
|
}
|
|
else
|
|
{
|
|
// just take the first character of the input
|
|
result=(*this)[i];
|
|
++i;
|
|
}
|
|
|
|
// remove the result string from the input string if so desired
|
|
if (truncateThis)
|
|
{
|
|
if (i<size())
|
|
(*this)=substr(i);
|
|
else
|
|
clear();
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
CSString firstWordConst() const
|
|
{
|
|
return const_cast<CSString *>(this)->firstWord();
|
|
}
|
|
|
|
// return sub string up to but not including first instance of given character
|
|
CSString tailFromFirstWord() const
|
|
{
|
|
CSString hold=*this;
|
|
hold.firstWord(true);
|
|
return hold;
|
|
}
|
|
|
|
// count the number of words (or quote delimited sub-strings) in a string
|
|
unsigned countWords() const
|
|
{
|
|
unsigned count=0;
|
|
CSString hold=strip();
|
|
while (!hold.empty())
|
|
{
|
|
hold=hold.tailFromFirstWord().strip();
|
|
++count;
|
|
}
|
|
return count;
|
|
}
|
|
|
|
// count the number of words (or quote delimited sub-strings) in a string
|
|
CSString word(unsigned idx) const
|
|
{
|
|
CSString hold=strip();
|
|
|
|
for (unsigned count=0;count<idx;++count)
|
|
hold=hold.tailFromFirstWord().strip();
|
|
|
|
return hold.firstWord();
|
|
}
|
|
|
|
// return first word or quote-encompassed sub-string
|
|
CSString firstWordOrWords(bool truncateThis=false)
|
|
{
|
|
CSString hold=strip();
|
|
if (hold[0]!='\"')
|
|
return firstWord(truncateThis);
|
|
|
|
// the string is quote enclosed
|
|
CSString result;
|
|
unsigned i=1; // skip leading quote
|
|
// copy from character following opening quote to char preceding closing quote (or end of string)
|
|
while (i<hold.size() && hold[i]!='\"')
|
|
{
|
|
result+=hold[i];
|
|
++i;
|
|
}
|
|
|
|
// remove the result string from the input string if so desired
|
|
if (truncateThis)
|
|
{
|
|
if (i<size()-1)
|
|
(*this)=substr(i+1); // +1 to skip the closing quote
|
|
else
|
|
clear();
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
CSString firstWordOrWordsConst() const
|
|
{
|
|
return const_cast<CSString *>(this)->firstWordOrWords();
|
|
}
|
|
|
|
// return sub string up to but not including first instance of given character
|
|
CSString tailFromFirstWordOrWords() const
|
|
{
|
|
CSString hold=*this;
|
|
hold.firstWordOrWords(true);
|
|
return hold;
|
|
}
|
|
|
|
// count the number of words (or quote delimited sub-strings) in a string
|
|
unsigned countWordOrWords() const
|
|
{
|
|
unsigned count=0;
|
|
CSString hold=strip();
|
|
while (!hold.empty())
|
|
{
|
|
hold=hold.tailFromFirstWordOrWords().strip();
|
|
++count;
|
|
}
|
|
return count;
|
|
}
|
|
|
|
// count the number of words (or quote delimited sub-strings) in a string
|
|
CSString wordOrWords(unsigned idx) const
|
|
{
|
|
CSString hold=strip();
|
|
|
|
for (unsigned count=0;count<idx;++count)
|
|
hold=hold.tailFromFirstWordOrWords().strip();
|
|
|
|
return hold.firstWordOrWords();
|
|
}
|
|
|
|
// a handy utility routine for knowing if a character is a white space character or not
|
|
static bool isWhiteSpace(char c) { return c==' ' || c=='\t' || c=='\n' || c=='\r' || c==26; }
|
|
|
|
// return a copy of the string with leading and trainling spaces rmoved
|
|
CSString strip() const
|
|
{
|
|
CSString result;
|
|
int i,j;
|
|
for (j=size()-1; j>=0 && isWhiteSpace((*this)[j]); --j) {}
|
|
for (i=0; i<j && isWhiteSpace((*this)[i]); ++i) {}
|
|
for (; i<=j; ++i)
|
|
result+=(*this)[i];
|
|
return result;
|
|
}
|
|
|
|
// making an upper case copy of a string
|
|
CSString toUpper() const
|
|
{
|
|
CSString result;
|
|
std::string::const_iterator it;
|
|
for (it=begin();it!=end();++it)
|
|
{
|
|
char c=(*it);
|
|
if (c>='a' && c<='z')
|
|
c^=('a'^'A');
|
|
result+=c;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
// making a lower case copy of a string
|
|
CSString toLower() const
|
|
{
|
|
CSString result;
|
|
std::string::const_iterator it;
|
|
for (it=begin();it!=end();++it)
|
|
{
|
|
char c=(*it);
|
|
if (c>='A' && c<='Z')
|
|
c^=('a'^'A');
|
|
result+=c;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
// replacing all occurences of one string with another
|
|
CSString replace(const char *toFind,const char *replacement) const
|
|
{
|
|
// just bypass the problems that can cause a crash...
|
|
if (toFind==NULL || *toFind==0)
|
|
return *this;
|
|
|
|
unsigned i,j;
|
|
CSString result;
|
|
for (i=0;i<size();)
|
|
{
|
|
// string compare toFind against (*this)+i ...
|
|
for (j=0;toFind[j];++j)
|
|
if ((*this)[i+j]!=toFind[j])
|
|
break;
|
|
// if strings were identical then j reffers to ASCIIZ terminator at end of 'toFind'
|
|
if (toFind[j]==0)
|
|
{
|
|
if (replacement!=NULL)
|
|
result+=replacement;
|
|
i+=j;
|
|
}
|
|
else
|
|
{
|
|
result+=(*this)[i];
|
|
++i;
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
// find index at which a sub-string starts - if sub-string not found then returns size()
|
|
unsigned find(const char *toFind,unsigned startLocation=0) const
|
|
{
|
|
// just bypass the problems that can cause a crash...
|
|
if (toFind==NULL || *toFind==0 || startLocation>size())
|
|
return size();
|
|
|
|
unsigned i,j;
|
|
for (i=startLocation;i<size();++i)
|
|
{
|
|
// string compare toFind against (*this)+i ...
|
|
for (j=0;toFind[j];++j)
|
|
if ((*this)[i+j]!=toFind[j])
|
|
break;
|
|
// if strings were identical then we're done
|
|
if (toFind[j]==0)
|
|
return i;
|
|
}
|
|
return i;
|
|
}
|
|
|
|
// return true if this contains given sub string
|
|
bool contains(const char *toFind) const
|
|
{
|
|
return find(toFind)!=size();
|
|
}
|
|
|
|
// a couple of handy atoi routines...
|
|
template <class C> bool atoi(C& result) const
|
|
{
|
|
result=::atoi(c_str());
|
|
return (result!=0 || *this=="0");
|
|
}
|
|
unsigned atoi() const
|
|
{
|
|
return ::atoi(c_str());
|
|
}
|
|
|
|
// a couple of handy atof routines...
|
|
template <class C> bool atof(C& result) const
|
|
{
|
|
result=::atof(c_str());
|
|
return (result!=0 || *this=="0");
|
|
}
|
|
double atof() const
|
|
{
|
|
return ::atof(c_str());
|
|
}
|
|
|
|
// case insensitive string compare
|
|
bool operator==(const std::string &other) const
|
|
{
|
|
return stricmp(c_str(),other.c_str())==0;
|
|
}
|
|
|
|
// case insesnsitive string compare
|
|
bool operator!=(const std::string &other) const
|
|
{
|
|
return !(*this==other);
|
|
}
|
|
};
|
|
|
|
#endif
|