home *** CD-ROM | disk | FTP | other *** search
/ PC World 1998 October / PCWorld_1998-10_cd.bin / software / prehled / komix / DATA.Z / String.cxx < prev    next >
C/C++ Source or Header  |  1997-06-12  |  20KB  |  931 lines

  1. /*---------------------------------------------------------------------------
  2.  *
  3.  * Copyright (c) 1993 by Westmount Technology B.V., Delft, The Netherlands.
  4.  *
  5.  * This software is furnished under a license and may be used only in
  6.  * accordance with the terms of such license and with the inclusion of
  7.  * the above copyright notice. This software or any other copies thereof
  8.  * may not be provided or otherwise made available to any other person.
  9.  * No title to and ownership of the software is hereby transferred.
  10.  *
  11.  * The information in this software is subject to change without notice
  12.  * and should not be construed as a commitment by Westmount Technology B.V.
  13.  *
  14.  *---------------------------------------------------------------------------
  15.  *
  16.  *    File        : @(#)String.cxx    /main/titanic/1    (1.7) (1.5)
  17.  *    Author        : NIH, erel
  18.  *    Original date    : 
  19.  *    Description    : Class String implements reference counted character
  20.  *        String objects.  Operations provided include + (concatenation)
  21.  *        and () (SubString extraction).  Type conversions between
  22.  *        String and char* are provided, permitting the two to be used
  23.  *        interchangeably in many contexts.
  24.  *    History        : March 1993: addded reference counting
  25.  *
  26.  *        Originally derived from String in the NIH-classes
  27.  *            Authors:
  28.  *                C. J. Eppich and K. E. Gorlen
  29.  *                Bg. 12A, Rm. 2033
  30.  *                Computer Systems Laboratory
  31.  *                Division of Computer Research and Technology
  32.  *                National Institutes of Health
  33.  *                Bethesda, Maryland 20892
  34.  *                uucp: uunet!nih-csl!kgorlen
  35.  *                Internet: kgorlen@alw.nih.gov
  36.  *
  37.  *---------------------------------------------------------------------------
  38.  */
  39. static const char SccsId[]=
  40. "@(#)String.cxx    /main/titanic/1    (1.7) (1.5)\t09 Jan 1996 Copyright 1993 Westmount Technology";
  41.  
  42. #include "String.hxx"
  43.  
  44. #include <stdlib.h>
  45. #include <string.h>
  46. #include <iostream.h>
  47. /* ctype used in an NLS-safe way! */
  48. #include <ctype.h>
  49. #include <malloc.h>
  50. #include <new.h>
  51. #include <assert.h>
  52.  
  53. /*
  54. ** MSVC MFC output
  55. */
  56. #ifdef _MSC_VER
  57. #define NOCRTOUTPUT 1
  58. #endif
  59.  
  60. /*
  61. ** Allocation
  62. */
  63.  
  64. static void
  65. insufficient_memory(void)
  66. {
  67.     void (*old_new_handler)(void) = set_new_handler(0);
  68.     if ( !old_new_handler ) {
  69. #ifndef NOCRTOUTPUT
  70.     cerr << "[INSUFMEM] No stringspace left" << endl;
  71. #endif
  72.     abort();
  73.     }
  74.  
  75.     (*old_new_handler)();
  76.     set_new_handler(old_new_handler);
  77.     return;
  78. }
  79.  
  80. static char*
  81. new_String(size_t sz)
  82. {
  83.     void *buf = malloc(sz);
  84.     if ( buf )
  85.     return (char*)buf;
  86.  
  87.     insufficient_memory();
  88.     return NULL;
  89. }
  90.  
  91. static char*
  92. string_realloc(char* p, size_t sz)
  93. {
  94.     void *buf = realloc(p, sz);
  95.     if ( buf )
  96.     return (char*)buf;
  97.  
  98.     insufficient_memory();
  99.     return NULL;
  100. }
  101.  
  102.  
  103. inline unsigned int
  104. MIN(unsigned int a, unsigned int b)
  105. { return a <= b ? a : b; }
  106.  
  107.  
  108. /* System-independent versions of toupper and tolower */
  109.  
  110. inline char
  111. to_upper(unsigned char c)
  112. { return (islower((int)c) ? toupper((int)c): c); }
  113.  
  114. inline char
  115. to_lower(unsigned char c)
  116. { return (isupper((int)c) ? tolower((int)c): c); }
  117.  
  118.  
  119. inline unsigned
  120. mod_sizeof_int(unsigned i)
  121.     { return sizeof(int)&sizeof(int)-1 ? i%sizeof(int) : i&sizeof(int)-1; }
  122.  
  123. inline unsigned
  124. div_sizeof_int(unsigned i)
  125.     { return i >> 2; }
  126.  
  127.  
  128. /*
  129. ** String representation
  130. */
  131.  
  132. struct fakeRep
  133. /*
  134. ** Hack to circumvent initialization (ordering) problems:
  135. ** theEmptyRep should be fully initialized before any (global)
  136. ** empty String is created.
  137. */
  138. {
  139.     unsigned rc;
  140.     unsigned ln;
  141.     char* p;
  142. };
  143.  
  144. static int sanity_check(void)
  145. {
  146.     assert( sizeof(fakeRep) == sizeof(StringRep) );
  147.     return 1;
  148. }
  149.  
  150. static int fake_ok = sanity_check();
  151. static fakeRep empty_rep = { 1, 0, "" };
  152. StringRep* const String::theEmptyRep = (StringRep* const)& empty_rep;
  153.  
  154.  
  155. StringRep::StringRep(void):
  156.     refcount (1),
  157.     len (0)
  158. {
  159.     p = new_String(1);
  160.     p[0] = '\0';
  161. }
  162.  
  163.  
  164. StringRep::StringRep(const StringRep& sr):
  165.     refcount (1),
  166.     len (sr.len)
  167. {
  168.     p = new_String(len+1);
  169.     strcpy(p, sr.p);
  170. }
  171.  
  172.  
  173. StringRep::StringRep(const char* cp):
  174.     refcount (1),
  175.     len (strlen(cp))
  176. {
  177.     p = new_String(len+1);
  178.     strcpy(p, cp);
  179. }
  180.  
  181.  
  182. StringRep::StringRep(char* buf, unsigned buflen):
  183.     refcount (1),
  184.     len (buflen-1),
  185.     p (buf)
  186. { /* empty */ }
  187.  
  188.  
  189. StringRep::~StringRep(void)
  190. {
  191.     free(p);
  192. }
  193.  
  194.  
  195. const StringRep&
  196. StringRep::operator= (const StringRep& sr)
  197. {
  198.     if ( &sr != this ) {
  199.     refcount = 1;
  200.     len = sr.len;
  201.     p = string_realloc(p, len+1);
  202.     strcpy(p, sr.p);
  203.     }
  204.     return *this;
  205. }
  206.  
  207.  
  208. unsigned
  209. StringRep::hash() const
  210. {
  211.     register unsigned h = len;
  212.     register unsigned i = div_sizeof_int(len);
  213.     register unsigned* q = (unsigned*)p;
  214.     while (i--) h ^= *q++;
  215.     if ((i = mod_sizeof_int(len)) != 0)
  216.     {
  217.     unsigned tailHash = 0;
  218.     memcpy((char*)&tailHash, (char*)q, i);
  219.     h ^= tailHash;
  220.     }
  221.     return h;
  222. }
  223.  
  224.  
  225. void
  226. StringRep::toAscii(void)
  227. {
  228.     register unsigned i = len;
  229.     register char* q = p;
  230.     while (i--) { *q = toascii((int)((unsigned char)*q)); q++; }
  231. }
  232.  
  233. void
  234. StringRep::toLower()
  235. {
  236.     register unsigned i = len;
  237.     register char* q = p;
  238.     while (i--) { *q = to_lower(*q); q++; }
  239. }
  240.  
  241. void
  242. StringRep::toUpper()
  243. {
  244.     register unsigned i = len;
  245.     register char* q = p;
  246.     while (i--) { *q = to_upper(*q); q++; }
  247. }
  248.  
  249. void
  250. StringRep::replace(const Range& r, const char* src, unsigned srclen)
  251. // Replace a SubString with the argument string
  252. // Terminology:
  253. //    head: portion of destination String before this SubString
  254. //    tail: portion of destination String after this SubString
  255. {
  256. #   ifdef DEBUG
  257.     cerr << "replacing " << p << '[' << r << ']' << " by ";
  258.     cerr.write(src, srclen);
  259.     cerr << " ...\n";
  260. #   endif
  261.  
  262.     int overlap = 0;    // src overlaps destination string
  263.     int tailDelta = 0;    // amount to adjust for tail movement
  264.     char* srcbuf = 0;    // buffer to hold src if it overlaps SubString
  265.  
  266.     if (src >= p && src <= &p[len]) {
  267.     // src overlaps destination string
  268.     overlap = 1;
  269.     if (src > &p[r.lastIndex()]) {
  270.         // src overlaps only tail of destination string
  271.         tailDelta = srclen-r.length();
  272.     }
  273.     else {        
  274.         if (src+srclen > &p[r.firstIndex()]) {
  275.         // src overlaps the SubString: move src to buffer
  276.         srcbuf = new char[srclen];
  277.         strncpy(srcbuf,src,srclen);
  278.         src = srcbuf;
  279.         overlap = 0;    // no overlap now
  280.         }
  281.     }
  282.     }
  283.  
  284. #   ifdef DEBUG
  285.     cerr << "overlap=" << overlap
  286.          << "  tailDelta=" << tailDelta
  287.          << "  srcbuf=" << (const void*)srcbuf << '\n';
  288. #   endif
  289.  
  290.     char* old_p = p;
  291.     unsigned new_len = len + srclen - r.length();
  292.     if ( new_len > len )    // stretch
  293.     p = string_realloc(p, new_len + 1);
  294.  
  295.     if ( overlap ) src += p - old_p;
  296.  
  297.     if ( srclen < r.length() ) {
  298.     // shift tail down
  299.     register const char* src_p = &p[r.lastIndex()+1];
  300.     register char* dst_p = &p[r.firstIndex()+srclen];
  301.     while (*dst_p++ = *src_p++);
  302.     }
  303.     else if ( srclen > r.length() ) {
  304.     // shift tail up
  305.     register const char* src_p = &p[len];
  306.     register char* dst_p = &p[new_len];
  307.     register unsigned n = len - r.lastIndex();
  308.     while (n--) *dst_p-- = *src_p--;
  309.     }
  310.     src += tailDelta;
  311.  
  312.     if ( new_len < len ) {
  313.     // shrink
  314.     p = string_realloc(p, new_len+1);
  315.     p[new_len] = '\0';
  316.     }
  317.     len = new_len;
  318.  
  319. #   ifdef DEBUG
  320.     cerr << "target " << *this << " source ";
  321.     cerr.write(src, srclen);
  322.     cerr << endl;
  323. #   endif
  324.  
  325.     strncpy(&p[r.firstIndex()], src, srclen);    // insert src into destination
  326.     delete srcbuf;
  327.  
  328. #   ifdef DEBUG
  329.     cerr << "... result: " << *this << '\n';
  330. #   endif
  331. }
  332.  
  333.  
  334. void
  335. StringRep::append(const char* src, unsigned srclen)
  336. // Append src to buffer
  337. {
  338.     p = string_realloc(p, len+srclen+1);
  339.     strncpy(&p[len], src, srclen);
  340.     len += srclen;
  341.     p[len] = '\0';
  342. }
  343.  
  344.  
  345.  
  346. //==== SubString functions:
  347.  
  348. /*
  349. The following compare functions were implemented because strncmp is
  350. not adequate for comparing character strings of unequal length.  For
  351. example, strncmp("abc","abcd",3) will return 0.
  352. */
  353.  
  354. int
  355. SubString::compare(const char* cs) const
  356. /*
  357. Return integer greater than, equal to, or less than 0, according as
  358. this SubString is lexicographically greater than, equal to, or less
  359. than cs.
  360. */
  361. {
  362.     int cl = strlen(cs);
  363.     int result = strncmp(ptr(), cs, length());
  364.     if (result != 0 || length() == cl) return result;
  365.     return (length()>cl ? 1 : -1);
  366. }
  367.  
  368. int
  369. SubString::compare(const String& s) const
  370. /*
  371. Return integer greater than, equal to, or less than 0, according as
  372. this SubString is lexicographically greater than, equal to, or less
  373. than s.
  374. */
  375. {
  376.     int result = strncmp(ptr(), s, length());
  377.     if (result != 0 || length() == s.length()) return result;
  378.     return (length()>s.length() ? 1 : -1);
  379. }
  380.  
  381. int
  382. SubString::compare(const SubString& ss) const
  383. /*
  384. Return integer greater than, equal to, or less than 0, according as
  385. this SubString is lexicographically greater than, equal to, or less
  386. than SubString ss.
  387. */
  388. {
  389.     int result = strncmp(ptr(), ss.ptr(), MIN(length(), ss.length()));
  390.     if (result != 0 || length() == ss.length()) return result;
  391.     return (length()>ss.length() ? 1 : -1);
  392. }
  393.  
  394.  
  395. int
  396. strncoll(const char* s1, const char* s2, int n)
  397. {
  398.     char *replace_p = NULL;
  399.     char  replace_c = '\0';
  400.  
  401.     if ( strlen(s1) > n )
  402.     replace_p = (char*)(&s1[n]);
  403.     else if ( strlen(s2) > n ) 
  404.     replace_p = (char*)(&s2[n]);
  405.     
  406.     if ( replace_p ) {
  407.     replace_c = *replace_p;
  408.     *replace_p = '\0';
  409.     }
  410.  
  411.     // Here at least one String is not longer than n
  412.     // so we can strcoll() them.
  413.     //
  414.     int result = strcoll(s1, s2);
  415.  
  416.     // Repair fumbled string
  417.     if ( replace_p ) *replace_p = replace_c;
  418.  
  419.     return result;
  420. }
  421.  
  422.  
  423. int
  424. SubString::collate(const char* cs) const
  425. /*
  426. Return integer greater than, equal to, or less than 0, according as
  427. this SubString is lexicographically greater than, equal to, or less
  428. than cs (According to the LC_COLLATE category of the current locale).
  429. */
  430. {
  431.     int cl = strlen(cs);
  432.     int result = strncoll(ptr(), cs, length());
  433.     if (result != 0 || length() == cl) return result;
  434.     return (length()>cl ? 1 : -1);
  435. }
  436.  
  437. int
  438. SubString::collate(const String& s) const
  439. /*
  440. Return integer greater than, equal to, or less than 0, according as
  441. this SubString is lexicographically greater than, equal to, or less
  442. than s (According to the LC_COLLATE category of the current locale).
  443. */
  444. {
  445.     int result = strncoll(ptr(), s, length());
  446.     if (result != 0 || length() == s.length()) return result;
  447.     return (length()>s.length() ? 1 : -1);
  448. }
  449.  
  450. int
  451. SubString::collate(const SubString& ss) const
  452. /*
  453. Return integer greater than, equal to, or less than 0, according as
  454. this SubString is lexicographically greater than, equal to, or less
  455. than SubString ss (According to the LC_COLLATE category of the current
  456. locale).
  457. */
  458. {
  459.     // avoid double inline expansion (too complex!?)
  460.     const char* ss_ptr = ss.ptr();
  461.     int ss_len = ss.length();
  462.     int result = strncoll(ptr(), ss_ptr, MIN(length(), ss_len));
  463.     if (result != 0 || length() == ss_len) return result;
  464.     return (length()>ss_len ? 1 : -1);
  465. }
  466.  
  467. SubString::SubString(const String& s, const Range& r):
  468.     st ((String&)s),
  469.     sr (r)
  470. {
  471.     checkSubStr();
  472. }
  473.     
  474. void
  475. SubString::dumpOn(ostream& strm) const
  476. // Dump this SubString on output stream strm.
  477. {
  478.     strm << String(*this);
  479.     strm << '[' << st;
  480.     strm << '(' << sr;
  481.     strm << ")]";
  482. }
  483.  
  484. void
  485. SubString::printOn(ostream& strm) const
  486. // Print this SubString on output stream strm.
  487. {
  488.     strm << String(*this);
  489. }
  490.  
  491.  
  492. static char* scratch_buf = NULL;    // scratch buffer
  493.  
  494. /*
  495. ** operator+ duplicates code to avoid creation of
  496. ** unneccessary temporary strings
  497. */
  498.  
  499. String
  500. SubString::operator+(const SubString& ss) const
  501. {
  502.     unsigned l1 = length();
  503.     unsigned l2 = ss.length();
  504.  
  505.     delete scratch_buf;    // previous result
  506.     scratch_buf = new char[l1 + l2 + 1];
  507.  
  508.     strncpy (scratch_buf, ptr(), l1);
  509.     strncpy (&scratch_buf[l1], ss.ptr(), l2);
  510.     scratch_buf[l1+l2] = '\0';
  511.     return String(scratch_buf);
  512. }
  513.  
  514. String
  515. SubString::operator+(const String& s) const
  516. {
  517.     unsigned l1 = length();
  518.     unsigned l2 = s.length();
  519.  
  520.     delete scratch_buf;    // previous result
  521.     scratch_buf = new char[l1 + l2 + 1];
  522.  
  523.     strncpy (scratch_buf, ptr(), l1);
  524.     strncpy (&scratch_buf[l1], s, l2);
  525.     scratch_buf[l1+l2] = '\0';
  526.     return String(scratch_buf);
  527. }
  528.  
  529. String
  530. SubString::operator+(const char* cs) const
  531. {
  532.     unsigned l1 = length();
  533.     unsigned l2 = strlen(cs);
  534.  
  535.     delete scratch_buf;    // previous result
  536.     scratch_buf = new char[l1 + l2 + 1];
  537.  
  538.     strncpy (scratch_buf, ptr(), l1);
  539.     strncpy (&scratch_buf[l1], cs, l2);
  540.     scratch_buf[l1+l2] = '\0';
  541.     return String(scratch_buf);
  542. }
  543.  
  544. String
  545. SubString::operator+(char c) const
  546. {
  547.     unsigned l1 = length();
  548.  
  549.     delete scratch_buf;    // previous result
  550.     scratch_buf = new char[l1 + 1 + 1];
  551.  
  552.     strncpy (scratch_buf, ptr(), l1);
  553.     scratch_buf[l1] = c;
  554.     scratch_buf[l1+1] = '\0';
  555.     return String(scratch_buf);
  556. }
  557.  
  558. String
  559. operator+(const char* cs, const SubString& ss)
  560. {
  561.     unsigned l1 = strlen(cs);
  562.     unsigned l2 = ss.length();
  563.  
  564.     delete scratch_buf;    // previous result
  565.     scratch_buf = new char[l1 + l2 + 1];
  566.  
  567.     strncpy (scratch_buf, cs, l1);
  568.     strncpy (&scratch_buf[l1], ss.ptr(), l2);
  569.     scratch_buf[l1+l2] = '\0';
  570.     return String(scratch_buf);
  571. }
  572.  
  573. String
  574. operator+(char c, const SubString& ss)
  575. {
  576.     unsigned l2 = ss.length();
  577.  
  578.     delete scratch_buf;    // previous result
  579.     scratch_buf = new char[1 + l2 + 1];
  580.  
  581.     scratch_buf[0] = c;
  582.     strncpy (&scratch_buf[1], ss.ptr(), l2);
  583.     scratch_buf[1+l2] = '\0';
  584.     return String(scratch_buf);
  585. }
  586.  
  587. void
  588. SubString::checkSubStr() const
  589. // check for legal SubString
  590. {
  591.     if ( sr.valid() && sr.lastIndex() <= (int)st.rep->buf_len() )
  592.         return;
  593.  
  594. #ifndef NOCRTOUTPUT
  595.     cerr << "[SUBSTRERR] Substring position/lenght out of Range ("
  596.          << sr.firstIndex() << ','; 
  597.     cerr << sr.length() << ')'
  598.          << endl;
  599. #endif
  600.     abort();
  601. }
  602.  
  603. //==== String functions:
  604.  
  605. void
  606. String::indexRangeErr() const
  607. {
  608. #ifndef NOCRTOUTPUT
  609.     cerr << "[INDEXRANGE] Index out of Range: string@"
  610.          << (void*)this
  611.          << endl;
  612. #endif
  613.     abort();
  614. }
  615.  
  616. void
  617. String::unique()
  618. {
  619.     if ( !rep->shared() ) return;
  620.  
  621.     StringRep* new_rep = new StringRep(*rep);
  622.     rep->removeRef();
  623.     rep = new_rep;
  624. }
  625.  
  626. //==== String Constructors:
  627.  
  628. String::String()
  629. {
  630.     rep = theEmptyRep;
  631.     rep->addRef();
  632. }
  633.  
  634. String::String(const char* cs)
  635. {
  636.     if ( cs[0] == '\0' ) {
  637.     rep = theEmptyRep;
  638.     rep->addRef();
  639.     }
  640.     else
  641.     rep = new StringRep(cs);
  642. }
  643.  
  644. String::String(const String& s):
  645.     rep (s.rep)
  646. {
  647.     rep->addRef();
  648. }
  649.  
  650. String::String(const char c, unsigned l)
  651. {
  652.     assert( l != 1 || isprint(c) );
  653.  
  654.     char* new_buf = new_String(l+1);
  655.     register char* p = &new_buf[l+1];
  656.     *--p = '\0';
  657.     while ( p > new_buf ) *--p = c;
  658.  
  659.     rep = new StringRep(new_buf, l+1);
  660. }
  661.  
  662. String::String(const char c)
  663. {
  664.     char* new_buf = new_String(2);
  665.     new_buf[0] = c;
  666.     new_buf[1] = '\0';
  667.     rep = new StringRep(new_buf, 2);
  668. }
  669.  
  670. String::String(const SubString& ss)
  671. {
  672.     unsigned buflen = ss.length();
  673.     char* new_buf = new_String(buflen+1);
  674.     strncpy(new_buf, ss.ptr(), buflen);
  675.     new_buf[buflen] = '\0';
  676.     rep = new StringRep(new_buf, buflen+1);
  677. }
  678.  
  679. String::~String()
  680. {
  681.     rep->removeRef();
  682. }
  683.  
  684. //==== Operators:
  685.  
  686. SubString
  687. String::operator()(const Range& r)
  688. {
  689.     if ( ! r.valid() ) {
  690. #ifndef NOCRTOUTPUT
  691.     cerr << "[BADRANGE] Invalid or undefined Range ["
  692.          << r
  693.          << "] for SubString" << endl;
  694. #endif
  695.     abort();
  696.     }
  697.     return SubString(*this, r);
  698. }
  699.  
  700. const SubString
  701. String::operator()(const Range& r) const
  702. {
  703.     if ( ! r.valid() ) {
  704. #ifndef NOCRTOUTPUT
  705.     cerr << "[BADRANGE] Invalid or undefined Range ["
  706.          << r
  707.          << "] for SubString" << endl;
  708. #endif
  709.     abort();
  710.     }
  711.     return SubString(*this, r);
  712. }
  713.  
  714. void
  715. String::operator=(const String& s)
  716. {
  717.     if ( &s == this ) return;
  718.     rep->removeRef();
  719.     rep = s.rep;
  720.     rep->addRef();
  721. }
  722.  
  723. void
  724. String::operator=(const SubString& ss)
  725. {
  726.     unsigned ln = ss.length();
  727.     char* new_buf = new_String(ln+1);
  728.     strncpy(new_buf, ss.ptr(), ln);
  729.     new_buf[ln] = '\0';
  730.     rep->removeRef();
  731.     rep = new StringRep(new_buf, ln+1);
  732. }
  733.  
  734. void
  735. String::operator=(const char* cs)
  736. {
  737.     rep->removeRef();
  738.     rep = new StringRep(cs);
  739. }
  740.  
  741. String
  742. String::operator+(const String& s) const
  743. {
  744.     unsigned l1 = length();
  745.     unsigned l2 = s.length();
  746.  
  747.     delete scratch_buf;
  748.     scratch_buf = new char[l1+l2+1];
  749.     strcpy(scratch_buf, rep->buf_ptr());
  750.     strcpy(&scratch_buf[l1], s.rep->buf_ptr());
  751.  
  752.     return String(scratch_buf);
  753. }
  754.  
  755. String
  756. String::operator+(const SubString& ss) const
  757. {
  758.     unsigned l1 = length();
  759.     unsigned l2 = ss.length();
  760.  
  761.     delete scratch_buf;
  762.     scratch_buf = new char[l1+l2+1];
  763.     strcpy(scratch_buf, rep->buf_ptr());
  764.     strncpy(&scratch_buf[l1], ss.ptr(), l2);
  765.     scratch_buf[l1+l2] = '\0';
  766.  
  767.     return String(scratch_buf);
  768. }
  769.  
  770. String
  771. String::operator+(const char* cs) const
  772. {
  773.     unsigned l1 = length();
  774.     unsigned l2 = strlen(cs);
  775.  
  776.     delete scratch_buf;
  777.     scratch_buf = new char[l1+l2+1];
  778.     strcpy(scratch_buf, rep->buf_ptr());
  779.     strcpy(&scratch_buf[l1], cs);
  780.  
  781.     return String(scratch_buf);
  782. }
  783.  
  784. String
  785. String::operator+(char c) const
  786. {
  787.     unsigned l1 = length();
  788.  
  789.     delete scratch_buf;
  790.     scratch_buf = new char[l1+1+1];
  791.     strcpy(scratch_buf, rep->buf_ptr());
  792.     scratch_buf[l1] = c;
  793.     scratch_buf[l1+1] = '\0';
  794.  
  795.     return String(scratch_buf);
  796. }
  797.  
  798. String
  799. operator+(const char* cs, const String& s)
  800. {
  801.     unsigned l1 = strlen(cs);
  802.     unsigned l2 = s.length();
  803.  
  804.     delete scratch_buf;
  805.     scratch_buf = new char[l1+l2+1];
  806.     strcpy(scratch_buf, cs);
  807.     strcpy(&scratch_buf[l1], s);
  808.  
  809.     return String(scratch_buf);
  810. }
  811.  
  812. String
  813. operator+(char c, const String& s)
  814. {
  815.     unsigned l2 = s.length();
  816.  
  817.     delete scratch_buf;
  818.     scratch_buf = new char[1+l2+1];
  819.     scratch_buf[0] = c;
  820.     strcpy(&scratch_buf[1], s);
  821.  
  822.     return String(scratch_buf);
  823. }
  824.  
  825. void
  826. String::operator+=(const String& s)
  827. // Concatenate a String with another
  828. {
  829.     unique();
  830.     rep->append(s, s.length());
  831. }
  832.  
  833. void
  834. String::operator+=(const SubString& ss)
  835. {
  836.     unique();
  837.     rep->append(ss.ptr(), ss.length());
  838. }
  839.  
  840. void
  841. String::operator+=(const char* cs)
  842. {
  843.     unique();
  844.     rep->append(cs, strlen(cs));
  845. }
  846.  
  847. void
  848. String::operator+=(char c)
  849. {
  850.     unique();
  851.     rep->append(&c, 1);
  852. }
  853.  
  854. char&
  855. String::operator[] (unsigned i)
  856. {
  857.     if (i >= length()) indexRangeErr();
  858.     unique();
  859.     return at(i);
  860. }
  861.  
  862. char
  863. String::operator[] (unsigned i) const 
  864. {
  865.     if (i >= length()) indexRangeErr();
  866.     return rep->buf_ptr()[i];
  867. }
  868.  
  869.  
  870. int
  871. String::index(char c, unsigned start_pos) const
  872. {
  873.     if ( c == '\0' || start_pos > length() ) return -1;
  874.  
  875.     const char* where = ::strchr(&rep->buf_ptr()[start_pos],c);
  876.     return ( where ? where - rep->buf_ptr() : -1 );
  877. }
  878.  
  879.  
  880. int
  881. String::rindex(char c, unsigned start_pos) const
  882. {
  883.     register const char* where;
  884.  
  885.     if ( start_pos > length() ) start_pos = length();
  886.  
  887.     for ( where = &rep->buf_ptr()[start_pos]; where > rep->buf_ptr(); where-- )
  888.     {
  889.     if ( *where == c ) {
  890.         return (where - rep->buf_ptr());
  891.     }
  892.     }
  893.     /* where == rep->p */
  894.     if ( *where == c )
  895.     return 0;
  896.     
  897.     return -1;
  898. }
  899.  
  900.  
  901. void
  902. String::printOn(ostream& strm) const
  903. {
  904.     strm << rep->buf_ptr();
  905. }
  906.  
  907. void
  908. String::scanFrom(istream& strm)
  909. //    Read next line of input from strm into this string.
  910. {
  911.     const INPUTBUFSIZE = 512;
  912.  
  913.     ostream* os = strm.tie((ostream*)0);
  914.     if (os != 0) {
  915.     os->flush();
  916.     strm.tie(os);
  917.     }
  918.     char c;
  919.     strm.get(c);
  920.     if (c != '\n') strm.putback(c);
  921.     char temp[INPUTBUFSIZE+1];
  922.     strm.get(temp,INPUTBUFSIZE+1);
  923.     *this = String(temp);
  924.  
  925.     while ( strm.gcount() >= INPUTBUFSIZE ) {
  926.     strm.get(temp,INPUTBUFSIZE+1);
  927.     *this += temp;
  928.     }
  929. }
  930.  
  931.