// ---------------------------------------------------------------------------
// String.C
//
// This file implements the member and non-member functions used with
// the String class.  A few functions where defined in String.h instead
// of in here.
//
// For 605.201: Introduction to C++ Programmin
// Paul McNamee
// ---------------------------------------------------------------------------

#include "String.h"

// ---------------------------------------------------------------------------
// Optional ctor.  Useful for building efficient operator+(). Keep private

String::String(const char* s1, int l1, const char* s2, int l2) {
   _len = l1 + l2;
   _str = new char [_len + 1];
   strcpy(_str, s1);
   strcat(_str, s2);
}


// ---------------------------------------------------------------------------
// A member function that lets you print without using operator<<.  You'd call
// this function with a String foo, by the call, foo.print(cout);

ostream & String::print(ostream &os) const {
   os << _str;
   return os;
}


// ---------------------------------------------------------------------------
// Const char * constructor.
// If we have a real string (not a NULL pointer), allocate memory w/ new [].
// Otherwise, use new[] to allocate 1 char.  Since new[] is used both places
// delete[] can be used unrestrainedly in the destructor.  I saw the idea
// of checking for a NULL pointer in this fashion from reading Meyer, Lippman,m
// or Stroustrup, but I am unable to find the reference now.
// (I think it's Meyer)

String::String(const char *s) {
  if (s) {                            // Check for NULL pointer!
    _len = strlen(s);                 // Assume a well terminated string.
    _str = new char[_len + 1];
    strcpy(_str, s);
  } else {
    _len = 0;
    _str = new char [1];              // Idea from Meyer or Lippman, to use delete []
    _str[_len] = '\0';
  }
}

// ---------------------------------------------------------------------------
// For copy non-null terminated

String::String(const char *s, int l) {
  _len = l;
  _str = new char[_len + 1];
  strncpy(_str, s, _len);
  _str[_len] = '\0';
}

// ---------------------------------------------------------------------------
// Assignment -- These must copy chars

const String & String::operator= (const String &s) {
  if (*this != s) {                 // Assumes operator== exists for String
    _len = s._len;
    delete [] _str;
    _str = new char [_len + 1];
    strcpy(_str, s._str);
  }
  return *this;
}
      
// ---------------------------------------------------------------------------
const String & String::operator= (const char *s) {
  // Dont have to check for this ptr since not assigning from a String.
  _len = strlen(s);
  delete [] _str;
  _str = new char [_len + 1];
  strcpy(_str, s);
  return *this;
}

// ---------------------------------------------------------------------------
// Append contents to string

const String & String::operator+= (const char *s) {
  _len = _len + strlen(s);
  char *tmp = new char [_len + 1];
  strcpy(tmp, _str);
  strcat(tmp, s);
  delete [] _str;
  _str = tmp;
  return *this;
}

// ---------------------------------------------------------------------------
// Create a new string w/ both the old string and the new part the (char*)
// string together.  Uses private 4 argument constructor.

String String::operator+ (const char *s) const {
  return String(_str, _len, s, strlen(s));
}

// ---------------------------------------------------------------------------
// Strings match?

int String::operator== (const char *s) const {
  return !strcmp(_str, s);
}

// ---------------------------------------------------------------------------
// Strings dont match.  This could be written based on the == operator, but
// for only two cases, the maintanence overhead seems managable.

int String::operator!= (const char *s) const {
  return strcmp(_str, s);
};

// ---------------------------------------------------------------------------
// String insertion operator.  Or the output operator.  Note that this is not
// a member function of Sting


ostream & operator<<(ostream &os, const String &s) {
   s.print(os);
   return os;
} 


