home *** CD-ROM | disk | FTP | other *** search
/ Fresh Fish 7 / FreshFishVol7.bin / bbs / gnu / libg++-2.6-fsf.lha / libg++-2.6 / libg++ / src / String.cc < prev    next >
C/C++ Source or Header  |  1994-07-18  |  28KB  |  1,314 lines

  1. /* 
  2. Copyright (C) 1988 Free Software Foundation
  3.     written by Doug Lea (dl@rocky.oswego.edu)
  4.  
  5. This file is part of the GNU C++ Library.  This library is free
  6. software; you can redistribute it and/or modify it under the terms of
  7. the GNU Library General Public License as published by the Free
  8. Software Foundation; either version 2 of the License, or (at your
  9. option) any later version.  This library is distributed in the hope
  10. that it will be useful, but WITHOUT ANY WARRANTY; without even the
  11. implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
  12. PURPOSE.  See the GNU Library General Public License for more details.
  13. You should have received a copy of the GNU Library General Public
  14. License along with this library; if not, write to the Free Software
  15. Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  16. */
  17.  
  18. /* 
  19.   String class implementation
  20.  */
  21.  
  22. #ifdef __GNUG__
  23. #pragma implementation
  24. #endif
  25. #include <String.h>
  26. #include <std.h>
  27. #include <ctype.h>
  28. #include <limits.h>
  29. #include <new.h>
  30. #include <builtin.h>
  31.  
  32. // extern "C" {
  33. #include <regex.h>
  34. // }
  35.  
  36. void String::error(const char* msg) const
  37. {
  38.   (*lib_error_handler)("String", msg);
  39. }
  40.  
  41. String::operator const char*() const
  42.   return (const char*)chars();
  43. }
  44.  
  45. //  globals
  46.  
  47. StrRep  _nilStrRep = { 0, 1, { 0 } }; // nil strings point here
  48. String _nilString;               // nil SubStrings point here
  49.  
  50.  
  51.  
  52.  
  53. /*
  54.  the following inline fcts are specially designed to work
  55.  in support of String classes, and are not meant as generic replacements
  56.  for libc "str" functions.
  57.  
  58.  inline copy fcts -  I like left-to-right from->to arguments.
  59.  all versions assume that `to' argument is non-null
  60.  
  61.  These are worth doing inline, rather than through calls because,
  62.  via procedural integration, adjacent copy calls can be smushed
  63.  together by the optimizer.
  64. */
  65.  
  66. // copy n bytes
  67. inline static void ncopy(const char* from, char* to, int n)
  68. {
  69.   if (from != to) while (--n >= 0) *to++ = *from++;
  70. }
  71.  
  72. // copy n bytes, null-terminate
  73. inline static void ncopy0(const char* from, char* to, int n)
  74. {
  75.   if (from != to) 
  76.   {
  77.     while (--n >= 0) *to++ = *from++;
  78.     *to = 0;
  79.   }
  80.   else
  81.     to[n] = 0;
  82. }
  83.  
  84. // copy until null
  85. inline static void scopy(const char* from, char* to)
  86. {
  87.   if (from != 0) while((*to++ = *from++) != 0);
  88. }
  89.  
  90. // copy right-to-left
  91. inline static void revcopy(const char* from, char* to, short n)
  92. {
  93.   if (from != 0) while (--n >= 0) *to-- = *from--;
  94. }
  95.  
  96.  
  97. inline static int slen(const char* t) // inline  strlen
  98. {
  99.   if (t == 0)
  100.     return 0;
  101.   else
  102.   {
  103.     const char* a = t;
  104.     while (*a++ != 0);
  105.     return a - 1 - t;
  106.   }
  107. }
  108.  
  109. // minimum & maximum representable rep size
  110.  
  111. #define MAXStrRep_SIZE   ((1 << (sizeof(short) * CHAR_BIT - 1)) - 1)
  112. #define MINStrRep_SIZE   16
  113.  
  114. #ifndef MALLOC_MIN_OVERHEAD
  115. #define MALLOC_MIN_OVERHEAD  4
  116. #endif
  117.  
  118. // The basic allocation primitive:
  119. // Always round request to something close to a power of two.
  120. // This ensures a bit of padding, which often means that
  121. // concatenations don't have to realloc. Plus it tends to
  122. // be faster when lots of Strings are created and discarded,
  123. // since just about any version of malloc (op new()) will
  124. // be faster when it can reuse identically-sized chunks
  125.  
  126. inline static StrRep* Snew(int newsiz)
  127. {
  128.   unsigned int siz = sizeof(StrRep) + newsiz + MALLOC_MIN_OVERHEAD;
  129.   unsigned int allocsiz = MINStrRep_SIZE;
  130.   while (allocsiz < siz) allocsiz <<= 1;
  131.   allocsiz -= MALLOC_MIN_OVERHEAD;
  132.   if (allocsiz >= MAXStrRep_SIZE)
  133.     (*lib_error_handler)("String", "Requested length out of range");
  134.     
  135.   StrRep* rep = (StrRep *) new char[allocsiz];
  136.   rep->sz = allocsiz - sizeof(StrRep);
  137.   return rep;
  138. }
  139.  
  140. // Do-something-while-allocating routines.
  141.  
  142. // We live with two ways to signify empty Sreps: either the
  143. // null pointer (0) or a pointer to the nilStrRep.
  144.  
  145. // We always signify unknown source lengths (usually when fed a char*)
  146. // via len == -1, in which case it is computed.
  147.  
  148. // allocate, copying src if nonull
  149.  
  150. StrRep* Salloc(StrRep* old, const char* src, int srclen, int newlen)
  151. {
  152.   if (old == &_nilStrRep) old = 0;
  153.   if (srclen < 0) srclen = slen(src);
  154.   if (newlen < srclen) newlen = srclen;
  155.   StrRep* rep;
  156.   if (old == 0 || newlen > old->sz)
  157.     rep = Snew(newlen);
  158.   else
  159.     rep = old;
  160.  
  161.   rep->len = newlen;
  162.   ncopy0(src, rep->s, srclen);
  163.  
  164.   if (old != rep && old != 0) delete old;
  165.  
  166.   return rep;
  167. }
  168.  
  169. // reallocate: Given the initial allocation scheme, it will
  170. // generally be faster in the long run to get new space & copy
  171. // than to call realloc
  172.  
  173. StrRep* Sresize(StrRep* old, int newlen)
  174. {
  175.   if (old == &_nilStrRep) old = 0;
  176.   StrRep* rep;
  177.   if (old == 0)
  178.     rep = Snew(newlen);
  179.   else if (newlen > old->sz)
  180.   {
  181.     rep = Snew(newlen);
  182.     ncopy0(old->s, rep->s, old->len);
  183.     delete old;
  184.   }
  185.   else
  186.     rep = old;
  187.  
  188.   rep->len = newlen;
  189.  
  190.   return rep;
  191. }
  192.  
  193. // like allocate, but we know that src is a StrRep
  194.  
  195. StrRep* Scopy(StrRep* old, const StrRep* s)
  196. {
  197.   if (old == &_nilStrRep) old = 0;
  198.   if (s == &_nilStrRep) s = 0;
  199.   if (old == s) 
  200.     return (old == 0)? &_nilStrRep : old;
  201.   else if (s == 0)
  202.   {
  203.     old->s[0] = 0;
  204.     old->len = 0;
  205.     return old;
  206.   }
  207.   else 
  208.   {
  209.     StrRep* rep;
  210.     int newlen = s->len;
  211.     if (old == 0 || newlen > old->sz)
  212.     {
  213.       if (old != 0) delete old;
  214.       rep = Snew(newlen);
  215.     }
  216.     else
  217.       rep = old;
  218.     rep->len = newlen;
  219.     ncopy0(s->s, rep->s, newlen);
  220.     return rep;
  221.   }
  222. }
  223.  
  224. // allocate & concatenate
  225.  
  226. StrRep* Scat(StrRep* old, const char* s, int srclen, const char* t, int tlen)
  227. {
  228.   if (old == &_nilStrRep) old = 0;
  229.   if (srclen < 0) srclen = slen(s);
  230.   if (tlen < 0) tlen = slen(t);
  231.   int newlen = srclen + tlen;
  232.   StrRep* rep;
  233.  
  234.   if (old == 0 || newlen > old->sz || 
  235.       (t >= old->s && t < &(old->s[old->len]))) // beware of aliasing
  236.     rep = Snew(newlen);
  237.   else
  238.     rep = old;
  239.  
  240.   rep->len = newlen;
  241.  
  242.   ncopy(s, rep->s, srclen);
  243.   ncopy0(t, &(rep->s[srclen]), tlen);
  244.  
  245.   if (old != rep && old != 0) delete old;
  246.  
  247.   return rep;
  248. }
  249.  
  250. // double-concatenate
  251.  
  252. StrRep* Scat(StrRep* old, const char* s, int srclen, const char* t, int tlen,
  253.              const char* u, int ulen)
  254. {
  255.   if (old == &_nilStrRep) old = 0;
  256.   if (srclen < 0) srclen = slen(s);
  257.   if (tlen < 0) tlen = slen(t);
  258.   if (ulen < 0) ulen = slen(u);
  259.   int newlen = srclen + tlen + ulen;
  260.   StrRep* rep;
  261.   if (old == 0 || newlen > old->sz || 
  262.       (t >= old->s && t < &(old->s[old->len])) ||
  263.       (u >= old->s && u < &(old->s[old->len])))
  264.     rep = Snew(newlen);
  265.   else
  266.     rep = old;
  267.  
  268.   rep->len = newlen;
  269.  
  270.   ncopy(s, rep->s, srclen);
  271.   ncopy(t, &(rep->s[srclen]), tlen);
  272.   ncopy0(u, &(rep->s[srclen+tlen]), ulen);
  273.  
  274.   if (old != rep && old != 0) delete old;
  275.  
  276.   return rep;
  277. }
  278.  
  279. // like cat, but we know that new stuff goes in the front of existing rep
  280.  
  281. StrRep* Sprepend(StrRep* old, const char* t, int tlen)
  282. {
  283.   char* s;
  284.   int srclen;
  285.   if (old == &_nilStrRep || old == 0)
  286.   {
  287.     s = 0; old = 0; srclen = 0;
  288.   }
  289.   else
  290.   {
  291.     s = old->s; srclen = old->len;
  292.   }
  293.   if (tlen < 0) tlen = slen(t);
  294.   int newlen = srclen + tlen;
  295.   StrRep* rep;
  296.   if (old == 0 || newlen > old->sz || 
  297.       (t >= old->s && t < &(old->s[old->len])))
  298.     rep = Snew(newlen);
  299.   else
  300.     rep = old;
  301.  
  302.   rep->len = newlen;
  303.  
  304.   revcopy(&(s[srclen]), &(rep->s[newlen]), srclen+1);
  305.   ncopy(t, rep->s, tlen);
  306.  
  307.   if (old != rep && old != 0) delete old;
  308.  
  309.   return rep;
  310. }
  311.  
  312.  
  313. // string compare: first argument is known to be non-null
  314.  
  315. inline static int scmp(const char* a, const char* b)
  316. {
  317.   if (b == 0)
  318.     return *a != 0;
  319.   else
  320.   {
  321.     signed char diff = 0;
  322.     while ((diff = *a - *b++) == 0 && *a++ != 0);
  323.     return diff;
  324.   }
  325. }
  326.  
  327.  
  328. inline static int ncmp(const char* a, int al, const char* b, int bl)
  329. {
  330.   int n = (al <= bl)? al : bl;
  331.   signed char diff;
  332.   while (n-- > 0) if ((diff = *a++ - *b++) != 0) return diff;
  333.   return al - bl;
  334. }
  335.  
  336. int fcompare(const String& x, const String& y)
  337. {
  338.   const char* a = x.chars();
  339.   const char* b = y.chars();
  340.   int al = x.length();
  341.   int bl = y.length();
  342.   int n = (al <= bl)? al : bl;
  343.   signed char diff = 0;
  344.   while (n-- > 0)
  345.   {
  346.     char ac = *a++;
  347.     char bc = *b++;
  348.     if ((diff = ac - bc) != 0)
  349.     {
  350.       if (ac >= 'a' && ac <= 'z')
  351.         ac = ac - 'a' + 'A';
  352.       if (bc >= 'a' && bc <= 'z')
  353.         bc = bc - 'a' + 'A';
  354.       if ((diff = ac - bc