mirror of
https://github.com/leozide/leocad
synced 2024-11-17 07:47:55 +01:00
402 lines
6.9 KiB
C++
402 lines
6.9 KiB
C++
//
|
|
// General purpose string class
|
|
//
|
|
|
|
#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)
|
|
{
|
|
int 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 > GetLength ())
|
|
count = 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 > GetLength ())
|
|
count = 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 > GetLength ())
|
|
count = 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 Left, Right;
|
|
|
|
Left = Expression.Left((p - Expression) - 1);
|
|
Right = Expression.Right(Expression.GetLength() - (p - Expression) - 1);
|
|
|
|
if (*p == '|')
|
|
return Match(Left) || Match(Right);
|
|
else
|
|
return Match(Left) && Match(Right);
|
|
}
|
|
|
|
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 + 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::MakeReverse ()
|
|
{
|
|
register char *h, *t;
|
|
|
|
h = m_pData;
|
|
t = m_pData + strlen (m_pData) - 1;
|
|
|
|
while (h < t)
|
|
{
|
|
register char c;
|
|
|
|
c = *h;
|
|
*h = *t;
|
|
h++;
|
|
*t = c;
|
|
t--;
|
|
}
|
|
}
|
|
|
|
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);
|
|
}
|