// ------------------------------- //
// -------- Start of File -------- //
// ------------------------------- //
// ----------------------------------------------------------- //
// C++ Header File Name: ustring.hpp 
// Compiler Used: MSVC40, DJGPP 2.7.2.1, GCC 2.7.2.1, HP CPP 10.24
// Produced By: Doug Gaer 
// File Creation Date: 11/29/1996  
// Date Last Modified: 10/23/1998
// Copyright (c) 1997 Douglas M. Gaer
// ----------------------------------------------------------- // 
// ---------- Include File Description and Details  ---------- // 
// ----------------------------------------------------------- // 
/*
The VBD C++ classes are copyright (c) 1997, by Douglas M. Gaer.
All those who put this code or its derivatives in a commercial
product MUST mention this copyright in their documentation for
users of the products in which this code or its derivative
classes are used. Otherwise, you have the freedom to redistribute
verbatim copies of this source code, adapt it to your specific
needs, or improve the code and release your improvements to the
public provided that the modified files carry prominent notices
stating that you changed the files and the date of any change.

THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND.
THE ENTIRE RISK OF THE QUALITY AND PERFORMANCE OF THIS SOFTWARE
IS WITH YOU. SHOULD ANY ELEMENT OF THIS SOFTWARE PROVE DEFECTIVE,
YOU WILL ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR, OR
CORRECTION.

The UString class is a user-defined string class used to create
and manipulate non null-terminated resizable, variable-length
strings of binary data. UString objects are implemented as a
concrete data type, just like the built-in data types: char,
int, long, float, and double. The UString class supports string
concatenation, find, fill, and sub-string creation.
*/
// ----------------------------------------------------------- //   
#ifndef __USTRING_HPP
#define __USTRING_HPP

#include <iostream.h>
#include <iomanip.h>
#include <string.h>

// (S)tring (D)ata class
class StrData 
{
private:
  friend class UString;
  StrData() { RefCount = 1; }

private:
  void *operator new(size_t StrSize, unsigned Bytes = 0);
  void operator delete(void *ptr);
  
private:
  unsigned int RefCount;   // Reference count for string text
  char Data[1];            // Start of the string text
  static StrData Null_Ptr; // For null strings
};

// (U)ser-defined (S)tring class
class UString
{
public:
  enum { DefSize = 16, DefInc = 16, NoMatch = 0xffff };
  UString(unsigned Bytes = DefSize, int GB = DefInc) { Alloc(Bytes, GB); }
  UString(const char *s, int GB = DefInc);
  UString(const char *s, unsigned Bytes, int GB = DefInc);
  
  // Constructor used to create substrings
  UString(const UString &s,
	 unsigned Offset, unsigned Bytes, int GB = DefInc);

  ~UString();
  UString(const UString &s);
  UString &operator=(const UString &s);
  UString &operator=(const char *s) { Copy(s); return *this; }
  
public:
  // Append specified number of bytes from s onto end of this string
  void Cat(const char *s, unsigned Bytes) { InsReplAt(Len, s, Bytes); }
  void Cat(const char *s) { InsReplAt(Len, s, strlen(s)); }
  void Copy(const char *s);    // Copy data from s into this object  
  void Copy(const UString &s); // Copy data from s into this object

  // Return index of matching pattern or 0xffff if not found 
  unsigned Find(char *s, unsigned Offset = 0); 
  unsigned Find(char *s, unsigned Bytes, unsigned Offset = 0) const;
  unsigned Find(const UString &s, unsigned Offset = 0) const {
    return Find(s.TextPtr, s.Len, Offset); }

  // Deletes specifed number of bytes from starting position
  unsigned DeleteAt(unsigned Pos, unsigned Bytes);

  // Replaces text at position Pos with bytes in s
  unsigned ReplaceAt(unsigned Pos, const char *s, unsigned Bytes) {
    return InsReplAt(Pos, s, Bytes, 0); }
  unsigned ReplaceAt(unsigned Pos, const char *s) {
    return InsReplAt(Pos, s, strlen(s), 0); }
  unsigned ReplaceAt(unsigned Pos, const UString &s) {
    return InsReplAt(Pos, s.TextPtr, s.Len, 0); }

  // Inserts text in s at position Pos
  unsigned InsertAt(unsigned Pos, const char *s, unsigned Bytes) {
    return InsReplAt(Pos, s, Bytes); }
  unsigned InsertAt(unsigned Pos, const char *s) {
    return InsReplAt(Pos, s, strlen(s)); }
  unsigned InsertAt(unsigned Pos, const UString &s) {
    return InsReplAt(Pos, s.TextPtr, s.Len); }
  
  // Fills the string with pattern p, up to length Ln, starting at Offset
  void Fill(const char *p, unsigned Bytes, unsigned Offset=0, unsigned Ln=0);
  void Fill(const char c, unsigned Offset=0, unsigned Ln=0) {
    Fill(&c, 1, Offset, Ln); }
  void Fill(const char *s, unsigned Offset=0, unsigned Ln=0) {
    Fill(s, strlen(s), Offset, Ln); }
  void Fill(const UString &s, unsigned Offset=0, unsigned Ln=0) {
    Fill(s.TextPtr, s.Len, Offset, Ln); }

  // Returns substring starting at Index, for number of bytes
  UString Mid(unsigned Index, unsigned Bytes) const; 

  UString Left(unsigned Ln) const;  // Returns left substring of length Ln
  UString Right(unsigned Ln) const; // Returns right substring of length Ln

  // Make the string null-terminated
  const char *UString::NullTermStr();

  unsigned GetLength() const { return Len; } // returns logical length
  unsigned length() const { return Len; } // returns logical length
  unsigned GetDimLen() const { return DimLen; } // returns allocated length
  char *GetTextPtr() { return TextPtr; } // returns pointer to start of text
  const char *GetTextPtr() const { return TextPtr; } 
  char *c_str(); // returns NULL terminated low level C string 
  const char *c_str() const;
  int Grow() { return Realloc(DimLen + GrowBy); } // Grow by default amount
  int Resize(unsigned Bytes) { return Realloc(Bytes); } // Resize the string
  int resize(unsigned Bytes) { return Realloc(Bytes); } // Resize the string
  int FreeExtra() { return Realloc(Len); } // Frees unused space in string
  void ChgGrowByInc(int GB) { GrowBy = GB; } // Change GrowBy increment

  // Sets the logical length of the string to <= maximum length
  void SetLength(unsigned Bytes);

  // Returns true if the string references Null_Ptr
  int IsNull() const { return DataPtr == &StrData::Null_Ptr; }
  int is_null() const { return DataPtr == &StrData::Null_Ptr; }
  
private: 
  // Copies data from s, resizing if Bytes > DimLen && GrowBy != 0
  void CopyN(const char *s, unsigned Bytes); 

  // Inserts/replaces data pointed by s, up to Bytes starting at Pos
  unsigned InsReplAt(unsigned Pos, const char *s, unsigned Bytes, int Ins=1);

  // Grows the string by the specified amount
  int Grow_By(unsigned Bytes) { return Realloc(DimLen + Bytes); }

  int EnsureUnique(); // Ensures that this string uniquely owns its data

  // Returns true if string references shared data or Null_Ptr
  int IsUnique() const { return DataPtr->RefCount == 1 || IsNull(); }

  // Check for string index being in bounds
  unsigned CheckIndex(unsigned i) {
    if(i >= Len) i = Len; // If not in bounds truncate to Len
    return i; }
  
private: // Memory allocation routines
  // If memory allocation for new string fails reference a null string of 0
  int Alloc(unsigned Bytes, int GB);

  // Redimenstions the string, returns 0 if memory not available
  int Realloc(unsigned NewDimLen, int Keep = 1);

  // Binds to the same data that s is bound to
  void Bind(const UString &s);
  
  void UnBind(); // Unbinds this object from the shared string data

  // Unbinds this string and then binds it to data shared by s
  void NewBinding(const UString &s);

private: 
  StrData *DataPtr;
  char *TextPtr;   // Pointer to start of string text
  unsigned DimLen; // Maximum length without reallocation
  unsigned Len;    // Logical length of text
  int GrowBy;      // Minimum resizing increment

public: // Class type to ostream type conversions
  friend ostream &operator<<(ostream &os, const UString &s);
  friend istream &operator>>(istream &os, UString &s);

public: // Overloaded operators
  char &operator[](unsigned i) {
    if(EnsureUnique()) // Ensure unique before allowing modifications
      return TextPtr[CheckIndex(i)];
    else return StrData::Null_Ptr.Data[0]; // Point byte to null string
  }

  void operator+=(const UString &s) { Cat(s.TextPtr, s.Len); }
  void operator+=(const char *s) { Cat(s, strlen(s)); }
  void operator+=(const char c) { Cat(&c, 1); }
  friend UString operator+(const UString &a, const UString &b)
  {
    UString buf(a.Len + b.Len);
    buf += a;
    buf += b;
    return buf;
  }

  friend int operator==(const UString &a, const UString &b)
  {
    return StringCompare(a, b) == 0;
  }

  friend int operator!=(const UString &a, const UString &b)
  {
    return StringCompare(a, b) != 0;
  }

  friend int operator>(const UString &a, const UString &b)
  {
    return StringCompare(a, b) > 0;
  }

  friend int operator>=(const UString &a, const UString &b)
  {
    return StringCompare(a, b) >= 0;
  }
  
  friend int operator<(const UString &a, const UString &b)
  {
    return StringCompare(a, b) < 0;
  }
  
  friend int operator<=(const UString &a, const UString &b)
  {
    return StringCompare(a, b) <= 0;
  }

public: // Friend functions
  // Returns -1 if a < b, 0 if a == b, and 1 if a > b
  friend int StringCompare(const UString &a, const UString &b);  
};

// General-purpose string routines that need to be ported from UNIX to DOS
int CaseICmp(const UString &s1, const UString &s2);
int CaseICmp(UString &s1, UString &s2);

#endif  // __USTRING_HPP //
// ----------------------------------------------------------- // 
// ------------------------------- //
// --------- End of File --------- //
// ------------------------------- //

