// This may look like C code, but it is really -*- C++ -*-

// <copyright>
// 
// Copyright (c) 1993
// Institute for Information Processing and Computer Supported New Media (IICM),
// Graz University of Technology, Austria.
// 
// </copyright>

//<file>
//
// Name:       str.h
//
// Purpose:    Character pointer with resource management
//
// Created:     1990    Gerald Pani
//
// Modified:   24 Aug 93    Gerald Pani
//
//
//
// Description:
//
//</file>


#ifndef hg_utils_str_h
#define hg_utils_str_h


#include "types.h"
#include <iostream.h>

//<class>
//
// Name:       StringRep
//
// Purpose:    Unique representation of a string
// 
//
// Private Interface:
//
// Accessible through class RString.
//
// - StringRep( const char* s)
//   Constructor. Makes a copy of s. s must be null-terminated. The
//   copy is null-terminated too.
//
// - StringRep( const char* s, int len)
//   Constructor. Makes a copy of s. The copy has len + 1 bytes and is
//   null-terminated. 
//
// - StringRep( const char* s1, const char* s2)
//   Constructor. Concatenation of s1 and s2. s1 and s2 must be
//   null-terminated. The copy is null-terminated. 
//
// - StringRep( StringRep& r1, StringRep& r2)
//   Constructor. Concatenation of r1 and r2. r1 or r2 can contain
//   null-characters. The copy is null-terminated. 
//
// - ~StringRep()
//   Destructor. Frees the storage used for the string.
//
// - static StringRep* lambda()
//   Gives a pointer to the empty string.
//   
//
// Description:
//
// 
//</class>

class StringRep {
 friend class RString;
     StringRep( const char*);
     StringRep( const char*, int len);
     StringRep( const char*, const char *);
     StringRep( StringRep&, StringRep&);
     ~StringRep() { delete str_; }

     static StringRep* lambda();

     char* str_;		// pointer to the character array
				// (always null-terminated)
     int refs_;			// reference count
     int len_;			// length of the character array
				// (without terminating
				// null-character) 
     static StringRep* lambda_;	// pointer to the representation of
				// the empty string ("")
};

inline StringRep* StringRep::lambda() {
     if (!lambda_)
	  lambda_ = new StringRep("");
     return lambda_;
}


//<class>
//
// Name:       RString
//
// Purpose:   
// 
//
// Public Interface:
//
// - RString()
//   Default constructor. Empty string (lambda).
//
// - RString( const char* s)
//   Constructor. s nil or "" -> lambda; otherwise make a copy of s (s
//   must be null-terminated). 
//
// - RString( const char* s, int len)
//   Constructor. s nil or len = 0 -> lambda; otherwise copy len
//   characters of s and append null-character.
//
// - RString( const RString& r)
//   Constructor. Pointer to the representation of r (increments the
//   reference count).
//
// - ~RString()
//   Destructor. Decrements the reference count and deletes the
//   StringRep if no other RString points to it.
//
// - int indexa( const RString& r) const
// - int indexa( const char* r) const
//   Index of the first character after r (0 <= index <= len) if r is
//   a substring of this or result -1 otherwise.
//   
// - int indexa( int index, const RString& r) const
// - int indexa( int index, const char* r) const
//   Like indexa( r) starting at index.
//   
// - int index( char c) const
// - int index( int index, char c) const
//   Index of the first occurence of character c (0 <= index < len) or
//   result -1 otherwise.
//   
// - RString gSubstrDelim( int index, char delim) const
//   Result is a new RString representating the substring beginning at
//   position index to the last character before delim or til end of
//   string if delim is not found.
//   
// - RString gSubstrIndex( int begin, int end) const
//   Result is a new RString representating the substring beginning at
//   position begin and ending at position end.
//   
// - RString gRight( int begin) const
//   Result is a new RString representating the substring beginning at
//   position begin.
//   
// - boolean gWord( int& index, const RString& white, RString& word) const
//   
// - boolean gWordChar( int& index, const char white, RString& word) const
//   
// - RString& gLine( istream& s, char delim = '\n') const
//   
// - int length() const
//   
// - RString& subst( char a, char b)
//
// - RString& invert()
// 
// - RString& tolower()
// 
// - RString& toupper()
// 
// - RString& sgml2Iso()
// 
// - RString& sgmlIso2LowerAscii()
// 
// - RString& dos2Unix()
// 
// - RString& unix2Dos()
//
// - static const RString lambda()
//
// - static const RString& lambdaRef()
//
// - RString& operator =( const RString& r)
//   Like ~RString and RString( r).
//
// - RString& operator =( const char* s)
//   Like ~RString and RString( s).
//
// - RString& operator +=( const RString& r)
//   Concatenation of this and r.
//
// - operator const char*() const
//   Cast operator. Use a RString as a constant character pointer.
//
// - char operator []( int i) const
//   Array operator.
//
// Friend operators:
//
// - friend RString operator +( const RString& r1, const RString& r2)
//   Result is contatenation or r1 and r2.
//   
// - friend int operator ==( const RString& r1, const RString& r2)
// - friend int operator ==( const RString& r1, const char* s2)
// - friend int operator ==( const char* s1, const RString& r2)
//   Result is true, if the arguments are equal.
//   
// - friend int operator !=( const RString& r1, const RString& r2)
// - friend int operator !=( const RString& r1, const char* s2)
// - friend int operator !=( const char* s1, const RString& r2)
//   Result is false, if the arguments are equal.
// 
// - friend int operator <( const RString&, const RString&)
// - friend int operator <( const char*, const RString&)
// - friend int operator <( const RString&, const char*)
//   Result as expected.
//   
// - friend int operator >( const RString& s1, const RString& s2)
// - friend int operator >( const char* s1, const RString& s2)
// - friend int operator >( const RString& s1, const char* s2)
//   Result as expected.
//
// - friend ostream& operator <<( ostream& o, const RString& s);
// 
//   
// Description:
//
// 
//</class>

class istream;

class RString {
 public:
     // constructors
     RString();
     RString( const char*);
     RString( const char*, int);
     RString( const RString&);
     // destructor
     ~RString();
     // operators
     RString& operator =( const RString&);
     RString& operator =( const char*);
     RString& operator +=( const RString&);
     operator const char*() const;
     const char* string() const;
     char operator []( int i) const;

  private:
     friend RString operator +( const RString&, const RString&);
     friend int operator ==( const RString&, const RString&);
     friend int operator ==( const RString&, const char*);
     friend int operator ==( const char*, const RString&);
     friend int operator !=( const RString&, const RString&);
     friend int operator !=( const RString&, const char*);
     friend int operator !=( const char*, const RString&);
     friend int operator <( const RString&, const RString&);
     friend int operator <( const char*, const RString&);
     friend int operator <( const RString&, const char*);
//      friend int operator >( const RString& s1, const RString& s2);
//      friend int operator >( const char* s1, const RString& s2);
//      friend int operator >( const RString& s1, const char* s2);

//      friend ostream& operator <<( ostream& o, const RString& s);
  public:
     int indexa( const RString& str) const; // index of first character after str in RString.
					    // 0 <= index <= len
     int indexa( const char* str) const;    // index == -1, str not found in RString
     int indexa( int index, const RString& str) const; // indexa starting at index
     int indexa( int index, const char* str) const;
     int index( char c) const;	// index of first occurence of character c in
				// RString. 0 <= index < len.
				// index == -1, c not found in RString
     int index( int index, char c) const;		  // index
							  // starting at index

     RString gSubstrDelim( int index, char delim) const;
     RString GetSubstrDelim( int index, char delim) const { return
							    gSubstrDelim( index, delim); } 
     RString gSubstrIndex( int begin, int end) const;	  // from index begin to end
     RString GetSubstrIndex( int begin, int end) const { return
							 gSubstrIndex(
								      begin, end); }
     RString gRight( int begin) const;			  // from begin to end of string
     RString GetRight( int begin) const { return gRight( begin); }

     boolean gWord( int& index, const RString& white, RString& word) const;
     boolean GetWord( int& index, const RString& white, RString& word) const { 
	  return gWord( index, white, word); }
     boolean gWordChar( int& index, const char white, RString& word) const;
     boolean GetWordChar( int& index, const char white, RString& word) const { 
	  return gWordChar( index, white, word); }
     RString& gLine( istream& s, char delim = '\n');
     RString& GetLine( istream& s) { return gLine( s); }
				
     int length() const { return r_->len_; }
     RString& subst( char a, char b); 			  // replace all a with b
     RString& invert();
     RString& tolower();
     RString& toupper();
     RString& sgml2Iso();
     RString& SGMLtoISO() { return sgml2Iso(); }
     RString& sgmlIso2LowerAscii();
     RString& SGMLISOtolowerASCII() { return sgmlIso2LowerAscii(); }
     RString& dos2Unix();
     RString& Dos2Unix() { return dos2Unix(); }
     RString& unix2Dos();
     RString& Unix2Dos() { return unix2Dos(); };

     static const RString lambda() { return lambda_; }
     static const RString& lambdaRef() { return lambda_; }
  protected:
     boolean gWordTable( int& index, const char white[], RString& word) const;
  private:
     RString( const RString&, const RString&);

     StringRep* r_;

     static const RString lambda_;
     // alles nur wegen Gnu!!! diesmal nicht HaHa; jetzt Uff!
     // static const int numents_;
//      static const char* sgml_[];
//      static const char iso_[];
//      static const char* low_[];
};
     
inline int operator >( const RString& s1, const RString& s2) {return (s2 < s1);}
inline int operator >( const char* s1, const RString& s2) {return (s2 < s1);}
inline int operator >( const RString& s1, const char* s2) {return (s2 < s1);}


inline RString::operator const char*() const {
     return (const char*) r_->str_;
}

inline const char* RString::string() const {
     return (const char*) r_->str_;
}

inline char RString::operator []( int i) const {
     return r_->str_[i];
}

inline ostream& operator <<( ostream& o, const RString& s) { return o << s.string(); }

#endif





