// UnderC Development Project, 2001
// A simplified standard string class

#ifndef __OLD_STRING_
#define __OLD_STRING_

#ifndef __UNDERC__
#include <string.h>
#include "\ucw\include\iostream"
#else
#ifndef NULL
#define NULL 0
#endif
#include <iostream>
#endif

namespace std {

class string {
protected:
 char *m_str;
 unsigned int m_len;
public:
 typedef unsigned long size_type;
 typedef char *iterator;
 typedef const char *const_iterator;
 enum { npos = 0xFFFFFFFF };

 char *c_str() const { return m_str; }
 size_type  length() const { return m_len; }
 size_type  size()   const { return m_len; }
 bool       empty()  const { return m_len == 0; }
 // *hack 0.9.5 These aren't really const methods (but!)
 iterator begin() const { return m_str; }
 iterator end() const  { return m_str + m_len; }


 void resize(size_type sz)
 {
  if(m_len > sz) {
   m_len = sz;
   return;  // buffer is quite big enough....
  }	  
  char *tmp = new char[sz+1];
  //printf("alloc %x\n",tmp);
  if (m_str) {
    strcpy(tmp,m_str);
    //delete m_str;
  }
  m_str = tmp;
  m_len = sz;
 }

 void append(char *s)
 {
  resize(m_len + strlen(s));
  strcat(m_str,s);
 }

 void push_back(char ch)
 {
  char st[2];
  st[0] = ch; st[1] = '\0';
  append(st);
 }

 void copy(char *str)
 {	
#ifdef STRING_TESTING
   printf("copy %x\n",str);
#endif
   resize(strlen(str));
   strcpy(m_str,str);
 }

 string(const char *str)
 {
  char* ps = (char*)str;
  if (!ps) ps = "";  // UCW bugge...
  m_len = 0;
  m_str = NULL;
  copy((char*)ps);
 }
 
 string(const char *str, int sz)
 {
   resize(sz);
   strcpy(m_str,str); 
 }

 string()
 {
  m_len = 0;
  m_str = NULL;
  copy("");
 }

 string(size_type sz, char ch)
 {
   resize(sz);
   for(size_type i = 0; i < sz; i++) m_str[i] = ch;
   m_str[sz] = '\0';
 }  

 string(const string& s)
 {
  m_str = NULL;
  m_len = 0;
  char *ptr = s.m_str;
  //printf("copy %s\n",ptr);
  copy(s.m_str);
 }

 string& operator= (const string& s)
 {
  copy(s.m_str);  return *this;
 }

 string& operator= (char *str)
 {
   copy(str);
   return *this;
 }
 
 string& operator+= (char *str)
 {
   append(str);  return *this;
 }

 string& operator+= (const string& s)
 {
   append(s.c_str());  return *this;
 }

 string& operator+= (char ch)
 {
   push_back(ch);
   return *this;
 }

 ~string()
 {
#ifdef STRING_TESTING
   printf("killing... '%s' %x\n",m_str,this); 
   if (m_str == NULL) puts("already dead!");
#endif
   delete m_str; 
//#endif
   m_str = NULL;
 }

 size_type find(char *str) const
 {
   char *ss = strstr(m_str,str);
   if (ss) return (size_type)(ss) - (size_type)(m_str);
      else return npos;
 }

 size_type find(const string& s) const
 {
   return find(s.m_str);
 }

 size_type find(char ch) const
 { 
  char str[2]; // init didn't work?
  str[0] = ch;
  str[1] = '\0';
  return find(str);
 }

 size_type rfind(char ch) const
 {
  char *ss = strrchr(m_str,ch);
  if (ss) return (size_type)(ss) - (size_type)(m_str);
      else return npos;
 }

 size_type bound(size_type n) const
 {
 // *hack 0.9.5 necessary while we have trouble w/ unsigned integers
  if (n > m_len || n == npos) n = m_len;
  return n;
 }

 string substr(size_type start, size_type n = npos) const
 {
  string ts;
  n = bound(n);
  ts.resize(n);
  char *s1 = ts.m_str;
  char *s2 = m_str+start;
  for(size_type i = 0; i < n; i++) {
      *s1++ = *s2++;
  }
  *s1 = '\0'; 
 // strncpy(s1,s2,n);
  return ts;
 }

 string& replace(size_type is, size_type n, char *repl)
 {
  n = bound(n);
  size_type rsz = strlen(repl);
  size_type nextra = rsz - n;
  size_type oldsz = m_len;
  if (nextra != 0) {
    resize(m_len+nextra);
    char *pend = m_str + is + n; // just past target
    memmove(pend+nextra,pend,oldsz-is-n);
    m_str[m_len] = '\0';
  }
  memmove(m_str+is,repl,rsz);
  return *this;
 }

 string& replace(size_type is, size_type n, const string& repl)
 {
   return replace(is,n,repl.m_str);
 }
 
 void insert(size_type idx, const string& repl)
 {
   replace(idx,0,repl); 
 }

 char& operator[] (size_type i)
 {
   return m_str[i];
 }
 
 #ifndef __UNDERC__
 char operator[] (size_type i) const
 {
   return m_str[i];
 }
 #endif  

 int compare(const string& s) const
 {
   return strcmp(m_str, s.m_str); 
 }

// *hack 0.9.7 used to be non-member, but that won't work for now!
 bool operator== (const string& s2) const
 {
  return compare(s2) == 0;
 }

 };

} // namespace std

//*SJD* Currently we aren't doing overloading with functions which
// span different namespaces.  So putting operator+ in std would 
// mean being unable to overload it for any other type.
  bool operator != (const std::string& s1, const std::string& s2)
 {
  return s1.compare(s2) != 0;
 }

 bool operator> (const std::string& s1, const std::string& s2)
 {
  return s1.compare(s2) > 0;
 }

 bool operator< (const std::string& s1, const std::string& s2)
 {
  return s1.compare(s2) < 0;
 }

 std::string operator+ (const std::string& s1, const std::string& s2)
 {
   std::string out = s1;
   out.append(s2.c_str());
   return out;
 }

std::string operator+ (const std::string& s1, char *str2)
 {
   std::string out = s1;
   out.append(str2);
   return out;
 }

//#ifdef _IOSTREAM_H

std::ostream& operator<< (std::ostream& os, const std::string& s)
{
  os << s.c_str();
  return os;
}

std::istream& operator>> (std::istream& is, std::string& s)
{ char buff[512 /*MAX_LINE*/]; 
  is >> buff;
  s = buff; 
  return is;
}

 std::istream& getline(std::istream& is, std::string& s)
 { 
   char buff[512 /*MAX_LINE*/ ];
   is.getline(buff,MAX_LINE);
   s = buff;
   return is;
 }

//#endif

#endif


 
