#include <ctype.h>

#include <stdlib.h>

#include <string.h>

#include <stdio.h>

#include "Strings.h"


Strings::Strings() 
{
  theString = new char [1];
  theString [0] = '\0';
}

Strings::Strings (char character) 
{
  theString = new char [2];
  theString [0] = character;
  theString [1] = '\0';
}

Strings::Strings (const char* string) 
{
  if (string != (char*)0)
    {
    theString = new char [strlen (string) + 1];
    strcpy (theString, string);
    }
  else
    {
    theString = new char [1];
    theString [0] = '\0';
    }
}

Strings::Strings (const Strings& string) 
{
  theString = new char [strlen (string.theString) + 1];
  strcpy (theString, string.theString);
}

Strings::~Strings() 
{
  delete [] theString;
}

int Strings::beginsWith (const char* string) const
{
int result;

  if (string == (char*)0)
    result = 0;
  else
    result = !(strncmp (theString, string, strlen(string)));
  return result;
}

int Strings::checkMatch (char* text, char* pattern) const 
{
// the following code was originally developed by Rich Salz.

// the following code was modified by Lars Mathiesen.

// the following code was modified by D J Supel

int last, matched, reverses;
char *t, *p;

  t = text;
  p = pattern;

  for ( ; *p; t++, p++) 
  {
    if (*t == '\0' && *p != '*')
      return 0;
    switch (*p) 
    {
      case '\\':
        /* Literal match with following character. */
        p++;
        /* FALLTHROUGH */
      default:
        if (*t != *p)
          return 0;
        continue;
      case '?':
        /* Match anything. */
        continue;
      case '*':
        while (*++p == '*')
          /* Consecutive stars act just like one. */
          continue;
        if (*p == '\0')
          /* Trailing star matches everything. */
          return 1;
        while (*t)
          if ((matched = checkMatch(t++, p)) != 0)
            return matched;
        return 0;
      case '[':
        reverses = p[1] == 1 ? 1 : 0;
        if (reverses)
          /* Inverted character class. */
          p++;
        for (last = 0400, matched = 0; *++p && *p != ']'; last = *p)
          if (*p == '-' ? *t <= *++p && *t >= last : *t == *p)
            matched = 1;
        if (matched == reverses)
          return 0;
        continue;
    }
  }
  return *t == '\0';
}

int Strings::contains (const char c) const
{
  for (unsigned int i=0; i<=strlen (theString); i++)
  {
    if (theString[i] == c)
      return 1;
  }
  return 0;
}

int Strings::contains (const char* string) const
{
  return (strstr (theString, string) != 0);
}

int Strings::contains (const Strings& string) const
{
  return (strstr (theString, string.theString) != 0);
}

unsigned int Strings::count (const char c) const
{
unsigned int theCount = 0;

  for (unsigned int i=0; i<=strlen (theString); i++)
  {
    if (theString[i] == c)
      theCount++;
  }
  return theCount;
}

int Strings::endsWith (const char* string) const
{
int result;
Strings thisString = *this;
Strings clientString = string;

  if (string == (char*)0)
    result = 0;
  else
  {
    thisString.reverse();
    clientString.reverse();
    result = thisString.beginsWith (clientString);
  }
  return result;
}

int Strings::empty() const
{
Strings emptyString;

  return (*this == emptyString); 
}

int Strings::isAlphabetic() const
{
  if (empty())
    return 0;
  
  for (unsigned int i = 0; i<length(); i++)
  {
    if (isalpha ((int)theString[i]) || isspace ((int)theString[i]))
      ;
    else 
      return 0;
  }
 return 1;
}

int Strings::isAlphanumeric() const
{
  if (empty())
    return 0;
  
  for (unsigned int i = 0; i<length(); i++)
  {
    if (isalnum ((int)theString[i]) || isspace ((int)theString[i]))
      ;
    else 
      return 0;
  }
 return 1;
}

int Strings::isLowercase() const
{
  if (empty())
    return 0;
  
  for (unsigned int i = 0; i<length(); i++)
  {
    if (islower ((int)theString[i]) || isspace ((int)theString[i]))
      ;
    else 
      return 0;
  }
 return 1;
}

int Strings::isNumeric() const
{
  if (empty())
    return 0;
  
  for (unsigned int i = 0; i<length(); i++)
  {
    if (isdigit ((int)theString[i]))
      ;
    else
      return 0;
  }
 return 1;
}

int Strings::isUppercase() const
{
  if (empty())
    return 0;
  
  for (unsigned int i = 0; i<length(); i++)
  {
    if (isupper ((int)theString[i]) || isspace ((int)theString[i]))
      ;
    else 
      return 0;
  }
 return 1;
}

unsigned int Strings::length() const
{
  return strlen (theString); 
}

Strings Strings::lowercaseOf() const
{
Strings string (theString);

  string.lowercase();
  return string;
}

int Strings::matches (const char* pattern) const
{
Strings thePattern = pattern;

  return matches (thePattern);
}

int Strings::matches (const Strings& pattern) const
{
  // validity check

  //

  if (pattern.empty())
    return 0;
  if (pattern.count ('[') != pattern.count (']'))
    return 0;
  

  if (pattern.theString[0] == '*' && pattern.theString[1] == '\0')
    return 1;
  return checkMatch (theString, pattern.theString);
}

int Strings::soundsLike (const char* string) const
{
Strings leftResult, rightResult;

  if (string == (char*)0)
    return 0;
  else
  {
    leftResult = soundexCodeOf (theString);
    rightResult = soundexCodeOf (string);
    //cerr << theString << " " << left << " " 

    //     << string     << " " << right << endl;

    
    // determine if the soundex code could be determined by checking

    // for the empty string

    //

    if (leftResult.empty() || rightResult.empty())
      return 0;
    else
      return (leftResult == rightResult);
  }
}

int Strings::soundsLike (const Strings& string) const
{
  return (soundsLike (string.theString));
}

double Strings::toDouble() const
{
  return atof (theString); 
}

int Strings::toInt() const
{
  return atoi (theString); 
}

long Strings::toLong() const
{
  return atol (theString); 
}

Strings Strings::sliceOf (const char delimitor) const
{
char *headMarker;
char *tailMarker;
Strings theToken;

  headMarker = theString;
  tailMarker = headMarker;

  while (tailMarker[0] && (tailMarker[0] != delimitor))
    tailMarker++; 
  
  // move the token to the return strings

  //

  while (headMarker != tailMarker)
  {
    theToken.append (headMarker[0]);
    headMarker++;
  }
  
  return theToken;
}

Strings Strings::token () const
{
char *headMarker;
char *tailMarker;
Strings theToken;

  headMarker = theString;

  // skip over the preceeding spaces and set a pointer

  //

  while (headMarker[0] && isspace (headMarker[0]))
    headMarker++; 
  
  // skip over non-blank characters and set another pointer

  //

  tailMarker = headMarker;
  while (tailMarker[0] && !isspace (tailMarker[0]))
    tailMarker++; 
  
  // move the token to the return strings

  //

  while (headMarker != tailMarker)
  {
    theToken.append (headMarker[0]);
    headMarker++;
  }
  
  return theToken;
}

Strings Strings::token (const char delimitor) const
{
char *headMarker;
char *tailMarker;
Strings theToken;

  headMarker = theString;

  // skip over the preceeding spaces 

  //

  while (headMarker[0] && isspace (headMarker[0]))
    headMarker++; 
  
  // skip over non-delimitor characters and set another pointer

  //

  tailMarker = headMarker;
  while (tailMarker[0] && (tailMarker[0] != delimitor))
    tailMarker++; 
  
  // move the token to the return strings

  //

  while (headMarker != tailMarker)
  {
    theToken.append (headMarker[0]);
    headMarker++;
  }
  
  return theToken;
}

Strings Strings::uppercaseOf() const
{
Strings string (theString);

  string.uppercase();
  return string;
}

void Strings::append (char character) 
{
char *ctemp;
char *temp;

  temp = new char [strlen (theString) + 1];
  strcpy (temp, theString);

  ctemp = new char [2];
  ctemp [0] = character;
  ctemp [1] = '\0';
 
  delete [] theString;
  theString = new char [strlen (temp) + strlen (ctemp) + 1];
  
  strcpy (theString, temp);
  strcat (theString, ctemp);

  delete [] ctemp;
  delete [] temp;
}

void Strings::append (const char* string) 
{
  if (string != (char*)0)
    {
    char* temp;
    
    temp = new char [strlen (theString) + 1];
    strcpy (temp, theString);

    delete [] theString;
    theString = new char [strlen (temp) + strlen (string) + 1];

    strcpy (theString, temp);
    strcat (theString, string);

    delete [] temp;
    }
}

void Strings::append (const Strings& string) 
{
char* temp;

  temp = new char [strlen (theString) + 1];
  strcpy (temp, theString);

  if (this != &string)
  {
    delete [] theString;
    theString = new char [strlen (temp) + strlen (string.theString) + 1];

    strcpy (theString, temp);
    strcat (theString, string.theString);
  }
  else
    append (temp);
    
  delete [] temp;
}

void Strings::append (const int integer) 
{
char number[20];

  sprintf (number, "%d", integer);
  append (number);
}

void Strings::clear() 
{
  delete [] theString;
  theString = new char [1];
  theString [0] = '\0';
}

void Strings::erase() 
{
  clear();
}

void Strings::lowercase() 
{
  for (unsigned int i=0; i<=strlen (theString); i++)
    theString[i] = tolower ((theString[i]));
}

void Strings::prepend (char character) 
{
char *ctemp;
char *temp;

  temp = new char [strlen (theString) + 1];
  strcpy (temp, theString);

  ctemp = new char [2];
  ctemp [0] = character;
  ctemp [1] = '\0';
 
  delete [] theString;
  theString = new char [strlen (temp) + strlen (ctemp) + 1];
  
  strcpy (theString, ctemp);
  strcat (theString, temp);

  delete [] ctemp;
  delete [] temp;
}

void Strings::prepend (const char* string) 
{
  if (string != (char*)0)
  {
    char* temp;
    
    temp = new char [strlen (theString) + 1];
    strcpy (temp, theString);

    delete [] theString;
    theString = new char [strlen (temp) + strlen (string) + 1];

    strcpy (theString, string);
    strcat (theString, temp);

    delete [] temp;
  }
}

void Strings::prepend (const Strings& string) 
{
char* temp;

  temp = new char [strlen (theString) + 1];
  strcpy (temp, theString);

  if (this != &string)
  {
  delete [] theString;
  theString = new char [strlen (temp) + strlen (string.theString) + 1];

  strcpy (theString, string.theString);
  strcat (theString, temp);
  }
  else
    prepend (temp);

  delete [] temp;
}

void Strings::prepend (const int integer) 
{
char number[20];

  sprintf (number, "%d", integer);
  prepend (number);
}

void Strings::remove (const char c)
{
char *newString;
char *ptr = theString;

  newString = new char [strlen (theString) + 1];
  newString[0] = '\0';
  
  for (unsigned int i=0; i<(strlen(theString)); i++)
  {
    if (theString[i] != c)
      strncat (newString, ptr, 1);
    ptr++;
  }

  delete[] theString;
  theString = newString;
}

void Strings::replace (const char oldChar, const char newChar)
{
  for (unsigned int i=0; i<=strlen (theString); i++)
  {
    if (theString[i] == oldChar)
      theString[i] = newChar;
  }
}

void Strings::replace (const char c, const char* string)
{
Strings result, token;

  if (contains (c)) // dont do anything if you dont have to

  { 
    while (!empty())
    {
      if (contains (c))
      {
        slice (token, c, 1);
        result.append (token);
        result.append (string);
      }
      else
      {
        slice (token, c, 1);
        result.append (token);
      }
    }
    *this = result;
  }
}

void Strings::replace (const char c, const Strings& string)
{
  replace (c, string.theString);
}

void Strings::reverse()
{
char c;

  for (unsigned int i=0, j=length()-1; i<length()/2; i++, j--) 
  {
    c = theString[i];
    theString[i] = theString[j];
    theString[j] = c;
  }
}

void Strings::slice (unsigned int num, const Directions direction) 
{
  switch (direction)
  {
  case left:
    sliceLeft (num);
    break;
  case right:
    sliceRight (num);
    break;
  case leftAndRight:
    sliceLeft (num);
    sliceRight (num);
    break;
  default:
    break;
  }
}

void Strings::slice (
    Strings& string, const char delimitor, int removeDelimitor)
{
  string = sliceOf (delimitor);
  sliceLeft (string.length());
  if (removeDelimitor)
     sliceLeft (1);
}

void Strings::sliceLeft (Strings& string, unsigned int num) 
{
char *newString;
unsigned int i;

  newString = new char [strlen (theString) + 1];
  strcpy (newString, theString);
  for (i=0; newString[i] && i!=num; i++)
    ;
  newString[i] = '\0';

  delete[] string.theString;
  string.theString = newString;

  sliceLeft (num);
}

void Strings::sliceLeft (unsigned int num) 
{
char *marker;

  marker = theString;

  for (unsigned int i = 0; i < num; i++)
  {
    if (theString[i] == '\0')
    {
      clear();
      return;
    }
    marker++;
  }

  if (marker != theString)
  {
  char *newString;

    newString = new char [strlen (marker) + 1];
    strcpy (newString, marker);
    delete [] theString;
    theString = newString;
  }
}

void Strings::sliceRight (unsigned int num) 
{
int i = 0; 
unsigned int j = 0;
  
   i = strlen (theString) - 1;
   if (i > 0)
     while ((i >= 0) && num != j++)
       theString[i--] = '\0';
}

void Strings::sliceToken (const unsigned int tokensToSlice)
{
Strings token;

  for (unsigned int i=0; i<tokensToSlice; i++)
    sliceToken (token);
}

void Strings::sliceToken (const char delimitor, int removeDelimitor)
{
Strings token;

  sliceToken (token, delimitor, removeDelimitor);
}

void Strings::sliceToken (Strings& theToken)
{
  trimLeft();
  theToken = token();
  sliceLeft (theToken.length());
  trimLeft();
}

void Strings::sliceToken (
    Strings& theToken, const char delimitor, int removeDelimitor)
{
  trimLeft();
  theToken = token (delimitor);
  sliceLeft (theToken.length());
  theToken.trimRight();
  if (removeDelimitor)
  {
     sliceLeft (1);
     trimLeft();
  }
}

Strings Strings::soundexCodeOf (const char* string) const
{
// The Soundex code is an indexing system which translates names into 

// a 4 digit code consisting of 1 letter and 3 numbers. The advantage 

// of Soundex is its ability to group names by sound rather than the 

// exact spelling. 

//

//                              Soundex Rules

//

//  1. All Soundex codes have 4 alphanumeric characters [no more, no less]

//        o 1 Letter

//        o 3 Digits

//  2. The Letter of the name is the first character of the Soundex code.

//  3. The 3 digits are defined sequentially from the name using the Soundex

//     Key below.

//        o Adjacent letters in the name which belong to the same Soundex Key

//          code number are assigned a single digit.

//        o If the end of the name is reached prior to filling 3 digits, use

//          zeroes to complete the code.

//        o All codes have only 4 characters, even if the name is long enough

//          to yield more.

//

int value, previous;
Strings code;

  // error checking for null pointers and strings of length zero

  //

  if (string == (char*)0)
    return code;
  if (!isalpha (string[0]))
    return code;
  
  code.append (string[0]);
  code.uppercase();
  
  value = 0;
  for (unsigned int i = 1; string[i]!= '\0' && (code.length() < 4); i++)
  {
    previous = value; 
    value = soundexNumericOf (string[i]);
    if ((value != 0) && (value != previous))
      code.append (value);
  }
 
  while (code.length() < 4)
   code.append ('0');
  
  return code;
}

int Strings::soundexNumericOf (const char c) const
{
// The Soundex Key

//

//   1           B P F V

//   2       C S K G J Q X Z

//   3             D T

//   4              L

//   5             M N 

//   6              R

//   no code  A E H I O U Y W

//

int result = 0;
char temp = toupper (c);

  switch (temp)
  {
  case 'B':
  case 'P':
  case 'F':
  case 'V':
    result = 1;
    break;
  case 'C':
  case 'S':
  case 'K':
  case 'G':
  case 'J':
  case 'Q':
  case 'X':
  case 'Z':
    result = 2;
    break;
  case 'D':
  case 'T':
    result = 3;
    break;
  case 'L':
    result = 4;
    break;
  case 'M':
  case 'N':
    result = 5;
    break;
  case 'R':
    result = 6;
    break;
  default:
    break;
  }
  return result;  
}

void Strings::swap (Strings& string)
{
Strings temp;

  temp = *this;
  *this = string;
  string = temp;
}

void Strings::trim (const Directions direction) 
{
  switch (direction)
  {
  case left:
    trimLeft();
    break;
  case right:
    trimRight();
    break;
  case leftAndRight:
    trimLeft();
    trimRight();
    break;
  default:
    break;
  }
}

void Strings::trimLeft() 
{
char *marker;

  marker = theString;

  while (isspace (marker[0]))
    marker++; 

  if (marker != theString)
  {
  char *newString;

    newString = new char [strlen (marker) + 1];
    strcpy (newString, marker);
    delete [] theString;
    theString = newString;
  }
}

void Strings::trimRight() 
{
int i;
  
   i = strlen (theString) - 1;
   if (i > 0)
     while ((i >= 0) && isspace (theString[i]))
       theString[i--] = '\0';
}

void Strings::trim (const char c, const Directions direction) 
{
  switch (direction)
  {
  case left:
    trimLeft (c);
    break;
  case right:
    trimRight (c);
    break;
  case leftAndRight:
    trimLeft (c);
    trimRight (c);
    break;
  default:
    break;
  }
}

void Strings::trimLeft (const char c) 
{
char *marker;

  marker = theString;

  while (c == marker[0])
    marker++; 

  if (marker != theString)
  {
  char *newString;

    newString = new char [strlen (marker) + 1];
    strcpy (newString, marker);
    delete [] theString;
    theString = newString;
  }
}

void Strings::trimRight (const char c) 
{
int i;
  
   i = strlen (theString) - 1;
   if (i > 0)
     while ((i >= 0) && c == theString[i])
       theString[i--] = '\0';
}

void Strings::uppercase() 
{
  for (unsigned int i=0; i<=strlen (theString); i++)
    theString[i] = toupper (theString[i]);
}

Strings::operator const char*() const 
{
  return theString;
}

ostream& operator << (ostream& outputStream, const Strings&  string)
{
  return outputStream << string.theString;
}

const Strings& Strings::operator = (char character)
{
  delete [] theString;
  theString = new char [2];
  theString [0] = character;
  theString [1] = '\0';
  return *this;
}

const Strings& Strings::operator = (const char* string)
{
  delete [] theString;
  if (string != (char*)0)
    {
    theString = new char [strlen (string) + 1];
    strcpy (theString, string);
    }
  else
    {
    theString = new char [1];
    theString [0] = '\0';
    }
  return *this;
}

const Strings& Strings::operator = (const Strings& string)
{
  if (this != &string)
  {
    delete [] theString;
    theString = new char [strlen (string.theString) + 1];
    strcpy (theString, string.theString);
  }
  return *this;
}

Strings operator + (const Strings& string1, const Strings& string2) 
{
Strings temp;

  temp = string1;
  temp.append (string2);
  return temp;
}

Strings operator + (const Strings& string, const char* s) 
{
Strings temp;

  temp = string;
  temp.append (s);
  return temp;
}

Strings operator + (const char* s, const Strings& string) 
{
Strings temp;

  temp = s;
  temp.append (string);
  return temp;
}

Strings operator + (const Strings& string, const char character) 
{
Strings temp;

  temp = string;
  temp.append (character);
  return temp;
}

Strings operator + (const char character, const Strings& string) 
{
Strings temp;

  temp = character;
  temp.append (string);
  return temp;
}

Strings operator + (const Strings& string, const int number) 
{
Strings temp;

  temp = string;
  temp.append (number);
  return temp;
}

Strings operator + (const int number, const Strings& string) 
{
Strings temp;

  temp.append (number);
  temp.append (string);
  return temp;
}

const Strings& Strings::operator += (char character)
{
  append (character);
  return *this;
}

const Strings& Strings::operator += (const char* string)
{
  append (string);
  return *this;
}

const Strings& Strings::operator += (const Strings& string)
{
  append (string);
  return *this;
}

const Strings& Strings::operator += (const int number)
{
  append (number);
  return *this;
}

int Strings::operator == (const Strings& string) const
{
  return (strcmp (theString, string.theString) == 0);
}

int Strings::operator == (const char* string) const
{
  return (strcmp (theString, string) == 0);
}

int Strings::operator != (const Strings& string) const
{
  return !(strcmp (theString, string.theString) == 0);
}

int Strings::operator != (const char* string) const
{
  return !(strcmp (theString, string) == 0);
}

int Strings::operator < (const Strings& string) const
{
  return (strcmp (theString, string.theString) < 0);
}

int Strings::operator < (const char* string) const
{
  return (strcmp (theString, string) < 0);
}

int Strings::operator > (const Strings& string) const
{
  return (strcmp (theString, string.theString) > 0);
}

int Strings::operator > (const char* string) const
{
  return (strcmp (theString, string) > 0);
}

int Strings::operator <= (const Strings& string) const
{
  return (strcmp (theString, string.theString) <= 0);
}

int Strings::operator <= (const char* string) const
{
  return (strcmp (theString, string) <= 0);
}

int Strings::operator >= (const Strings& string) const
{
  return (strcmp (theString, string.theString) >= 0);
}

int Strings::operator >= (const char* string) const
{
  return (strcmp (theString, string) >= 0);
}

const char& Strings::operator [] (const unsigned int index) const
{
  if (index > length())
    return theString[length()];
  else
    return theString[index];
}


// Copyright (c) 1995-1997 D J Supel and ISX Corporation





syntax highlighted by Code2HTML, v. 0.9.1