/****************************************************************************************

XString

(c) 1996 by Jens von Pilgrim

Details: See header file

History:

Note: in Strip: while-loops (correct for non-short-evaluation... (first<length)

*****************************************************************************************/


#include "stdio.h"      // only for testing...


#include "XDefines.h"

#include "XString.h"

#include "stdlib.h"

// Friend-Functionen:
XString operator +(const XString Str1, const char *pszChar2)
{
  ASSERT(Str1.m_pszChar!=NULL);
  ASSERT(pszChar2!=NULL);

  ASSERT(Str1.m_Length == strlen(Str1.m_pszChar));

  XString Res;
  size_t C2Length=strlen(pszChar2);

  Res.m_Length = Str1.m_Length+C2Length;
  free(Res.m_pszChar);
  Res.m_pszChar = (char *) malloc(Res.m_Length+1);

  ASSERT(Res.m_pszChar != NULL);

  memcpy(Res.m_pszChar, Str1.m_pszChar, Str1.m_Length);
  memcpy(&Res.m_pszChar[Str1.m_Length], pszChar2, C2Length+1);

  ASSERT(Res.GetLength() == strlen(Res.m_pszChar));

  return Res;
}


XString operator +(const char *pszChar1, const XString Str2)
{
  ASSERT(Str2.m_pszChar!=NULL);
  ASSERT(pszChar1!=NULL);

  ASSERT(Str2.m_Length == strlen(Str2.m_pszChar));

  XString Res;
  size_t C1Length = strlen(pszChar1);

  Res.m_Length = Str2.m_Length+C1Length;
  free(Res.m_pszChar);
  Res.m_pszChar = (char *) malloc(Res.m_Length+1);

  ASSERT(Res.m_pszChar != NULL);

  memcpy(Res.m_pszChar, pszChar1, C1Length);
  memcpy(&Res.m_pszChar[C1Length], Str2.m_pszChar, Str2.m_Length+1);

  ASSERT(Res.m_Length == strlen(Res.m_pszChar));

  return Res;
}


XString operator +(XString Str1, XString Str2)
{
  ASSERT(Str2.m_pszChar!=NULL);
  ASSERT(Str1.m_pszChar!=NULL);

  ASSERT(Str1.m_Length == strlen(Str1.m_pszChar));
  ASSERT(Str2.m_Length == strlen(Str2.m_pszChar));

  XString Res;

  Res.m_Length = Str2.m_Length+Str1.m_Length;
  free(Res.m_pszChar);
  Res.m_pszChar = (char *) malloc(Res.m_Length+1);

  ASSERT(Res.m_pszChar != NULL);

  memcpy(Res.m_pszChar, Str1.m_pszChar, Str1.m_Length);
  memcpy(&Res.m_pszChar[Str1.m_Length], Str2.m_pszChar, Str2.m_Length+1);

  ASSERT(Res.GetLength() == strlen(Res.m_pszChar));

  return Res;
}

/*DOC XString::StrCmp(const XString &inThen)
GROUP Comperasion
REMARKS Returns exactly the result from strcmp, usefull if other function needs this result.
The Result is

== 0: this string == inThen

 < 0: this string < inThen

 > 0: this string > inThen
*/
int XString::StrCmp(const XString &inThen)
{ ASSERT(m_pszChar!=NULL);
  ASSERT( inThen.m_pszChar!=NULL);

  return strcmp(m_pszChar, inThen.m_pszChar);
}


/*DOC XString::operator ==(const XString &inThen)
GROUP Comperasion
REMARKS Compares one string with another, returns TRUE if both strings are equal, else FALSE
*/
int XString::operator ==(const XString &inThen)
{ ASSERT(m_pszChar!=NULL);
  ASSERT( inThen.m_pszChar!=NULL);

  return strcmp(m_pszChar, inThen.m_pszChar)==0;
}

/*DOC XString::operator ==(const char *inCharPtr)
GROUP Comperasion
Overload for Charpointer, because this case is often used!
*/
int XString::operator ==(const char *inCharPtr)
{ ASSERT(m_pszChar!=NULL);
  ASSERT(inCharPtr!=NULL);

  return strcmp(m_pszChar, inCharPtr)==0;
}


/*DOC int XString::operator !=
GROUP Comperasion
REMARKS Compares one string with another, returns TRUE if both strings are not equal, else FALSE
*/
int XString::operator !=(const XString &inThen)
{ ASSERT(m_pszChar!=NULL);
  ASSERT( inThen.m_pszChar!=NULL);

  return strcmp(m_pszChar, inThen.m_pszChar)!=0;
}

/*DOC int XString::operator >=
GROUP Comperasion
REMARKS Compares one string with another, returns TRUE if the first string is greater/equal, else FALSE
*/
int XString::operator >=(const XString &inThen)
{ ASSERT(m_pszChar!=NULL);
  ASSERT( inThen.m_pszChar!=NULL);

  return strcmp(m_pszChar, inThen.m_pszChar)>=0;
}

/*DOC XString::operator <=
GROUP Comperasion
REMARKS Compares one string with another, returns TRUE if the first string is less/equal, else FALSE
*/
int XString::operator <=(const XString &inThen)
{ ASSERT(m_pszChar!=NULL);
  ASSERT( inThen.m_pszChar!=NULL);

  return strcmp(m_pszChar, inThen.m_pszChar)<=0;
}

/*DOC int XString::operator >
GROUP Comperasion
REMARKS Compares one string with another, returns TRUE if the first string is greater then the second string, else FALSE
*/
int XString::operator >(const XString &inThen)
{ ASSERT(m_pszChar!=NULL);
  ASSERT( inThen.m_pszChar!=NULL);

  return strcmp(m_pszChar, inThen.m_pszChar)>0;
}

/*DOC int XString::operator <
GROUP Comperasion
REMARKS Compares one string with another, returns TRUE if the first string is less then the second string, else FALSE
*/
int XString::operator <(const XString &inThen)
{ ASSERT(m_pszChar!=NULL);
  ASSERT( inThen.m_pszChar!=NULL);

  return strcmp(m_pszChar, inThen.m_pszChar)<0;
}

/*DOC int XString::XString()
GROUP Constructor/Destructor
REMARKS Constructs an empty string
*/
XString::XString()
{
  m_pszChar = (char *) malloc(1);
  ASSERT(m_pszChar != NULL);
  m_pszChar[0] = '\0';
  m_Length = 0;

}

/*DOC int XString::XString(const XString &aString)
GROUP Constructor/Destructor
REMARKS Constructs a string as a copy of 'aString'
*/
XString::XString(const XString &aString)
{
  ASSERT(&aString != NULL);
  ASSERT(&aString.m_pszChar != NULL);
  ASSERT(strlen(aString.m_pszChar) == aString.m_Length);

  m_Length = aString.m_Length;

  m_pszChar = (char *) malloc(m_Length+1);
  ASSERT(m_pszChar != NULL);

  memcpy(m_pszChar, aString.m_pszChar, m_Length+1);

  ASSERT(m_Length == strlen(m_pszChar));
}

/*DOC int XString::XString(char *pszChar)
GROUP Constructor/Destructor
REMARKS Constructs a string as a copy of pszChar, usefull as caster
*/
XString::XString(char *pszChar)
{
    ASSERT(pszChar != NULL);
    m_Length = strlen(pszChar);
    m_pszChar = (char *) malloc(m_Length+1);
    ASSERT(m_pszChar != NULL);

    memcpy(m_pszChar, pszChar, m_Length+1);

    ASSERT(GetLength() == strlen(m_pszChar));
}


XString::XString(char *pszChar, int DUPLICATE)
{
    if (pszChar != NULL) m_Length = strlen(pszChar);
    else m_Length = 0;
    m_pszChar = pszChar;
}


/*DOC int XString::XString(char aChar)
GROUP Constructor/Destructor
REMARKS Constructs a string with first char == aChar
*/
XString::XString(char aChar)
{
  m_Length = 1;
  m_pszChar = (char *) malloc(m_Length+1);
    ASSERT(m_pszChar != NULL);

  m_pszChar[0] = aChar;
  m_pszChar[1] = '\0';

  ASSERT(m_Length == strlen(m_pszChar));
}

/*DOC int XString::XString(int aNumber, int Radix)
GROUP Constructor/Destructor
REMARKS Constructs a string and casts an int, usefull as caster
*/
XString::XString(int aNumber, int Radix)
{ m_pszChar = (char *) malloc(20);
  _itoa(aNumber, m_pszChar, Radix);
  m_Length = strlen(m_pszChar);
  ReleaseBuffer();
}

/*DOC int XString::XString(long aNumber, int Radix)
GROUP Constructor/Destructor
REMARKS Constructs a string and casts an int, usefull as caster
*/
XString::XString(long aNumber, int Radix)
{ m_pszChar = (char *) malloc(40);
  _ltoa(aNumber, m_pszChar, Radix);
  m_Length = strlen(m_pszChar);
  ReleaseBuffer();
}

/*DOC int XString::~XString()
GROUP Constructor/Destructor
REMARKS (Virtual) Destructor, removes string from memory
*/
XString::~XString()
{
  ASSERT (m_pszChar != NULL);
  free(m_pszChar);
}



/*DOC XString::operator =(const XString &aString)
GROUP Set
RETURNS Returns copy of aString
REMARKS The Sourcestring aString is copied (duplicated) to this-string
*/
XString XString::operator =(const XString &aString)
{
  ASSERT(aString.m_pszChar != NULL);
  ASSERT(aString.m_Length == strlen(aString.m_pszChar));
  ASSERT(strlen(aString.m_pszChar) == aString.m_Length);

  free(m_pszChar);
  m_Length = aString.m_Length;
  m_pszChar = (char *) malloc(m_Length+1);
  ASSERT(m_pszChar != NULL);

  memcpy(m_pszChar, aString.m_pszChar, m_Length+1);

  ASSERT(m_Length == strlen(m_pszChar));

  return *this;
}


/*DOC XString::operator() (size_t inCount)
GROUP Get
RETURNS Returns a pointer to chars.
REMARKS Usefull in functions requiering char-pointer like
printf (printf("Hallo %s", aString()); ). The method works like Left, so
AString(5) returns the first 5 chars.
*/
char* XString::operator() (size_t inCount)
{
  return Left(inCount)(0);
}


/*DOC XString::operator() ()
GROUP Get
*/
char* XString::operator() ()
{ return m_pszChar;
}

/*DOC char XString::operator[]
GROUP Get
REMARKS The same as function At. The first char has index 0!
RETURNS Returns the char at position inZeroIndex.
*/
char XString::operator[](size_t inZeroIndex)
{ ASSERT(inZeroIndex<m_Length);
  return m_pszChar[inZeroIndex];
}

/*DOC char XString::At
GROUP Get
REMARKS The same as operator []. The first char has index 0!
RETURNS Returns the char at position inZeroIndex.
*/
char XString::At(size_t inZeroIndex)
{ ASSERT(inZeroIndex<m_Length);
  return m_pszChar[inZeroIndex];
}


/*DOC XString::operator int()
GROUP Caster
RETURNS String as an int
REMARKS Uses standard C-function atoi
*/
XString::operator int()
{ ASSERT(m_pszChar != NULL);
  return atoi(m_pszChar); }

/*DOC XString::operator long()
GROUP Caster
RETURNS String as a long int
REMARKS Uses standard C-function atol
*/
XString::operator long()
{ ASSERT(m_pszChar != NULL);
  return atol(m_pszChar); }

/*DOC XString::operator double()
GROUP Caster
RETURNS String as a double
REMARKS Uses standard C-function atof
*/
XString::operator double()
{ ASSERT(m_pszChar != NULL);
  return atof(m_pszChar); }

/*DOC XString::operator const int()
GROUP Caster
RETURNS String as a constant int, sometimes a const is required.
Uses standard C-function atoi
*/
XString::operator const int()
{ ASSERT(m_pszChar != NULL);
  return atoi(m_pszChar); }

/*DOC XString::operator const long()
GROUP Caster
RETURNS String as a constant long int, sometimes a const is required.
REMARS Uses standard C-function atol
*/
XString::operator const long()
{ ASSERT(m_pszChar != NULL);
  return atol(m_pszChar); }

/*DOC XString::operator const double()
GROUP Caster
RETURNS String as a constant float (double), sometimes a const is required.
REMARS Uses standard C-function atof
*/
XString::operator const double()
{ ASSERT(m_pszChar != NULL);
  return atof(m_pszChar); }


/*DOC XString::operator +=(const XString &Str)
GROUP Set
RETURNS Returns thisString+Str
REMARS Concats string with another string Str and saves the result in string.
Like this:

XString a,b,c;

...

a=(b+=c);

Result: (a==b) = TRUE
*/
XString XString::operator +=(const XString &Str)
{
  ASSERT(Str.m_pszChar!=NULL);
  ASSERT(m_pszChar!=NULL);
  ASSERT(m_Length==strlen(m_pszChar));

  m_pszChar = (char *) realloc (m_pszChar, m_Length+Str.m_Length+1);
  ASSERT(m_pszChar != NULL);

  memcpy(&m_pszChar[m_Length], Str.m_pszChar, Str.m_Length + 1);

  m_Length += Str.m_Length;

  ASSERT(m_Length == strlen(m_pszChar));

  return *this;

}


/*DOC XString::operator +=(const char *Str)
GROUP Set
REMARKS Adds a string
*/
XString XString::operator +=(const char *Str)
{
  ASSERT(Str!=NULL);
  ASSERT(m_pszChar!=NULL);
  ASSERT(m_Length==strlen(m_pszChar));

  size_t length = strlen(Str);

  m_pszChar = (char *) realloc (m_pszChar, m_Length+length+1);
  ASSERT(m_pszChar != NULL);

  memcpy(&m_pszChar[m_Length], Str, length + 1);

  m_Length += length;

  ASSERT(m_Length == strlen(m_pszChar));

  return *this;

}

/*DOC XString::Mid(size_t From, size_t Count)
GROUP Get
RETURNS Returns substring with Count-length from position From in string.
REMARKS If From>GetLength(), an empty string is returned; if From+Count>GetLength(),
a string with a length of (GetLength()-From) is returned.
*/

XString XString::Mid(size_t From, size_t Count)
{
  ASSERT(m_pszChar != NULL);
  ASSERT(m_Length == strlen(m_pszChar));

  if ((Count == 0) || (From>=m_Length)) return XString();
  if (From+Count>m_Length) Count=m_Length-From;

  ASSERT (Count<=m_Length);

  XString Res(NULL, 1);
  Res.m_pszChar = (char *) malloc(Count+1);
  ASSERT(Res.m_pszChar != NULL);

  memcpy(Res.m_pszChar, m_pszChar+From, Count);
  Res.m_pszChar[Count]=0;
  Res.m_Length = Count;

  ASSERT(Res.m_Length == strlen(Res.m_pszChar));

  return Res;
}

/*DOC XString::Left(size_t Count)
GROUP Get
RETURNS Returns the first Count chars as a XString from string. Thus, it's equal to Mid(0, nCount).
REMARKS If Count>GetLength(), a copy of the string is returned, if Count is 0, an empty string is returned.
*/

XString XString::Left(size_t Count)
{
  ASSERT(m_pszChar != NULL);

  if (Count==0) return XString();

  if (Count>m_Length) Count=m_Length;

  XString Res(NULL, 1);
  Res.m_Length = Count;
  Res.m_pszChar = (char *) malloc(Count+1);
  ASSERT(Res.m_pszChar != NULL);

  memcpy(Res.m_pszChar, m_pszChar, Count);
  Res.m_pszChar[Count]=0;

 ASSERT(Res.m_Length == strlen(Res.m_pszChar));

  return Res;
}


/*DOC XString::Right
GROUP Get
REMARKS What do you think this methods is for? See Left() for details, rigth up!
*/
XString XString::Right(size_t Count)
{
  ASSERT(m_pszChar != NULL);

  if (Count==0) return XString();
  if (Count>m_Length) Count=m_Length;

  XString Res(NULL, 1);
  Res.m_Length = Count;
  Res.m_pszChar = (char *) malloc(Count+1);

  ASSERT(Res.m_pszChar != NULL);

  memcpy(Res.m_pszChar, &m_pszChar[m_Length-Count], Count+1);
  // abschlieáendes 0 wird mitkopiert

  ASSERT(Res.m_Length == strlen(Res.m_pszChar));

  return Res;
}

/*DOC XString::Find
GROUP Enhanced
RETURNS TRUE, if substring is in string, outPos is the (zero-indexed) position of the substring in string (the first). FALSE, if the substring was not found
REMARKS Because some parameters have standard values, you can call this method also with Find(pos, "...").
*/
BOOL XString::Find(size_t &outPos, const XString &SubString, size_t From, size_t inTo)
{ ASSERT (SubString.m_pszChar != NULL);

  if (inTo>GetLength()) inTo = GetLength();
  if (inTo==0) inTo = GetLength();
  if (inTo<From) return FALSE;

  ASSERT (m_pszChar!=NULL);

  if (SubString.m_Length==0) return FALSE;
  if (SubString.m_Length>inTo-From) return FALSE;

  size_t StrI, SubI=0,
         SubLength=SubString.m_Length-1,
         First;

  for (StrI=From; StrI<inTo-SubLength; StrI++)
  {
    if (m_pszChar[StrI]==SubString.m_pszChar[SubI])
    { First = StrI;
      do
      {
	if (SubI == SubLength) { outPos = First; return TRUE; };
	SubI++;
	StrI++;
      }
      while (m_pszChar[StrI]==SubString.m_pszChar[SubI]);
      SubI=0;
      StrI = First; // !!, eg */ in ***/ nicht gefunden!
    }
  }
  return FALSE;
}




/*DOC XString::FindRev(size_t &outPos, const XString &SubString, size_t From = 0, size_t inTo = 0)
GROUP Enhanced
RETURNS TRUE, if substring is in string, outPos is the (zero-indexed) position of the substring in string (the first). FALSE, if the substring was not found
REMARKS Because some parameters have standard values, you can call this method also with Find(pos, "...").
*/
BOOL XString::FindRev(size_t &outPos, const XString &SubString, size_t From, size_t inTo)
{ ASSERT (SubString.m_pszChar != NULL);

  if (From>inTo) return FALSE;

  if (inTo==0) inTo = GetLength();

  ASSERT (m_pszChar!=NULL);

  if (SubString.m_Length==0) return FALSE;
  if (SubString.m_Length>inTo-From) return FALSE;

  size_t StrI, SubI=SubString.m_Length-1,
         SubLength=SubString.m_Length-1,
         First;

  for (StrI=inTo; StrI>From+SubLength; StrI--)
  {
    if (m_pszChar[StrI]==SubString.m_pszChar[SubI])
    { First = StrI;
      do
      {
	if (SubI == 0) { outPos = First; return TRUE; };
	SubI--;
	StrI--;
      }
      while (m_pszChar[StrI]==SubString.m_pszChar[SubI]);
      SubI=SubLength;
      StrI = First; // !!, eg */ in ***/ nicht gefunden!
    }
  }
  return FALSE;
}



/*
int XString::FastFind(const XString &SubString, XString &SearchTab, size_t From)
{ ASSERT (SubString.m_pszChar != NULL);

  if (m_pszChar==NULL) return -1;
  if (SubString.m_Length==0) return -2;

  size_t StrI=From, SubI=0, SubLength=SubString.m_Length-1, First;
  char d;

  if (SearchTab.IsEmpty()) // Tabelle initialisieren
  {
    SearchTab = "\1";
    for (StrI=1; StrI<100; StrI++) SearchTab += SubString.m_Length;
    if (SubLength>255) First = 255; else First = SubLength;
    for (StrI=0; StrI<First; StrI--)
      SearchTab.m_pszChar[StrI] = (char) SubLength-StrI;
  }


  for (StrI=SubLength-1; StrI<m_Length; StrI+=SearchTab.m_pszChar[m_pszChar[StrI]])
  {
    if (m_pszChar[StrI]==SubString.m_pszChar[SubLength])
    { First = StrI; SubI=SubLength;
      do
      {
	if (SubLength==0) return First;
	SubI--;
	First--;
      }
      while (m_pszChar[SubI]==SubString.m_pszChar[First]);
    }
  }
  return -1;
}
*/


/*DOC XString::GetLength()
GROUP Get
REMARKS Returns the length of the string!
*/
size_t XString::GetLength()
{ return m_Length; }


/*DOC XString::GetBuffer(size_t Size)
GROUP Caster
REMARKS This is the most dangerous function, because it allows you access to the heart of XString, the
char-buffer! Don't use this function for dircet manipulations of the buffer! This function has
another job to do!

The job of this method is to work as a caster, when some awefull and dirty C-functions needs a
char-pointer, like sprintf. Size is the size you initialize the string, take care that the size
is great enough!

Don't forget to call the ReleaseBuffer()-Function after GetBuffer()! ReleaseBuffer correct the length
of the string.

The Size is exactly the size of chars in the buffer, the byte for the zero-byte is automatically added!

See the example!
EXAMPLE
XString a;

double pi=3.14;

sprintf(a.GetBuffer(100), "Pi = %2.3f", pi); a.ReleaseBuffer();
*/
char* XString::GetBuffer(size_t Size)
{
  ASSERT (Size+1!=0);

  m_pszChar = (char *) realloc(m_pszChar, Size+1);
  ASSERT(m_pszChar!=NULL);
  m_pszChar[Size]=0;
  m_Length = Size;

  return m_pszChar;
}


/*DOC XString::ReleaseBuffer(size_t Length)
GROUP Caster
REMARKS After getting the buffer with GetBuffer, and after setting the size of the string to Size, this function
correct the size of the buffer, so that the size of the buffer is equal to the length of the string.
Don't use any other function after GetBuffer, before not calling ReleaseBuffer!!!!!!!!!!
*/
int XString::ReleaseBuffer(size_t Length)
{
  if (Length==0) Length = strlen(m_pszChar);

  ASSERT (Length<=m_Length);

  m_pszChar = (char *) realloc(m_pszChar, Length+1);
  ASSERT (m_pszChar!=NULL);
  m_pszChar[Length] = 0;
  m_Length = Length;

  ASSERT(m_Length == strlen(m_pszChar));

  return Length;
}


/*DOC XString::Strip(int inWhere, char inChar)
GROUP Enhanced
RETURNS Number of removed chars
REMARKS Strip removes all inChars at the beginning (inWhere=XLEFT), at the end (inWhere=XRIGHT), at both ends
(inWhere=XBOTH) or removes all inChars (inWhere=XALL) from the string!
If you have to remove substring, use Replace() instead!
*/
int XString::Strip(int inWhere, char inChar)
{

  ASSERT(m_pszChar != NULL);
  if (m_Length == 0) return 0;

  size_t First=0, Last=m_Length;  // Last 1index (>0)...

  if (inWhere != XRIGHT) // then strip left
  {
    while ((First<m_Length) && (m_pszChar[First] == inChar)) First++;

    if (First==m_Length) // Stripp all
    { m_pszChar = (char *) realloc(m_pszChar, 1);
      ASSERT(m_pszChar != NULL);
      m_pszChar[0] = '\0';
      m_Length = 0;

      ASSERT(m_Length == strlen(m_pszChar));

      return Last;
    }
  }

  if (inWhere != XLEFT) // then strip right
  {

    while ((Last>0) && (m_pszChar[Last-1] == inChar))
    {  Last--; }
    if (Last==0) // Stripp all
    { m_pszChar = (char *) realloc(m_pszChar, 1);
      ASSERT(m_pszChar != NULL);
      m_pszChar[0] = '\0';
      Last = m_Length;
      m_Length = 0;

      ASSERT(m_Length == strlen(m_pszChar));

      return Last;
    }
  }

  char *stripped;

  if (inWhere != XALL) // then  build result string
  {
    if ((First==0) && (Last==m_Length)) // then nothing to do
      return 0;

    stripped = (char *) malloc(Last-First+1);
    ASSERT (stripped != NULL);
    memcpy(stripped, m_pszChar+First, Last-First);

    stripped[Last-First] = 0;
    free(m_pszChar);
    m_pszChar = stripped;
    size_t ret=m_Length;
    m_Length = Last-First;

    ASSERT(m_Length == strlen(m_pszChar));

    return ret-m_Length;
  }

  // inWhere == ALL
  stripped = (char *) malloc(Last-First+1);
  ASSERT (stripped != NULL);

  size_t index=First, strindex=0;    // 0-index
  while (index<Last)
  { if (m_pszChar[index] != inChar) // else ignore this char
    { stripped[strindex] = m_pszChar[index];
      strindex++;
    }
    index++;
  }

  free(m_pszChar);
  size_t oldL=m_Length;
  m_pszChar = (char *) malloc(strindex+1);
  ASSERT (m_pszChar != NULL);
  memcpy(m_pszChar, stripped, strindex);
  m_pszChar[strindex] = 0;

  free(stripped);
  m_Length = strindex;

  ASSERT(m_Length == strlen(m_pszChar));
  return oldL-m_Length;
}


/*DOC XString::DelSubString(XString inSubString)
GROUP Set
REMARKS Deletes the first place occurrence of inSubString
*/
int XString::DelSubString(XString inSubString)
{
  ASSERT(inSubString.m_pszChar!=NULL);
  ASSERT(inSubString.m_Length>0);

  size_t pos;
  if (Find(pos, inSubString)) return DelSubString(pos, inSubString.m_Length);
  return X_ERR;
}

/*DOC XString::DelSubString
GROUP Set
REMARKS Deletes inCount-chars from inFrom (Zero-Index!).
*/
int XString::DelSubString(size_t inFrom, size_t inCount=1)
{
  ASSERT(inFrom<m_Length);
  if (inCount==0) return X_ERR;

  if (inFrom+inCount>m_Length) inCount=m_Length-inFrom;

  char *temp = (char *) malloc(m_Length-inCount+1);
  ASSERT(temp!=NULL);

  memcpy(temp, m_pszChar, inFrom);
  memcpy(temp+inFrom, m_pszChar+inFrom+inCount, m_Length-(inCount+inFrom));
  temp[m_Length-inCount] = '\0';
  m_Length -= inCount;
  free(m_pszChar);
  m_pszChar = temp;

  ASSERT(m_Length == strlen(m_pszChar));

  return X_OK;
}

/*DOC XString::Replace(XString inSearch, XString inReplace, int inTimes, size_t inFrom, size_t inTo)
GROUP Enhanced
RETURNS Number of replacements
PARAMETERS inSearch is the substring to search, inReplace is the string wich replaces the searchstring, the substring
is max. inTimes replaced and inFrom and inTo mark the scope.
REMARKS This is one of the most powerful methods of XString. It works as the Search-Replace-Function of you editor.
Of course, the search- and the replace-substring must NOT have the same length! The methods is working very fast,
because it first searches the substring, allocs new memory by calculing the new size, and then a new string is build.
When the new string is build, there is no more search necessary (only if the replacement-string is greater then the
searchstring and the length of the searchstring is smaller then the size of a size_t-type!).

In this moment I'm working at another Replace-method: Replace(BadEnglish, CorrectEnglish, everywhere in this docu...) ;-)
*/
int XString::Replace(XString inSearch, XString inReplace, int inTimes, size_t inFrom, size_t inTo)
{
  size_t pos=inFrom, count=0;
  char *temp;


  if (inTo==0) inTo=GetLength();
  if (inTo<inFrom)
  { count = inTo; inTo = inFrom; inFrom = count; count =0; }
  if (inFrom>inTo) return 0;


  ASSERT(m_Length == strlen(m_pszChar));

  if (inSearch.GetLength() == inReplace.GetLength())
  {
    while (Find(pos,inSearch, pos, inTo))
    { count++;
      memcpy(&m_pszChar[pos], inReplace.m_pszChar, inReplace.GetLength());
      if (count==inTimes) break;
      pos += inSearch.GetLength();
    }
  }
  else
  if (inSearch.GetLength() > inReplace.GetLength())
  {
    while (Find(pos,inSearch, pos, inTo))
    { count++;
      memcpy(&m_pszChar[pos], inReplace.m_pszChar, inReplace.GetLength());
      memmove(&m_pszChar[pos+inReplace.GetLength()],
              &m_pszChar[pos+inSearch.GetLength()], GetLength()+1-(pos+inSearch.GetLength()));
      if (count==inTimes) break;
      pos += inReplace.GetLength();
    }
    if (count>0)
    {
    temp = (char *) malloc(GetLength()+1-count*(inSearch.GetLength()-inReplace.GetLength()));
    memcpy(temp, m_pszChar,GetLength()+1-count*(inSearch.GetLength()-inReplace.GetLength()));
    free(m_pszChar);
    m_pszChar = temp;
    m_Length = GetLength()-count*(inSearch.GetLength()-inReplace.GetLength());
    }
  }
  else // inSearch.GetLength() < inReplace.GetLength()
  {
    size_t *posptr, firstpos, lastpos;
    unsigned char offset, nextNull=0, offsets=0;

    if (inSearch.GetLength()>=sizeof(size_t))    // ptrlist in string
    {

      while (Find(pos,inSearch, pos, inTo))
      { count++;
        if (count==1) firstpos = pos;
        else *posptr = pos;

        posptr = (size_t*) (&m_pszChar[pos]);
        if (count==inTimes) break;
        pos += inSearch.GetLength();
      }

    }
    else
    { offsets = 1;
      while (Find(pos, inSearch, pos, inTo))
      {  count++;
         if (count==1) firstpos=pos;
         pos += inSearch.GetLength();
      }
    }
    if (count>0)
    { size_t i=0, nextpos = 0;
      lastpos = 0;
      pos = firstpos;

      temp = (char *) malloc(GetLength()+1+count*(inReplace.GetLength()-inSearch.GetLength()));

      while (i<count)
      {
       if (offsets)   Find(nextpos, inSearch, pos+inSearch.GetLength(), inTo);
       else           nextpos = *( (size_t*) (m_pszChar+pos) ) ;

        if (i>0)
        {  memcpy(&temp[inSearch.GetLength()+lastpos+(inReplace.GetLength()-inSearch.GetLength())*i ],
               &m_pszChar[lastpos+inSearch.GetLength()],
               pos-(lastpos+inSearch.GetLength()));                    // ...RRRxxxx...
           memcpy(&temp[inSearch.GetLength()+pos+(inReplace.GetLength()-inSearch.GetLength())*i
                         -inSearch.GetLength()],
                inReplace.m_pszChar, inReplace.GetLength()+1);           //...RRRxxxxRRR
        }
        else
        { memcpy(temp, m_pszChar, pos);
          memcpy(&temp[pos],inReplace.m_pszChar, inReplace.GetLength()+1);
        }


        lastpos = pos;
        pos = nextpos;
        i++;
      }

      memcpy(&temp[inSearch.GetLength()+lastpos+(inReplace.GetLength()-inSearch.GetLength())*i],    /// RRRxxxxx
             &m_pszChar[lastpos+inSearch.GetLength()],
             GetLength()-(lastpos+inSearch.GetLength())+1);

      size_t A1, A2;
      A1 =inSearch.GetLength()+lastpos+(inReplace.GetLength()-inSearch.GetLength())*i+GetLength()-(lastpos+inSearch.GetLength());
      A2 = GetLength()+count*(inReplace.GetLength()-inSearch.GetLength());

ASSERT(A1==A2);


      free(m_pszChar);
      m_pszChar = temp;
      m_Length = GetLength()+count*(inReplace.GetLength()-inSearch.GetLength());

    }
  }
  return count;
}

