(file) Return to String.cpp CVS log (file) (dir) Up to [Pegasus] / pegasus / src / Pegasus / Common

Diff for /pegasus/src/Pegasus/Common/String.cpp between version 1.64 and 1.111.2.16

version 1.64, 2002/09/20 19:57:09 version 1.111.2.16, 2005/10/07 14:47:33
Line 1 
Line 1 
 //%/////////////////////////////////////////////////////////////////////////////  //%2005////////////////////////////////////////////////////////////////////////
 // //
 // Copyright (c) 2000, 2001, 2002 BMC Software, Hewlett-Packard Company, IBM,  // Copyright (c) 2000, 2001, 2002 BMC Software; Hewlett-Packard Development
 // The Open Group, Tivoli Systems  // Company, L.P.; IBM Corp.; The Open Group; Tivoli Systems.
   // Copyright (c) 2003 BMC Software; Hewlett-Packard Development Company, L.P.;
   // IBM Corp.; EMC Corporation, The Open Group.
   // Copyright (c) 2004 BMC Software; Hewlett-Packard Development Company, L.P.;
   // IBM Corp.; EMC Corporation; VERITAS Software Corporation; The Open Group.
   // Copyright (c) 2005 Hewlett-Packard Development Company, L.P.; IBM Corp.;
   // EMC Corporation; VERITAS Software Corporation; The Open Group.
 // //
 // Permission is hereby granted, free of charge, to any person obtaining a copy // Permission is hereby granted, free of charge, to any person obtaining a copy
 // of this software and associated documentation files (the "Software"), to // of this software and associated documentation files (the "Software"), to
Line 23 
Line 29 
 // //
 // Author: Mike Brasher (mbrasher@bmc.com) // Author: Mike Brasher (mbrasher@bmc.com)
 // //
 // Modified By: Roger Kumpf, Hewlett-Packard Company (roger_kumpf@hp.com)  // Modified By:
   //     Roger Kumpf, Hewlett-Packard Company (roger_kumpf@hp.com)
   //     Josephine Eskaline Joyce, IBM (jojustin@in.ibm.com) for Bug#3297
   //     David Dillard, VERITAS Software Corp. (david.dillard@veritas.com)
   //     Mike Brasher (mike-brasher@austin.rr.com)
 // //
 //%///////////////////////////////////////////////////////////////////////////// //%/////////////////////////////////////////////////////////////////////////////
  
   #ifndef PEGASUS_USE_INTERNAL_INLINES
   # define PEGASUS_USE_INTERNAL_INLINES
   #endif
  
 #include <cctype>  
 #include <cstring>  
 #include "String.h" #include "String.h"
 #include "Array.h"  #include <cassert>
 #include "InternalException.h" #include "InternalException.h"
 #include <iostream>  #include "CommonUTF.h"
 #include <fstream>  #include "MessageLoader.h"
 #ifndef PEGASUS_REMOVE_DEPRECATED  
 #include "System.h"  // for strcasecmp  
 #endif  
  
 PEGASUS_USING_STD;  #ifdef PEGASUS_HAS_ICU
   #include <unicode/ustring.h>
   #include <unicode/uchar.h>
   #endif
  
 PEGASUS_NAMESPACE_BEGIN PEGASUS_NAMESPACE_BEGIN
  
 ///////////////////////////////////////////////////////////////////////////////  //==============================================================================
   //
   // Compile-time macros (undefined by default).
   //
   //     PEGASUS_STRING_NO_THROW -- suppresses throwing of exceptions
 // //
 // CString  //     PEGASUS_STRING_NO_UTF8 -- don't generate slower UTF8 code.
 // //
 ///////////////////////////////////////////////////////////////////////////////  //     PEGASUS_USE_INTERNAL_INLINES -- enables internal inlining feature.
   //
   //     PEGASUS_USE_STRING_EXTENSIONS -- enabled new string functions.
   //
   //==============================================================================
  
 CString::CString()  //==============================================================================
     : _rep(0)  //
   // File-scope definitions:
   //
   //==============================================================================
   
   const Uint8 _to_upper_tbl[256] =
   {
       0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
       0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,
       0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,
       0x18,0x19,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F,
       0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,
       0x28,0x29,0x2A,0x2B,0x2C,0x2D,0x2E,0x2F,
       0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,
       0x38,0x39,0x3A,0x3B,0x3C,0x3D,0x3E,0x3F,
       0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,
       0x48,0x49,0x4A,0x4B,0x4C,0x4D,0x4E,0x4F,
       0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,
       0x58,0x59,0x5A,0x5B,0x5C,0x5D,0x5E,0x5F,
       0x60,0x41,0x42,0x43,0x44,0x45,0x46,0x47,
       0x48,0x49,0x4A,0x4B,0x4C,0x4D,0x4E,0x4F,
       0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,
       0x58,0x59,0x5A,0x7B,0x7C,0x7D,0x7E,0x7F,
       0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,
       0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,
       0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,
       0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F,
       0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,
       0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,
       0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,
       0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF,
       0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,
       0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,
       0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,
       0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF,
       0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,
       0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,
       0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,
       0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF,
   };
   
   const Uint8 _to_lower_tbl[256] =
   {
       0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
       0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,
       0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,
       0x18,0x19,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F,
       0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,
       0x28,0x29,0x2A,0x2B,0x2C,0x2D,0x2E,0x2F,
       0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,
       0x38,0x39,0x3A,0x3B,0x3C,0x3D,0x3E,0x3F,
       0x40,0x61,0x62,0x63,0x64,0x65,0x66,0x67,
       0x68,0x69,0x6A,0x6B,0x6C,0x6D,0x6E,0x6F,
       0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,
       0x78,0x79,0x7A,0x5B,0x5C,0x5D,0x5E,0x5F,
       0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,
       0x68,0x69,0x6A,0x6B,0x6C,0x6D,0x6E,0x6F,
       0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,
       0x78,0x79,0x7A,0x7B,0x7C,0x7D,0x7E,0x7F,
       0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,
       0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,
       0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,
       0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F,
       0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,
       0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,
       0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,
       0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF,
       0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,
       0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,
       0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,
       0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF,
       0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,
       0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,
       0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,
       0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF,
   };
   
   // Converts 16-bit characters to upper case.
   inline Uint16 _to_upper(Uint16 x)
 { {
       return (x & 0xFF00) ? x : _to_upper_tbl[x];
 } }
  
 CString::CString(const CString& cstr)  // Converts 16-bit characters to lower case.
   inline Uint16 _to_lower(Uint16 x)
 { {
     _rep = (void*)new char[strlen((char*)cstr._rep)+1];      return (x & 0xFF00) ? x : _to_lower_tbl[x];
     strcpy((char*)_rep, (char*)cstr._rep);  
 } }
  
 CString::CString(char* cstr)  // Rounds x to the next power of two (or just returns 8 if x < 8).
     : _rep(cstr)  static Uint32 _next_pow_2(Uint32 x)
 { {
       if (x < 8)
           return 8;
   
       x--;
       x |= (x >> 1);
       x |= (x >> 2);
       x |= (x >> 4);
       x |= (x >> 8);
       x |= (x >> 16);
       x++;
   
       return x;
 } }
  
 CString::~CString()  template<class P, class Q>
   static void _copy(P* p, const Q* q, size_t n)
 { {
     if (_rep)      // Use loop unrolling.
         delete [] (char*)_rep;  
       while (n >= 8)
       {
           p[0] = q[0];
           p[1] = q[1];
           p[2] = q[2];
           p[3] = q[3];
           p[4] = q[4];
           p[5] = q[5];
           p[6] = q[6];
           p[7] = q[7];
           p += 8;
           q += 8;
           n -= 8;
 } }
  
 CString& CString::operator=(const CString& cstr)      while (n >= 4)
 { {
     _rep = (char*)new char[strlen((char*)cstr._rep)+1];          p[0] = q[0];
     strcpy((char*)_rep, (char*)cstr._rep);          p[1] = q[1];
     return *this;          p[2] = q[2];
           p[3] = q[3];
           p += 4;
           q += 4;
           n -= 4;
 } }
  
 CString::operator const char*() const      while (n--)
           *p++ = *q++;
   }
   
   static Uint16* _find(const Uint16* s, size_t n, Uint16 c)
   {
       while (n >= 4)
 { {
     return (char*)_rep;          if (s[0] == c)
               return (Uint16*)s;
           if (s[1] == c)
               return (Uint16*)&s[1];
           if (s[2] == c)
               return (Uint16*)&s[2];
           if (s[3] == c)
               return (Uint16*)&s[3];
   
           n -= 4;
           s += 4;
 } }
  
 ///////////////////////////////////////////////////////////////////////////////      if (n)
 //      {
 // String          if (*s == c)
               return (Uint16*)s;
           s++;
           n--;
       }
   
       if (n)
       {
           if (*s == c)
               return (Uint16*)s;
           s++;
           n--;
       }
   
       if (n && *s == c)
           return (Uint16*)s;
   
       // Not found!
       return 0;
   }
   
   static int _compare(const Uint16* s1, const Uint16* s2)
   {
       while (*s1 && *s2)
       {
           int r = *s1++ - *s2++;
   
           if (r)
               return r;
       }
   
       if (*s2)
           return -1;
       else if (*s1)
           return 1;
   
       return 0;
   }
   
   static int _compare_no_utf8(const Uint16* s1, const char* s2)
   {
       Uint16 c1;
       Uint16 c2;
   
       do
       {
           c1 = *s1++;
           c2 = *s2++;
   
           if (c1 == 0)
               return c1 - c2;
       }
       while (c1 == c2);
   
       return c1 - c2;
   }
   
   static int _compare(const Uint16* s1, const Uint16* s2, size_t n)
   {
       // This should only be called when s1 and s2 have the same length.
   
       while (n-- && (*s1++ - *s2++) == 0)
           ;
   
 // //
 ///////////////////////////////////////////////////////////////////////////////  
  
 const String String::EMPTY = String();      return s1[-1] - s2[-1];
   }
   
   static inline void _copy(Uint16* s1, const Uint16* s2, size_t n)
   {
       memcpy(s1, s2, n * sizeof(Uint16));
   }
   
   void String_throw_out_of_bounds()
   {
       throw IndexOutOfBoundsException();
   }
  
 Uint32 _strnlen(const char* str, Uint32 n)  #ifdef PEGASUS_STRING_NO_THROW
   # define _check_null_pointer(ARG) /* empty */
   #else
   template<class T>
   inline void _check_null_pointer(const T* ptr)
 { {
     if (!str)      if (!ptr)
         throw NullPointer();         throw NullPointer();
   }
   #endif
  
     for (Uint32 i=0; i<n; i++)  static size_t _copy_from_utf8(Uint16* dest, const char* src, size_t n)
     {     {
         if (!*str)      Uint16* p = dest;
       const Uint8* q = (const Uint8*)src;
   
       // Process leading 7-bit ASCII characters (to avoid UTF8 overhead later).
       // Use loop-unrolling.
   
       while (n >=8 && ((q[0]|q[1]|q[2]|q[3]|q[4]|q[5]|q[6]|q[7]) & 0x80) == 0)
         {         {
             return i;          p[0] = q[0];
           p[1] = q[1];
           p[2] = q[2];
           p[3] = q[3];
           p[4] = q[4];
           p[5] = q[5];
           p[6] = q[6];
           p[7] = q[7];
           p += 8;
           q += 8;
           n -= 8;
         }         }
   
       while (n >=4 && ((q[0]|q[1]|q[2]|q[3]) & 0x80) == 0)
       {
           p[0] = q[0];
           p[1] = q[1];
           p[2] = q[2];
           p[3] = q[3];
           p += 4;
           q += 4;
           n -= 4;
     }     }
  
     return n;      switch (n)
       {
           case 0:
               return p - dest;
           case 1:
               if (q[0] < 128)
               {
                   p[0] = q[0];
                   return p + 1 - dest;
 } }
               break;
           case 2:
               if (((q[0]|q[1]) & 0x80) == 0)
               {
                   p[0] = q[0];
                   p[1] = q[1];
                   return p + 2 - dest;
               }
               break;
           case 3:
               if (((q[0]|q[1]|q[2]) & 0x80) == 0)
               {
                   p[0] = q[0];
                   p[1] = q[1];
                   p[2] = q[2];
                   return p + 3 - dest;
               }
               break;
       }
   
       // Process remaining characters.
  
 Uint32 _strnlen(const Char16* str, Uint32 n)      while (n)
 { {
     if (!str)          // Optimize for 7-bit ASCII case.
         throw NullPointer();  
  
     for (Uint32 i=0; i<n; i++)          if (*q < 128)
           {
               *p++ = *q++;
               n--;
           }
           else
     {     {
         if (!*str)              Uint8 c = UTF_8_COUNT_TRAIL_BYTES(*q) + 1;
   
               if (c > n || !isValid_U8(q, c) ||
                   UTF8toUTF16(&q, q + c, &p, p + n) != 0)
         {         {
             return i;                  MessageLoaderParms parms("Common.String.BAD_UTF8",
                       "The byte sequence starting at index $0 "
                       "is not valid UTF-8 encoding.",
                        q - (const Uint8*)src);
                   throw Exception(parms);
               }
   
               n -= c;
         }         }
     }     }
  
     return n;      return p - dest;
 } }
  
 inline Uint32 _StrLen(const char* str)  // Note: dest must be at least three times src (plus an extra byte for
   // terminator).
   static inline size_t _copy_to_utf8(char* dest, const Uint16* src, size_t n)
 { {
     if (!str)      const Uint16* q = src;
         throw NullPointer();      Uint8* p = (Uint8*)dest;
  
     return strlen(str);      while (n >= 4 && q[0] < 128 && q[1] < 128 && q[2] < 128 && q[3] < 128)
       {
           p[0] = q[0];
           p[1] = q[1];
           p[2] = q[2];
           p[3] = q[3];
           p += 4;
           q += 4;
           n -= 4;
 } }
  
 inline Uint32 _StrLen(const Char16* str)      switch (n)
 { {
     if (!str)          case 0:
         throw NullPointer();              return p - (Uint8*)dest;
           case 1:
               if (q[0] < 128)
               {
                   p[0] = q[0];
                   return p + 1 - (Uint8*)dest;
               }
               break;
           case 2:
               if (q[0] < 128 && q[1] < 128)
               {
                   p[0] = q[0];
                   p[1] = q[1];
                   return p + 2 - (Uint8*)dest;
               }
               break;
           case 3:
               if (q[0] < 128 && q[1] < 128 && q[2] < 128)
               {
                   p[0] = q[0];
                   p[1] = q[1];
                   p[2] = q[2];
                   return p + 3 - (Uint8*)dest;
               }
               break;
       }
   
       // If this line was reached, there must be characters greater than 128.
  
     Uint32 n = 0;      UTF16toUTF8(&q, q + n, &p, p + 3 * n);
  
     while (*str++)      return p - (Uint8*)dest;
         n++;  }
  
   static inline size_t _convert(Uint16* p, const char* q, size_t n)
   {
   #ifdef PEGASUS_STRING_NO_UTF8
       _copy(p, q, n);
     return n;     return n;
   #else
       return _copy_from_utf8(p, q, n);
   #endif
 } }
  
 class StringRep  //==============================================================================
   //
   // class CString
   //
   //==============================================================================
   
   CString::CString(const CString& cstr) : _rep(0)
   {
       if (cstr._rep)
 { {
 public:          size_t n = strlen(cstr._rep) + 1;
     StringRep()          _rep = (char*)operator new(n);
     {}          memcpy(_rep, cstr._rep, n);
     StringRep(const StringRep& r)      }
         : c16a(r.c16a)  }
     {}  
     StringRep(const Char16* str)  
         : c16a(str, _StrLen(str) + 1)  
     {}  
  
     Array<Char16> c16a;  CString& CString::operator=(const CString& cstr)
 };  {
       if (&cstr != this)
       {
           if (_rep)
           {
               operator delete(_rep);
               _rep = 0;
           }
  
 String::String()          if (cstr._rep)
 { {
     _rep = new StringRep;              size_t n = strlen(cstr._rep) + 1;
     _rep->c16a.append('\0');              _rep = (char*)operator new(n);
               memcpy(_rep, cstr._rep, n);
           }
       }
   
       return *this;
 } }
  
 String::String(const String& str)  //==============================================================================
   //
   // class StringRep
   //
   //==============================================================================
   
   StringRep StringRep::_empty_rep;
   
   inline StringRep* StringRep::alloc(size_t cap)
 { {
     _rep = new StringRep(*str._rep);      StringRep* rep = (StringRep*)::operator new(
           sizeof(StringRep) + cap * sizeof(Uint16));
       rep->cap = cap;
       Atomic_create(&rep->refs, 1);
   
       return rep;
   }
   
   static inline void _reserve(StringRep*& rep, Uint32 cap)
   {
       if (cap > rep->cap || Atomic_get(&rep->refs) != 1)
       {
           size_t n = _next_pow_2(cap);
           StringRep* new_rep = StringRep::alloc(n);
           new_rep->size = rep->size;
           _copy(new_rep->data, rep->data, rep->size + 1);
           StringRep::unref(rep);
           rep = new_rep;
       }
 } }
  
   StringRep* StringRep::create(const Uint16* data, size_t size)
   {
       StringRep* rep = StringRep::alloc(size);
       rep->size = size;
       _copy(rep->data, data, size);
       rep->data[size] = '\0';
       return rep;
   }
   
   StringRep* StringRep::copy_on_write(StringRep* rep)
   {
       // Return a new copy of rep. Release rep.
   
       StringRep* new_rep = StringRep::alloc(rep->size);
       new_rep->size = rep->size;
       _copy(new_rep->data, rep->data, rep->size);
       new_rep->data[new_rep->size] = '\0';
       StringRep::unref(rep);
       return new_rep;
   }
   
   StringRep* StringRep::create(const char* data, size_t size)
   {
       StringRep* rep = StringRep::alloc(size);
       rep->size = _convert((Uint16*)rep->data, data, size);
       rep->data[rep->size] = '\0';
   
       return rep;
   }
   
   StringRep* StringRep::createASCII7(const char* data, size_t size)
   {
       StringRep* rep = StringRep::alloc(size);
       _copy((Uint16*)rep->data, data, size);
       rep->data[rep->size = size] = '\0';
       return rep;
   }
   
   Uint32 StringRep::length(const Uint16* str)
   {
       // Note: We could unroll this but it is rarely called.
   
       const Uint16* end = (Uint16*)str;
   
       while (*end++)
           ;
   
       return end - str - 1;
   }
   
   //==============================================================================
   //
   // class String
   //
   //==============================================================================
   
   const String String::EMPTY;
   
 String::String(const String& str, Uint32 n) String::String(const String& str, Uint32 n)
 { {
     _rep = new StringRep;      _check_bounds(n, str._rep->size);
     assign(str.getChar16Data(), n);      _rep = StringRep::create(str._rep->data, n);
 } }
  
 String::String(const Char16* str) String::String(const Char16* str)
 { {
     _rep = new StringRep(str);      _check_null_pointer(str);
       _rep = StringRep::create((Uint16*)str, StringRep::length((Uint16*)str));
 } }
  
 String::String(const Char16* str, Uint32 n) String::String(const Char16* str, Uint32 n)
 { {
     _rep = new StringRep;      _check_null_pointer(str);
     assign(str, n);      _rep = StringRep::create((Uint16*)str, n);
 } }
  
 String::String(const char* str) String::String(const char* str)
 { {
     _rep = new StringRep;      _check_null_pointer(str);
     assign(str);      _rep = StringRep::create(str, strlen(str));
   }
   
   #ifdef PEGASUS_USE_STRING_EXTENSIONS
   String::String(const char* str, String::ASCII7Tag tag)
   {
       _check_null_pointer(str);
       _rep = StringRep::createASCII7(str, strlen(str));
 } }
   #endif /* PEGASUS_USE_STRING_EXTENSIONS */
  
 String::String(const char* str, Uint32 n) String::String(const char* str, Uint32 n)
 { {
     _rep = new StringRep;      _check_null_pointer(str);
     assign(str, n);      _rep = StringRep::create(str, n);
 } }
  
 String::~String()  #ifdef PEGASUS_USE_STRING_EXTENSIONS
   String::String(const char* str, size_t n, String::ASCII7Tag tag)
 { {
     delete _rep;      _check_null_pointer(str);
       _rep = StringRep::createASCII7(str, n);
 } }
   #endif /* PEGASUS_USE_STRING_EXTENSIONS */
  
 String& String::operator=(const String& str)  #ifdef PEGASUS_USE_STRING_EXTENSIONS
   String::String(const String& s1, const String& s2)
 { {
     return assign(str);      size_t n1 = s1._rep->size;
       size_t n2 = s2._rep->size;
       size_t n = n1 + n2;
       _rep = StringRep::alloc(n);
       _copy(_rep->data, s1._rep->data, n1);
       _copy(_rep->data + n1, s2._rep->data, n2);
       _rep->size = n;
       _rep->data[n] = '\0';
 } }
   #endif /* PEGASUS_USE_STRING_EXTENSIONS */
  
 String& String::assign(const String& str)  #ifdef PEGASUS_USE_STRING_EXTENSIONS
   String::String(const String& s1, const char* s2)
 { {
     _rep->c16a = str._rep->c16a;      _check_null_pointer(s2);
     return *this;      size_t n1 = s1._rep->size;
       size_t n2 = strlen(s2);
       _rep = StringRep::alloc(n1 + n2);
       _copy(_rep->data, s1._rep->data, n1);
       _rep->size = n1 + _convert((Uint16*)_rep->data + n1, s2, n2);
       _rep->data[_rep->size] = '\0';
 } }
   #endif /* PEGASUS_USE_STRING_EXTENSIONS */
  
 String& String::assign(const Char16* str)  #ifdef PEGASUS_USE_STRING_EXTENSIONS
   String::String(const char* s1, const String& s2)
 { {
     _rep->c16a.clear();      _check_null_pointer(s1);
     _rep->c16a.append(str, _StrLen(str) + 1);      size_t n1 = strlen(s1);
     return *this;      size_t n2 = s2._rep->size;
       _rep = StringRep::alloc(n1 + n2);
       _rep->size = n2 + _convert((Uint16*)_rep->data, s1, n1);
       _copy(_rep->data + n1, s2._rep->data, n2);
       _rep->data[_rep->size] = '\0';
 } }
   #endif /* PEGASUS_USE_STRING_EXTENSIONS */
  
 String& String::assign(const Char16* str, Uint32 n)  String& String::assign(const String& str)
 { {
     _rep->c16a.clear();      if (_rep != str._rep)
     Uint32 m = _strnlen(str, n);      {
     _rep->c16a.append(str, m);          StringRep::unref(_rep);
     _rep->c16a.append('\0');          StringRep::ref(_rep = str._rep);
       }
   
     return *this;     return *this;
 } }
  
 String& String::assign(const char* str)  String& String::assign(const Char16* str, Uint32 n)
 { {
     _rep->c16a.clear();      _check_null_pointer(str);
  
     Uint32 n = strlen(str) + 1;      if (n > _rep->cap || Atomic_get(&_rep->refs) != 1)
     _rep->c16a.reserveCapacity(n);      {
           StringRep::unref(_rep);
           _rep = StringRep::alloc(n);
       }
  
     while (n--)      _rep->size = n;
         _rep->c16a.append(*str++);      _copy(_rep->data, (Uint16*)str, n);
       _rep->data[n] = '\0';
  
     return *this;     return *this;
 } }
  
 String& String::assign(const char* str, Uint32 n) String& String::assign(const char* str, Uint32 n)
 { {
     _rep->c16a.clear();      _check_null_pointer(str);
   
     Uint32 _n = _strnlen(str, n);  
     _rep->c16a.reserveCapacity(_n + 1);  
  
     while (_n--)      if (n > _rep->cap || Atomic_get(&_rep->refs) != 1)
         _rep->c16a.append(*str++);      {
           StringRep::unref(_rep);
           _rep = StringRep::alloc(n);
       }
  
     _rep->c16a.append('\0');      _rep->size = _convert(_rep->data, str, n);
       _rep->data[_rep->size] = 0;
  
     return *this;     return *this;
 } }
  
 void String::clear()  #ifdef PEGASUS_USE_STRING_EXTENSIONS
   String& String::assignASCII7(const char* str, Uint32 n)
 { {
     _rep->c16a.clear();      _check_null_pointer(str);
     _rep->c16a.append('\0');  
 }  
  
 void String::reserveCapacity(Uint32 capacity)      if (n > _rep->cap || Atomic_get(&_rep->refs) != 1)
 { {
     _rep->c16a.reserveCapacity(capacity + 1);          StringRep::unref(_rep);
           _rep = StringRep::alloc(n);
       }
   
       _copy(_rep->data, str, n);
       _rep->data[_rep->size = n] = 0;
   
       return *this;
 } }
   #endif /* PEGASUS_USE_STRING_EXTENSIONS */
  
 Uint32 String::size() const  void String::clear()
   {
       if (_rep->size)
       {
           if (Atomic_get(&_rep->refs) == 1)
               _rep->size = 0;
           else
 { {
     return _rep->c16a.size() - 1;              StringRep::unref(_rep);
               _rep = &StringRep::_empty_rep;
           }
       }
 } }
  
 const Char16* String::getChar16Data() const  void String::reserveCapacity(Uint32 cap)
 { {
     return _rep->c16a.getData();      _reserve(_rep, cap);
 } }
  
 CString String::getCString() const CString String::getCString() const
 { {
     Uint32 n = size() + 1;  #ifdef PEGASUS_STRING_NO_UTF8
     char* str = new char[n];      char* str = (char*)operator new(_rep->size + 1);
     char* p = str;      _copy(str, _rep->data, _rep->size);
     const Char16* q = getChar16Data();      str[_rep->size] = '\0';
       return CString(str);
   #else
       Uint32 n = 3 * _rep->size;
       char* str = (char*)operator new(n + 1);
       size_t size = _copy_to_utf8(str, _rep->data, _rep->size);
       str[size] = '\0';
       return CString(str);
   #endif
   }
  
     for (Uint32 i = 0; i < n; i++)  String& String::append(const Char16* str, Uint32 n)
     {     {
         Uint16 c = *q++;      _check_null_pointer(str);
         *p++ = char(c);  
  
         //if (c & 0xff00)      size_t old_size = _rep->size;
         //    truncatedCharacters = true;      size_t new_size = old_size + n;
     }      _reserve(_rep, new_size);
       _copy(_rep->data + old_size, (Uint16*)str, n);
       _rep->size = new_size;
       _rep->data[new_size] = '\0';
  
     return CString(str);      return *this;
 } }
  
 Char16& String::operator[](Uint32 index)  String& String::append(const String& str)
 { {
     if (index > size())      return append((Char16*)str._rep->data, str._rep->size);
         throw IndexOutOfBoundsException();  
   
     return _rep->c16a[index];  
 } }
  
 const Char16 String::operator[](Uint32 index) const  #ifdef PEGASUS_USE_STRING_EXTENSIONS
   String& String::append(const char* str, Uint32 size)
 { {
     if (index > size())      _check_null_pointer(str);
         throw IndexOutOfBoundsException();  
  
     return _rep->c16a[index];      size_t old_size = _rep->size;
 }      size_t cap = old_size + size;
  
 String& String::append(const Char16& c)      _reserve(_rep, cap);
 {      _rep->size += _convert((Uint16*)_rep->data + old_size, str, size);
     _rep->c16a.insert(_rep->c16a.size() - 1, c);      _rep->data[_rep->size] = '\0';
     return *this;  
 }  
  
 String& String::append(const Char16* str, Uint32 n)  
 {  
     Uint32 m = _strnlen(str, n);  
     _rep->c16a.reserveCapacity(_rep->c16a.size() + m);  
     _rep->c16a.remove(_rep->c16a.size() - 1);  
     _rep->c16a.append(str, m);  
     _rep->c16a.append('\0');  
     return *this;     return *this;
 } }
   #endif /* PEGASUS_USE_STRING_EXTENSIONS */
  
 String& String::append(const String& str)  void String::remove(Uint32 index, Uint32 n)
 { {
     return append(str.getChar16Data(), str.size());      if (n == PEG_NOT_FOUND)
 }          n = _rep->size - index;
  
 void String::remove(Uint32 index, Uint32 size)      _check_bounds(index + n, _rep->size);
 {  
     if (size == PEG_NOT_FOUND)  
         size = this->size() - index;  
  
     if (index + size > this->size())      if (Atomic_get(&_rep->refs) != 1)
         throw IndexOutOfBoundsException();          _rep = StringRep::copy_on_write(_rep);
   
       assert(index + n <= _rep->size);
  
     if (size)      size_t rem = _rep->size - (index + n);
         _rep->c16a.remove(index, size);      Uint16* data = _rep->data;
   
       if (rem)
           memmove(data + index, data + index + n, rem * sizeof(Uint16));
   
       _rep->size -= n;
       data[_rep->size] = '\0';
 } }
  
 String String::subString(Uint32 index, Uint32 length) const  String String::subString(Uint32 index, Uint32 n) const
 { {
     if (index < size())      // Note: this implementation is very permissive but used for
       // backwards compatibility.
   
       if (index < _rep->size)
     {     {
         if ((length == PEG_NOT_FOUND) || (length > size() - index))          if (n == PEG_NOT_FOUND || n > _rep->size - index)
             length = size() - index;              n = _rep->size - index;
  
         return String(getChar16Data() + index, length);          return String((Char16*)_rep->data + index, n);
     }     }
     else  
         return String();         return String();
 } }
  
 Uint32 String::find(Char16 c) const Uint32 String::find(Char16 c) const
 { {
     const Char16* first = getChar16Data();      Uint16* p = (Uint16*)_find(_rep->data, _rep->size, c);
  
     for (const Char16* p = first; *p; p++)      if (p)
     {          return p - _rep->data;
         if (*p == c)  
             return  p - first;  
     }  
  
     return PEG_NOT_FOUND;     return PEG_NOT_FOUND;
 } }
  
 Uint32 String::find(Uint32 index, Char16 c) const Uint32 String::find(Uint32 index, Char16 c) const
 { {
     const Char16* data = getChar16Data();      _check_bounds(index, _rep->size);
  
     for (Uint32 i = index, n = size(); i < n; i++)      if (index >= _rep->size)
     {          return PEG_NOT_FOUND;
         if (data[i] == c)  
             return i;      Uint16* p = (Uint16*)_find(_rep->data + index, _rep->size - index, c);
     }  
       if (p)
           return p - _rep->data;
  
     return PEG_NOT_FOUND;     return PEG_NOT_FOUND;
 } }
  
 Uint32 String::find(const String& s) const  Uint32 String::_find_aux(const Char16* s, Uint32 n) const
 { {
     const Char16* pSubStr = s.getChar16Data();      _check_null_pointer(s);
     const Char16* pStr = getChar16Data();  
     Uint32 subStrLen = s.size();      const Uint16* data = _rep->data;
     Uint32 strLen = size();      size_t rem = _rep->size;
  
     if (subStrLen > strLen)      while (n <= rem)
     {     {
         return PEG_NOT_FOUND;          Uint16* p = (Uint16*)_find(data, rem, s[0]);
     }  
  
     // loop to find first char match          if (!p)
     Uint32 loc = 0;              break;
     for( ; loc <= (strLen-subStrLen); loc++)  
     {          if (memcmp(p, s, n * sizeof(Uint16)) == 0)
         if (*pStr++ == *pSubStr)  // match first char              return p - _rep->data;
         {  
             // point to substr 2nd char          p++;
             const Char16* p = pSubStr + 1;          rem -= p - data;
           data = p;
             // Test remaining chars for equal  
             Uint32 i = 1;  
             for (; i < subStrLen; i++)  
                 if (*pStr++ != *p++ )  
                     {pStr--; break;} // break from loop  
             if (i == subStrLen)  
                 return loc;  
         }  
     }     }
   
     return PEG_NOT_FOUND;     return PEG_NOT_FOUND;
 } }
  
   #ifdef PEGASUS_USE_STRING_EXTENSIONS
   Uint32 String::find(const char* s) const
   {
       _check_null_pointer(s);
   
       // Note: could optimize away creation of temporary, but this is rarely
       // called.
       return find(String(s));
   }
   #endif /* PEGASUS_USE_STRING_EXTENSIONS */
   
 Uint32 String::reverseFind(Char16 c) const Uint32 String::reverseFind(Char16 c) const
 { {
     const Char16* first = getChar16Data();      Uint16 x = c;
     const Char16* last = getChar16Data() + size();      Uint16* p = _rep->data;
       Uint16* q = _rep->data + _rep->size;
  
     while (last != first)      while (q != p)
     {     {
         if (*--last == c)          if (*--q == x)
             return last - first;              return q - p;
     }     }
  
     return PEG_NOT_FOUND;     return PEG_NOT_FOUND;
 } }
  
 // ATTN-RK-P3-20020509: Define case-sensitivity for non-English characters  
 void String::toLower() void String::toLower()
 { {
     for (Char16* p = &_rep->c16a[0]; *p; p++)  #ifdef PEGASUS_HAS_ICU
     {  
         if (*p <= PEGASUS_MAX_PRINTABLE_CHAR)  
             *p = tolower(*p);  
     }  
 }  
  
 int String::compare(const String& s1, const String& s2, Uint32 n)      if (InitializeICU::initICUSuccessful())
 { {
     const Char16* s1c16 = s1.getChar16Data();          if (Atomic_get(&_rep->refs) != 1)
     const Char16* s2c16 = s2.getChar16Data();                  _rep = StringRep::copy_on_write(_rep);
  
     while (n--)          // This will do a locale-insensitive, but context-sensitive convert.
     {          // Since context-sensitive casing looks at adjacent chars, this
         int r = *s1c16++ - *s2c16++;          // prevents optimizations where the us-ascii is converted before
           // calling ICU.
           // The string may shrink or expand after the convert.
  
         if (r)          //// First calculate size of resulting string. u_strToLower() returns
             return r;          //// only the size when zero is passed as the destination size argument.
   
           UErrorCode err = U_ZERO_ERROR;
   
           int32_t new_size = u_strToLower(
               NULL, 0, (UChar*)_rep->data, _rep->size, NULL, &err);
   
           err = U_ZERO_ERROR;
   
           //// Reserve enough space for the result.
   
           if ((Uint32)new_size > _rep->cap)
               _reserve(_rep, new_size);
   
           //// Perform the conversion (overlapping buffers are allowed).
   
           u_strToLower((UChar*)_rep->data, new_size,
               (UChar*)_rep->data, _rep->size, NULL, &err);
   
           _rep->size = new_size;
           return;
     }     }
  
     return 0;  #endif /* PEGASUS_HAS_ICU */
   
       if (Atomic_get(&_rep->refs) != 1)
           _rep = StringRep::copy_on_write(_rep);
   
       Uint16* p = _rep->data;
       size_t n = _rep->size;
   
       for (; n--; p++)
       {
           if (!(*p & 0xFF00))
               *p = _to_lower(*p);
       }
 } }
  
 int String::compare(const String& s1, const String& s2)  void String::toUpper()
 { {
     const Char16* s1c16 = s1.getChar16Data();  #ifdef PEGASUS_HAS_ICU
     const Char16* s2c16 = s2.getChar16Data();  
  
     while (*s1c16 && *s2c16)      if (InitializeICU::initICUSuccessful())
     {     {
         int r = *s1c16++ - *s2c16++;          if (Atomic_get(&_rep->refs) != 1)
               _rep = StringRep::copy_on_write(_rep);
  
         if (r)          // This will do a locale-insensitive, but context-sensitive convert.
             return r;          // Since context-sensitive casing looks at adjacent chars, this
           // prevents optimizations where the us-ascii is converted before
           // calling ICU.
           // The string may shrink or expand after the convert.
   
           //// First calculate size of resulting string. u_strToUpper() returns
           //// only the size when zero is passed as the destination size argument.
   
           UErrorCode err = U_ZERO_ERROR;
   
           int32_t new_size = u_strToUpper(
               NULL, 0, (UChar*)_rep->data, _rep->size, NULL, &err);
   
           err = U_ZERO_ERROR;
   
           //// Reserve enough space for the result.
   
           if ((Uint32)new_size > _rep->cap)
               _reserve(_rep, new_size);
   
           //// Perform the conversion (overlapping buffers are allowed).
   
           u_strToUpper((UChar*)_rep->data, new_size,
               (UChar*)_rep->data, _rep->size, NULL, &err);
   
           _rep->size = new_size;
   
           return;
     }     }
  
     if (*s2c16)  #endif /* PEGASUS_HAS_ICU */
         return -1;  
     else if (*s1c16)  
         return 1;  
  
     return 0;      if (Atomic_get(&_rep->refs) != 1)
           _rep = StringRep::copy_on_write(_rep);
   
       Uint16* p = _rep->data;
       size_t n = _rep->size;
   
       for (; n--; p++)
           *p = _to_upper(*p);
 } }
  
 int String::compareNoCase(const String& s1, const String& s2)  int String::compare(const String& s1, const String& s2, Uint32 n)
 { {
     const Char16* _s1 = s1.getChar16Data();      assert(n <= s1._rep->size);
     const Char16* _s2 = s2.getChar16Data();      assert(n <= s2._rep->size);
   
       // Ignoring error in which n is greater than s1.size() or s2.size()
       return _compare(s1._rep->data, s2._rep->data, n);
   }
  
     while (*_s1 && *_s2)  int String::compare(const String& s1, const String& s2)
     {     {
         int r;      return _compare(s1._rep->data, s2._rep->data);
   }
  
         if (*_s1 <= PEGASUS_MAX_PRINTABLE_CHAR &&  #ifdef PEGASUS_USE_STRING_EXTENSIONS
             *_s2 <= PEGASUS_MAX_PRINTABLE_CHAR)  int String::compare(const String& s1, const char* s2)
         {         {
             r = tolower(*_s1++) - tolower(*_s2++);      _check_null_pointer(s2);
   
   #ifdef PEGASUS_STRING_NO_UTF8
       return _compare_no_utf8(s1._rep->data, s2);
   #else
       // ATTN: optimize this!
       return String::compare(s1, String(s2));
   #endif
         }         }
         else  #endif /* PEGASUS_USE_STRING_EXTENSIONS */
   
   int String::compareNoCase(const String& str1, const String& str2)
   {
   #ifdef PEGASUS_HAS_ICU
   
       if (InitializeICU::initICUSuccessful())
         {         {
             r = *_s1++ - *_s2++;          return  u_strcasecmp(
               str1._rep->data, str2._rep->data, U_FOLD_CASE_DEFAULT);
         }         }
  
   #endif /* PEGASUS_HAS_ICU */
   
       const Uint16* s1 = str1._rep->data;
       const Uint16* s2 = str2._rep->data;
   
       while (*s1 && *s2)
       {
           int r = _to_lower(*s1++) - _to_lower(*s2++);
   
         if (r)         if (r)
             return r;             return r;
     }     }
  
     if (*_s2)      if (*s2)
         return -1;         return -1;
     else if (*_s1)      else if (*s1)
         return 1;         return 1;
  
     return 0;     return 0;
 } }
  
 Boolean String::equal(const String& str1, const String& str2)  Boolean String::equalNoCase_aux(const String& s1, const String& s2)
 { {
     return String::compare(str1, str2) == 0;  #ifdef PEGASUS_HAS_ICU
 }  
       return String::compareNoCase(s1, s2) == 0;
   
   #else /* PEGASUS_HAS_ICU */
  
 Boolean String::equalNoCase(const String& str1, const String& str2)      Uint16* p = (Uint16*)s1._rep->data;
       Uint16* q = (Uint16*)s2._rep->data;
       Uint32 n = s2._rep->size;
   
       while (n >= 8)
       {
           if (((p[0] - q[0]) && (_to_upper(p[0]) - _to_upper(q[0]))) ||
               ((p[1] - q[1]) && (_to_upper(p[1]) - _to_upper(q[1]))) ||
               ((p[2] - q[2]) && (_to_upper(p[2]) - _to_upper(q[2]))) ||
               ((p[3] - q[3]) && (_to_upper(p[3]) - _to_upper(q[3]))) ||
               ((p[4] - q[4]) && (_to_upper(p[4]) - _to_upper(q[4]))) ||
               ((p[5] - q[5]) && (_to_upper(p[5]) - _to_upper(q[5]))) ||
               ((p[6] - q[6]) && (_to_upper(p[6]) - _to_upper(q[6]))) ||
               ((p[7] - q[7]) && (_to_upper(p[7]) - _to_upper(q[7]))))
 { {
     if (str1.size() != str2.size())  
         return false;         return false;
           }
  
     const Char16* p = str1.getChar16Data();          n -= 8;
     const Char16* q = str2.getChar16Data();          p += 8;
           q += 8;
     Uint32 n = str1.size();      }
  
     while (n--)      while (n >= 4)
     {     {
         if (*p <= PEGASUS_MAX_PRINTABLE_CHAR &&          if (((p[0] - q[0]) && (_to_upper(p[0]) - _to_upper(q[0]))) ||
             *q <= PEGASUS_MAX_PRINTABLE_CHAR)              ((p[1] - q[1]) && (_to_upper(p[1]) - _to_upper(q[1]))) ||
               ((p[2] - q[2]) && (_to_upper(p[2]) - _to_upper(q[2]))) ||
               ((p[3] - q[3]) && (_to_upper(p[3]) - _to_upper(q[3]))))
         {         {
             if (tolower(*p++) != tolower(*q++))  
                 return false;                 return false;
         }         }
         else if (*p++ != *q++)  
           n -= 4;
           p += 4;
           q += 4;
       }
   
       while (n--)
       {
           if (((p[0] - q[0]) && (_to_upper(p[0]) - _to_upper(q[0]))))
             return false;             return false;
   
           p++;
           q++;
     }     }
  
     return true;     return true;
   
   #endif /* PEGASUS_HAS_ICU */
 } }
  
   #ifdef PEGASUS_USE_STRING_EXTENSIONS
   Boolean String::equalNoCase(const String& s1, const char* s2)
   {
       _check_null_pointer(s2);
  
 // ATTN-RK-P3-20020603: This code is not completely correct  #if defined(PEGASUS_HAS_ICU)
  // Wildcard String matching function that may be useful in the future  
 // The following code was provided by Bob Blair.  
   
 /* _StringMatch Match input MatchString against a GLOB style pattern  
        Note that MatchChar is the char type so that this source  
        in portable to different string types. This is an internal function  
   
   Results: The return value is 1 if string matches pattern, and  
         0 otherwise.  The matching operation permits the following  
         special characters in the pattern: *?\[] (see the manual  
         entry for details on what these mean).  
  
   Side effects: None.      return String::equalNoCase(s1, String(s2));
  */  
  
 /* MatchChar defined as a separate entity because this function source used  #elif defined(PEGASUS_STRING_NO_UTF8)
     elsewhere was an unsigned char *. Here we use Uint16 to  maintain 16 bit  
     size.  
 */  
 typedef Uint16 MatchChar;  
  
 inline Uint16 _ToLower(Uint16 ch)      const Uint16* p1 = (Uint16*)s1._rep->data;
 {      const char* p2 = s2;
     return ch <= PEGASUS_MAX_PRINTABLE_CHAR ? tolower(char(ch)) : ch;      size_t n = s1._rep->size;
 }  
  
 inline Boolean _Equal(MatchChar ch1, MatchChar ch2, int nocase)      while (n--)
 { {
     if (nocase)          if (!*p2)
         return _ToLower(ch1) == _ToLower(ch2);              return false;
     else  
         return ch1 == ch2;          if (_to_upper(*p1++) != _to_upper_tbl[int(*p2++)])
               return false;
 } }
  
       if (*p2)
           return false;
  
 static const MatchChar *      return true;
 _matchrange(const MatchChar *range, MatchChar c, int nocase)  
 {  
   const MatchChar *p = range;  
   const MatchChar *rstart = range + 1;  
   const MatchChar *rend = 0;  
   MatchChar compchar;  
  
   for (rend = rstart; *rend && *rend != ']'; rend++);  #else /* PEGASUS_HAS_ICU */
   if (*rend == ']') {  // if there is an end to this pattern  
     for (compchar = *rstart; rstart != rend; rstart++) {  
       if (_Equal(*rstart, c, nocase))  
         return ++rend;  
       if (*rstart == '-') {  
         rstart++;  
         if (c >= compchar && c <= *rstart)  
           return ++rend;  
       }  
     }  
   }  
   return (const MatchChar *)0;  
 }  
  
 static int      // ATTN: optimize this!
 _StringMatch(      return String::equalNoCase(s1, String(s2));
     const MatchChar *testString,  
     const MatchChar *pattern,  
     int nocase )                /* Ignore case if this is true */  
 {  
   const MatchChar *pat = pattern;  
   const MatchChar *str = testString;  
   unsigned int done = 0;  
   unsigned int res = 0;  // the result: 1 == match  
  
   while (!done) { // main loop walks through pattern and test string  #endif /* PEGASUS_HAS_ICU */
     //cerr << "Comparing <" << *pat << "> and <" << *str << ">" << endl;  
     if (!*pat) {                                         //end of pattern  
       done = 1;                                          // we're done  
       if (!*str)                                         //end of test, too?  
         res = 1;                                         // then we matched  
     } else {                                             //Not end of pattern  
       if (!*str) {                                       // but end of test  
         done = 1;                                        // We're done  
         if (*pat == '*')                                 // If pattern openends  
           res = 1;                                       //  then we matched  
       } else {                                           //Not end of test  
         if (*pat == '*') {                               //Ambiguuity found  
           if (!*++pat) {                                 //and it ends pattern  
             done = 1;                                    //  then we're done  
             res = 1;                                     //  and match  
           } else {                                       //if it doesn't end  
             while (!done) {                              //  until we're done  
               if (_StringMatch(str, pat, nocase)) {      //  we recurse  
                 done = 1;                                //if it recurses true  
                 res = 1;                                 //  we done and match  
               } else {                                   //it recurses false  
                 if (!*str)                               // see if test is done  
                   done = 1;                              //  yes: we done  
                 else                                     // not done:  
                   str++;                                 //   keep testing  
               } // end test on recursive call  
             } // end looping on recursive calls  
           } // end logic when pattern is ambiguous  
         } else {                                         //pattern not ambiguus  
           if (*pat == '?') {                             //pattern is 'any'  
             pat++, str++;                                //  so move along  
           } else if (*pat == '[') {                      //see if it's a range  
             pat = _matchrange(pat, *str, nocase);         // and is a match  
             if (!pat) {                                  //It is not a match  
               done = 1;                                  //  we're done  
               res = 0;                                   //  no match  
             } else {                                     //Range matches  
               str++, pat++;                              //  keep going  
             }             }
           } else {               // only case left is individual characters  #endif /* PEGASUS_USE_STRING_EXTENSIONS */
             if (!_Equal(*pat++, *str++, nocase))         // if they don't match  
               done = 1;                                  //   bail.  
           }  
         }  // end ("pattern is not ambiguous (*)" logic  
       } // end logic when pattern and string still have data  
     } // end logic when pattern still has data  
   } // end main loop  
   return res;  
 }  
   
  
 Boolean String::match(const String& str, const String& pattern)  Boolean String::equal(const String& s1, const String& s2)
 { {
     return _StringMatch(      return s1._rep->size == s2._rep->size && memcmp(s1._rep->data,
         (Uint16*)str.getChar16Data(), (Uint16*)pattern.getChar16Data(), 0) != 0;          s2._rep->data, s1._rep->size * sizeof(Uint16)) == 0;
 } }
  
 Boolean String::matchNoCase(const String& str, const String& pattern)  #ifdef PEGASUS_USE_STRING_EXTENSIONS
   Boolean String::equal(const String& s1, const char* s2)
 { {
     return _StringMatch(  #ifdef PEGASUS_STRING_NO_UTF8
         (Uint16*)str.getChar16Data(), (Uint16*)pattern.getChar16Data(), 1) != 0;  
 }  
  
       _check_null_pointer(s2);
  
 ///////////////////////////////////////////////////////////////////////////////      const Uint16* p = (Uint16*)s1._rep->data;
 //      const char* q = s2;
 // String-related functions  
 //  
 ///////////////////////////////////////////////////////////////////////////////  
  
 Boolean operator==(const String& str1, const String& str2)      while (*p && *q)
 { {
     return String::equal(str1, str2);          if (*p++ != Uint16(*q++))
               return false;
 } }
  
 Boolean operator==(const String& str1, const char* str2)      return !(*p || *q);
 {  
     return String::equal(str1, str2);  #else /* PEGASUS_STRING_NO_UTF8 */
   
       return String::equal(s1, String(s2));
   
   #endif /* PEGASUS_STRING_NO_UTF8 */
 } }
   #endif /* PEGASUS_USE_STRING_EXTENSIONS */
  
 Boolean operator==(const char* str1, const String& str2)  PEGASUS_STD(ostream)& operator<<(PEGASUS_STD(ostream)& os, const String& str)
 { {
     return String::equal(str1, str2);  #if defined(PEGASUS_OS_OS400)
 }  
       CString cstr = str.getCString();
       const char* utf8str = cstr;
       os << utf8str;
       return os;
   #else
   
   #if defined(PEGASUS_HAS_ICU)
  
 Boolean operator!=(const String& str1, const String& str2)      if (InitializeICU::initICUSuccessful())
 { {
     return !String::equal(str1, str2);          char *buf = NULL;
           const int size = str.size() * 6;
           UnicodeString UniStr(
               (const UChar *)str.getChar16Data(), (int32_t)str.size());
           Uint32 bufsize = UniStr.extract(0,size,buf);
           buf = new char[bufsize+1];
           UniStr.extract(0,bufsize,buf);
           os << buf;
           os.flush();
           delete [] buf;
           return os;
 } }
  
 PEGASUS_STD(ostream)& operator<<(PEGASUS_STD(ostream)& os, const String& str)  #endif  // PEGASUS_HAS_ICU
 {  
     for (Uint32 i = 0, n = str.size(); i < n; i++)     for (Uint32 i = 0, n = str.size(); i < n; i++)
     {     {
         Uint16 code = str[i];         Uint16 code = str[i];
  
         if (code > 0 && code <= PEGASUS_MAX_PRINTABLE_CHAR)          if (code > 0 && !(code & 0xFF00))
         {  
             os << char(code);             os << char(code);
         }  
         else         else
         {         {
             // Print in hex format:             // Print in hex format:
Line 724 
Line 1278 
     }     }
  
     return os;     return os;
   #endif // PEGASUS_OS_OS400
 } }
  
 String operator+(const String& str1, const String& str2)  void String::_append_char_aux()
 { {
     return String(str1).append(str2);      StringRep* tmp;
 }  
  
 Boolean operator<(const String& str1, const String& str2)      if (_rep->cap)
 { {
     return String::compare(str1, str2) < 0;          tmp = StringRep::alloc(2 * _rep->cap);
           tmp->size = _rep->size;
           _copy(tmp->data, _rep->data, _rep->size);
 } }
       else
 Boolean operator<=(const String& str1, const String& str2)  
 { {
     return String::compare(str1, str2) <= 0;          tmp = StringRep::alloc(8);
           tmp->size = 0;
 } }
  
 Boolean operator>(const String& str1, const String& str2)      StringRep::unref(_rep);
       _rep = tmp;
   }
   
   PEGASUS_NAMESPACE_END
   
   /*
   ================================================================================
   
   String optimizations:
   
       1.  Added mechanism allowing certain functions to be inlined only when
           used by internal Pegasus modules. External modules (i.e., providers)
           link to a non-inline version, which allows for binary compatibility.
   
       2.  Implemented copy-on-write with atomic increment/decrement. This
           yieled a 10% improvement for the 'gc' benchmark and a 11% improvment
           for the 'ni1000' benchmark.
   
       3.  Employed loop unrolling in several places. For example, see:
   
               static Uint16* _find(const Uint16* s, size_t n, Uint16 c);
   
       4.  Used the "empty-rep" optimization (described in whitepaper from the
           GCC Developers Summit). This reduced default construction to a simple
           pointer assignment.
   
               inline String::String() : _rep(&_empty_rep) { }
   
       5.  Implemented Uint16 versions of toupper() and tolower() using tables.
           For example:
   
               static const char _upper[] =
               {
                   0,1,2,...255
               };
   
               inline Uint16 _to_upper(Uint16 x)
 { {
     return String::compare(str1, str2) > 0;                  return (x & 0xFF00) ? x : _upper[x];
 } }
  
 Boolean operator>=(const String& str1, const String& str2)          This outperforms the system implementation by avoiding an anding
           operation.
   
       6.  Implemented char* version of the following member functions to
           eliminate unecessary creation of anonymous string objects
           (temporaries).
   
               String(const String& s1, const char* s2);
               String(const char* s1, const String& s2);
               String& String::operator=(const char* str);
               Uint32 String::find(const char* s) const;
               bool String::equal(const String& s1, const char* s2);
               static int String::compare(const String& s1, const char* s2);
               String& String::append(const char* str);
               String& String::append(const char* str, Uint32 size);
               static bool String::equalNoCase(const String& s1, const char* s2);
               String& operator=(const char* str)
               String& String::assign(const char* str)
               String& String::append(const char* str)
               Boolean operator==(const String& s1, const char* s2)
               Boolean operator==(const char* s1, const String& s2)
               Boolean operator!=(const String& s1, const char* s2)
               Boolean operator!=(const char* s1, const String& s2)
               Boolean operator<(const String& s1, const char* s2)
               Boolean operator<(const char* s1, const String& s2)
               Boolean operator>(const String& s1, const char* s2)
               Boolean operator>(const char* s1, const String& s2)
               Boolean operator<=(const String& s1, const char* s2)
               Boolean operator<=(const char* s1, const String& s2)
               Boolean operator>=(const String& s1, const char* s2)
               Boolean operator>=(const char* s1, const String& s2)
               String operator+(const String& s1, const char* s2)
               String operator+(const char* s1, const String& s2)
   
       7.  Optimized _next_pow_2(), used in rounding the capacity to the next
           power of two (algorithm from the book "Hacker's Delight").
   
               static Uint32 _next_pow_2(Uint32 x)
 { {
     return String::compare(str1, str2) >= 0;                  if (x < 8)
                       return 8;
   
                   x--;
                   x |= (x >> 1);
                   x |= (x >> 2);
                   x |= (x >> 4);
                   x |= (x >> 8);
                   x |= (x >> 16);
                   x++;
   
                   return x;
 } }
  
 #ifndef PEGASUS_REMOVE_DEPRECATED      8.  Implemented "concatenating constructors" to eliminate temporaries
 int CompareNoCase(const char* s1, const char* s2)          created by operator+(). This scheme employs the "return-value
           optimization" described by Stan Lippman.
   
               inline String operator+(const String& s1, const String& s2)
 { {
     return System::strcasecmp(s1, s2);                  return String(s1, s2, 0);
 } }
 #endif  
  
 PEGASUS_NAMESPACE_END      9.  Experimented to find the optimial initial size for a short string.
           Eight seems to offer the best tradeoff between space and time.
   
       10. Inlined all members of the Char16 class.
   
       11. Used Uint16 internally in the String class. This showed no improvememnt
           since Char16 was already fully inlined and was essentially reduced to
           Uint16 in any case.
   
       12. Implemented conditional logic (#if) allowing error checking logic to
           be excluded to better performance. Examples include bounds checking
           and null-pointer checking.
   
       13. Used memcpy() and memcmp() where possible. These are implemented using
           the rep family of intructions under Intel and are much faster.
   
       14. Used loop unrolling, jump-tables, and short-circuiting to reduce UTF8
           copy routine overhead.
   
       15. Added ASCII7 form of the constructor and assign().
   
               String s("hello world", String::ASCII7);
   
               s.assignASCII7("hello world");
   
           This avoids slower UTF8 processing when not needed.
   
   ================================================================================
   */


Legend:
Removed from v.1.64  
changed lines
  Added in v.1.111.2.16

No CVS admin address has been configured
Powered by
ViewCVS 0.9.2