modules/up/src/gnug++/String.cc

/* [<][>]
[^][v][top][bottom][index][help] */

FUNCTIONS

This source file includes following functions.
  1. error
  2. ncopy
  3. ncopy0
  4. scopy
  5. revcopy
  6. slen
  7. Snew
  8. Salloc
  9. Sresize
  10. alloc
  11. Scopy
  12. Scat
  13. Scat
  14. Sprepend
  15. scmp
  16. ncmp
  17. fcompare
  18. compare
  19. compare
  20. compare
  21. compare
  22. compare
  23. compare
  24. search
  25. search
  26. match
  27. assign
  28. _gsub
  29. _gsub
  30. del
  31. del
  32. del
  33. del
  34. del
  35. del
  36. at
  37. before
  38. through
  39. after
  40. from
  41. at
  42. at
  43. at
  44. at
  45. at
  46. before
  47. before
  48. before
  49. before
  50. before
  51. through
  52. through
  53. through
  54. through
  55. through
  56. after
  57. after
  58. after
  59. after
  60. after
  61. from
  62. from
  63. from
  64. from
  65. from
  66. split
  67. split
  68. RETURN
  69. RETURNS
  70. RETURN_OBJECT
  71. RETURN
  72. RETURNS
  73. RETURN_OBJECT
  74. join
  75. Sreverse
  76. Supcase
  77. Sdowncase
  78. Scapitalize
  79. replicate
  80. replicate
  81. common_prefix
  82. common_suffix
  83. replicate
  84. replicate
  85. common_prefix
  86. common_suffix
  87. readline
  88. freq
  89. freq
  90. freq
  91. freq
  92. OK
  93. OK

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

/* [<][>][^][v][top][bottom][index][help] */