/*
**
** StringClass.cpp
**
** (c) 1998 Didier Levet
**
** String classes
**
** $Revision: 1.4 $
** $State: Exp $
** $Date: 1998/11/23 14:38:53 $
**
** $Log: StringClass.cpp $
** Revision 1.4  1998/11/23 14:38:53  kakace
** Reworked CString and CStrArray classes
**
** Revision 1.3  1998/11/22 14:57:17  kakace
** Class CStrArray now uses class CString and seems to work fine
**
** Revision 1.2  1998/11/21 20:58:24  kakace
** Class CString seems to be okay now
**
** Revision 1.1  1998/11/11 16:35:49  kakace
** Initial revision
**
**
*/


#ifndef  _STRING_CLASS_HPP
#include "StringClass.hpp"
#endif

#ifndef  _INCLUDE_STDLIB_H
#include <stdlib.h>
#endif

#ifndef  _INCLUDE_STRING_H
#include <string.h>
#endif


//----------------------------------------------------------------------------------------------------
//========================================== Class CString ===========================================
//----------------------------------------------------------------------------------------------------

//==================================================================================================
//
//   SYNOPSIS                                                                       CString::CString
//   CString::CString(str, minLength = 0)
//   CString::CString(STRING, ULONG);
//
//   FUNCTION
//      Initialize the instance with the string given. The string buffer is allocated on the heap,
//      and its size is equal to MAX(minLength, strlen(str)).
//
//   INPUTS
//   str       - String to copy into a new buffer, or NULL.
//   minLength - Minimum buffer size.
//
//   NOTES
//
//   SEE ALSO
//
//   HISTORY
//
//==================================================================================================
/// CString::CONSTRUCTOR


CString::CString(STRING str, ULONG minLength)
{
    ULONG c = stringlen(str);

    if (c < minLength) c = minLength;

    release();                          // Initialize the instance to a NULL state.
    newstring(str, c);
}
///

//==================================================================================================
//
//   SYNOPSIS                                                                        CString::extend
//   buffsize = CString::extend(newSize)
//   ULONG CString::extend(ULONG);
//
//   FUNCTION
//      Extend the string buffer to be newSize bytes wide, unless it is currently larger than that.
//
//   INPUTS
//   newSize - New buffer size.
//
//   RESULT
//   buffsize - Current buffer size.
//
//   NOTES
//
//   SEE ALSO
//
//   HISTORY
//
//==================================================================================================
/// CString::extend()


ULONG CString::extend(ULONG newSize)
{
    if (iBuffLen < newSize)
    {
        newstring(pcString, newSize);
    }

    return iBuffLen;
}
///

//==================================================================================================
//
//   SYNOPSIS                                                                              operator>
//   bool = CString::operator>(str)
//   int CString::operator>(const CString&);
//
//   FUNCTION
//      Compare two strings.
//
//   INPUTS
//   str - String to compare with (can be NULL).
//
//   RESULT
//   bool - TRUE if this string is "greater" than the string given in parameter, FALSE otherwise.
//      The result is also valid when one (or both) string is undefined (NULL).
//
//   NOTES
//
//   SEE ALSO
//
//   HISTORY
//
//==================================================================================================
/// CString::OPERATOR >


int CString::operator > (const CString& str) const
{
    int result;

    if (pcString == NULL)
    {
        result = FALSE;
    }
    else if (str == EMPTY || strcmp(pcString, str) > 0)
    {
        result = TRUE;
    }

    return result;
}
///

//==================================================================================================
//
//   SYNOPSIS                                                                             operator!=
//   bool = CString::operator!=(str)
//   int CString::operator!=(const CString&);
//
//   FUNCTION
//      Compare two strings.
//
//   INPUTS
//   str - String to compare with (can be NULL)
//
//   RESULT
//   bool - TRUE if the strings are different, FALSE otherwise. The result is also valid when one
//      (or both) string is undefined (NULL).
//
//   NOTES
//
//   SEE ALSO
//
//   HISTORY
//
//==================================================================================================
/// CString::OPERATOR !=


int CString::operator !=(const CString& str) const
{
    int result = (pcString != str.pcString);    // FALSE if pcString == str.pcString == NULL
                                                // (a string can't be pointed to by more than one pointer).

    if (iLength == str.iLength && pcString != NULL && str.pcString != NULL && strcmp(pcString, str) == 0)
        result = FALSE;

    return result;
}
///

//==================================================================================================
//
//   SYNOPSIS                                                                    CString::stringcopy
//   len = CString::stringcopy(source, dest)
//   ULONG CString::stringcopy(STRING, char *);
//
//   FUNCTION
//      Copy the source NUL terminated string to the destination buffer.
//
//   INPUTS
//   source - Source string, or NULL, or empty string.
//   dest   - Destination buffer. It must be large enough to hold the whole string.
//
//   RESULT
//   len - Length of the string copied.
//
//   PRECONDITIONS
//      dest != NULL
//
//   POSTCONDITIONS
//      The destination buffer holds a NUL terminated string that is either an empty string or the
//      copy of the source string.
//
//   NOTES
//
//   SEE ALSO
//
//   HISTORY
//
//==================================================================================================
///CString::stringcopy()           [PROTECTED]


ULONG CString::stringcopy(STRING source, char *dest)
{
    ULONG  len = 0;
    STRING start = source;

    if (source != NULL)
    {
        while ( (*dest++ = *source++) != '\0')
            ;
        len = source - start - 1;
    }
    else *dest = '\0';

    return len;
}
///

//==================================================================================================
//
//   SYNOPSIS                                                                     CString::newstring
//   CString::newstring(str, size)
//   void CString::newstring(STRING, ULONG);
//
//   FUNCTION
//      Allocate a new buffer then copy the string given into it.
//
//   INPUTS
//   str  - String to copy. Can be an empty string, or NULL.
//   size - Minimum buffer size or string's length. If size is equal to ZERO, this function
//      releases the buffer currently held.
//
//   PRECONDITIONS
//      size >= strlen(str)
//
//   POSTCONDITIONS
//      pcString == NULL : iLength = iBuffLen = 0
//      pcString != NULL : iLength = string's length, iBuffLen = buffer's size.
//
//   NOTES
//
//   SEE ALSO
//
//   HISTORY
//
//==================================================================================================
/// CString::newstring()            [PROTECTED]


void CString::newstring(STRING str, ULONG size)
{
    char  *p = NULL;

    iBuffLen = iLength = 0;

    // Allocate a new buffer.

    if (size > 0 && (p = new char[size + 1]) != NULL)
    {
        iLength = stringcopy(str, p);
        iBuffLen = size + 1;
    }

    freebuff();                     // Free the old buffer if necessary.
    pcString = p;
}
///

//==================================================================================================
//
//   SYNOPSIS                                                                     CString::stringlen
//   len = CString::stringlen(s)
//   ULONG CString::stringlen(const char []);
//
//   FUNCTION
//      Returns the length of the string passed in parameter.
//
//   INPUTS
//   s - Pointer to a NUL terminated string, or NULL.
//
//   RESULT
//   len - Length of the given string, or ZERO if the string is empty or undefined (NULL).
//
//   NOTES
//
//   SEE ALSO
//
//   HISTORY
//
//==================================================================================================
/// CString::stringlen()            [PROTECTED]


ULONG CString::stringlen(const char s[])
{
    STRING str = s;
    ULONG len = 0;

    if (str != NULL)
    {
        while (*str++ != '\0')
            ;
        len = str - s - 1;
    }

    return len;
}
///

//==================================================================================================
//
//   SYNOPSIS                                                                        CString::concat
//   CString::concat(str, len)
//   void CString::concat(STRING, ULONG);
//
//   FUNCTION
//      Concatenate the string with the current object. The buffer is extended when necessary.
//
//   INPUTS
//   str - String to add (or NULL).
//   len - Length of the string to add.
//
//   PRECONDITIONS
//      len >= strlen(str)
//
//   NOTES
//
//   SEE ALSO
//
//   HISTORY
//
//==================================================================================================
/// CString::concat()               [PROTECTED]


void CString::concat(STRING str, ULONG len)
{
    if (pcString == NULL)
    {
        newstring(str, len);
    }
    else
    {
        ULONG total_len = iLength + len;

        if(extend(total_len) >= total_len)
        {
            iLength += stringcopy(str, pcString + iLength);
        }
    }
}
///

//==================================================================================================
//
//   SYNOPSIS                                                                     CString::duplicate
//   CString::duplicate(str, len)
//   void CString::duplicate(STRING, ULONG);
//
//   FUNCTION
//      Duplicate the string passed in.
//
//   INPUTS
//   str - String to copy.
//   len - Buffer size
//
//   PRECONDITIONS
//      len >= strlen(str)
//
//   NOTES
//
//   SEE ALSO
//
//   HISTORY
//
//==================================================================================================
/// CString::duplicate()            [PROTECTED]


void CString::duplicate(STRING str, ULONG len)
{
    if (iBuffLen > len)                         // <==> pcString != NULL
    {
        iLength = stringcopy(str, pcString);
    }
    else
    {
        newstring(str, len);
    }
}
///


//----------------------------------------------------------------------------------------------------
//========================================= Class CStrArray ==========================================
//----------------------------------------------------------------------------------------------------

//==================================================================================================
//
//   SYNOPSIS                                                                   CStrArray::operator=
//   object = CStrArray::operator=(array)
//   CStrArray& CStrArray::operator=(CStrArray&);
//
//   FUNCTION
//      Make the current object to adopt array's buffers.
//
//   INPUTS
//   array - Source object.
//
//   RESULT
//   object - Destination object.
//
//   NOTES
//      All buffers held by the current object (*this) are freed before adopting the new ones.
//
//   SEE ALSO
//      CStrArray::freebuff(), CStrArray::adopt()
//
//   HISTORY
//
//==================================================================================================
/// CStrArray::operator = (array)


CStrArray& CStrArray::operator =(CStrArray& array)
{
    if (&array != this)
    {
        freebuff();             // Free the current array.
        AdoptArray(array);
    }

    return *this;
}
///

//==================================================================================================
//
//   SYNOPSIS                                                                   CStrArray::operator=
//   object = CStrArray::operator=(array)
//   CStrArray& CStrArray::operator=(STRING *);
//
//   FUNCTION
//      Initialize the current object with the string array. All strings are copied into new
//      buffers.
//
//   INPUTS
//   array - String array to copy.
//
//   RESULT
//   object - Current object.
//
//   NOTES
//
//   SEE ALSO
//      CStrArray::Add()
//
//   HISTORY
//
//==================================================================================================
/// CStrArray::operator = (STRING *)


CStrArray& CStrArray::operator =(STRING *array)
{
    if (array != NULL)
    {
        while (*array)
        {
            if (Add(*array) == FALSE)
            {
                cleanup();
                break;
            }
            ++array;
        }
    }

    return *this;
}
///

//==================================================================================================
//
//   SYNOPSIS                                                                       CStrArray::adopt
//   result = CStrArray::adopt(str)
//   bool CStrArray::adopt(CString&);
//
//   FUNCTION
//      Add a new string into the array. This array is extended when required.
//      The string is adopted by the string array. This means that it goes in an empty state.
//
//   INPUTS
//   str - String object to add.
//
//   RESULT
//   result - FALSE if an error as occured (not enough memory).
//
//   NOTES
//
//   SEE ALSO
//      CStrArray::extend(), CStrArray::newstring()
//
//   HISTORY
//
//==================================================================================================
/// CStrArray::adopt()


int CStrArray::adopt(CString& str)
{
    if (extend() != FALSE)
    {
        if (str != CString::EMPTY) newstring(str);
        return TRUE;
    }

    return FALSE;
}
///

//==================================================================================================
//
//   SYNOPSIS                                                                      CStrArray::extend
//   result = CStrArray::extend(size = granularity())
//   bool CStrArray::extend(ULONG);
//
//   FUNCTION
//      Extend the buffer when necessary.
//
//   RESULT
//   result - FALSE if an error has occured (not enough memory).
//
//   NOTES
//
//   SEE ALSO
//
//   HISTORY
//
//==================================================================================================
///CStrArray::extend()


int CStrArray::extend(ULONG size)
{
    int result = TRUE;

    if (iCurrentIndex == iNumEntries)
    {
        ULONG num_entries  = iNumEntries + size;
        CString *array = new CString[num_entries];

        if (array != NULL)
        {
            for (int i = 0; i < iCurrentIndex; ++i)
            {
                array[i].adopt(voStringArray[i]);
            }

            freebuff();
            voStringArray = array;
            iNumEntries   = num_entries;
        }
        else result = FALSE;
    }

    return result;
}
///

