leocad/common/str.cpp
2016-03-06 20:19:02 +00:00

384 lines
6.7 KiB
C++

//
// General purpose string class
//
#include "lc_global.h"
#include <ctype.h>
#include "str.h"
static String aux;
// =============================================================================
// Construction / Destruction
String::String ()
{
m_pData = new char[1];
m_pData[0] = '\0';
}
String::~String ()
{
delete []m_pData;
}
// =============================================================================
// Operators
const String& String::operator= (const String& src)
{
delete []m_pData;
m_pData = new char[src.GetLength () + 1];
strcpy (m_pData, src.m_pData);
return *this;
}
const String& String::operator= (char ch)
{
delete []m_pData;
m_pData = new char[2];
m_pData[0] = ch;
m_pData[1] = '\0';
return *this;
}
const String& String::operator= (const char *src)
{
delete []m_pData;
m_pData = new char[strlen (src) + 1];
strcpy (m_pData, src);
return *this;
}
const String& String::operator+= (const String& src)
{
char *tmp = new char[GetLength () + src.GetLength () + 1];
strcpy (tmp, m_pData);
strcat (tmp, src.m_pData);
delete []m_pData;
m_pData = tmp;
return *this;
}
const String& String::operator+= (char ch)
{
size_t len = GetLength ();
char *tmp = new char[len + 1 + 1];
strcpy (tmp, m_pData);
tmp[len] = ch;
tmp[len+1] = '\0';
delete []m_pData;
m_pData = tmp;
return *this;
}
const String& String::operator+= (const char *src)
{
char *tmp = new char[GetLength () + strlen (src) + 1];
strcpy (tmp, m_pData);
strcat (tmp, src);
delete []m_pData;
m_pData = tmp;
return *this;
}
// =============================================================================
// Non-member operators
String& operator+ (const String& string1, const String& string2)
{
String s;
s = string1;
s += string2;
aux = s;
return aux;
}
String& operator+ (const String& string, char ch)
{
String s;
s = string;
s += ch;
aux = s;
return aux;
}
String& operator+ (char ch, const String& string)
{
String s;
s = ch;
s += string;
aux = s;
return aux;
}
String& operator+ (const String& string1, const char *string2)
{
String s;
s = string1;
s += string2;
aux = s;
return aux;
}
String& operator+ (const char *string1, const String& string2)
{
String s;
s = string1;
s += string2;
aux = s;
return aux;
}
// =============================================================================
// Sub-string extraction
String& String::Mid (int first, int count) const
{
if (count < 0)
count = 0;
else if (count > (int)GetLength ())
count = (int)GetLength ();
String s;
strncpy (s.GetBuffer (count+1), m_pData + first, count);
s.m_pData[count] = '\0';
aux = s;
return aux;
}
String& String::Left (int count) const
{
if (count < 0)
count = 0;
else if (count > (int)GetLength ())
count = (int)GetLength ();
String s;
strncpy (s.GetBuffer (count+1), m_pData, count);
s.m_pData[count] = '\0';
aux = s;
return aux;
}
String& String::Right (int count) const
{
if (count < 0)
count = 0;
else if (count > (int)GetLength ())
count = (int)GetLength ();
String s;
strncpy (s.GetBuffer (count+1), m_pData + GetLength () - count, count);
s.m_pData[count] = '\0';
aux = s;
return aux;
}
// =============================================================================
// Other functions
// Evaluates the contents of the string against a boolean expression.
// For example: (^Car | %Animal) & !Parrot
// Will return true for any strings that have the Car word or
// begin with Animal and do not have the word Parrot.
bool String::Match(const String& Expression) const
{
// Check if we need to split the test expression.
const char* p = Expression;
while (*p)
{
if (*p == '!')
{
return !Match(String(p + 1));
}
else if (*p == '(')
{
// const char* Start = p;
int c = 0;
// Skip what's inside the parenthesis.
do
{
if (*p == '(')
c++;
else if (*p == ')')
c--;
else if (*p == 0)
return false; // Mismatched parenthesis.
p++;
}
while (c);
if (*p == 0)
break;
}
else if ((*p == '|') || (*p == '&'))
{
String LeftStr, RightStr;
LeftStr = Expression.Left((p - Expression) - 1);
RightStr = Expression.Right((int)Expression.GetLength() - (p - Expression) - 1);
if (*p == '|')
return Match(LeftStr) || Match(RightStr);
else
return Match(LeftStr) && Match(RightStr);
}
p++;
}
if (Expression.Find('(') != -1)
{
p = Expression;
while (*p)
{
if (*p == '(')
{
const char* Start = p;
int c = 0;
// Extract what's inside the parenthesis.
do
{
if (*p == '(')
c++;
else if (*p == ')')
c--;
else if (*p == 0)
return false; // Mismatched parenthesis.
p++;
}
while (c);
String Expr = Expression.Mid(Start - Expression + 1, p - Start - 2);
return Match(Expr);
}
p++;
}
}
// Testing a simple case.
String Search = Expression;
Search.TrimRight();
Search.TrimLeft();
const char* Word = Search;
// Check for modifiers.
bool WholeWord = 0;
bool Begin = 0;
for (;;)
{
if (Word[0] == '^')
WholeWord = true;
else if (Word[0] == '%')
Begin = true;
else
break;
Word++;
}
int Result = Find(Word);
if (Result == -1)
return false;
if (Begin && (Result != 0))
{
if ((Result != 1) || ((GetAt(Result-1) != '_') && (GetAt(Result-1) != '~')))
return false;
}
if (WholeWord)
{
char End = GetAt(Result + (int)strlen(Word));
if ((End != 0) && (End != ' '))
return false;
if ((Result != 0) && ((GetAt(Result-1) == '_') || (GetAt(Result-1) == '~')))
Result--;
if ((Result != 0) && (GetAt(Result-1) != ' '))
return false;
}
return true;
}
int String::CompareNoCase (const char *string) const
{
char c1, c2, *ch = m_pData;
while (*ch && *string)
{
c1 = tolower (*ch);
c2 = tolower (*string);
if (c1 != c2)
return (c1 - c2);
ch++; string++;
}
return (((int)*ch) - ((int)*string));
}
int String::CompareNoCase(const char *string, int count) const
{
char c1, c2, *ch = m_pData;
while (*ch && *string)
{
c1 = tolower (*ch);
c2 = tolower (*string);
if (c1 != c2)
return (c1 - c2);
ch++;
string++;
count--;
if (!count)
return 0;
}
return (((int)*ch) - ((int)*string));
}
void String::MakeUpper ()
{
for (char *cp = m_pData; *cp; ++cp)
if ('a' <= *cp && *cp <= 'z')
*cp += 'A' - 'a';
}
void String::MakeLower ()
{
for (char *cp = m_pData; *cp; ++cp)
if ('A' <= *cp && *cp <= 'Z')
*cp += 'a' - 'A';
}
void String::TrimRight ()
{
for (char *s = m_pData + strlen (m_pData) - 1; s >= m_pData && isspace (*s); s--)
*s = '\0';
}
void String::TrimLeft ()
{
char *ch;
ch = m_pData;
while (isspace (*ch))
ch++;
memmove (m_pData, ch, strlen (ch)+1);
}