home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 1999 mARCH / PCWK3A99.iso / Linux / DDD331 / DDD-3_1_.000 / DDD-3_1_ / ddd-3.1.1 / ddd / strclass.C < prev    next >
C/C++ Source or Header  |  1998-09-22  |  31KB  |  1,435 lines

  1. // $Id: strclass.C,v 1.20 1998/09/22 11:31:33 zeller Exp $ -*- C++ -*-
  2. // The libg++ String class, but named "string" for coexistence with Xt
  3.  
  4. /* 
  5. Copyright (C) 1988 Free Software Foundation
  6.     written by Doug Lea (dl@rocky.oswego.edu)
  7.  
  8. This file is part of the GNU C++ Library.  This library is free
  9. software; you can redistribute it and/or modify it under the terms of
  10. the GNU Library General Public License as published by the Free
  11. Software Foundation; either version 2 of the License, or (at your
  12. option) any later version.  This library is distributed in the hope
  13. that it will be useful, but WITHOUT ANY WARRANTY; without even the
  14. implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
  15. PURPOSE.  See the GNU Library General Public License for more details.
  16. You should have received a copy of the GNU Library General Public
  17. License along with this library; if not, write to the Free Software
  18. Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  19. */
  20.  
  21. char strclass_rcsid[] = 
  22.     "$Id: strclass.C,v 1.20 1998/09/22 11:31:33 zeller Exp $";
  23.  
  24. /* 
  25.   string class implementation
  26.  */
  27.  
  28. #ifdef __GNUG__
  29. #pragma implementation
  30. #endif
  31.  
  32. #ifndef MALLOC_DEBUG
  33. #define MALLOC_DEBUG 0
  34. #endif
  35.  
  36. #if MALLOC_DEBUG
  37. extern "C" int malloc_verify();
  38. #include "assert.h"
  39. #endif
  40.  
  41. #include "strclass.h"
  42. #include "config.h"
  43. #include "return.h"
  44. #include <ctype.h>
  45. #include <limits.h>
  46. #include <new.h>
  47. #include <stdlib.h>
  48.  
  49. #if HAVE_LIMITS_H
  50. #include <limits.h>
  51. #endif
  52.  
  53. void string::error(const char* msg) const
  54. {
  55.     cerr << "string: " << msg << "\n";
  56.     abort();
  57. }
  58.  
  59. string::operator const char*() const
  60.     return (const char *)chars();
  61. }
  62.  
  63. string::operator char*() const
  64.     return (char *)chars();
  65. }
  66.  
  67. //  globals
  68.  
  69. // nil strings point here
  70. strRep _nilstrRep = { 0, 1, &(_nilstrRep.mem[0]), { '\0' } };
  71.  
  72. // nil subStrings point here
  73. string _nilstring;
  74.  
  75.  
  76.  
  77.  
  78. /*
  79.  the following inline fcts are specially designed to work
  80.  in support of string classes, and are not meant as generic replacements
  81.  for libc "str" functions.
  82.  
  83.  inline copy fcts -  I like left-to-right from->to arguments.
  84.  all versions assume that `to' argument is non-null
  85.  
  86.  These are worth doing inline, rather than through calls because,
  87.  via procedural integration, adjacent copy calls can be smushed
  88.  together by the optimizer.
  89. */
  90.  
  91. // copy n bytes
  92. inline static void ncopy(const char* from, char* to, int n)
  93. {
  94.     if (from != to) while (--n >= 0) *to++ = *from++;
  95. }
  96.  
  97. // copy n bytes, null-terminate
  98. inline static void ncopy0(const char* from, char* to, int n)
  99. {
  100.     if (from != to) 
  101.     {
  102.     while (--n >= 0) *to++ = *from++;
  103.     *to = 0;
  104.     }
  105.     else
  106.     to[n] = 0;
  107. }
  108.  
  109. // copy until null
  110. inline static void scopy(const char* from, char* to)
  111. {
  112.     if (from != 0) while((*to++ = *from++) != 0);
  113. }
  114.  
  115. // copy right-to-left
  116. inline static void revcopy(const char* from, char* to, int n)
  117. {
  118.     if (from != 0) while (--n >= 0) *to-- = *from--;
  119. }
  120.  
  121.  
  122. inline static int slen(const char* t) // inline  strlen
  123. {
  124.     if (t == 0)
  125.     return 0;
  126.     else
  127.     {
  128.     const char* a = t;
  129.     while (*a++ != 0);
  130.     return a - 1 - t;
  131.     }
  132. }
  133.  
  134.  
  135.  
  136. // The remaining size for the current string in REP
  137. inline unsigned int string_Sremainder(strRep *rep)
  138. {
  139.     return rep->allocated - (rep->s - &(rep->mem[0]));
  140. }
  141.  
  142.  
  143. // minimum & maximum representable rep size
  144.  
  145. #if 0
  146. const unsigned long MAX_STRREP_SIZE = (1 << (sizeof(int) * CHAR_BIT - 1)) - 1;
  147. #endif
  148.  
  149. const unsigned long MIN_STRREP_SIZE = 16;
  150.  
  151. #ifndef MALLOC_MIN_OVERHEAD
  152. #define MALLOC_MIN_OVERHEAD  4
  153. #endif
  154.  
  155. // The basic allocation primitive:
  156. // Always round request to something close to a power of two.
  157. // This ensures a bit of padding, which often means that
  158. // concatenations don't have to realloc. Plus it tends to
  159. // be faster when lots of Strings are created and discarded,
  160. // since just about any version of malloc (op new()) will
  161. // be faster when it can reuse identically-sized chunks
  162.  
  163. inline static strRep* string_Snew(int newsiz)
  164. {
  165.     unsigned int siz = sizeof(strRep) + newsiz + MALLOC_MIN_OVERHEAD;
  166.     unsigned int allocsiz = MIN_STRREP_SIZE;
  167.     while (allocsiz < siz) allocsiz <<= 1;
  168.     allocsiz -= MALLOC_MIN_OVERHEAD;
  169.  
  170. #if 0
  171.     if ((unsigned long)allocsiz >= MAX_STRREP_SIZE)
  172.     {
  173.     cerr << "string: requested length out of range\n";
  174.     abort();
  175.     }
  176. #endif
  177.  
  178. #if HAVE_PLACEMENT_NEW
  179.     strRep* rep = new (operator new (allocsiz)) strRep;
  180. #else
  181.     strRep* rep = (strRep *) new char[allocsiz];
  182. #endif
  183.     rep->allocated = allocsiz - sizeof(strRep);
  184.     rep->s  = &rep->mem[0];
  185.     return rep;
  186. }
  187.  
  188. // Do-something-while-allocating routines.
  189.  
  190. // We live with two ways to signify empty Sreps: either the
  191. // null pointer (0) or a pointer to the nilstrRep.
  192.  
  193. // We always signify unknown source lengths (usually when fed a char*)
  194. // via len == -1, in which case it is computed.
  195.  
  196. // allocate, copying src if nonull
  197.  
  198. strRep* string_Salloc(strRep* old, const char* src, int srclen, int newlen)
  199. {
  200. #if MALLOC_DEBUG
  201.     assert(malloc_verify());
  202. #endif
  203.  
  204.     if (old == &_nilstrRep) old = 0;
  205.     if (srclen < 0) srclen = slen(src);
  206.     if (newlen < srclen) newlen = srclen;
  207.     strRep* rep;
  208.     if (old == 0 || unsigned(newlen) > old->allocated)
  209.     rep = string_Snew(newlen);
  210.     else
  211.     rep = old;
  212.  
  213.     rep->len = newlen;
  214.     rep->s   = &(rep->mem[0]);
  215.     ncopy0(src, rep->s, srclen);
  216.  
  217.     if (old != rep && old != 0)
  218.     string_DeleteRep(old);
  219.  
  220.     return rep;
  221. }
  222.  
  223. // reallocate: Given the initial allocation scheme, it will
  224. // generally be faster in the long run to get new space & copy
  225. // than to call realloc
  226.  
  227. static strRep *string_Sresize(strRep* old, int newlen)
  228. {
  229. #if MALLOC_DEBUG
  230.     assert(malloc_verify());
  231. #endif
  232.  
  233.     if (old == &_nilstrRep) old = 0;
  234.     strRep* rep;
  235.     if (old == 0)
  236.     rep = string_Snew(newlen);
  237.     else if (unsigned(newlen) > old->allocated)
  238.     {
  239.     rep = string_Snew(newlen);
  240.     ncopy0(old->s, rep->s, old->len);
  241.     string_DeleteRep(old);
  242.     }
  243.     else
  244.     rep = old;
  245.  
  246.     rep->len = newlen;
  247.  
  248.     return rep;
  249. }
  250.  
  251. void string::alloc (int newsize)
  252. {
  253.     unsigned short old_len = rep->len;
  254.     rep = string_Sresize(rep, newsize);
  255.     rep->len = old_len;
  256. }
  257.  
  258.  
  259. // like allocate, but we know that src is a strRep
  260.  
  261. strRep* string_Scopy(strRep* old, strRep* s)
  262. {
  263. #if MALLOC_DEBUG
  264.     assert(malloc_verify());
  265. #endif
  266.  
  267.     if (old == &_nilstrRep) old = 0;
  268.     if (s == &_nilstrRep) s = 0;
  269.     if (old == s) 
  270.     return (old == 0)? &_nilstrRep : old;
  271.     else if (s == 0)
  272.     {
  273.     old->s[0] = 0;
  274.     old->len = 0;
  275.     return old;
  276.     }
  277.     else 
  278.     {
  279.     strRep* rep;
  280.     unsigned newlen = s->len;
  281.     if (old == 0 || newlen > old->allocated)
  282.     {
  283.         if (old != 0) 
  284.         string_DeleteRep(old);
  285.         rep = string_Snew(newlen);
  286.     }
  287.     else
  288.         rep = old;
  289.  
  290.     rep->len = newlen;
  291.     rep->s = &(rep->mem[0]);
  292.     ncopy0(s->s, rep->s, newlen);
  293.     return rep;
  294.     }
  295. }
  296.  
  297. // allocate & concatenate
  298.  
  299. strRep* string_Scat(strRep* old, 
  300.             const char* s, 
  301.             int srclen, 
  302.             const char* t, 
  303.             int tlen)
  304. {
  305. #if MALLOC_DEBUG
  306.     assert(malloc_verify());
  307. #endif
  308.  
  309.     if (old == &_nilstrRep) old = 0;
  310.     if (srclen < 0) srclen = slen(s);
  311.     if (tlen < 0) tlen = slen(t);
  312.     unsigned newlen = srclen + tlen;
  313.     strRep* rep;
  314.  
  315.     if (old == 0 || newlen > old->allocated || 
  316.     (t >= old->s && t < &(old->s[old->len]))) // beware of aliasing
  317.     rep = string_Snew(newlen);
  318.     else
  319.     rep = old;
  320.  
  321.     rep->len = newlen;
  322.     rep->s = &(rep->mem[0]);
  323.  
  324.     ncopy(s, rep->s, srclen);
  325.     ncopy0(t, &(rep->s[srclen]), tlen);
  326.  
  327.     if (old != rep && old != 0)
  328.     string_DeleteRep(old);
  329.  
  330.     return rep;
  331. }
  332.  
  333. // double-concatenate
  334.  
  335. strRep* string_Scat(strRep* old, const char* s, int srclen, 
  336.             const char* t, int tlen,
  337.             const char* u, int ulen)
  338. {
  339. #if MALLOC_DEBUG
  340.     assert(malloc_verify());
  341. #endif
  342.  
  343.     if (old == &_nilstrRep) old = 0;
  344.     if (srclen < 0) srclen = slen(s);
  345.     if (tlen < 0) tlen = slen(t);
  346.     if (ulen < 0) ulen = slen(u);
  347.     unsigned newlen = srclen + tlen + ulen;
  348.     strRep* rep;
  349.     if (old == 0 || newlen > old->allocated || 
  350.     (t >= old->s && t < &(old->s[old->len])) ||
  351.     (u >= old->s && u < &(old->s[old->len])))
  352.     rep = string_Snew(newlen);
  353.     else
  354.     rep = old;
  355.  
  356.     rep->len = newlen;
  357.     rep->s = &(rep->mem[0]);
  358.  
  359.     ncopy(s, rep->s, srclen);
  360.     ncopy(t, &(rep->s[srclen]), tlen);
  361.     ncopy0(u, &(rep->s[srclen+tlen]), ulen);
  362.  
  363.     if (old != rep && old != 0)
  364.     string_DeleteRep(old);
  365.  
  366.     return rep;
  367. }
  368.  
  369. // like cat, but we know that new stuff goes in the front of existing rep
  370.  
  371. strRep* string_Sprepend(strRep* old, const char* t, int tlen)
  372. {
  373. #if MALLOC_DEBUG
  374.     assert(malloc_verify());
  375. #endif
  376.  
  377.     char* s;
  378.     int srclen;
  379.     if (old == &_nilstrRep || old == 0)
  380.     {
  381.     s = 0; old = 0; srclen = 0;
  382.     }
  383.     else
  384.     {
  385.     s = old->s; srclen = old->len;
  386.     }
  387.     if (tlen < 0) tlen = slen(t);
  388.     unsigned newlen = srclen + tlen;
  389.     strRep* rep;
  390.     if (old == 0 || newlen > string_Sremainder(old) || 
  391.     (t >= old->s && t < &(old->s[old->len])))
  392.     rep = string_Snew(newlen);
  393.     else
  394.     rep = old;
  395.  
  396.     rep->len = newlen;
  397.  
  398.     revcopy(&(s[srclen]), &(rep->s[newlen]), srclen+1);
  399.     ncopy(t, rep->s, tlen);
  400.  
  401.     if (old != rep && old != 0)
  402.     string_DeleteRep(old);
  403.  
  404.     return rep;
  405. }
  406.  
  407.  
  408. // string compare: first argument is known to be non-null
  409.  
  410. inline static int scmp(const char* a, const char* b)
  411. {
  412.     if (b == 0)
  413.     return *a != 0;
  414.     else
  415.     {
  416.     signed char diff = 0;
  417.     while ((diff = *a - *b++) == 0 && *a++ != 0);
  418.     return diff;
  419.     }
  420. }
  421.  
  422.  
  423. inline static int ncmp(const char* a, int al, const char* b, int bl)
  424. {
  425.     int n = (al <= bl)? al : bl;
  426.     signed char diff;
  427.     while (n-- > 0) if ((diff = *a++ - *b++) != 0) return diff;
  428.     return al - bl;
  429. }
  430.  
  431. int fcompare(const string& x, const string& y)
  432. {
  433.     const char* a = x.chars();
  434.     const char* b = y.chars();
  435.     int al = x.length();
  436.     int bl = y.length();
  437.     int n = (al <= bl)? al : bl;
  438.     signed char diff = 0;
  439.     while (n-- > 0)
  440.     {
  441.     char ac = *a++;
  442.     char bc = *b++;
  443.     if ((diff = ac - bc) != 0)
  444.     {
  445.         if (ac >= 'a' && ac <= 'z')
  446.         ac = ac - 'a' + 'A';
  447.         if (bc >= 'a' && bc <= 'z')
  448.         bc = bc - 'a' + 'A';
  449.         if ((diff = ac - bc) != 0)
  450.         return diff;
  451.     }
  452.     }
  453.     return al - bl;
  454. }
  455.  
  456. // these are not inline, but pull in the above inlines, so are 
  457. // pretty fast
  458.  
  459. int compare(const string& x, const char* b)
  460. {
  461.     return scmp(x.chars(), b);
  462. }
  463.  
  464. int compare(const char *x, const string& y)
  465. {
  466.     return scmp(x, y.chars());
  467. }
  468.  
  469. int compare(const string& x, const string& y)
  470. {
  471.     return scmp(x.chars(), y.chars());
  472. }
  473.  
  474. int compare(const string& x, const subString& y)
  475. {
  476.     return ncmp(x.chars(), x.length(), y.chars(), y.length());
  477. }
  478.  
  479. int compare(const subString& x, const string& y)
  480. {
  481.     return ncmp(x.chars(), x.length(), y.chars(), y.length());
  482. }
  483.  
  484. int compare(const subString& x, const subString& y)
  485. {
  486.     return ncmp(x.chars(), x.length(), y.chars(), y.length());
  487. }
  488.  
  489. int compare(const subString& x, const char* y)
  490. {
  491.     if (y == 0)
  492.     return x.length();
  493.     else
  494.     {
  495.     const char* a = x.chars();
  496.     int n = x.length();
  497.     signed char diff;
  498.     while (n-- > 0) if ((diff = *a++ - *y++) != 0) return diff;
  499.     return (*y == 0) ? 0 : -1;
  500.     }
  501. }
  502.  
  503. int compare(const char *x, const subString& y)
  504. {
  505.     if (x == 0)
  506.     return y.length();
  507.     else
  508.     {
  509.     const char* a = y.chars();
  510.     int n = y.length();
  511.     signed char diff;
  512.     while (n-- > 0) if ((diff = *x++ - *a++) != 0) return diff;
  513.     return (*x == 0) ? 0 : -1;
  514.     }
  515. }
  516.  
  517.  
  518. /*
  519.  index fcts
  520. */
  521.  
  522. int string::search(int start, int sl, char c) const
  523. {
  524.     const char* s = chars();
  525.     if (sl > 0)
  526.     {
  527.     if (start >= 0)
  528.     {
  529.         const char* a = &(s[start]);
  530.         const char* lasta = &(s[sl]);
  531.         while (a < lasta) if (*a++ == c) return --a - s;
  532.     }
  533.     else
  534.     {
  535.         const char* a = &(s[sl + start + 1]);
  536.         while (--a >= s) if (*a == c) return a - s;
  537.     }
  538.     }
  539.     return -1;
  540. }
  541.  
  542. int string::search(int start, int sl, const char* t, int tl) const
  543. {
  544.     const char* s = chars();
  545.     if (tl < 0) tl = slen(t);
  546.     if (sl > 0 && tl > 0)
  547.     {
  548.     if (start >= 0)
  549.     {
  550.         const char* lasts = &(s[sl - tl]);
  551.         const char* lastt = &(t[tl]);
  552.         const char* p = &(s[start]);
  553.  
  554.         while (p <= lasts)
  555.         {
  556.         const char* x = p++;
  557.         const char* y = t;
  558.         while (*x++ == *y++) if (y >= lastt) return --p - s;
  559.         }
  560.     }
  561.     else
  562.     {
  563.         const char* firsts = &(s[tl - 1]);
  564.         const char* lastt =  &(t[tl - 1]);
  565.         const char* p = &(s[sl + start + 1]); 
  566.  
  567.         while (--p >= firsts)
  568.         {
  569.         const char* x = p;
  570.         const char* y = lastt;
  571.         while (*x-- == *y--) if (y < t) return ++x - s;
  572.         }
  573.     }
  574.     }
  575.     return -1;
  576. }
  577.  
  578. int string::match(int start, int sl, int exact, const char* t, int tl) const
  579. {
  580.     if (tl < 0) tl = slen(t);
  581.  
  582.     if (start < 0)
  583.     {
  584.     start = sl + start - tl + 1;
  585.     if (start < 0 || (exact && start != 0))
  586.         return -1;
  587.     }
  588.     else if (exact && sl - start != tl)
  589.     return -1;
  590.  
  591.     if (sl == 0 || tl == 0 || sl - start < tl || start >= sl)
  592.     return -1;
  593.  
  594.     int n = tl;
  595.     const char* s = &(rep->s[start]);
  596.     while (--n >= 0) if (*s++ != *t++) return -1;
  597.     return tl;
  598. }
  599.  
  600. void subString::assign(strRep* ysrc, const char* ys, int ylen)
  601. {
  602.     if (&S == &_nilstring) return;
  603.  
  604.     assert(!S.consuming());
  605.  
  606.     if (ylen < 0) ylen = slen(ys);
  607.     strRep* targ = S.rep;
  608.     unsigned sl = targ->len - len + ylen;
  609.  
  610.     if (ysrc == targ || sl >= string_Sremainder(targ))
  611.     {
  612.     strRep* oldtarg = targ;
  613.     targ = string_Sresize(0, sl);
  614.     ncopy(oldtarg->s, targ->s, pos);
  615.     ncopy(ys, &(targ->s[pos]), ylen);
  616.     scopy(&(oldtarg->s[pos + len]), &(targ->s[pos + ylen]));
  617.     string_DeleteRep(oldtarg);
  618.     }
  619.     else if (len == unsigned(ylen))
  620.     ncopy(ys, &(targ->s[pos]), len);
  621.     else if (unsigned(ylen) < len)
  622.     {
  623.     ncopy(ys, &(targ->s[pos]), ylen);
  624.     scopy(&(targ->s[pos + len]), &(targ->s[pos + ylen]));
  625.     }
  626.     else
  627.     {
  628.     revcopy(&(targ->s[targ->len]), &(targ->s[sl]), targ->len-pos-len +1);
  629.     ncopy(ys, &(targ->s[pos]), ylen);
  630.     }
  631.     targ->len = sl;
  632.     S.rep = targ;
  633. }
  634.  
  635.  
  636.  
  637. /*
  638.  * substitution
  639.  */
  640.  
  641.  
  642. int string::_gsub(const char* pat, int pl, const char* r, int rl)
  643. {
  644.     assert(!consuming());
  645.  
  646.     int nmatches = 0;
  647.     if (pl < 0) pl = slen(pat);
  648.     if (rl < 0) rl = slen(r);
  649.     int sl = length();
  650.     if (sl <= 0 || pl <= 0 || sl < pl)
  651.     return nmatches;
  652.   
  653.     const char* s = chars();
  654.  
  655.     // prepare to make new rep
  656.     strRep* nrep = 0;
  657.     int nsz = 0;
  658.     char* x = 0;
  659.  
  660.     int si = 0;
  661.     int xi = 0;
  662.     int remaining = sl;
  663.  
  664.     while (remaining >= pl)
  665.     {
  666.     int pos = search(si, sl, pat, pl);
  667.     if (pos < 0)
  668.         break;
  669.     else
  670.     {
  671.         ++nmatches;
  672.         int mustfit = xi + remaining + rl - pl;
  673.         if (mustfit >= nsz)
  674.         {
  675.         if (nrep != 0) nrep->len = xi;
  676.         nrep = string_Sresize(nrep, mustfit);
  677.         nsz = string_Sremainder(nrep);
  678.         x = nrep->s;
  679.         }
  680.         pos -= si;
  681.         ncopy(&(s[si]), &(x[xi]), pos);
  682.         ncopy(r, &(x[xi + pos]), rl);
  683.         si += pos + pl;
  684.         remaining -= pos + pl;
  685.         xi += pos + rl;
  686.     }
  687.     }
  688.  
  689.     if (nrep == 0)
  690.     {
  691.     if (nmatches == 0)
  692.         return nmatches;
  693.     else
  694.         nrep = string_Sresize(nrep, xi+remaining);
  695.     }
  696.  
  697.     ncopy0(&(s[si]), &(x[xi]), remaining);
  698.     nrep->len = xi + remaining;
  699.  
  700.     if (nrep->len <= rep->allocated)   // fit back in if possible
  701.     {
  702.     rep->len = nrep->len;
  703.     rep->s = &(rep->mem[0]);
  704.     ncopy0(nrep->s, rep->s, rep->len);
  705.     string_DeleteRep(nrep);
  706.     }
  707.     else
  708.     {
  709.     string_DeleteRep(rep);
  710.     rep = nrep;
  711.     }
  712.     return nmatches;
  713. }
  714.  
  715. int string::_gsub(const regex& pat, const char* r, int rl)
  716. {
  717.     assert(!consuming());
  718.  
  719.     int nmatches = 0;
  720.     int sl = length();
  721.     if (sl <= 0)
  722.     return nmatches;
  723.  
  724.     if (rl < 0) rl = slen(r);
  725.  
  726.     const char* s = chars();
  727.  
  728.     strRep* nrep = 0;
  729.     int nsz = 0;
  730.  
  731.     char* x = 0;
  732.  
  733.     int si = 0;
  734.     int xi = 0;
  735.     int remaining = sl;
  736.     int  pos, pl = 0;        // how long is a regular expression?
  737.  
  738.     while (remaining > 0)
  739.     {
  740.     // unlike string search, the pos returned here is absolute
  741.     pos = pat.search(s, sl, pl, si);
  742.     if (pos < 0 || pl <= 0)
  743.         break;
  744.     else
  745.     {
  746.         ++nmatches;
  747.         int mustfit = xi + remaining + rl - pl;
  748.         if (mustfit >= nsz)
  749.         {
  750.         if (nrep != 0) nrep->len = xi;
  751.         nrep = string_Sresize(nrep, mustfit);
  752.         x = nrep->s;
  753.         nsz = string_Sremainder(nrep);
  754.         }
  755.         pos -= si;
  756.         ncopy(&(s[si]), &(x[xi]), pos);
  757.         ncopy(r, &(x[xi + pos]), rl);
  758.         si += pos + pl;
  759.         remaining -= pos + pl;
  760.         xi += pos + rl;
  761.     }
  762.     }
  763.  
  764.     if (nrep == 0)
  765.     {
  766.     if (nmatches == 0)
  767.         return nmatches;
  768.     else
  769.         nrep = string_Sresize(nrep, xi+remaining);
  770.     }
  771.  
  772.     ncopy0(&(s[si]), &(x[xi]), remaining);
  773.     nrep->len = xi + remaining;
  774.  
  775.     if (nrep->len <= rep->allocated)   // fit back in if possible
  776.     {
  777.     rep->len = nrep->len;
  778.     rep->s = &(rep->mem[0]);
  779.     ncopy0(nrep->s, rep->s, rep->len);
  780.     string_DeleteRep(nrep);
  781.     }
  782.     else
  783.     {
  784.     string_DeleteRep(rep);
  785.     rep = nrep;
  786.     }
  787.     return nmatches;
  788. }
  789.  
  790.  
  791. /*
  792.  * deletion
  793.  */
  794.  
  795. void string::del(int pos, int len)
  796. {
  797.     assert(!consuming());
  798.  
  799.     if (pos < 0 || len <= 0 || (unsigned)(pos + len) > length()) return;
  800.     int nlen = length() - len;
  801.     int first = pos + len;
  802.     ncopy0(&(rep->s[first]), &(rep->s[pos]), length() - first);
  803.     rep->len = nlen;
  804. }
  805.  
  806. void string::del(const regex& r, int startpos)
  807. {
  808.     int mlen;
  809.     int first = r.search(chars(), length(), mlen, startpos);
  810.     del(first, mlen);
  811. }
  812.  
  813. void string::del(const char* t, int startpos)
  814. {
  815.     int tlen = slen(t);
  816.     int p = search(startpos, length(), t, tlen);
  817.     del(p, tlen);
  818. }
  819.  
  820. void string::del(const string& y, int startpos)
  821. {
  822.     del(search(startpos, length(), y.chars(), y.length()), y.length());
  823. }
  824.  
  825. void string::del(const subString& y, int startpos)
  826. {
  827.     del(search(startpos, length(), y.chars(), y.length()), y.length());
  828. }
  829.  
  830. void string::del(char c, int startpos)
  831. {
  832.     del(search(startpos, length(), c), 1);
  833. }
  834.  
  835. /*
  836.  * subString extraction
  837.  */
  838.  
  839.  
  840. subString string::at(int first, int len)
  841. {
  842.     return _substr(first, len);
  843. }
  844.  
  845. subString string::operator() (int first, int len)
  846. {
  847.     return _substr(first, len);
  848. }
  849.  
  850. subString string::before(int pos)
  851. {
  852.     return _substr(0, pos);
  853. }
  854.  
  855. subString string::through(int pos)
  856. {
  857.     return _substr(0, pos+1);
  858. }
  859.  
  860. subString string::after(int pos)
  861. {
  862.     return _substr(pos + 1, length() - (pos + 1));
  863. }
  864.  
  865. subString string::from(int pos)
  866. {
  867.     return _substr(pos, length() - pos);
  868. }
  869.  
  870. subString string::at(const string& y, int startpos)
  871. {
  872.     int first = search(startpos, length(), y.chars(), y.length());
  873.     return _substr(first,  y.length());
  874. }
  875.  
  876. subString string::at(const subString& y, int startpos)
  877. {
  878.     int first = search(startpos, length(), y.chars(), y.length());
  879.     return _substr(first, y.length());
  880. }
  881.  
  882. subString string::at(const regex& r, int startpos)
  883. {
  884.     int mlen;
  885.     int first = r.search(chars(), length(), mlen, startpos);
  886.     return _substr(first, mlen);
  887. }
  888.  
  889. subString string::at(const char* t, int startpos)
  890. {
  891.     int tlen = slen(t);
  892.     int first = search(startpos, length(), t, tlen);
  893.     return _substr(first, tlen);
  894. }
  895.  
  896. subString string::at(char c, int startpos)
  897. {
  898.     int first = search(startpos, length(), c);
  899.     return _substr(first, 1);
  900. }
  901.  
  902. subString string::before(const string& y, int startpos)
  903. {
  904.     int last = search(startpos, length(), y.chars(), y.length());
  905.     return _substr(0, last);
  906. }
  907.  
  908. subString string::before(const subString& y, int startpos)
  909. {
  910.     int last = search(startpos, length(), y.chars(), y.length());
  911.     return _substr(0, last);
  912. }
  913.  
  914. subString string::before(const regex& r, int startpos)
  915. {
  916.     int mlen;
  917.     int first = r.search(chars(), length(), mlen, startpos);
  918.     return _substr(0, first);
  919. }
  920.  
  921. subString string::before(char c, int startpos)
  922. {
  923.     int last = search(startpos, length(), c);
  924.     return _substr(0, last);
  925. }
  926.  
  927. subString string::before(const char* t, int startpos)
  928. {
  929.     int tlen = slen(t);
  930.     int last = search(startpos, length(), t, tlen);
  931.     return _substr(0, last);
  932. }
  933.  
  934. subString string::through(const string& y, int startpos)
  935. {
  936.     int last = search(startpos, length(), y.chars(), y.length());
  937.     if (last >= 0) last += y.length();
  938.     return _substr(0, last);
  939. }
  940.  
  941. subString string::through(const subString& y, int startpos)
  942. {
  943.     int last = search(startpos, length(), y.chars(), y.length());
  944.     if (last >= 0) last += y.length();
  945.     return _substr(0, last);
  946. }
  947.  
  948. subString string::through(const regex& r, int startpos)
  949. {
  950.     int mlen;
  951.     int first = r.search(chars(), length(), mlen, startpos);
  952.     if (first >= 0) first += mlen;
  953.     return _substr(0, first);
  954. }
  955.  
  956. subString string::through(char c, int startpos)
  957. {
  958.     int last = search(startpos, length(), c);
  959.     if (last >= 0) last += 1;
  960.     return _substr(0, last);
  961. }
  962.  
  963. subString string::through(const char* t, int startpos)
  964. {
  965.     int tlen = slen(t);
  966.     int last = search(startpos, length(), t, tlen);
  967.     if (last >= 0) last += tlen;
  968.     return _substr(0, last);
  969. }
  970.  
  971. subString string::after(const string& y, int startpos)
  972. {
  973.     int first = search(startpos, length(), y.chars(), y.length());
  974.     if (first >= 0) first += y.length();
  975.     return _substr(first, length() - first);
  976. }
  977.  
  978. subString string::after(const subString& y, int startpos)
  979. {
  980.     int first = search(startpos, length(), y.chars(), y.length());
  981.     if (first >= 0) first += y.length();
  982.     return _substr(first, length() - first);
  983. }
  984.  
  985. subString string::after(char c, int startpos)
  986. {
  987.     int first = search(startpos, length(), c);
  988.     if (first >= 0) first += 1;
  989.     return _substr(first, length() - first);
  990. }
  991.  
  992. subString string::after(const regex& r, int startpos)
  993. {
  994.     int mlen;
  995.     int first = r.search(chars(), length(), mlen, startpos);
  996.     if (first >= 0) first += mlen;
  997.     return _substr(first, length() - first);
  998. }
  999.  
  1000. subString string::after(const char* t, int startpos)
  1001. {
  1002.     int tlen = slen(t);
  1003.     int first = search(startpos, length(), t, tlen);
  1004.     if (first >= 0) first += tlen;
  1005.     return _substr(first, length() - first);
  1006. }
  1007.  
  1008. subString string::from(const string& y, int startpos)
  1009. {
  1010.     int first = search(startpos, length(), y.chars(), y.length());
  1011.     return _substr(first, length() - first);
  1012. }
  1013.  
  1014. subString string::from(const subString& y, int startpos)
  1015. {
  1016.     int first = search(startpos, length(), y.chars(), y.length());
  1017.     return _substr(first, length() - first);
  1018. }
  1019.  
  1020. subString string::from(const regex& r, int startpos)
  1021. {
  1022.     int mlen;
  1023.     int first = r.search(chars(), length(), mlen, startpos);
  1024.     return _substr(first, length() - first);
  1025. }
  1026.  
  1027. subString string::from(char c, int startpos)
  1028. {
  1029.     int first = search(startpos, length(), c);
  1030.     return _substr(first, length() - first);
  1031. }
  1032.  
  1033. subString string::from(const char* t, int startpos)
  1034. {
  1035.     int tlen = slen(t);
  1036.     int first = search(startpos, length(), t, tlen);
  1037.     return _substr(first, length() - first);
  1038. }
  1039.  
  1040.  
  1041.  
  1042. /*
  1043.  * split/join
  1044.  */
  1045.  
  1046.  
  1047. int split(const string& src, string *results, int n, const string& sep)
  1048. {
  1049.     string x = src;
  1050.     const char* s = x.chars();
  1051.     int sl = x.length();
  1052.     int i = 0;
  1053.     int pos = 0;
  1054.     while (i < n && pos < sl)
  1055.     {
  1056.     int p = x.search(pos, sl, sep.chars(), sep.length());
  1057.     if (p < 0)
  1058.         p = sl;
  1059.     results[i].rep = string_Salloc(results[i].rep, &(s[pos]), p - pos, p - pos);
  1060.     i++;
  1061.     pos = p + sep.length();
  1062.     }
  1063.     return i;
  1064. }
  1065.  
  1066. int split(const string& src, string *results, int n, const regex& r)
  1067. {
  1068.     string x = src;
  1069.     const char* s = x.chars();
  1070.     int sl = x.length();
  1071.     int i = 0;
  1072.     int pos = 0;
  1073.     int p, matchlen;
  1074.     while (i < n && pos < sl)
  1075.     {
  1076.     p = r.search(s, sl, matchlen, pos);
  1077.     if (p < 0)
  1078.         p = sl;
  1079.     results[i].rep = string_Salloc(results[i].rep, &(s[pos]), p - pos, p - pos);
  1080.     i++;
  1081.     pos = p + matchlen;
  1082.     }
  1083.     return i;
  1084. }
  1085.  
  1086. string join(string *src, int n, const string& separator) RETURNS(x)
  1087. {
  1088.     RETURN_OBJECT(string, x);
  1089.     string sep = separator;
  1090.     int xlen = 0;
  1091.     int i;
  1092.     for (i = 0; i < n; ++i)
  1093.     xlen += src[i].length();
  1094.     xlen += (n - 1) * sep.length();
  1095.  
  1096.     x.alloc(xlen);
  1097.     x.rep->len = xlen;
  1098.  
  1099.     int j = 0;
  1100.   
  1101.     for (i = 0; i < n - 1; ++i)
  1102.     {
  1103.     ncopy(src[i].chars(), &(x.rep->s[j]), src[i].length());
  1104.     j += src[i].length();
  1105.     ncopy(sep.chars(), &(x.rep->s[j]), sep.length());
  1106.     j += sep.length();
  1107.     }
  1108.     ncopy0(src[i].chars(), &(x.rep->s[j]), src[i].length());
  1109.     RETURN(x);
  1110. }
  1111.  
  1112.   
  1113. /*
  1114.  misc
  1115. */
  1116.  
  1117.     
  1118. strRep* string_Sreverse(strRep* src, strRep* dest)
  1119. {
  1120.     int n = src->len;
  1121.     if (src != dest)
  1122.     dest = string_Salloc(dest, src->s, n, n);
  1123.     if (n > 0)
  1124.     {
  1125.     char* a = dest->s;
  1126.     char* b = &(a[n - 1]);
  1127.     while (a < b)
  1128.     {
  1129.         char t = *a;
  1130.         *a++ = *b;
  1131.         *b-- = t;
  1132.     }
  1133.     }
  1134.     return dest;
  1135. }
  1136.  
  1137.  
  1138. strRep* string_Supcase(strRep* src, strRep* dest)
  1139. {
  1140.     int n = src->len;
  1141.     if (src != dest) dest = string_Salloc(dest, src->s, n, n);
  1142.     char* p = dest->s;
  1143.     char* e = &(p[n]);
  1144.     for (; p < e; ++p) if (islower(*p)) *p = toupper(*p);
  1145.     return dest;
  1146. }
  1147.  
  1148. strRep* string_Sdowncase(strRep* src, strRep* dest)
  1149. {
  1150.     int n = src->len;
  1151.     if (src != dest) dest = string_Salloc(dest, src->s, n, n);
  1152.     char* p = dest->s;
  1153.     char* e = &(p[n]);
  1154.     for (; p < e; ++p) if (isupper(*p)) *p = tolower(*p);
  1155.     return dest;
  1156. }
  1157.  
  1158. strRep* string_Scapitalize(strRep* src, strRep* dest)
  1159. {
  1160.     int n = src->len;
  1161.     if (src != dest) dest = string_Salloc(dest, src->s, n, n);
  1162.  
  1163.     char* p = dest->s;
  1164.     char* e = &(p[n]);
  1165.     for (; p < e; ++p)
  1166.     {
  1167.     int at_word;
  1168.     if ((at_word = islower(*p)))
  1169.         *p = toupper(*p);
  1170.     else 
  1171.         at_word = isupper(*p) || isdigit(*p);
  1172.  
  1173.     if (at_word)
  1174.     {
  1175.         while (++p < e)
  1176.         {
  1177.         if (isupper(*p))
  1178.             *p = tolower(*p);
  1179.         else if (!islower(*p) && !isdigit(*p))
  1180.             break;
  1181.         }
  1182.     }
  1183.     }
  1184.     return dest;
  1185. }
  1186.  
  1187. #if HAVE_NAMED_RETURN_VALUES
  1188.  
  1189. #if 0                // already defined in -lg++
  1190. string replicate(char c, int n) return w;
  1191. {
  1192.     w.rep = string_Sresize(w.rep, n);
  1193.     char* p = w.rep->s;
  1194.     while (n-- > 0) *p++ = c;
  1195.     *p = 0;
  1196. }
  1197. #endif
  1198.  
  1199. string replicate(const string& y, int n) return w
  1200. {
  1201.     int len = y.length();
  1202.     w.rep = string_Sresize(w.rep, n * len);
  1203.     char* p = w.rep->s;
  1204.     while (n-- > 0)
  1205.     {
  1206.     ncopy(y.chars(), p, len);
  1207.     p += len;
  1208.     }
  1209.     *p = 0;
  1210. }
  1211.  
  1212. string common_prefix(const string& x, const string& y, int startpos) return r;
  1213. {
  1214.     const char* xchars = x.chars();
  1215.     const char* ychars = y.chars();
  1216.     const char* xs = &(xchars[startpos]);
  1217.     const char* ss = xs;
  1218.     const char* topx = &(xchars[x.length()]);
  1219.     const char* ys = &(ychars[startpos]);
  1220.     const char* topy = &(ychars[y.length()]);
  1221.     int l;
  1222.     for (l = 0; xs < topx && ys < topy && *xs++ == *ys++; ++l);
  1223.     r.rep = string_Salloc(r.rep, ss, l, l);
  1224. }
  1225.  
  1226. string common_suffix(const string& x, const string& y, int startpos) return r;
  1227. {
  1228.     const char* xchars = x.chars();
  1229.     const char* ychars = y.chars();
  1230.     const char* xs = &(xchars[x.length() + startpos]);
  1231.     const char* botx = xchars;
  1232.     const char* ys = &(ychars[y.length() + startpos]);
  1233.     const char* boty = ychars;
  1234.     int l;
  1235.     for (l = 0; xs >= botx && ys >= boty && *xs == *ys ; --xs, --ys, ++l);
  1236.     r.rep = string_Salloc(r.rep, ++xs, l, l);
  1237. }
  1238.  
  1239. #else // !HAVE_NAMED_RETURN_VALUES
  1240.  
  1241. #if 0
  1242. string replicate(char c, int n)
  1243. {
  1244.     string w;
  1245.     w.rep = string_Sresize(w.rep, n);
  1246.     char* p = w.rep->s;
  1247.     while (n-- > 0) *p++ = c;
  1248.     *p = 0;
  1249.     return w;
  1250. }
  1251. #endif
  1252.  
  1253. string replicate(const string& y, int n)
  1254. {
  1255.     string w;
  1256.     int len = y.length();
  1257.     w.rep = string_Sresize(w.rep, n * len);
  1258.     char* p = w.rep->s;
  1259.     while (n-- > 0)
  1260.     {
  1261.     ncopy(y.chars(), p, len);
  1262.     p += len;
  1263.     }
  1264.     *p = 0;
  1265.     return w;
  1266. }
  1267.  
  1268. string common_prefix(const string& x, const string& y, int startpos)
  1269. {
  1270.     string r;
  1271.     const char* xchars = x.chars();
  1272.     const char* ychars = y.chars();
  1273.     const char* xs = &(xchars[startpos]);
  1274.     const char* ss = xs;
  1275.     const char* topx = &(xchars[x.length()]);
  1276.     const char* ys = &(ychars[startpos]);
  1277.     const char* topy = &(ychars[y.length()]);
  1278.     int l;
  1279.     for (l = 0; xs < topx && ys < topy && *xs++ == *ys++; ++l);
  1280.     r.rep = string_Salloc(r.rep, ss, l, l);
  1281.     return r;
  1282. }
  1283.  
  1284. string common_suffix(const string& x, const string& y, int startpos) 
  1285. {
  1286.     string r;
  1287.     const char* xchars = x.chars();
  1288.     const char* ychars = y.chars();
  1289.     const char* xs = &(xchars[x.length() + startpos]);
  1290.     const char* botx = xchars;
  1291.     const char* ys = &(ychars[y.length() + startpos]);
  1292.     const char* boty = ychars;
  1293.     int l;
  1294.     for (l = 0; xs >= botx && ys >= boty && *xs == *ys ; --xs, --ys, ++l);
  1295.     r.rep = string_Salloc(r.rep, ++xs, l, l);
  1296.     return r;
  1297. }
  1298.  
  1299. #endif // !HAVE_NAMED_RETURN_VALUES
  1300.  
  1301. // IO
  1302.  
  1303. istream& operator>>(istream& s, string& x)
  1304. {
  1305. #ifdef _OLD_STREAMS
  1306.     if (!s.good())
  1307.     {
  1308.     return s;
  1309.     }
  1310.     s >> ws;
  1311.     if (!s.good())
  1312.     {
  1313.     return s;
  1314.     }
  1315. #else
  1316.     if (!s.ipfx(0) || (!(s.flags() & ios::skipws) && !ws(s)))
  1317.     {
  1318.     s.clear(ios::failbit|s.rdstate()); // Redundant if using GNU iostreams.
  1319.     return s;
  1320.     }
  1321. #endif
  1322.     int ch;
  1323.     unsigned i = 0;
  1324.     x.rep = string_Sresize(x.rep, 20);
  1325.     register streambuf *sb = s.rdbuf();
  1326.     while ((ch = sb->sbumpc()) != EOF)
  1327.     {
  1328.     if (isspace(ch))
  1329.         break;
  1330.     if (i >= string_Sremainder(x.rep) - 1)
  1331.         x.rep = string_Sresize(x.rep, i+1);
  1332.     x.rep->s[i++] = ch;
  1333.     }
  1334.     x.rep->s[i] = 0;
  1335.     x.rep->len = i;
  1336.     int new_state = s.rdstate();
  1337.     if (i == 0) new_state |= ios::failbit;
  1338.     if (ch == EOF) new_state |= ios::eofbit;
  1339.     s.clear(new_state);
  1340.     return s;
  1341. }
  1342.  
  1343. int readline(istream& s, string& x, char terminator, int discard)
  1344. {
  1345.     assert(!x.consuming());
  1346.  
  1347. #ifdef _OLD_STREAMS
  1348.     if (!s.good())
  1349. #else
  1350.     if (!s.ipfx(0))
  1351. #endif
  1352.     {
  1353.         return 0;
  1354.     }
  1355.     int ch;
  1356.     unsigned i = 0;
  1357.     x.rep = string_Sresize(x.rep, 80);
  1358.     register streambuf *sb = s.rdbuf();
  1359.     while ((ch = sb->sbumpc()) != EOF)
  1360.     {
  1361.     if (ch != terminator || !discard)
  1362.     {
  1363.         if (i >= string_Sremainder(x.rep) - 1)
  1364.         x.rep = string_Sresize(x.rep, i+1);
  1365.         x.rep->s[i++] = ch;
  1366.     }
  1367.     if (ch == terminator)
  1368.         break;
  1369.     }
  1370.     x.rep->s[i] = 0;
  1371.     x.rep->len = i;
  1372.     if (ch == EOF) s.clear(s.rdstate() | ios::eofbit);
  1373.     return i;
  1374. }
  1375.  
  1376.  
  1377.  
  1378.  
  1379. // from John.Willis@FAS.RI.CMU.EDU
  1380.  
  1381. int string::freq(const subString& y) const
  1382. {
  1383.     int found = 0;
  1384.     for (unsigned int i = 0; i < length(); i++) 
  1385.     if (match(i,length(),0,y.chars(), y.length())>= 0) found++;
  1386.     return(found);
  1387. }
  1388.  
  1389. int string::freq(const string& y) const
  1390. {
  1391.     int found = 0;
  1392.     for (unsigned int i = 0; i < length(); i++) 
  1393.     if (match(i,length(),0,y.chars(),y.length()) >= 0) found++;
  1394.     return(found);
  1395. }
  1396.  
  1397. int string::freq(const char* t) const
  1398. {
  1399.     int found = 0;
  1400.     for (unsigned int i = 0; i < length(); i++) 
  1401.     if (match(i,length(),0,t) >= 0) found++;
  1402.     return(found);
  1403. }
  1404.  
  1405. int string::freq(char c) const
  1406. {
  1407.     int found = 0;
  1408.     for (unsigned int i = 0; i < length(); i++) 
  1409.     if (match(i,length(),0,&c,1) >= 0) found++;
  1410.     return(found);
  1411. }
  1412.  
  1413.  
  1414. bool string::OK() const
  1415. {
  1416.     if (rep == 0                       // Don't have a rep
  1417.     || rep->len > string_Sremainder(rep)   // Len out of bounds
  1418.     || rep->s < rep->mem                   // Ptr out of bounds
  1419.     || rep->s >= rep->mem + rep->allocated // Ptr out of bounds
  1420.     || rep->s[rep->len] != '\0')           // Not null-terminated
  1421.     error("invariant failure");
  1422.  
  1423.     return true;
  1424. }
  1425.  
  1426. bool subString::OK() const
  1427. {
  1428.     // Check for legal string and pos and len outside bounds
  1429.     if (!S.OK() || pos + len > S.rep->len)
  1430.     S.error("subString invariant failure");
  1431.     return true;
  1432. }
  1433.