// file: $isip/class/system/SysString/SysString.h
// version: $Id: SysString.h 9418 2004-03-10 17:11:33Z parihar $
//

// make sure definitions are only made once
//
#ifndef ISIP_SYS_STRING
#define ISIP_SYS_STRING

// include the configure output:
//  this has to be done here since wchar.h is possibly included before
//  File.h (which in turn includes Integral.h and IntegralConfigure.h)
//
#ifndef ISIP_INTEGRAL_CONFIGURE
#define ISIP_INTERNAL_USE_ONLY
#include <IntegralConfigure.h>
#undef ISIP_INTERNAL_USE_ONLY
#endif

// include definition for the SysComplex type
//
#ifndef ISIP_SYS_COMPLEX
#include <SysComplex.h>
#endif

// system include files needed for non Solaris systems
//
#if ISIP_WCHAR_MODE == ISIP_WCHAR_REDHAT
#include <wchar.h>
#endif

// isip include files:
//  though we could get by with a forward class definition, it is very
//  convenient to include SysChar here, since virtually all methods
//  use it. File is needed so we can convert the File::MODE
//  enumeration into a string. a benefit of having SysChar in the
//  header file is so we can convert the SysChar::ENCODING enumeration
//  into a string, as well
//
#ifndef ISIP_SYS_CHAR
#include <SysChar.h>
#endif

#ifndef ISIP_FILE
#include <File.h>
#endif

// SysString: a class that manages a string of unicode characters. this is
// needed at a low-level in the system so that other low-level classes,
// such as Sof, can operate on unicode characters. most users will
// interact with a higher-level version of this class in math/scalar
// called String.
//
class SysString {
    
  //---------------------------------------------------------------------------
  //
  // public constants
  //
  //---------------------------------------------------------------------------
public:

  // define the class name
  //
  static const SysString CLASS_NAME;
  
  //---------------------------------------
  //
  // other important constants
  //
  //---------------------------------------

  // miscellaneous constants
  //
  static const long MAX_LENGTH = 1024;
  static const long BIG_BUFFER_LENGTH = 8192;
  static const long STATIC_BUFFER_SIZE = 16;

  // define special strings
  //
  static const unichar NULL_STRING[];
  static const SysString NULL_PTR;
  
  // text corresponding to boolean values
  //
  static const SysString BOOL_TRUE;
  static const SysString BOOL_FALSE;

  // text corresponding to debug values
  //
  static const SysString DBG_NONE;
  static const SysString DBG_BRIEF;
  static const SysString DBG_DETAILED;
  static const SysString DBG_ALL;
  
  // text corresponding to compare values
  //
  static const SysString CMP_EQUAL;
  static const SysString CMP_LESSER;
  static const SysString CMP_GREATER;

  // text corresponding to file mode values
  //
  static const SysString MODE_READ_ONLY;
  static const SysString MODE_READ_PLUS;
  static const SysString MODE_WRITE_ONLY;
  static const SysString MODE_WRITE_PLUS;
  static const SysString MODE_APPEND_ONLY;
  static const SysString MODE_APPEND_PLUS;

  // text corresponding to file type values
  //
  static const SysString TYPE_TEXT;
  static const SysString TYPE_BINARY;
  
  // text corresponding to file binary mode values
  //
  static const SysString BMODE_NATIVE;
  static const SysString BMODE_SWAP;
  static const SysString BMODE_BIG_ENDIAN;
  static const SysString BMODE_LITTLE_ENDIAN;
  
  // text corresponding to SysChar encode values
  //
  static const SysString ENCODE_ASCII;
  static const SysString ENCODE_UTF8;
  static const SysString ENCODE_UTF16;
  
  // text corresponding to MemoryManager modes
  //
  static const SysString MMGR_MODE_OPTIMIZE;
  static const SysString MMGR_MODE_TRACK;
  
  // small state machine for symbolPad
  //
  static const long STATE_PAD_NOSPACE = 0;
  static const long STATE_PAD_SPACE = 1;
  
  // format for the debug method output
  //
  static const SysString DBG_FORMAT_0;
  static const SysString DBG_FORMAT_1;
  static const SysString DBG_FORMAT_2;
  static const SysString DBG_FORMAT_3;

  // format for the debugStr output
  //
  static const SysString DBGS_FORMAT_0;
  static const SysString DBGS_FORMAT_1;
  static const SysString DBGS_FORMAT_2;
  static const SysString DBGS_FORMAT_3;

  // 8-bit version of the default format strings (for efficiency)
  //
  static const char DEF_FMT_VOIDP_8BIT[];
  static const char DEF_FMT_ULONG_8BIT[];
  static const char DEF_FMT_ULLONG_8BIT[];
  static const char DEF_FMT_LONG_8BIT[];
  static const char DEF_FMT_LLONG_8BIT[];
  static const char DEF_RFMT_FLOAT_8BIT[];
  static const char DEF_WFMT_FLOAT_8BIT[];
  static const char DEF_RFMT_DOUBLE_8BIT[];
  static const char DEF_WFMT_DOUBLE_8BIT[];

  //----------------------------------------
  //
  // default values and arguments
  //
  //----------------------------------------  

  // define the default value(s) of the class data
  //
  static const long DEF_CAPACITY = 0;
  static const SysString DEF_VALUE;

  // default arguments to methods
  //
  static const unichar DEF_TERM = (unichar)NULL;
  static const byte DEF_TERM_BYTE = (byte)NULL;
  static const long DEF_POS = Integral::NO_POS;

  //----------------------------------------
  //
  // error codes
  //
  //----------------------------------------  

  static const long ERR = 1300;
  
  //---------------------------------------------------------------------------
  //
  // protected data
  //
  //---------------------------------------------------------------------------
protected:

  // internal data - be careful not to add anything that isn't absolutely
  // necessary, so that higher level classes (e.g., vector) do not waste space
  //
  unichar* value_d;
  long capacity_d;

  // declare a static debug level for all class instantiations
  //
  static Integral::DEBUG debug_level_d;
  
  //---------------------------------------------------------------------------
  //
  // required public methods
  //
  //---------------------------------------------------------------------------
public:

  // method: name
  //
  static const SysString& name() {
    return CLASS_NAME;
  }
  
  // other static methods
  //
  static boolean diagnose(Integral::DEBUG debug_level);

  // method: setDebug
  //  the setDebug method for this class is static because the debug_level is
  //  shared across all objects of this class type
  //
  static boolean setDebug(Integral::DEBUG level) {
    debug_level_d = level;
    return true;
  }

  // other debug methods
  //
  boolean debug(const unichar* msg) const;
  
  // destructor/constructor(s)
  //

  // method: destructor
  //
  ~SysString() {
    freeMem();
  }

  // method: default constructor
  //
  SysString(long capacity = DEF_CAPACITY);

  // method: copy constructor
  //
  SysString(const SysString& arg);
  
  // assign methods
  //
  boolean assign(const SysString& arg);

  // method: operator=
  //
  SysString& operator=(const SysString& arg) {
    assign(arg);
    return *this;
  }

  // i/o methods:
  //  these methods are omitted because SysString can not write itself to an
  //  sof file
  //

  // equality methods
  //
  boolean eq(const SysString& value, boolean case_sensitive = true) const;

  // memory management methods:
  //  the new and delete methods are omitted because only classes at the
  //  math library level and above are required to override new and delete
  //
  boolean clear(Integral::CMODE ctype = Integral::DEF_CMODE);

  //---------------------------------------------------------------------------
  //
  // class-specific public methods:
  //  extensions to required methods
  //
  //---------------------------------------------------------------------------

  // constructors
  //
  SysString(const unichar* data);
  SysString(const byte* data, SysChar::ENCODE encoding = SysChar::DEF_ENCODE);

  // assign methods
  //
  boolean assign(const unichar* data);
  boolean assign(const byte* data, long max_size = BIG_BUFFER_LENGTH,
		 SysChar::ENCODE encoding = SysChar::DEF_ENCODE);

  // numeric conversion assignment methods:
  //
  boolean assign(const void* arg);
  boolean assign(boolean arg);
  boolean assign(const byte arg);
  boolean assign(unichar arg);
  boolean assign(const ushort arg);
  boolean assign(const ulong arg);
  boolean assign(const ullong arg);
  boolean assign(const short arg);
  boolean assign(const long arg);
  boolean assign(const llong arg);
  boolean assign(const float arg);
  boolean assign(const double arg);

  template <class TIntegral>
  boolean assign(const SysComplex<TIntegral>& arg);

  // define versions of the assign methods that take format strings
  //
  boolean assign(const SysString& arg, const unichar* fmt);
  boolean assign(const unichar* data, const unichar* fmt);
  boolean assign(const byte* data, const unichar* fmt,
		 long max_size = BIG_BUFFER_LENGTH,
		 SysChar::ENCODE encoding = SysChar::DEF_ENCODE);

  // numeric conversion assignment methods:
  //  these methods are similar to sprintf() in C
  //
  boolean assign(const void* arg, const unichar* fmt);
  boolean assign(const boolean arg, const unichar* fmt);
  boolean assign(const byte arg, const unichar* fmt);
  boolean assign(const unichar arg, const unichar* fmt);
  boolean assign(const ushort arg, const unichar* fmt);
  boolean assign(const ulong arg, const unichar* fmt);
  boolean assign(const ullong arg, const unichar* fmt);
  boolean assign(const short arg, const unichar* fmt);
  boolean assign(const long arg, const unichar* fmt);
  boolean assign(const llong arg, const unichar* fmt);
  boolean assign(const float arg, const unichar* fmt);
  boolean assign(const double arg, const unichar* fmt);

  template <class TIntegral>
  boolean assign(const SysComplex<TIntegral>& arg, const unichar* fmt);

  // enum assignment methods
  //
  boolean assign(Integral::DEBUG arg);
  boolean assign(Integral::COMPARE arg);
  boolean assign(File::MODE arg);
  boolean assign(File::BMODE arg);
  boolean assign(File::TYPE arg);
  boolean assign(SysChar::ENCODE arg);
  boolean assign(MemoryManager::MODE arg);
  
  // special assignment methods:
  //  swaps pointers and is meant to be very fast
  //
  boolean swap(SysString& arg);

  //---------------------------------------------------------------------------
  //
  // class-specific public methods:
  //  relational and logical methods
  //
  //---------------------------------------------------------------------------
  
  // method: compare
  //
  Integral::COMPARE compare(const SysString& str) const {
    return compare(*this, str);
  }
  
  // other generic compare methods
  //
  Integral::COMPARE compare(const SysString& arg1,
			    const SysString& arg2) const;
  Integral::COMPARE compare(const unichar* str) const;
  Integral::COMPARE comparePartial(const SysString& arg,
				   long arg_offset,
				   long num_elements, long offset) const;
  Integral::COMPARE comparePartial(const unichar* arg,
				   long arg_offset,
				   long num_elements, long offset) const;

  // method: ne
  //
  boolean ne(const SysString& vector, boolean case_sensitive = true) const {
    return !eq(vector, case_sensitive);
  }

  // other equality methods:
  //
  boolean eq(const unichar* value, boolean case_sensitive = true) const;
  boolean ne(const unichar* value, boolean case_sensitive = true) const;

  // method: gt
  //
  boolean gt(const SysString& vector) const {
    return (compare(vector) == Integral::GREATER);
  }

  // other greater than methods
  //
  boolean gt(const unichar* value) const;

  // method: lt
  //
  boolean lt(const SysString& vector) const {
    return (compare(vector) == Integral::LESSER);
  }

  // other less than methods
  //
  boolean lt(const unichar* value) const;

  // method: ge
  //
  boolean ge(const SysString& vector) const {
    return (compare(vector) != Integral::LESSER);
  }

  // other greater than or equal to methods
  //
  boolean ge(const unichar* value) const;

  // method: le
  //
  boolean le(const SysString& vector) const {
    return (compare(vector) != Integral::GREATER);
  }

  // other less than or equal to methods
  //
  boolean le(const unichar* value) const;

  // unichar comapre methods:
  //  these methods give the number of characters equal or not equal
  //  to the argument
  //
  long numEqual(unichar test_value) const;

  // method: numNotEqual
  //
  long numNotEqual(unichar test_value) const {
    return (length() - numEqual(test_value));
  }
  
  //---------------------------------------------------------------------------
  //
  // class-specific public methods:
  //  indexing methods
  //
  //---------------------------------------------------------------------------
  
  // method: operator()
  //
  unichar& operator()(long index) {
    return value_d[index];
  }

  // method: operator()
  //
  const unichar& operator()(long index) const {
    return value_d[index];
  }

  //---------------------------------------------------------------------------
  //
  // class-specific public methods:
  //  conversion methods
  //
  //---------------------------------------------------------------------------
  
  // automatic type conversion methods
  //
  operator byte*() const;
  operator unichar*() const;
  
  // numeric conversion methods
  //
  boolean get(void*& arg) const;
  boolean get(boolean& arg) const;
  boolean get(byte& arg) const;
  boolean get(unichar& arg) const;
  boolean get(SysChar& arg) const;
  boolean get(ushort& arg) const;
  boolean get(ulong& arg) const;
  boolean get(ullong& arg) const;
  boolean get(short& arg) const;
  boolean get(long& arg) const;
  boolean get(llong& arg) const;
  boolean get(float& arg) const;
  boolean get(double& arg) const;

  template <class TIntegral>
  boolean get(SysComplex<TIntegral>& arg) const;

  //---------------------------------------------------------------------------
  //
  // class-specific public methods:
  //  size-related methods
  //
  //---------------------------------------------------------------------------

  // method: length
  //
  long length() const {
    return isip_wcslen(value_d);
  }

  // size methods
  //
  long memSize() const;

  // capacity-related methods
  //
  boolean setCapacity(long cap);
  
  //---------------------------------------------------------------------------
  //
  // class-specific public methods:
  //  string manipulation methods
  //
  //---------------------------------------------------------------------------

  // array-oriented methods
  //
  long getBuffer(unichar* buffer, long max) const;
  long getBuffer(byte* buffer, long max,
		 SysChar::ENCODE encoding = SysChar::DEF_ENCODE) const;
  boolean substr(SysString& str, long offset,
		 long num_elements = Integral::NO_POS) const;

  // insert/replace a substring into the string methods
  //
  boolean insert(const SysString& str, long index);
  boolean insert(const unichar* str, long index);
  boolean replace(const SysString& str, long index);
  boolean replace(const unichar* str, long index);
  boolean replace(const SysString& pattern, const SysString& new_stuff);
  boolean replaceAll(const SysString& pattern, const SysString& new_stuff);
  boolean deleteRange(long offset, long num_elements);

  // append to the end of the string methods
  //
  boolean concat(const SysString& str);
  boolean concat(const SysString& str1, const SysString& str2);

  // method: concat
  //
  boolean concat(const unichar* arg) {
    SysString temp;
    temp.assign(arg);
    return concat(temp);
  }

  // method: concat
  //
  boolean concat(unichar arg) {
    SysString temp;
    temp.assign(arg);
    return concat(temp);
  }

  // numeric concatenation methods:
  //  these methods are similar to sprintf() in C
  //

  // method: concat
  //
  boolean concat(const void* arg) {
    SysString temp;
    temp.assign(arg);
    return concat(temp);
  }
  
  // method: concat
  //
  boolean concat(boolean arg) {
    SysString temp;
    temp.assign(arg);
    return concat(temp);
  }
  
  // method: concat
  //
  boolean concat(const byte arg) {
    SysString temp;
    temp.assign(arg);
    return concat(temp);
  }
  
  // method: concat
  //
  boolean concat(const ushort arg) {
    SysString temp;
    temp.assign(arg);
    return concat(temp);
  }
  
  // method: concat
  //
  boolean concat(const ulong arg) {
    SysString temp;
    temp.assign(arg);
    return concat(temp);
  }
  
  // method: concat
  //
  boolean concat(const ullong arg) {
    SysString temp;
    temp.assign(arg);
    return concat(temp);
  }
  
  // method: concat
  //
  boolean concat(const short arg) {
    SysString temp;
    temp.assign(arg);
    return concat(temp);
  }
  
  // method: concat
  //
  boolean concat(const long arg) {
    SysString temp;
    temp.assign(arg);
    return concat(temp);
  }
  
  // method: concat
  //
  boolean concat(const llong arg) {
    SysString temp;
    temp.assign(arg);
    return concat(temp);
  }
  
  // method: concat
  //
  boolean concat(const float arg) {
    SysString temp;
    temp.assign(arg);
    return concat(temp);
  }
  
  // method: concat
  //
  boolean concat(const double arg) {
    SysString temp;
    temp.assign(arg);
    return concat(temp);
  }
  
  // method: concat
  //
  template <class TIntegral>
  boolean concat(const SysComplex<TIntegral>& arg) {
    SysString temp;
    temp.assign(arg);
    return concat(temp);
  }
    
  // append to the end of the string methods with format
  //

  // method: concat
  //
  boolean concat(const SysString& arg, const unichar* fmt) {
    SysString temp;
    temp.assign(arg, fmt);
    return concat(temp);
  }
  
  // method: concat
  //
  boolean concat(const unichar* arg, const unichar* fmt) {
    SysString temp;
    temp.assign(arg, fmt);
    return concat(temp);
  }
  
  // method: concat
  //
  boolean concat(unichar arg, const unichar* fmt) {
    SysString temp;
    temp.assign(arg, fmt);
    return concat(temp);
  }
  
  // numeric concatenation methods with format:
  //  these methods are similar to sprintf() in C
  //

  // method: concat
  //
  boolean concat(const void* arg, const unichar* fmt) {
    SysString temp;
    temp.assign(arg, fmt);
    return concat(temp);
  }
  
  // method: concat
  //
  boolean concat(boolean arg, const unichar* fmt) {
    SysString temp;
    temp.assign(arg, fmt);
    return concat(temp);
  }
  
  // method: concat
  //
  boolean concat(const byte arg, const unichar* fmt) {
    SysString temp;
    temp.assign(arg, fmt);
    return concat(temp);
  }
  
  // method: concat
  //
  boolean concat(const ushort arg, const unichar* fmt) {
    SysString temp;
    temp.assign(arg, fmt);
    return concat(temp);
  }
  
  // method: concat
  //
  boolean concat(const ulong arg, const unichar* fmt) {
    SysString temp;
    temp.assign(arg, fmt);
    return concat(temp);
  }
  
  // method: concat
  //
  boolean concat(const ullong arg, const unichar* fmt) {
    SysString temp;
    temp.assign(arg, fmt);
    return concat(temp);
  }
  
  // method: concat
  //
  boolean concat(const short arg, const unichar* fmt) {
    SysString temp;
    temp.assign(arg, fmt);
    return concat(temp);
  }
  
  // method: concat
  //
  boolean concat(const long arg, const unichar* fmt) {
    SysString temp;
    temp.assign(arg, fmt);
    return concat(temp);
  }
  
  // method: concat
  //
  boolean concat(const llong arg, const unichar* fmt) {
    SysString temp;
    temp.assign(arg, fmt);
    return concat(temp);
  }
  
  // method: concat
  //
  boolean concat(const float arg, const unichar* fmt) {
    SysString temp;
    temp.assign(arg, fmt);
    return concat(temp);
  }
  
  // method: concat
  //
  boolean concat(const double arg, const unichar* fmt) {
    SysString temp;
    temp.assign(arg, fmt);
    return concat(temp);
  }
  
  // method: concat
  //
  template <class TIntegral>
  boolean concat(const SysComplex<TIntegral>& arg, const unichar* fmt) {
    SysString temp;
    temp.assign(arg, fmt);
    return concat(temp);
  }
  
  // trim away characters from string methods
  //
  boolean trim();
  boolean trim(const SysString& chars);
  boolean trim(const unichar* chars);
  
  boolean trimLeft();
  boolean trimLeft(const SysString& chars);
  boolean trimLeft(const unichar* chars);
  
  boolean trimRight();
  boolean trimRight(const SysString& chars);
  boolean trimRight(const unichar* chars);
 
  // string case conversion methods
  //
  boolean toUpper();
  boolean toLower();
  boolean toMixed();
  boolean toMixed(const SysString& sep_chrs);

  //---------------------------------------------------------------------------
  //
  // class-specific public methods:
  //  string search methods
  //
  //---------------------------------------------------------------------------

  // method: firstStr
  //
  long firstStr(const unichar* str, long start = Integral::NO_POS) const {
    SysString temp(str);
    return firstStr(temp, start);
  }
  
  // other first string methods
  //
  long firstStr(const SysString& str, long start = Integral::NO_POS) const;

  // method: lastStr
  //
  long lastStr(const unichar* str, long end = Integral::NO_POS) const {
    SysString temp(str);
    return lastStr(temp, end);
  }    

  // other last string methods
  //
  long lastStr(const SysString& str, long end = Integral::NO_POS) const;

  // method: firstChr
  //
  long firstChr(const unichar* chrs, long start = Integral::NO_POS) const {
    SysString temp(chrs);
    return firstChr(temp, start);
  }
  
  // other first char methods
  //
  long firstChr(const SysString& chrs, long start = Integral::NO_POS) const;
  long firstChr(unichar chr, long start = Integral::NO_POS) const;
  
  // method: lastChr
  //
  long lastChr(const unichar* chrs, long end = Integral::NO_POS) const {
    SysString temp(chrs);
    return lastChr(temp, end);
  }
  
  // other last char methods
  //
  long lastChr(const SysString& chrs, long end = Integral::NO_POS) const;
  long lastChr(unichar chr, long end = Integral::NO_POS) const;

  // not char methods:
  //
  long firstNotChr(const SysString& chrs, long start = Integral::NO_POS) const;
  long firstNotChr(unichar chr, long start = Integral::NO_POS) const;
  
  long lastNotChr(const SysString& chrs, long end = Integral::NO_POS) const;
  long lastNotChr(unichar chr, long end = Integral::NO_POS) const;

  // method: firstAlnum
  //
  long firstAlnum(long start = Integral::NO_POS) const {
    return firstChar(start, &SysChar::isAlnum);
  }

  // method: firstAlpha
  //
  long firstAlpha(long start = Integral::NO_POS) const {
    return firstChar(start, &SysChar::isAlpha);
  }

  // method: firstDigit
  //
  long firstDigit(long start = Integral::NO_POS) const {
    return firstChar(start, &SysChar::isDigit);
  }

  // method: firstLower
  //
  long firstLower(long start = Integral::NO_POS) const {
    return firstChar(start, &SysChar::isLower);
  }

  // method: firstPrint
  //
  long firstPrint(long start = Integral::NO_POS) const {
    return firstChar(start, &SysChar::isPrint);
  }

  // method: firstPunct
  //
  long firstPunct(long start = Integral::NO_POS) const {
    return firstChar(start, &SysChar::isPunct);
  }

  // method: firstSpace
  //
  long firstSpace(long start = Integral::NO_POS) const {
    return firstChar(start, &SysChar::isSpace);
  }

  // method: firstUpper
  //
  long firstUpper(long start = Integral::NO_POS) const {
    return firstChar(start, &SysChar::isUpper);
  }

  // method: lastAlnum
  //
  long lastAlnum(long end = Integral::NO_POS) const {
    return lastChar(end, &SysChar::isAlnum);
  }

  // method: lastAlpha
  //
  long lastAlpha(long end = Integral::NO_POS) const {
    return lastChar(end, &SysChar::isAlpha);
  }

  // method: lastDigit
  //
  long lastDigit(long end = Integral::NO_POS) const {
    return lastChar(end, &SysChar::isDigit);
  }

  // method: lastLower
  //
  long lastLower(long end = Integral::NO_POS) const {
    return lastChar(end, &SysChar::isLower);
  }

  // method: lastPrint
  //
  long lastPrint(long end = Integral::NO_POS) const {
    return lastChar(end, &SysChar::isPrint);
  }

  // method: lastPunct
  //
  long lastPunct(long end = Integral::NO_POS) const {
    return lastChar(end, &SysChar::isPunct);
  }

  // method: lastSpace
  //
  long lastSpace(long end = Integral::NO_POS) const {
    return lastChar(end, &SysChar::isSpace);
  }

  // method: lastUpper
  long lastUpper(long end = Integral::NO_POS) const {
    return lastChar(end, &SysChar::isUpper);
  }

  // method: firstNotAlnum
  //
  long firstNotAlnum(long start = Integral::NO_POS) const {
    return firstNotChar(start, &SysChar::isAlnum);
  }

  // method: firstNotAlpha
  //
  long firstNotAlpha(long start = Integral::NO_POS) const {
    return firstNotChar(start, &SysChar::isAlpha);
  }

  // method: firstNotDigit
  //
  long firstNotDigit(long start = Integral::NO_POS) const {
    return firstNotChar(start, &SysChar::isDigit);
  }

  // method: firstNotLower
  //
  long firstNotLower(long start = Integral::NO_POS) const {
    return firstNotChar(start, &SysChar::isLower);
  }

  // method: firstNotPrint
  //
  long firstNotPrint(long start = Integral::NO_POS) const {
    return firstNotChar(start, &SysChar::isPrint);
  }

  // method: firstNotPunct
  //
  long firstNotPunct(long start = Integral::NO_POS) const {
    return firstNotChar(start, &SysChar::isPunct);
  }

  // method: firstNotSpace
  //
  long firstNotSpace(long start = Integral::NO_POS) const {
    return firstNotChar(start, &SysChar::isSpace);
  }

  // method: firstNotUpper
  //
  long firstNotUpper(long start = Integral::NO_POS) const {
    return firstNotChar(start, &SysChar::isUpper);
  }

  // method: lastNotAlnum
  //
  long lastNotAlnum(long end = Integral::NO_POS) const {
    return lastNotChar(end, &SysChar::isAlnum);
  }

  // method: lastNotAlpha
  //
  long lastNotAlpha(long end = Integral::NO_POS) const {
    return lastNotChar(end, &SysChar::isAlpha);
  }

  // method: lastNotDigit
  //
  long lastNotDigit(long end = Integral::NO_POS) const {
    return lastNotChar(end, &SysChar::isDigit);
  }

  // method: lastNotLower
  //
  long lastNotLower(long end = Integral::NO_POS) const {
    return lastNotChar(end, &SysChar::isLower);
  }

  // method: lastNotPrint
  //
  long lastNotPrint(long end = Integral::NO_POS) const {
    return lastNotChar(end, &SysChar::isPrint);
  }

  // method: lastNotPunct
  //
  long lastNotPunct(long end = Integral::NO_POS) const {
    return lastNotChar(end, &SysChar::isPunct);
  }

  // method: lastNotSpace
  //
  long lastNotSpace(long end = Integral::NO_POS) const {
    return lastNotChar(end, &SysChar::isSpace);
  }

  // method: lastNotUpper
  //
  long lastNotUpper(long end = Integral::NO_POS) const {
    return lastNotChar(end, &SysChar::isUpper);
  }
  
  //---------------------------------------------------------------------------
  //
  // class-specific public methods:
  //  tokenize methods
  //
  //---------------------------------------------------------------------------

  // method: countTokens
  //   count the tokens when delimiter is white space
  //
  long countTokens() const {
    static SysString temp(L" ");
    return countTokens(temp);
  }
  
  // other count tokens methods
  //
  long countTokens(unichar delimiter) const;
  long countTokens(const SysString& delimiters) const;

  // method: countDelimiters
  //   count the delimiters when delimiter is white space
  //
  long countDelimiters() const {
    static SysString temp(L" ");
    return countDelimiters(temp);
  }
  
  // other count delimiters methods
  //
  long countDelimiters(unichar delimiter) const;
  long countDelimiters(const SysString& delimiters) const;

  // method: tokenize
  //  tokenize the string when delimiter is white space
  //
  boolean tokenize(SysString& sub, long& pos) const {
    static SysString temp(L" ");
    return tokenize(sub, pos, temp);
  }

  // other string tokenize methods
  //
  boolean tokenize(SysString& sub, long& pos, unichar delim) const;
  boolean tokenize(SysString& sub, long& pos, const SysString delim) const;
  
  // pad symbols methods
  //  this aides in tokenization by ensuring the specified symbols are padded
  //
  boolean symbolPad(const SysString& symbols);
  
  // debug string creation methods
  //
  boolean debugStr(const SysString& class_name, const unichar* message_a,
		   const unichar* variable_name,
		   const SysString& variable_value);
  
  boolean debugStr(const SysString& class_name, const unichar* message_a,
		   const unichar* variable_name);

  boolean debugStrPrefix(const SysString& class_name,
			 const unichar* message_a);

  // method: getEmptyString
  //  empty string creation methods
  //
  static const SysString& getEmptyString() {
    static SysString temp;
    return temp;
  }
  
  //---------------------------------------------------------------------------
  //
  // private methods
  //
  //---------------------------------------------------------------------------
private:

  // general string search methods:
  //  these are special methods used for class-specific string search
  //  methods. these methods have function pointer as an argument
  //  which allow us to specify any method of the type "boolean
  //  doWhatever() const" of SysChar class.
  //
  long firstChar(long start, boolean (SysChar::*method) (void) const) const;
  long lastChar(long end, boolean (SysChar::*method) (void) const) const;
  long firstNotChar(long start,
		    boolean (SysChar::*method) (void) const) const;  
  long lastNotChar(long end,
		   boolean (SysChar::*method) (void) const) const;
  
  // memory allocation methods
  //
  boolean allocateMem();
  boolean freeMem();
  boolean growMem(long new_size);

  //---------------------------------------------------------------------------
  //
  // wrap the system wchar methods
  //
  //---------------------------------------------------------------------------

  //  the following private methods are to wrap wide character
  //  support. wide character support is in a great state of flux, so
  //  the "isip_" prefix is meant to clarify that our api is not
  //  dependent on the specific operating system.
  //

  // method: isip_wcslen
  //
  static ulong isip_wcslen(const unichar* ws) {
    return wcslen(ws);
  }

  // method: isip_wcscmp
  //
  static long isip_wcscmp(const unichar* ws1, const unichar* ws2) {
    return wcscmp(ws1, ws2);
  }

  // method: isip_wcsncmp
  //
  static long isip_wcsncmp(const unichar* ws1, const unichar* ws2,
				  ulong n) {
    return wcsncmp(ws1, ws2, n);
  }

  // method: isip_wcschr
  //
  static unichar* isip_wcschr(const unichar* ws1,
				     const unichar ws2) {
    return wcschr(ws1, ws2);
  }

  // method: isip_wcscat
  //
  static unichar* isip_wcscat(unichar* ws1, const unichar* ws2) {
    return wcscat(ws1, ws2);
  }

  // method: isip_wcscpy
  //  
  static unichar* isip_wcscpy(unichar* ws1, const unichar* ws2) {
    return wcscpy(ws1, ws2);
  }

  // method: isip_wcsncpy
  //  
  static unichar* isip_wcsncpy(unichar* ws1, const unichar* ws2,
				      ulong n) {
    return wcsncpy(ws1, ws2, n);
  }

  // method: isip_wctomb
  //  
  static int isip_wctomb(char* s, const unichar wchar) {
    return wctomb(s, (wchar_t)wchar);
  }

  // other wrappers for wchar methods
  //
  static unichar* isip_wcsstr(const unichar* ws1, const unichar* ws2);
  static unichar* isip_wcstok(unichar* ws, const unichar* delim,
			      unichar** ptr);
  static unichar* isip_fgetws(unichar* s, int n, FILE* stream);
  static long isip_fputws(const unichar* s, FILE* stream);
  static wint_t isip_fgetwc(FILE* stream);
  static wint_t isip_fputwc(wint_t wc, FILE* stream);

  //---------------------------------------------------------------------------
  //
  // friend functions:
  //  while friend functions are generally discouraged in the ISIP
  //  environment, they are used in the SysString class to isolate
  //  implementation details. currently, wide character support varies
  //  greatly between different operating systems, so we abstract a
  //  core group of wide character functions in this class as private
  //  methods. the file class also needs to access these wrappers
  //  directly for I/O purposes, though, so the friend directive is
  //  used.
  //
  //---------------------------------------------------------------------------

  // put methods
  //
  friend boolean File::put(const SysString& str);
  friend boolean File::put(const SysChar chr);

  // get methods
  //
  friend boolean File::get(SysString& str, long len);
  friend boolean File::get(SysChar& chr);
};

// end of include file
//
#endif
