home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / snip9707.zip / STR.CPP < prev    next >
C/C++ Source or Header  |  1997-07-05  |  14KB  |  690 lines

  1. // +++Date last modified: 05-Jul-1997
  2.  
  3. //
  4. // Implements simple string class 'str'
  5. //
  6.  
  7. # include   "str.h"
  8. # include   <string.h>
  9. # include   <ctype.h>
  10. # include   "snip_str.h"                  /* For stristr()  */
  11.  
  12. #if defined(_MSC_VER)
  13.  #include <memory.h>
  14. #elif defined(__TURBOC__)
  15.  #include <mem.h>
  16. #else
  17.  #include <string.h>
  18. #endif
  19.  
  20. # include   <stdlib.h>
  21. # if defined( _MSC_VER )
  22. #  pragma warning(disable:4505)
  23. # endif
  24.  
  25. # define STDLEN 32
  26.  
  27. extern "C" void * malloc (unsigned sz);
  28. extern "C" void free (void * ptr);
  29.  
  30.  
  31. # if defined( PLACEMENT_NEW_BUG )
  32.  
  33. inline void *
  34. operator new (unsigned sz, short allocsz)
  35. {
  36.     return malloc (sz + allocsz);
  37. }
  38.  
  39. # else
  40.  
  41. void *
  42. refstr::operator new (unsigned sz, short allocsz)
  43. {
  44.     return malloc (sz + allocsz);
  45. }
  46.  
  47. # endif
  48.  
  49. unsigned short str::default_flags = 0;
  50.  
  51. str::str(void)
  52. {
  53.     _strinit();
  54. }
  55.  
  56. str::str(char const * s, short len)
  57. {
  58.     _strinit(s, len, -1);
  59. }
  60.  
  61. str::str(unsigned char const * s, short len)
  62. {
  63.     _strinit((char const *)s, len, -1);
  64. }
  65.  
  66. # if !defined( SIGNED_CHAR_BUG )
  67. str::str (signed char const * s, short len)
  68. {
  69.     _strinit((char const *)s, len, -1);
  70. }
  71. # endif
  72.  
  73. str::str (char c)
  74. {
  75.     _strinit (&c, 1, -1);
  76. }
  77.  
  78. str::str (int val, int radix)
  79. {
  80.     Bool    positive;
  81.  
  82.     if (val >= 0)
  83.         positive = True;
  84.     else
  85.     {
  86.         positive = False;
  87.         val = -val;
  88.     }
  89.     _strinit((unsigned long)val, positive, radix);
  90. }
  91.  
  92. str::str (unsigned int val, int radix)
  93. {
  94.     _strinit((unsigned long)val, True, radix);
  95. }
  96.  
  97. str::str (short val, int radix)
  98. {
  99.     Bool    positive;
  100.  
  101.     if (val >= 0)
  102.         positive = True;
  103.     else
  104.     {
  105.         positive = False;
  106.         val = short(-val);
  107.     }
  108.     _strinit((unsigned long)val, positive, radix);
  109. }
  110.  
  111. str::str (unsigned short val, int radix)
  112. {
  113.     _strinit((unsigned long)val, True, radix);
  114. }
  115.  
  116. str::str (long val, int radix)
  117. {
  118.     Bool positive;
  119.  
  120.     if (val >= 0L)
  121.         positive = True;
  122.     else
  123.     {
  124.         positive = False;
  125.         val = -val;
  126.     }
  127.     _strinit((unsigned long)val, positive, radix);
  128. }
  129.  
  130. str::str (unsigned long val, int radix)
  131. {
  132.     _strinit(val, True, radix);
  133. }
  134.  
  135. str::str (unsigned char c)
  136. {
  137.     _strinit ((char const *)&c, 1, -1);
  138. }
  139.  
  140. # if !defined( SIGNED_CHAR_BUG )
  141. str::str (signed char c)
  142. {
  143.     _strinit ((char const *)&c, 1, -1);
  144. }
  145.  
  146. # endif
  147.  
  148. str::str (str const & s)
  149.   : strdata(s.strdata)
  150. {
  151.     ++strdata->_refs;
  152. }
  153.  
  154. str::~str (void)
  155. {
  156.     if (!--strdata->_refs)
  157.         delete strdata;
  158. }
  159.  
  160. void
  161. str::_strinit (char const * s, short len, short siz, unsigned short flgs)
  162. {
  163.     if (len < 0)
  164.         len = (short) ((s) ? strlen (s) : 0);
  165.     if (siz < 0)
  166.         siz = STDLEN;
  167.     if (siz < short(len + 1))
  168.         siz = short(len + 1);
  169.     strdata = new(siz) refstr(len, siz, flgs);
  170.     if (s && len)
  171.         memcpy (c_ptr(), s, len);
  172. }
  173.  
  174. void
  175. str::_strinit (unsigned long val, Bool positive, int radix)
  176. {
  177.     char    buf[32], * p = buf;
  178.  
  179.     if (!positive)
  180.         *p = '-';
  181.     ultoa(val, p, radix);
  182.     _strinit(buf, -1, 0);
  183. }
  184.  
  185. str &
  186. str::clear(void)
  187. {
  188.     if (strdata->_refs == 1)
  189.         strdata->_length = 0;
  190.     else
  191.     {
  192.         --strdata->_refs;
  193.         _strinit(0, False, -1);
  194.     }
  195.     return *this;
  196. }
  197.  
  198.         // Called whenever string is to be modified or grown
  199. int
  200. str::_chksize (short sz)
  201. {
  202.     refstr * old = 0;
  203.     if (strdata->_refs > 1) // Need to dup memory
  204.         --strdata->_refs;   // Dec existing string reference
  205.     else if (sz >= size())
  206.         old = strdata;
  207.     else
  208.         return 0;
  209.     _strinit (c_ptr(), length(), sz);
  210.     delete old;
  211.     return 1;
  212. }
  213.  
  214. str &
  215. str::operator= (str const & s)
  216. {
  217.     if (&s != this)
  218.     {
  219.         if (!--strdata->_refs)
  220.             delete strdata;
  221.         strdata = s.strdata;
  222.         ++strdata->_refs;
  223.     }
  224.     return *this;
  225. }
  226.  
  227. str &
  228. str::operator= (char const * s)
  229. {
  230.     if (s != c_ptr())
  231.     {
  232.         short len = (short) strlen (s);
  233.         _chksize (short(len + 1));
  234.         memcpy (c_ptr(), s, len);
  235.         strdata->_length = len;
  236.     }
  237.     return *this;
  238. }
  239.  
  240. str &
  241. str::operator= (char c)
  242. {
  243.     _chksize (2);
  244.     *c_ptr() = c;
  245.     strdata->_length = 1;
  246.     return *this;
  247. }
  248.  
  249. int
  250. str::copy(char * dst, short maxlen) const
  251. {
  252.     if (maxlen == -1)
  253.         maxlen = short(length() + 1);
  254.     short len = short(maxlen - 1);
  255.     if (len > length())
  256.         len = length();
  257.     if (len > 0)
  258.         memcpy(dst, c_ptr(), len);
  259.     if (len >= 0)
  260.         dst[len] = '\0';
  261.     return len;
  262. }
  263.  
  264. short
  265. str::insert (short pos, char const * s, short len)
  266. {
  267.     if (len < 0)
  268.         len = (short) strlen (s);
  269.     if (len)
  270.     {
  271.         short leng = strdata->_length;
  272.         if (pos < 0 || pos > leng)
  273.             pos = leng;
  274.         _chksize (short(leng + len + 1));
  275.         char * buf = c_ptr();
  276.         if (pos < leng)
  277.             memmove (buf + pos + len, buf + pos, leng - pos);
  278.         memcpy (buf + pos, s, len);
  279.         strdata->_length += len;
  280.     }
  281.     return length();
  282. }
  283.  
  284. short
  285. str::remove (short pos, short len)
  286. {
  287.     if (pos >= 0 && pos < length())
  288.     {
  289.         short leng = strdata->_length;
  290.         if (len < 0 || (pos + len) > leng)
  291.             len = short(leng - pos);
  292.         if (len)
  293.         {
  294.             _chksize (0);
  295.             char * buf = c_ptr();
  296.             memcpy (buf + pos, buf + pos + len, leng - (pos + len));
  297.             strdata->_length -= len;
  298.         }
  299.     }
  300.     return length();
  301. }
  302.  
  303. short
  304. str::replace (short pos, char const * s, short clen, short len)
  305. {
  306.     if (pos >= 0)
  307.     {
  308.         short leng = strdata->_length;
  309.         if (clen < 0 || (pos + clen) > leng)
  310.             clen = short(leng - pos);
  311.         if (len < 0)
  312.             len = (short) strlen (s);
  313.         if (pos > leng)
  314.             pos = leng;
  315.         _chksize (short(leng - clen + len + 1));
  316.         char * buf = c_ptr();
  317.         if (clen != len && clen)
  318.             memmove (buf + pos + len, buf + pos + clen,
  319.                      leng - (pos + clen - len));
  320.         if (len)
  321.             memcpy (buf + pos, s, len);
  322.         strdata->_length += short(len - clen);
  323.     }
  324.     return length();
  325. }
  326.  
  327. str &
  328. str::left (short len, char padch)
  329. {
  330.     if (len < 0)
  331.         return right (short(-len), padch);
  332.     short leng = strdata->_length;
  333.     if (len != leng)
  334.     {
  335.         _chksize (short(len + 1));
  336.         if (len > leng)
  337.             memset (strdata->ptr() + leng, padch, len - leng);
  338.         strdata->_length = len;
  339.     }
  340.     return *this;
  341. }
  342.  
  343. str &
  344. str::right (short len, char padch)
  345. {
  346.     if (len < 0)
  347.         return left(-1, padch);
  348.     short leng = strdata->_length;
  349.     if (len != leng)
  350.     {
  351.         _chksize (short(len + 1));
  352.         if (len > leng)
  353.         {
  354.             char * buf = strdata->ptr();
  355.             memmove (buf + len - leng, buf, leng);
  356.             memset (buf, padch, len - leng);
  357.         }
  358.         strdata->_length = len;
  359.     }
  360.     return *this;
  361. }
  362.  
  363. str &
  364. str::mid (short pos, short len, char padch)
  365. {
  366.     if (pos <= 0)
  367.         return left(len, padch);
  368.     short leng = strdata->_length;
  369.     if (pos > leng)
  370.         pos = leng;
  371.     if (leng < len)         // Are we padding?
  372.     {
  373.         _chksize (short(len + 1));
  374.         char * buf = strdata->ptr();
  375.         short nlen = short((len - (leng - pos)) / 2);
  376.         if (nlen > 0)
  377.         {
  378.             memmove (buf, buf + pos, leng - pos);
  379.             memset (buf + leng - pos, padch, nlen);
  380.             strdata->_length -= short(pos - nlen);
  381.         }
  382.     }
  383.     return right (len, padch);
  384. }
  385.  
  386. str
  387. str::substr(short start, short len) const
  388. {
  389.     if (start < 0)
  390.         start = short(length() + start);
  391.     if (start < 0 || start >= strdata->_length)
  392.         return str();   // Empty
  393.     if (len < 0 || (short(start + len) > strdata->_length))
  394.         len = short(strdata->_length - start);
  395.     return str(c_ptr() + start, len);
  396. }
  397.  
  398.  
  399. int
  400. str::_concat (char const * s, short len)
  401. {
  402.     if (len < 0)
  403.         len = (short) strlen (s);
  404.     if (len > 0)
  405.     {
  406.         // Special case - are we concatenating ourselves??
  407.         if (strdata->_refs == 1 &&  // No danger if we'll be reallocated anyway
  408.             s >= c_ptr() &&         // Refers to us, or substring of us
  409.             s <= (c_ptr() + length()))
  410.         {   // This is handled separately, since we do not wish
  411.             // to pass this heinous overhead onto all cases,
  412.             // especially when this particular case is so rare...
  413.             str tmpstr(s, len);                 // Copy this string first
  414.             _chksize(short(len + length() + 1));
  415.             memcpy(c_ptr() + length(), tmpstr.c_ptr(), len);
  416.         }
  417.         else
  418.         {
  419.             _chksize (short(len + length() + 1));
  420.             memcpy (c_ptr() + length(), s, len);
  421.         }
  422.         strdata->_length += len;
  423.     }
  424.     return length();
  425. }
  426.  
  427. str &
  428. str::operator<< (char const * s)    // concatenate
  429. {
  430.     _concat (s);
  431.     return *this;
  432. }
  433.  
  434. str &
  435. str::operator<< (unsigned char const * s)
  436. {
  437.     _concat ((char const *)s);
  438.     return *this;
  439. }
  440.  
  441. # if !defined( SIGNED_CHAR_BUG )
  442. str &
  443. str::operator<< (signed char const * s)
  444. {
  445.     _concat ((char const *)s);
  446.     return *this;
  447. }
  448. # endif
  449.  
  450. str &
  451. str::operator<< (str const & s)
  452. {
  453.     _concat (s);
  454.     return *this;
  455. }
  456.  
  457. str &
  458. str::operator<< (int val)
  459. {
  460.     _concat (str(val));
  461.     return *this;
  462. }
  463.  
  464. str &
  465. str::operator<< (unsigned int val)
  466. {
  467.     _concat (str(val));
  468.     return *this;
  469. }
  470.  
  471. str &
  472. str::operator<< (short val)
  473. {
  474.     _concat (str(val));
  475.     return *this;
  476. }
  477.  
  478. str &
  479. str::operator<< (unsigned short val)
  480. {
  481.     _concat (str(val));
  482.     return *this;
  483. }
  484.  
  485. str &
  486. str::operator<< (long val)
  487. {
  488.     _concat (str(val));
  489.     return *this;
  490. }
  491.  
  492. str &
  493. str::operator<< (unsigned long val)
  494. {
  495.     _concat (str(val));
  496.     return *this;
  497. }
  498.  
  499. str &
  500. str::operator<< (char c)
  501. {
  502.     _concat (c);
  503.     return *this;
  504. }
  505.  
  506. str &
  507. str::operator<< (unsigned char c)
  508. {
  509.     _concat (c);
  510.     return *this;
  511. }
  512.  
  513. # if !defined( SIGNED_CHAR_BUG )
  514. str &
  515. str::operator<< (signed char c)
  516. {
  517.     _concat (c);
  518.     return *this;
  519. }
  520. # endif
  521.  
  522.     // String is never modified in this version
  523.  
  524. char const &
  525. str::operator[] (short pos) const
  526. {
  527.     if (pos < 0)            // Negative index addresses from eos
  528.         pos = short(strdata->_length + pos);
  529.     if (pos >= strdata->_length)
  530.     {
  531.         char * buf = c_ptr() + length();
  532.         *buf = 0;
  533.         return *buf;
  534.     }
  535.     return c_ptr()[pos];
  536. }
  537.  
  538.     // ... but here it may be
  539.  
  540. char &
  541. str::operator[] (short pos)
  542. {
  543.     if (pos < 0)                       // Negative index addresses from eos
  544.         pos = short(strdata->_length + pos);
  545.     if (pos < 0)                     // Any cleaner way without exceptions?
  546.         pos = strdata->_length;
  547.     if (pos < strdata->_length)
  548.         _chksize(0);
  549.     else
  550.     {
  551.         _chksize(short(pos + 2));
  552.         ::memset(c_ptr() + length(), ' ', pos - strdata->_length + 1);
  553.         strdata->_length = short(pos+1);
  554.     }
  555.     return c_ptr()[pos];
  556. }
  557.  
  558. int
  559. str::_compare(str const s) const
  560. {
  561.     if ((strdata->flags() & refstr::ICASE) ||
  562.         (s.strdata->flags() & refstr::ICASE))
  563.         return stricmp(c_str(), s.c_str());
  564.     return strcmp(c_str(), s.c_str());
  565. }
  566.  
  567. #if 0
  568. extern "C" char *
  569. stristr(char const * s, char const * u)
  570. {
  571.     while (*s)
  572.     {
  573.         int     i = -1;
  574.         do
  575.             if (u[++i] == '\0')
  576.                 return (char *)s;
  577.         while (toupper(s[i]) == toupper(u[i]));
  578.         ++s;
  579.     }
  580.     return 0;
  581. }
  582. #endif
  583.  
  584. short
  585. str::_strstr(str const s) const
  586. {
  587.     char    *p;
  588.     if (!(strdata->flags() & refstr::ICASE) &&
  589.         !(s.strdata->flags() & refstr::ICASE))
  590.         p = ::strstr(c_str(), s.c_str());
  591.     else
  592.         p = ::stristr(c_str(), s.c_str());
  593.     return short((p) ? (p - strdata->ptr()) : -1);
  594. }
  595.  
  596.  
  597. short
  598. str::removech (char const * clist)
  599. {
  600.     short result = 0;
  601.     if (*clist)
  602.     {
  603.         char * buf, * sub, * bas;
  604.         bas = buf = sub = strdata->ptr();
  605.         short nlen = strdata->_length;
  606.         for (short i = 0; i < nlen; ++i)
  607.         {
  608.             if (strchr (clist, *buf) == 0)
  609.             {
  610.                 if (result)
  611.                     *sub = *buf;
  612.                 ++sub;
  613.             }
  614.             else if (!result++)
  615.             {
  616.                 _chksize (0);
  617.                 buf = strdata->ptr() + (buf - bas);
  618.                 sub = strdata->ptr() + (sub - bas);
  619.                 bas = strdata->ptr();
  620.             }
  621.             ++buf;
  622.         }
  623.         strdata->_length = short(nlen - result);
  624.     }
  625.     return result;
  626. }
  627.  
  628. short
  629. str::countch (char const * clist)
  630. {
  631.     short result = 0;
  632.     if (*clist)
  633.     {
  634.         char * buf = strdata->ptr();
  635.         short nlen = strdata->_length;
  636.         for (short i = 0; i < nlen; ++i, ++buf)
  637.             if (strchr (clist, *buf) != 0)
  638.                 ++result;
  639.     }
  640.     return result;
  641. }
  642.  
  643. void
  644. str::setflags (unsigned short flags)
  645. {
  646.     if ((strdata->flags() & refstr::ICASE) != flags)
  647.     {
  648.         _chksize(0);        // Dupe string if necessary
  649.         strdata->setf(flags);
  650.     }
  651. }
  652.  
  653. void
  654. str::resetflags (unsigned short flags)
  655. {
  656.     if ((strdata->flags() & flags) != 0)
  657.     {
  658.         _chksize(0);        // Dupe string if necessary
  659.         strdata->resetf(flags);
  660.     }
  661. }
  662.  
  663.  
  664. #include    <iostream.h>
  665.  
  666. ostream &
  667. operator<< (ostream & os, str const & s)
  668. {
  669.     os << s.c_str();
  670.     return os;
  671. }
  672.  
  673. istream &
  674. operator>> (istream & is, str & s)
  675. {
  676.     s.clear();
  677.     while (is.good())
  678.     {
  679.         int     c;
  680.         char    buf[256];
  681.  
  682.         is.get(buf, sizeof buf);
  683.         s << buf;
  684.         if ((c = is.get()) == '\n' || c == EOF)
  685.             break;
  686.         is.putback((char)c);
  687.     }
  688.     return is;
  689. }
  690.