void substr(const std::string &input, char *output, std::string::size_type start, std::string::size_type length);
std::string one_argument(const std::string &argument, char *first, std::string::size_type max=MAX_INPUT_LENGTH);
std::string one_argument(const std::string &argument, std::string &first);
void substr(const std::string &input, char *output, std::string::size_type start, std::string::size_type length)
{
std::string::size_type pos, cnt;
pos = start;
cnt = 0;
while(cnt < length)
{
output[cnt] = input[pos];
cnt++;
pos++;
}
output[cnt] = '\0';
}
std::string one_argument(const std::string &argument, char *first, std::string::size_type max)
{
std::string::size_type start, stop, stop2, chk_len, chk_max;
char find;
// Init
start = 0;
chk_max = max-1; // Leave room for '\0'
// Empty?
if (argument.length() < 1)
{
first[0] = '\0';
return "";
}
// Strip leading spaces
if (argument[0] == ' ')
{
start = argument.find_first_not_of(' ');
// Empty?
if (start == argument.npos)
{
first[0] = '\0';
return "";
}
}
// Quotes or space?
switch(argument[start])
{
case '\'':
find = '\'';
start++;
break;
case '\"':
find = '\"';
start++;
break;
default:
find = ' ';
}
// Find end of argument.
stop = argument.find_first_of(find, start);
// Empty leftovers?
if (stop == argument.npos)
{
chk_len = (argument.length()-start);
substr(argument, first, start, UMIN(chk_len, chk_max));
return "";
}
// Update first
chk_len = (stop-start);
substr(argument, first, start, UMIN(chk_len, chk_max));
// Strip leading spaces from leftovers
stop2 = argument.find_first_not_of(' ', stop+1);
// Empty leftovers?
if (stop2 == argument.npos)
return "";
// Return leftovers.
return argument.substr(stop2);
}
// Pick off one argument from a string and return the rest.
std::string one_argument(const std::string &argument, std::string &first)
{
std::string::size_type start, stop, stop2;
char find;
// Init
start = 0;
// Empty?
if (argument.length() < 1)
{
first = "";
return "";
}
// Strip leading spaces
if (argument[0] == ' ')
{
start = argument.find_first_not_of(' ');
// Empty?
if (start == argument.npos)
{
first = "";
return "";
}
}
// Quotes or space?
switch(argument[start])
{
case '\'':
find = '\'';
start++;
break;
case '\"':
find = '\"';
start++;
break;
default:
find = ' ';
}
// Find end of argument.
stop = argument.find_first_of(find, start);
// Empty leftovers?
if (stop == argument.npos)
{
first = argument.substr(start);
return "";
}
// Update first
first = argument.substr(start, (stop-start));
// Strip leading spaces from leftovers
stop2 = argument.find_first_not_of(' ', stop+1);
// Empty leftovers?
if (stop2 == argument.npos)
return "";
// Return leftovers.
return argument.substr(stop2);
}
std::string prefix_argument(const std::string &argument, std::string &prefix)
{
std::string::size_type start, end;
if ((end = argument.find_first_of('.')) == argument.npos)
{
prefix = "";
return argument;
}
start = argument.find_first_not_of(' ');
prefix = argument.substr(start, (end-start));
return argument.substr((end+1));
}
bool is_number(const std::string &argument)
{
std::string::const_iterator it, end;
// Empty
if (argument.length() < 1)
return FALSE;
it = argument.begin();
end = argument.end();
for (; it != end; it++)
{
if (!isdigit(*it))
return FALSE;
}
return TRUE;
}
std::string number_prefix(const std::string &argument, int &num)
{
std::string prefix, ret;
ret = prefix_argument(argument, prefix);
if (is_number(prefix))
{
num = atoi(prefix.c_str());
return ret;
}
num = -1;
return argument;
}
std::transform(buf.begin(), buf.end(), buf.begin(), (int(*)(int))std::tolower);
// Case insensitive compare
bool str_cmp(const std::string & s1, const std::string & s2)
{
if (s1.size() != s2.size())
return true;
std::string::const_iterator p1 = s1.begin(), p2 = s2.begin();
while(p1 != s1.end() && p2 != s2.end()) {
if(tolower(*p1) != tolower(*p2))
return true;
p1++;
p2++;
}
return false;
}
typedef std::string STR_TOKENIZER(const std::string &input, std::string &next);
typedef int STR_COMPARE(const std::string &astr, const std::string &bstr);
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Comparison
// Compare: astr is equal to bstr.
// Case insensitive.
// – Justice
bool str_equal(const std::string &astr, const std::string bstr)
{
std::string::const_iterator a1, a2, b1, b2;
a1 = astr.begin();
a2 = astr.end();
b1 = bstr.begin();
b2 = bstr.end();
while(a1 != a2 && b1 != b2)
{
if (std::toupper(*a1) != std::toupper(*b1))
return FALSE;
a1++;
b1++;
}
return (bstr.size()==astr.size());
}
// Compare: astr starts with bstr.
// Case insensitive.
// – Justice
bool str_starts(const std::string &astr, const std::string bstr)
{
std::string::const_iterator a1, a2, b1, b2;
a1 = astr.begin();
a2 = astr.end();
b1 = bstr.begin();
b2 = bstr.end();
while(a1 != a2 && b1 != b2)
{
if (std::toupper(*a1) != std::toupper(*b1))
return FALSE;
a1++;
b1++;
}
return TRUE;
}
// Compare: astr ><= bstr.
// <0 = astr < bstr
// 0 = astr == bstr
// >0 = astr > bstr
// Case insensitive.
// – Justice
int str_cmp(const std::string &astr, const std::string &bstr)
{
std::string::const_iterator a1, a2, b1, b2;
a1 = astr.begin();
a2 = astr.end();
b1 = bstr.begin();
b2 = bstr.end();
while(a1 != a2 && b1 != b2)
{
if (std::toupper(*a1) != std::toupper(*b1))
return (std::toupper(*a1)<std::toupper(*b1) ? -1 : 1);
a1++;
b1++;
}
return (bstr.size()==astr.size() ? 0 : (astr.size() < bstr.size() ? -1 : 1));
}
// Compare: astr ><= bstr (astr prefix of bstr)
// <0 = astr < bstr
// 0 = astr == bstr
// >0 = astr > bstr
// Case insensitive.
// Shrinks bstr to equal length if necessary. (prefix)
// – Justice
int str_prefix(const std::string &astr, const std::string &bstr)
{
std::string::const_iterator a1, a2, b1, b2;
a1 = astr.begin();
a2 = astr.end();
b1 = bstr.begin();
b2 = bstr.end();
while(a1 != a2 && b1 != b2)
{
if (std::toupper(*a1) != std::toupper(*b1))
return (std::toupper(*a1)<std::toupper(*b1) ? -1 : 1);
a1++;
b1++;
}
return 0;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Specialized Searches
bool has_string(const std::string &find, const std::string &text, STR_COMPARE *comp, STR_TOKENIZER *token)
{
std::string buf, cur;
buf = text;
while(!buf.empty())
{
// Strip Keyword
buf = token(buf, cur);
if (!comp(find, cur))
return TRUE;
}
return FALSE;
}
class sharedstring
{
class istring
{
public:
std::string str;
int ref;
public istring( std::string s ) : str(s), ref(1) {};
};
static private istring blankString = "";
istring *str;
sharedstring()
sharedstring* operator=( const char *str ) {
if ( –str->ref <= 0 )
delete str;
str = new istring( str );
return *this;
}
sharedstring* operator=( const sharedstring &str ) {
if ( –str->ref <= 0 )
delete str;
str = str.str;
str-ref++;
}
}
This code is untested in compile or execution - it is based (mostly) on my own working and very stable code, however it is modified so as not to be dependent on other parts of my code.
Permission is granted to Kiasyn@Talon to repost this elsewhere, if the entirety (including this header) is copied verbatim. Bugfixes are permitted.
// SharedString.h
// Code by Chris Jacobson (FearItself @ AvP)
// Based on code from LexiMUD (Aliens vs Predator: The MUD, and Raze the Dead)
// Modified to remove namespaces, target std::string, and eliminate dependency on my own shared object system
// Permission to use in your own code, so long as this header remains intact.
class SharedString
{
public:
SharedString() : m_Shared(GetBlank()) { m_Shared->Retain(); }
explicit SharedString(const char *str) : m_Shared(NULL) { Assign(str); }
SharedString(const std::string &str) : m_Shared(NULL) { Assign(str.c_str()); }
SharedString(const SharedString &str) : m_Shared(str.m_Shared) { m_Shared->Retain(); }
void operator=(const char *str) { Assign(str); }
void operator=(const std::string &str) { Assign(str.c_str()); }
void operator=(const SharedString &str) { m_Shared->Release(); m_Shared = str.m_Shared; m_Shared->Retain(); }
bool operator==(const SharedString &ss) const { return *static_cast<std::string *>(m_Shared) == *ss.m_Shared; }
bool operator==(const std::string &str) const { return *static_cast<std::string *>(m_Shared) == *str; }
bool operator==(const char *str) const { return *static_cast<std::string *>(m_Shared) == str; }
operator const std::string &() const { return *m_Shared; }
const char * c_str() const { return m_Shared->c_str(); }
bool empty() const { return m_Shared->empty(); }
size_type length() const { return m_Shared->length(); }
// This is a dangerous function; it is useful if you want to update everything at once.
// Note that LexiMUD does NOT use a hashtable for sharing, as that can cause very poor
// performance in a MUD that uses a lot of dynamic names or dynamic object name changing
std::string & GetStringRef() { return *m_Shared; }
private:
class Implementation : public std::string
{
public:
Implementation(const char *str) : std::string(str), m_Refs(1) {}
Implementation(const std::string &str) : std::string(str), m_Refs(1) {}
void Retain() { ++m_Refs; }
void Release() { if (–m_Refs == 0) delete this; }
private:
/* unimp */ Implementation();
/* unimp */ Implementation(const Implementation &);
int m_Refs;
};
void Assign(const char *str);
Implementation * m_Shared;
static Implementation * GetBlank();
};
// SharedString.cpp
// Code by Chris Jacobson (FearItself @ AvP)
// Based on code from LexiMUD (Aliens vs Predator: The MUD, and Raze the Dead)
// Modified to remove namespaces and target std::string.
// Permission to use in your own code, so long as this header remains intact.
// Due to static initialization order, the safest way to get a static is by a function that returns
// a pointer or reference to it. Anything global/static-initialized could potentially initialize before
// another static/global object that it depends on. Using a function guarantees the object gets
// initialized because it will be initialized when the function is called, not during global static
// initializers
SharedString::Implementation *SharedString::GetBlank()
{
static SharedString::Implementation s_Blank("");
return &s_Blank;
}
void SharedString::Assign(const char *str)
{
if (m_Shared) m_Shared->Release(); // This will always happen EXCEPT on new objects under construction
if (str && *str) m_Shared = new Implementation(str);
else
{
m_Shared = GetBlank();
m_Shared->Retain();
}
}