//
// Simple string class
// Public domain
//
// Written by david nugent
// davidn@csource.pronet.com
// 3:632/348@fidonet
//

# if !defined( _str_h )
# define _str_h 1

# if defined( __BORLANDC__ ) && ( __BORLANDC__ <= 0x0300 )
# define PLACEMENT_NEW_BUG
# define SIGNED_CHAR_BUG
# endif


struct refstr
{
    short _size;
    short _length;
    short _refs;
    refstr (short length, short size)
        : _length(length), _size(size), _refs(1)
        {}
    ~refstr (void) {}
# if !defined( PLACEMENT_NEW_BUG )
    void * operator new(unsigned sz, short allocsz);
# endif
    char * ptr (void)
    {
        return ((char *)this) + sizeof(refstr);
    }
};




class str
{

  public:

        // constructors/destructors

    str (void)
    {
        _strinit();
    }

    str (char const * s, short len =-1)
    {
        _strinit(s, len, -1);
    }

    str (unsigned char const * s, short len =-1)
    {
        _strinit((char const *)s, len, -1);
    }
# if !defined( SIGNED_CHAR_BUG )
    str (signed char const * s, short len =-1)
    {
        _strinit((char const *)s, len, -1);
    }
# endif

    str (char c)
    {
        _strinit (&c, 1, -1);
    }

    str (unsigned char c)
    {
        _strinit ((char const *)&c, 1, -1);
    }
# if !defined( SIGNED_CHAR_BUG )
    str (signed char c)
    {
        _strinit ((char const *)&c, 1, -1);
    }
# endif
    str (str const & s)
      : strdata(s.strdata)
    {
        ++strdata->_refs;
    }

    ~str (void)
    {
        if (!--strdata->_refs)
            delete strdata;
    }

        // assignment

    str & operator= (str const & s);
    str & operator= (char const * s);
    str & operator= (char c);

    str & operator= (unsigned char const * s)
    {
        return operator= ((char const *)s);
    }
# if !defined( SIGNED_CHAR_BUG )
    str & operator= (signed char const * s)
    {
        return operator= ((char const *)s);
    }
# endif

        // primitive members

    short length (void) const
    {
        return strdata->_length;
    }

    short size (void) const
    {
        return strdata->_size;
    }

        // operators

    str & operator<< (char const * s)   // concatenate
    {
        _concat (s);
        return *this;
    }

    str & operator<< (unsigned char const * s)
    {
        _concat ((char const *)s);
        return *this;
    }
# if !defined( SIGNED_CHAR_BUG )
    str & operator<< (signed char const * s)
    {
        _concat ((char const *)s);
        return *this;
    }
# endif
    str & operator<< (str const & s)
    {
        _concat (s);
        return *this;
    }

    str & operator<< (char c)
    {
        _concat (c);
        return *this;
    }

    str & operator<< (unsigned char c)
    {
        _concat (c);
        return *this;
    }

# if !defined( SIGNED_CHAR_BUG )
    str & operator<< (signed char c)
    {
        _concat (c);
        return *this;
    }
# endif

    char & operator[] (short pos)
    {
        if (pos < 0 || pos >= strdata->_length)
        {
            char * buf = c_ptr() + length();
            *buf = 0;
            return *buf;
        }
        return c_ptr()[pos];
    }

    char * c_ptr (void) const   // not necessarily NUL terminated!
    {                           // Use with caution...
        return strdata->ptr();
    }

    char const * c_str (void) const    // return char*
    {
        char * buf = c_ptr();
        buf[strdata->_length] = 0;
        return buf;
    }

    unsigned char const * u_str (void) const
    {
        return (unsigned char const *)c_str();
    }

        // manipulators

    short insert (short pos, char const * s, short len =-1);

    short insert (short pos, str const & s)
    {
        return insert (pos, s.c_ptr(), s.length());
    }

    short insert (short pos, unsigned char const * s,
                    short len =-1)
    {
        return insert (pos, (char const *)s, len);
    }
# if !defined( SIGNED_CHAR_BUG )
    short insert (short pos, signed char const * s,
                    short len =-1)
    {
        return insert (pos, (char const *)s, len);
    }
# endif
    short insert (short pos, char c)
    {
        return insert (pos, &c, 1);
    }

    short insert (short pos, unsigned char c)
    {
        return insert (pos, (char const *)&c, 1);
    }
# if !defined( SIGNED_CHAR_BUG )
    short insert (short pos, signed char c)
    {
        return insert (pos, (char const *)&c, 1);
    }
# endif

    short remove (short pos =0, short len =-1);

    short replace (short pos, char const * s, short clen =-1,
                    short len =-1);

    short replace (short pos, str & s, short clen =-1)
    {
        return replace (pos, s.c_ptr(), clen, s.length());
    }

    short replace (short pos, unsigned char const * s,
                    short clen =-1, short len =-1)
    {
        return replace (pos, (char const *)s, clen, len);
    }
# if !defined( SIGNED_CHAR_BUG )
    short replace (short pos, signed char const * s,
                    short clen =-1, short len =-1)
    {
        return replace (pos, (char const *)s, clen, len);
    }
# endif
    short replace (short pos, char c, short clen =-1)
    {
        return replace (pos, &c, clen, 1);
    }

    short replace (short pos, unsigned char c, short clen =-1)
    {
        return replace (pos, (char const *)&c, clen, 1);
    }
# if !defined( SIGNED_CHAR_BUG )
    short replace (short pos, signed char c, short clen =-1)
    {
        return replace (pos, (char const *)&c, clen, 1);
    }
# endif

    str & left (short len, char padch =' ');
    str & right (short len, char padch =' ');
    str & mid (short pos, short len, char padch =' ');

    short removech (char const * clist ="\r\n");
    short countch (char const * clist);

  protected:

    refstr * strdata;

    // Check to see if big enough for size
    int _chksize (short sz =0);

    int _concat (char const * s, short len =-1);

    int _concat (str const & s)
    {
        return _concat (s.c_ptr(), s.length());
    }

    int _concat (char ch)
    {
        return _concat (&ch, 1);
    }

    int _concat (unsigned char const * s, short len =-1)
    {
        return _concat ((char const *)s, len);
    }
# if !defined( SIGNED_CHAR_BUG )
    int _concat (signed char const * s, short len =-1)
    {
        return _concat ((char const *)s, len);
    }
# endif

  private:
        // Common constructor
    void _strinit (char const * s =0, short slen =0,
                    short siz =-1);

};


str left (str const & s, short len, char padch =' ');
str right (str const & s, short len, char padch =' ');
str mid (str const & s, short pos, short len, char padch =' ');

# endif
