home *** CD-ROM | disk | FTP | other *** search
- // ------------------------------- //
- // -------- Start of File -------- //
- // ------------------------------- //
- // ----------------------------------------------------------- //
- // C++ Source Code File Name: ustring.cpp
- // 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: 03/31/1999
- // Copyright (c) 1997 Douglas M. Gaer
- // ----------------------------------------------------------- //
- // ------------- Program 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.
- */
- // ----------------------------------------------------------- //
- #include <ctype.h>
- #include "ustring.h"
-
- StrData StrData::Null_Ptr;
-
- void *StrData::operator new(size_t StrSize, unsigned Bytes)
- // Overloaded new operator used to allocate memory for the size
- // of a StrData object plus number of bytes that represent the
- // length of the string's data. The memory for the string is
- // allocated as an array of characters. It is the responsibility
- // of the UString class to keep track of the string's length.
- // The UString class must store the string data immediately following
- // the reference count. A null pointer object will be statically
- // allocated when a new StrData object is constructed. Null strings
- // will always point to the null pointer object.
- {
- // StrSize already accounts for one character
- void *ptr = new char[StrSize + Bytes - 1];
- if(!ptr) { // If allocation fails reference Null_Ptr
- ptr = &Null_Ptr;
- ((StrData *)ptr)->RefCount++;
- }
- return ptr;
- }
-
- void StrData::operator delete(void *ptr)
- // The delete operator is overloaded so that
- // both the string data the reference count
- // are deleted.
- {
- delete[] (char *)ptr;
- }
-
- int UString::Alloc(unsigned Bytes, int GB)
- {
- DataPtr = new(Bytes) StrData;
- TextPtr = DataPtr->Data;
- Len = 0;
- if (IsNull()) { // Could not allocate memory for string
- DimLen = 1;
- GrowBy = 0;
- return 0;
- }
- else {
- DimLen = Bytes;
- GrowBy = GB;
- return 1;
- }
- }
-
- void UString::Bind(const UString &s)
- {
- // Bind DataPtr to the same that s is bound to
- DataPtr = s.DataPtr;
- DataPtr->RefCount++;
- }
-
- void UString::UnBind()
- {
- DataPtr->RefCount--;
-
- // Make sure RefCount is a non-zero value
- if(DataPtr == &StrData::Null_Ptr && DataPtr->RefCount == 0)
- DataPtr->RefCount = 1;
-
- if(DataPtr->RefCount == 0) delete DataPtr;
- }
-
- void UString::NewBinding(const UString &s)
- {
- // Unbind string from DataPtr that holds it, and
- // bind it to the DataPtr shared by s
- if(DataPtr != s.DataPtr) {
- UnBind();
- Bind(s);
- }
- }
-
- UString::UString(const char *s, unsigned Bytes, int GB)
- {
- if(Alloc(Bytes, GB)) CopyN(s, Bytes);
- }
-
- UString::UString(const char *s, int GB)
- {
- unsigned StringLen = strlen(s);
- unsigned DimensionLen = StringLen;
- if(GB) { // Compute next highest multiple of GB
- unsigned AddValue = (DimensionLen % GB) ? GB : 0;
- DimensionLen = (DimensionLen / GB) * GB + AddValue;
- }
- if(Alloc(DimensionLen, GB)) CopyN(s, StringLen);
- }
-
- UString::UString(const UString &s, unsigned Offset, unsigned Bytes, int GB)
- // A constructor used to create a subset of this string.
- {
- Bind(s);
-
- // Keep offset and length in range
- if(Offset > s.Len-1) Offset = s.Len - 1;
- if(Bytes + Offset > s.Len) Bytes = s.Len - Offset;
-
- // Set max and logical bounds of the substring
- DimLen = Bytes;
- Len = Bytes;
- GrowBy = GB;
- TextPtr = s.TextPtr + Offset; // Compute starting text element
- }
-
- UString::UString(const UString &s)
- {
- Bind(s);
- Len = s.Len;
- DimLen = s.DimLen;
- GrowBy = s.GrowBy;
- TextPtr = s.TextPtr;
- }
-
- UString::~UString()
- {
- UnBind();
- }
-
- UString &UString::operator=(const UString &s)
- {
- if(this != &s) {
- NewBinding(s);
- Len = s.Len;
- DimLen = s.DimLen;
- GrowBy = s.GrowBy;
- TextPtr = s.TextPtr;
- }
- return *this;
- }
-
- unsigned UString::InsReplAt(unsigned Pos,
- const char *s, unsigned Bytes, int Ins)
- {
- unsigned Room, Needed, AddVal;
-
- if(Ins) {
- Room = DimLen - Len;
- if(Bytes > Room && GrowBy != 0) {
- Needed = (Bytes - Room);
- AddVal = (Needed % GrowBy) ? GrowBy : 0;
- Needed = (Needed / GrowBy) * GrowBy + AddVal;
- Grow_By(Needed);
- }
- }
-
- if (!EnsureUnique()) return 0; // Can't update
- if (Pos >= Len) Pos = Len; // Don't allow gaps
-
- if(Ins) { // Keep things in range. May have to truncate
- if(Bytes > DimLen - Len) Bytes = DimLen - Len;
- if(Pos < Len) {
- // Make room in the middle for inserted data
- memmove(TextPtr+Pos+Bytes, TextPtr+Pos, Len-Pos);
- }
- }
- else {
- if(Bytes > DimLen - Pos) Bytes = DimLen -Pos;
- }
-
- // Copy in source, compute final length
- memmove(TextPtr+Pos, s, Bytes);
- if(Ins) {
- Len += Bytes;
- }
- else {
- if((Pos+Bytes) > Len) Len = Pos+Bytes;
- }
- return Bytes;
- }
-
- int UString::Realloc(unsigned NewDimLen, int Keep)
- {
- if(GrowBy == 0) return 0;
-
- StrData *NewStrData = new(NewDimLen) StrData;
- if(NewStrData == &StrData::Null_Ptr) return 0;
-
- if(Keep) { // Copy old data into new space.
- if(NewDimLen < Len) Len = NewDimLen;
- memmove(NewStrData->Data, TextPtr, Len);
- }
- else { // Do not keep old data
- Len = 0;
- }
-
- UnBind(); // Unbind from old data
- DataPtr = NewStrData; // Bind to new Data
- TextPtr = DataPtr->Data; // Point to starting text
- DimLen = NewDimLen; // Record new allocated length
- return 1;
- }
-
- int UString::EnsureUnique()
- {
- if(!IsUnique()) {
- // Create a unique clone of this string
- UString buf(DimLen, GrowBy);
- buf.CopyN(TextPtr, Len);
- if(buf.IsNull()) return 0; // Could not copy
- NewBinding(buf); // Bind to copy
- TextPtr = buf.TextPtr; // Initialize starting text element
- }
- return 1;
- }
-
- void UString::SetLength(unsigned Bytes)
- {
- if(Bytes > DimLen) Bytes = DimLen;
- Len = Bytes;
- }
-
- void UString::CopyN(const char *s, unsigned Bytes)
- {
- Len = 0; InsReplAt(0, s, Bytes);
- }
-
- void UString::Copy(const char *s)
- {
- CopyN(s, strlen(s));
- }
-
- void UString::Copy(const UString &s)
- {
- CopyN(s.TextPtr, s.Len);
- }
-
- unsigned UString::Find(char *s, unsigned Offset)
- // Returns index of first occurrence of pattern char *s
- // Returns 0xffff if pattern not found
- {
- char *Start = TextPtr + Offset; // Start of string data
- char *Next = Start; // Next string element
- char *Pattern = s; // Next pattern element
- unsigned i = Offset; // Next string element index
-
- while(i < Len && *Pattern) {
- if (*Next == *Pattern) {
- Pattern++;
- if(*Pattern == 0) return i; // Pattern was found
- Next++;
- }
- else {
- i++;
- Start++;
- Next = Start;
- Pattern = s;
- }
- }
- return NoMatch; // No match was found
- }
-
- unsigned UString::IFind(char *s, unsigned Offset)
- // Returns index of first occurrence of pattern char *s
- // starting at specified offset using a case insensitive
- // compare. Returns 0xffff if pattern not found.
- {
- char *Start = TextPtr + Offset; // Start of string data
- char *Next = Start; // Next string element
- char *Pattern = s; // Next pattern element
- unsigned i = Offset; // Next string element index
-
- while(i < Len && *Pattern) {
- if (tolower(*Next) == tolower(*Pattern)) {
- Pattern++;
- if(*Pattern == 0) return i; // Pattern was found
- Next++;
- }
- else {
- i++;
- Start++;
- Next = Start;
- Pattern = s;
- }
- }
- return NoMatch; // No match was found
- }
-
- unsigned UString::Find(char *s, unsigned Bytes, unsigned Offset) const
- // Returns index of first occurrence of pattern char *s
- // Returns 0xffff if pattern not found
- {
- char *Start = TextPtr + Offset; // Start of string data
- char *Next = Start; // Next string element
- char *Pattern = s; // Next pattern element
- unsigned i = Offset, j = 1; // String and pattern indexes
-
- while(i < Len && j <= Bytes) {
- if (*Next == *Pattern) { // Matching character
- if(j == Bytes) return i; // Entire match was found
- Next++; Pattern++; j++;
- }
- else { // Try next spot in string
- i++;
- Start++;
- Next = Start;
- Pattern = s; j = 1;
- }
- }
- return NoMatch; // No match was found
- }
-
- unsigned UString::IFind(char *s, unsigned Bytes, unsigned Offset) const
- // Returns index of first occurrence of pattern char *s starting at
- // specified offset using a case insensitive compare. Returns 0xffff
- // if pattern is not found.
- {
- char *Start = TextPtr + Offset; // Start of string data
- char *Next = Start; // Next string element
- char *Pattern = s; // Next pattern element
- unsigned i = Offset, j = 1; // String and pattern indexes
-
- while(i < Len && j <= Bytes) {
- if (tolower(*Next) == tolower(*Pattern)) {
- if(j == Bytes) return i; // Entire match was found
- Next++; Pattern++; j++;
- }
- else { // Try next spot in string
- i++;
- Start++;
- Next = Start;
- Pattern = s; j = 1;
- }
- }
- return NoMatch; // No match was found
- }
-
- unsigned UString::DeleteAt(unsigned Pos, unsigned Bytes)
- {
- unsigned long buf; // long is used to prevent overflows
- unsigned End;
-
- if(Pos < Len && Bytes !=0) {
- if(!EnsureUnique()) return 0; // Can't update
- buf = Pos + Bytes;
- if(buf > Len) buf = Len;
- End = unsigned(buf);
- Bytes = End - Pos;
- // Move the elements up to take their place
- memmove(TextPtr+Pos, TextPtr+End, Len-End);
- Len -= Bytes;
- }
- else
- Bytes = 0;
-
- return Bytes;
- }
-
- void UString::Fill(const char *p, unsigned Bytes, unsigned Offset, unsigned Ln)
- {
- if (DimLen == 0 || Bytes == 0) return; // Nothing to do
- if (!EnsureUnique()) return; // Can't fill
- // Keep parms in range
- if (Ln == 0) Ln = DimLen;
- if (Offset >= DimLen) Offset = DimLen-1; // DimLen must be > 0!
- if (Ln + Offset > DimLen) Ln = DimLen - Offset;
- Len = Ln + Offset;
- char *t = TextPtr + Offset;
- if (Bytes == 1) {
- // Use fast method for single character fills
- memset(t, *p, Ln);
- }
- else {
- // Multi-character pattern fills
- unsigned np = Bytes;
- const char *s = p;
- while(Ln) {
- *t++ = *s++;
- if (np == 1) {
- np = Bytes;
- s = p;
- } else np--;
- Ln--;
- }
- }
- }
-
- UString UString::Mid(unsigned Index, unsigned Bytes) const
- // Returns substring starting at Index, for number of bytes
- {
- // Call the substring constructor
- UString buf(*this, Index, Bytes);
-
- return buf;
- }
-
- UString UString::Left(unsigned Ln) const
- // Returns left substring of length Ln
- {
- // Call the substring constructor
- UString buf(*this, 0, Ln);
-
- return buf;
- }
-
- UString UString::Right(unsigned Ln) const
- // Returns right substring of length Ln
- {
- if(Ln > Len) Ln = Len;
-
- // Call the substring constructor
- UString buf(*this, Len - Ln, Ln);
-
- return buf;
- }
-
- const char *UString::NullTermStr()
- // If a null byte has to be added, the string is grown.
- // If the string can't grow, the last character is replaced.
- {
- static char Null_String[1] = {0};
- if(IsNull()) return Null_String;
- char *ptr = TextPtr;
- unsigned Bytes = Len;
-
- // Search for null byte already in string
- while(Bytes--) if(*ptr++ == 0) return TextPtr;
-
- // Grow if length == allocated length grow the string
- if(Len == DimLen) Grow();
-
- // Make sure string can grow and is unique
- if(DimLen == 0 || !EnsureUnique()) return Null_String;
- if(Len == DimLen) Len--; // Forced to replace good character
- TextPtr[Len] = 0;
- return TextPtr;
- }
-
- char *UString::c_str()
- // If a null byte has to be added, the string is grown.
- // If the string can't grow, the last character is replaced.
- {
- static char Null_String[1] = {0};
- if(IsNull()) return Null_String;
- char *ptr = TextPtr;
- unsigned Bytes = Len;
-
- // Search for null byte already in string
- while(Bytes--) if(*ptr++ == 0) return TextPtr;
-
- // Grow if length == allocated length grow the string
- if(Len == DimLen) Grow();
-
- // Make sure string can grow and is unique
- if(DimLen == 0 || !EnsureUnique()) return Null_String;
- if(Len == DimLen) Len--; // Forced to replace good character
- TextPtr[Len] = 0;
- return TextPtr;
- }
-
- const char *UString::c_str() const
- // If a null byte has to be added the last character is replaced.
- {
- static char Null_String[1] = {0};
- if(IsNull()) return Null_String;
- char *ptr = TextPtr;
- unsigned Bytes = Len;
-
- // Search for null byte already in string
- while(Bytes--) if(*ptr++ == 0) return TextPtr;
-
- TextPtr[Len] = 0;
- return TextPtr;
- }
-
- ostream &operator<<(ostream &os, const UString &s)
- {
- return os.write(s.TextPtr, s.Len);
- }
-
- istream &operator>>(istream &os, UString &s)
- {
- os >> setw(s.DimLen) >> s.TextPtr;
- s.SetLength(strlen(s.TextPtr));
- return os;
- }
-
- int StringCompare(const UString &a, const UString &b)
- // Returns -1 if a < b, 0 if a == b, and 1 if a > b
- {
- unsigned an = a.Len;
- unsigned bn = b.Len;
- unsigned sn = (an < bn) ? an : bn;
- unsigned char *ap = (unsigned char *)a.TextPtr;
- unsigned char *bp = (unsigned char *)b.TextPtr;
-
- for(unsigned i = 0; i < sn; i++) {
- if(*ap < *bp) return -1;
- if(*ap++ > *bp++) return 1;
- }
-
- if(an == bn) return 0;
- if(an < bn) return -1;
- return 1;
- }
-
- // General-purpose string routines that need to be ported from UNIX to DOS
- // -----------------------------------------------------------------------
-
- int CaseICmp(const UString &s1, const UString &s2)
- // Compare two UString objects without regard to the case of the letters
- {
- #if defined (__DOS__)
- // Case-insensitive compare for most DOS/Windows Compilers
- return stricmp(s1.c_str(), s2.c_str());
- #elif defined(__VISUALC__) || ( defined(__MWERKS__) && defined(__INTEL__) )
- return stricmp(s1.c_str(), s2.c_str());
- #elif defined(__SC__)
- return stricmp(s1.c_str(), s2.c_str());
- #elif defined(__SALFORDC__)
- return stricmp(s1.c_str(), s2.c_str());
- #elif defined(__BORLANDC__)
- return stricmp(s1.c_str(), s2.c_str());
- #elif defined(__WATCOMC__)
- return stricmp(s1.c_str(), s2.c_str());
- #elif defined (__UNIX__) || defined(__GNUWIN32__)
- // Case-insensitive compare for most UNIX Compilers
- return strcasecmp(s1.c_str(), s2.c_str());
- #else
- register char c1, c2;
- const char *str1 = s1.c_str(); const char *str2 = s2.c_str();
- do {
- c1 = tolower(*str1++);
- c2 = tolower(*str2++);
- } while ( c1 && (c1 == c2) );
-
- return c1 - c2;
- #endif
- }
-
- int CaseICmp(UString &s1, UString &s2)
- // Compare two UString objects without regard to the case of the letters
- {
- #if defined (__DOS__)
- // Case-insensitive compare for most DOS/Windows Compilers
- return stricmp(s1.c_str(), s2.c_str());
- #elif defined(__VISUALC__) || ( defined(__MWERKS__) && defined(__INTEL__) )
- return stricmp(s1.c_str(), s2.c_str());
- #elif defined(__SC__)
- return stricmp(s1.c_str(), s2.c_str());
- #elif defined(__SALFORDC__)
- return stricmp(s1.c_str(), s2.c_str());
- #elif defined(__BORLANDC__)
- return stricmp(s1.c_str(), s2.c_str());
- #elif defined(__WATCOMC__)
- return stricmp(s1.c_str(), s2.c_str());
- #elif defined (__UNIX__) || defined(__GNUWIN32__)
- // Case-insensitive compare for most UNIX Compilers
- return strcasecmp(s1.c_str(), s2.c_str());
- #else
- register char c1, c2;
- char *str1 = s1.c_str(); char *str2 = s2.c_str();
- do {
- c1 = tolower(*str1++);
- c2 = tolower(*str2++);
- } while ( c1 && (c1 == c2) );
-
- return c1 - c2;
- #endif
- }
- // ----------------------------------------------------------- //
- // ------------------------------- //
- // --------- End of File --------- //
- // ------------------------------- //
-