// String.C  -*- C++ -*-
// Copyright (c) 1997, 1998 Etienne BERNARD

// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// any later version.

// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307, USA.

#include "String.H"

#include <cstring>
#include <cctype>
#include <sstream>

String::String()
{
  p = new srep;
  len = 0;
  p->s = 0;
}

String::String(const char *s)
{
  p = new srep;
  len = strlen(s);
  p->s = new char[len + 1];
  std::strcpy(p->s, s);
}

String::String(const std::string & s)
{
  p = new srep;
  len = s.length ();
  p->s = new char[len + 1];
  std::strcpy (p->s, s.c_str ());
}

String::String(const String & s)
{
  s.p->n++;
  p = s.p;
  len = s.len;
}

String::String(long i)
{
  std::ostringstream temp;
  temp << i;

  p = new srep;
  len = strlen(temp.str().c_str ());
  p->s = new char[len + 1];
  strcpy(p->s, temp.str().c_str ());
}

String::String(char c)
{
  p = new srep;
  p->s = new char[2];
  p->s[0] = c;
  p->s[1] = '\0';
  len = 1;
}

String::~String()
{
  if (--p->n == 0) {
    delete[] p->s;
    delete p;
  }
}

String &
String::operator=(const char *s)
{
  if (p->n > 1) {
    p->n--;
    p = new srep;
  }
  else
    delete[] p->s;
  
  len = strlen(s);
  p->s = new char[len + 1];
  strcpy(p->s, s);
  
  return *this;
}

String &
String::operator=(const String & s)
{
  s.p->n++; // protection contre st = st
  if (--p->n == 0) {
    delete[] p->s;
    delete p;
  }
  p = s.p;
  len = s.len;
  return *this;
}

String &
String::operator=(const std::string & s)
{
  if (p->n > 1) {
    p->n--;
    p = new srep;
  }
  else
    delete[] p->s;
  
  len = s.length ();
  p->s = new char[len + 1];
  strcpy(p->s, s.c_str ());
  
  return *this;
}

int
String::length() const
{
  return len;
}

int
String::find(char c)
{
  if (!strchr(p->s, c))
    return -1;
  
  return (int)(strchr(p->s, c) - p->s);
}

void
String::fill(char c)
{
  for (char * s = p->s; *s; s++)
    *s = c;
}

String
String::pad(int n)
{
  int l = len;

  if (n <= l)
    return subString(0, n-1);

  char *temp = new char[n+1];
  strcpy(temp, p->s);

  for (int i = l; i < n; i++)
    temp[i] = ' ';
  temp[n] = '\0';

  String res(temp);
  delete temp;

  return res;
}

String
String::subString(int debut, int fin)
{
  if (fin < debut) return "";

  char * temp = new char[fin-debut+2];
  strncpy(temp, p->s + debut, fin - debut + 1);
  temp[fin - debut + 1] = '\0';
  String res(temp);
  delete temp;
  return res;
}

String
String::subString(int debut)
{
  return subString(debut, len - 1);
}

String
String::toLower()
{
  char *temp = new char[len + 1];

  for (int i = 0; i < len + 1; i++)
    if (isupper(p->s[i]))
      temp[i] = tolower(p->s[i]);
    else
      temp[i] = p->s[i];

  String res(temp);
  delete temp;
  return res;
}

String
String::toUpper()
{
  char *temp = new char[len + 1];

  for (int i = 0; i < len + 1; i++)
    if (islower(p->s[i]))
      temp[i] = toupper(p->s[i]);
    else
      temp[i] = p->s[i];

  String res(temp);
  delete temp;
  return res;
}

String
String::trim()
{
  int i = 0, j = len - 1;

  while (i < j && (p->s[i] == ' ' || p->s[i] == '\t' || p->s[i] == '\r'))
    i++;
  
  while (j > 0 && (p->s[j] == ' ' || p->s[j] == '\t' || p->s[i] == '\r'))
    j--;
  
  return subString(i, j);
}

int
String::indexOf(char c)
{
  char *s = std::strchr(p->s, c);
  if (s)
    return p->s - s;
  
  return -1;
}

char &
String::operator[](int i)
{
  if (i < 0 || len < i) {
    std::cerr << "String index out of range\n";
    std::exit(1);
  }
  return p->s[i];
}

const char &
String::operator[](int i) const
{
  if (i < 0 || len < i) {
    std::cerr << "String index out of range\n";
    exit(1);
  }
  return p->s[i];
}

bool
String::operator==(const char *s) const
{
  return std::strcmp(p->s, s) == 0;
}

bool
String::operator==(const String & s) const
{
  return (p == s.p) || (std::strcmp(p->s, s.p->s) == 0);
}

bool
String::operator==(const std::string & s) const
{
  return (p->s == s.c_str ()) || (std::strcmp (p->s, s.c_str()) == 0);
}

bool
String::operator!=(const char *s) const
{
  return std::strcmp(p->s, s) != 0;
}

bool
String::operator!=(const String & s) const
{
  return std::strcmp(p->s, s.p->s) != 0;
}

bool
String::operator!=(const std::string & s) const
{
  return ! (*this == s);
}

bool
String::operator<(const String & s) const
{
  return std::strcmp(p->s, s.p->s) < 0;
}

bool
String::operator<(const std::string & s) const
{
  return std::strcmp(p->s, s.c_str ()) < 0;
}

bool
String::operator>(const String & s) const
{
  return std::strcmp(p->s, s.p->s) > 0;
}

bool
String::operator<=(const String & s) const
{
  return std::strcmp(p->s, s.p->s) <= 0;
}

bool
String::operator<=(const std::string & s) const
{
  return (*this < s) || (*this == s);
}

bool
String::operator>=(const String & s) const
{
  return std::strcmp(p->s, s.p->s) >= 0;
}

bool String::operator>=(const std::string & s) const
{
  return ! (*this < s);
}

String
String::operator+(const char *s)
{
  char *temp = new char[len + std::strlen(s) + 1];

  std::strcpy(temp, p->s);
  std::strcat(temp, s);

  String res(temp);
  delete temp;

  return res;
}

String
String::operator+(const String & s)
{
  char * temp = new char[len + s.len + 1];

  std::strcpy(temp, p->s);
  std::strcat(temp, s.p->s);

  String res(temp);
  delete temp;

  return res;
}

String
String::operator+(const std::string & s)
{
  char * temp = new char[len + s.length () + 1];
  std::strcpy (temp, p->s);
  std::strcat (temp, s.c_str ());

  String res (temp);
  delete temp;

  return res;
}

String::operator const char *() const
{
  return p->s;
}

String::operator std::string () const
{
  return std::string (p->s);
}

std::ostream &
operator<<(std::ostream & s, const String & st)
{
  return s << st.p->s;
}

std::istream &
operator>>(std::istream & s, String & st)
{
  if (st.p->n > 1) {
    st.p->n--;
    st.p = new String::srep;
  }
  else
    delete[] st.p->s;
  
  char buf[2048];
  char c;

  s.getline (buf, 2048, '\n');
  //s.get(c);

  st.len = strlen(buf);
  st.p->s = new char[st.len + 1];
  strcpy(st.p->s, buf);

  return s;
}

std::string operator+(const std::string & s, const String & p)
{
  std::string temp = s;
  temp += p.p->s;
  return temp;
}

bool operator==(const std::string & s, const String & p)
{
  return p == s;
}

bool operator!=(const std::string & s, const String & p)
{
  return p != s;
}

bool operator>(const std::string & s, const String & p)
{
  return p <= s;
}

bool operator<(const std::string & s, const String & p)
{
  return p >= s;
}

bool operator<=(const std::string & s, const String & p)
{
  return p > s;
}

bool operator>=(const std::string & s, const String & p)
{
  return p < s;
}


syntax highlighted by Code2HTML, v. 0.9.1