////////////////////////////////////////////////////////////////////////////////
// GSString.h
//
// Copyright 1996-1999 Diehl Graphsoft, Inc.
// All Rights Reserved.
//
////////////////////////////////////////////////////////////////////////////////

#ifndef _GSSTRING_
#define _GSSTRING_

#pragma once

#include <StdArg.h>

#include "GSTypes.h"

#if _MINICAD_
	#define GS_STRING_API	GS_COMP_API
#else
	#define GS_STRING_API	GS_API
#endif


/* Macros */
/* ------ */
/* Converts ASCII-only string literal to UTF-16; */
/*  str must be in quotes, e.g. UCSTR("String")  */
/*** Not currently available, because need CW9 compiler for ***/
/***  __L16; using preceding L yields UTF-32 like wchar_t   ***/
#if 0
#if GS_WIN
#define UCSTR(str)  L##str
#else
#define UCSTR(str)  __L16##str
#endif
#endif


/* Constants */
/* --------- */
/* For comparison and search routines */
const bool	kDoIgnoreCase   = true;
const bool	kDontIgnoreCase = false;
const bool	kFindFwd = true;
const bool	kFindRev = false;


/* Types */
/* ----- */
/* Character encoding standard--uses platform-specific values */
#if GS_WIN
typedef Uint32			GSTextEncoding;
#else
typedef TextEncoding	GSTextEncoding;
#endif


/*============================================================================*/
/*============================================================================*/
/**************************************************/
/* Unicode Character String Manipulation Routines */
/**************************************************/

// The intent here is to provide support routines for TXUniString, and for
// only-as-required handling of Unicode character runs from external sources.
// Thus, there will not be a full set of string-manipulation functions as
// are provided by VW for non-Unicode Pascal and C Strings.  MFH 02/2005


/* Unicode Encoding Converter Routines */
UCCharCnt	StringToUnicodeMaxChars (Uint32 srcLen);
bool		StringToUnicode (GSTextEncoding srcEncoding, const char* srcArray,
			 size_t srcLen, UCCharPtr dstUCArray, UCCharCnt maxDstChars,
			 UCCharCnt* pDstLen);
bool		StringToUnicode (GSTextEncoding srcEncoding, const char* srcStr,
             UCStrPtr dstUCStr, UCCharCnt maxDstChars, UCCharCnt* pDstLen);
bool		StringToUnicode (GSTextEncoding srcEncoding, ConstGSStr255Param srcStr,
             UCStrPtr dstUCStr, UCCharCnt maxDstChars, UCCharCnt* pDstLen);
size_t		UnicodeToStringMaxChars (UCCharCnt srcLen);
bool		UnicodeToString (GSTextEncoding dstEncoding,
			          ConstUCCharPtr srcUCArray, UCCharCnt srcLen,
			          char* dstArray, size_t maxDstBytes, size_t* pDstLen);
bool		UnicodeToString (GSTextEncoding dstEncoding, ConstUCStrPtr srcUCStr,
                      char* dstStr, size_t maxDstBytes, size_t* pDstLen);
bool		UnicodeToString (GSTextEncoding dstEncoding, ConstUCStrPtr srcUCStr,
                      GSStringPtr dstStr, size_t maxDstBytes, size_t* pDstLen);

/* Unicode String Manipulation Routines */
UCCharCnt	StringLength (ConstUCStrPtr ucString);
bool		StringEqual (ConstUCStrPtr str1, ConstUCStrPtr str2, bool ignoreCase);
bool		StringEqual (ConstUCCharPtr chars1, UCCharCnt len1,
			              ConstUCCharPtr chars2, UCCharCnt len2, bool ignoreCase);
void		StringCopy (ConstUCStrPtr srcStr, UCStrPtr dstStr, size_t maxDstBytes);
bool		FindCharClusterBreak (ConstUCCharPtr charArray, UCCharCnt length,
		             UCCharCnt startPos, bool forward, UCCharCnt* pBreakPos);


/*============================================================================*/
/*============================================================================*/
/***********************************************************************/
/* Non-Unicode Pascal and C String Manuipulation Routines and Classes */
/***********************************************************************/


////////////////////////////////////////////////////////////////////////////////
// OS-Specific Character Encoding Routines

//XXXAlturaAAO - The following two functions were formerly named ASI_AnsiToMacBuf(...) and ASI_MacToAnsiBuf(...) - 
//these were changed in order to resolve linker errors that resulted from implementing the calls of the same name
//(simply wrappers for externals that actually called the respective functions in AlturaStubs.cpp) in 
//AlturaStubs.cpp (caused link errors in GSESDK.lib). [AAO, 2-6-03]

// EJK 12/07/2006 - We now have a need to use the MacToAnsi conversion on the Mac platform
	
	enum EStringExpansion {
		eAllowStringExpansion,
		eDontAllowStringExpansion
	};
	
	short GS_STRING_API WinAnsiToMacBuf(unsigned char const *AnsiStr, unsigned char *MacStr, short ansiLen);
	short GS_STRING_API WinMacToAnsiBuf(unsigned char const *MacStr, unsigned char *AnsiStr, short macLen, EStringExpansion expansion = eAllowStringExpansion);

void GS_STRING_API SetMacToAnsiTablesToGreek();

#if GS_WIN
extern Boolean	gl_MapUpperChars;	// Where is this defined?
#endif // GS_WIN

// System and Application Encoding Retrieval Routines
GSTextEncoding	GetSystemEncoding ();
GSTextEncoding	GetApplicationEncoding ();
#if GS_MAC
bool	UseIcelandicEncoding ();
#endif


////////////////////////////////////////////////////////////////////////////////
#if __cplusplus

/*
	For complete documentation on the things in this section, see the
	Graphsoft String Library document.
	
	Most of the routines here are overloaded to accept any mix of Pascal-
	style (unsigned char *) and C-style (char *) strings.  In any function
	that takes a string size (i.e. StringCopy and StringCat), the size is
	the total number of bytes occupied by the string, which is one greater
	than the maximum character length.  We do this so you can pass sizeof(T)
	as the length.  For example, to copy a string into a GSStr255, you would
	say "StringCopy(someString, aStr255, sizeof(GSStr255))".
	
	All of the functions can accept "unusual" input values, i.e. null pointers
	and negative lengths.  An input of a null pointer or non-positive string
	length is interpreted like an empty string, if given as an output, nothing
	will be written to it.
*/


////////////////////////////////////////
// Length tests: GetLength (formerly length), IsEmpty.

//   NOTE: IsEmpty(s) is faster than GetLength(s) == 0, particularly for C-style strings.
inline Uint8	GetLength(ConstGSStr255Param s)		{ return s ? s[0] : 0; }
inline size_t	GetLength(const char *s)			{ return s ? strlen(s) : 0; }
inline Bool8	IsEmpty(ConstGSStr255Param s)		{ return !s || s[0] == 0; }
inline Bool8	IsEmpty(const char *s)				{ return !s || s[0] == '\0'; }


////////////////////////////////////////
// SetLength

inline void SetLength(GSStringPtr s, Uint8 len)	{ if (s) s[0] = len; }
inline void SetLength(char *s, size_t len)		{ if (s) s[len] = '\0'; }


////////////////////////////////////////
// StringCopy

// These functions all return void now to get around a bug in the Visual C++ 4.1 & 4.2 linker. [DMB 12/4/96]
void GS_STRING_API StringCopy(ConstGSStr255Param src, GSStringPtr dst, size_t sizeofDst);
void GS_STRING_API StringCopy(const char *src, GSStringPtr dst, size_t sizeofDst);
void GS_STRING_API StringCopy(const void *src, size_t len, GSStringPtr dst, size_t sizeofDst);
void GS_STRING_API StringCopy(ConstGSStr255Param src, char *dst, size_t sizeofDst);
void GS_STRING_API StringCopy(const char *src, char *dst, size_t sizeofDst);
void GS_STRING_API StringCopy(const void *src, size_t len, char *dst, size_t sizeofDst);


////////////////////////////////////////
// StringCat

GSStringPtr GS_STRING_API StringCat(GSStringPtr dst, ConstGSStr255Param src, size_t sizeofDst);
GSStringPtr GS_STRING_API StringCat(GSStringPtr dst, const char *src, size_t sizeofDst);
GSStringPtr GS_STRING_API StringCat(GSStringPtr dst, const void *src, size_t len, size_t sizeofDst);
char GS_STRING_API * StringCat(char *dst, ConstGSStr255Param src, size_t sizeofDst);
char GS_STRING_API * StringCat(char *dst, const char *src, size_t sizeofDst);
char GS_STRING_API * StringCat(char *dst, const void *src, size_t len, size_t sizeofDst);


////////////////////////////////////////
// StringEqual

Bool8 GS_STRING_API StringEqual(ConstGSStr255Param a, ConstGSStr255Param b);
Bool8 GS_STRING_API StringEqual(ConstGSStr255Param a, const char *b);
inline Bool8		StringEqual(const char *a, ConstGSStr255Param b)				{ return StringEqual(b, a); }
Bool8 GS_STRING_API StringEqual(const char *a, const char *b);


////////////////////////////////////////
// StringEqualIgnoringCase

Bool8 GS_STRING_API StringEqualIgnoringCase(ConstGSStr255Param a, ConstGSStr255Param b);
Bool8 GS_STRING_API StringEqualIgnoringCase(ConstGSStr255Param a, const char *b);
inline Bool8		StringEqualIgnoringCase(const char *a, ConstGSStr255Param b)	{ return StringEqualIgnoringCase(b, a); }
Bool8 GS_STRING_API StringEqualIgnoringCase(const char *a, const char *b);


////////////////////////////////////////
// StringCompare

short GS_STRING_API StringCompare(ConstGSStr255Param a, ConstGSStr255Param b);
short GS_STRING_API StringCompare(ConstGSStr255Param a, const char *b);
short GS_STRING_API StringCompare(const char *a, ConstGSStr255Param b);
short GS_STRING_API StringCompare(const char *a, const char *b);


////////////////////////////////////////
// StringCompareIgnoringCase

short GS_STRING_API StringCompareIgnoringCase(ConstGSStr255Param a, ConstGSStr255Param b);
short GS_STRING_API StringCompareIgnoringCase(ConstGSStr255Param a, const char *b);
short GS_STRING_API StringCompareIgnoringCase(const char *a, ConstGSStr255Param b);
short GS_STRING_API StringCompareIgnoringCase(const char *a, const char *b);


////////////////////////////////////////
// StringInsert

void GS_STRING_API StringInsert(ConstGSStr255Param src, GSStringPtr dst, Uint8 index);


////////////////////////////////////////
// StringDelete

void GS_STRING_API StringDelete(GSStringPtr s, Uint8 start, Uint8 count);
void GS_STRING_API StringDelete(char *s, size_t start, size_t count);


////////////////////////////////////////
// StringPos

#ifdef _MINICAD_
short GS_STRING_API StringPos (ConstGSStr255Param findStr, ConstGSStr255Param str);
#endif


////////////////////////////////////////
// Truncate (formerly trunc)

inline void Truncate(GSStringPtr s, Uint8 len)		{ if (s && GetLength(s) > len) SetLength(s, len); }
inline void Truncate(char *s, size_t len)		{ if (s) s[len] = '\0'; }


////////////////////////////////////////
// psprintf

int GS_STRING_API psprintf(char *s, const char *format, ...);
int GS_STRING_API psprintf(GSStr255 s, const char *format, ...);
int GS_STRING_API psprintf(char *s, ConstGSStr255Param format, ...);
int GS_STRING_API psprintf(GSStr255 s, ConstGSStr255Param format, ...);


////////////////////////////////////////
// str*cmp

#if !_WINDOWS
int stricmp(const char *a, const char *b);
int strnicmp(const char *a, const char *b, size_t max);
#endif // !_WINDOWS


////////////////////////////////////////
/* USAGE FOR NULLSTR, DUMMYSTR, _ccp, _cucp:

	Since IBM PC compilers don't generally know about the \p convention for strings,
	you should avoid the use of string literals in your code.  If you need an empty
	string, use NULLSTR.  If you need an innocuous but non-empty string, use DUMMYSTR.
	(This case usually turns up with AppendMenu, which treats certain characters
	specially.  DUMMYSTR is not guaranteed to be anything in particular, but is
	guaranteed to not make AppendMenu do something strange.)
	
	If you need your own string literal, define it like this: _cucp "\011my string".
	You must encode the length byte explicitly, since the IBM PC compilers can't handle
	\p; the _cucp (shorthand for "const unsigned char pointer"), casts the string
	to the standard type for Pascal-style string literals; const unsigned char *.
	_ccp (const char *) casts to a standard C-style string

	_ccp  == (ConstGSCStrPtr)
	_cucp == (ConstGSStringPtr)
*/
#define _ccp		   (const char *)
#define _cucp	       (const unsigned char *)
#if GS_MAC
	#define NULLSTR   ((const unsigned char *) "\p")
	#define DUMMYSTR  ((const unsigned char *) "\px")
#else
	#define NULLSTR   ((const unsigned char *) "\0")
	#define DUMMYSTR  ((const unsigned char *) "\001x")
#endif



////////////////////////////////////////////////////////////////////////////////
// - PStr<>

template <size_t maxCharLen>
class PStr {
#if GS_WIN
	friend class PStr<maxCharLen>;  // Updated for CW Pro 6
#endif
	
	private:
		Uint8 buf[maxCharLen+1 + ((maxCharLen+1)%2)];
	
	public:
		/* - Constructors
		*/
		PStr()											{ buf[0] = 0; }
		PStr(const PStr &s)								{ StringCopy(s.buf, buf, maxCharLen+1); }
		PStr(ConstGSStringPtr s)						{ StringCopy(s, buf, maxCharLen+1); }
		PStr(const char *s)								{ StringCopy(s, buf, maxCharLen+1); }
		PStr(const void *s, size_t size)				{ StringCopy(s, size, buf, maxCharLen+1); }
		
#if !_WINDOWS
		template <size_t maxCharLen2>
		PStr(const PStr<maxCharLen2>& s) { StringCopy(s, buf, maxCharLen+1);  }
#endif
		
		/* - Assignment operators
		*/
		PStr& operator=(ConstGSStringPtr s)				{ StringCopy(s, buf, maxCharLen+1); return *this; }
		PStr& operator=(const char *s)					{ StringCopy(s, buf, maxCharLen+1); return *this; }

		template <size_t maxCharLen2>
		PStr& operator=(const PStr<maxCharLen2>& s){
			StringCopy(s, buf, maxCharLen+1); 
			return *this; 
		}
		
		void CopyToStr(unsigned char* s) 				{ StringCopy(buf, s, maxCharLen+1); }

		/* - Casts
		*/
		operator GSStringPtr() 							{ return buf; }
//		operator ConstGSStr255Param() const				{ return buf; }
		operator ConstGSStringPtr() const				{ return buf; }

		/* - String length
		*/
		Uint8 GetLength() const							{ return buf[0]; }
		static Uint8 GetMaxLength()						{ return (Uint8) maxCharLen; }
		static Uint8 MaxLength()						{ return (Uint8) maxCharLen; }
		void SetLength(Uint8 len)						{ buf[0] = len; }
		void Truncate(Uint8 len)						{ if (GetLength() > len) SetLength(len); }
		Bool8 IsEmpty() const							{ return GetLength() == 0; }
		void Clear()									{ buf[0] = 0; }
		
		/* - Subscript operators
		*/
		#if 0
		// Both Mac and Win compilers find these operators ambiguous when
		// you say aString[i], due to being able to implicitly cast to char*.
		unsigned char& operator[](Uint8 i)				{ return buf[i]; }
		unsigned char operator[](Uint8 i) const			{ return buf[i]; }
		#endif
		
		/* - Comparison operators
		*/
		Bool8 operator==(ConstGSStringPtr s) const 		{ return StringEqualIgnoringCase(buf, s); }
		// TODO template <size_t maxCharLen>
		Bool8 operator==(const PStr<maxCharLen>& s) const 	{ return StringEqualIgnoringCase(buf, s); }

		Bool8 operator!=(const PStr &s)					{ return !StringEqualIgnoringCase(buf, s); }
		Bool8 operator!=(ConstGSStringPtr s)	 		{ return !StringEqualIgnoringCase(buf, s); }
		Bool8 operator!=(ConstGSStringPtr s) const 		{ return !StringEqualIgnoringCase(buf, s); }
		Bool8 operator==(const char * const s) const	{ return StringEqualIgnoringCase(buf, s); }
		Bool8 operator!=(const char * s) const			{ return !StringEqualIgnoringCase(buf, s); }
		Bool8 operator!=(const char * s)				{ return !StringEqualIgnoringCase(buf, s); }

		Bool8 operator==(char c) const					{ return GetLength() == 1 && ((const char *) buf)[1] == c; }
		Bool8 operator!=(char c) const					{ return GetLength() != 1 || ((const char *) buf)[1] != c; }
		Bool8 operator<(ConstGSStringPtr s) const		{ return StringCompare(buf, s) < 0; }
		Bool8 operator<(const char *s) const			{ return StringCompare(buf, s) < 0; }
		
		template<size_t maxCharLen2>
		Bool8 operator==(const PStr<maxCharLen2> &s) const			{ return StringEqualIgnoringCase(buf, s); }
		
		/* - Append operators
		*/
		PStr& operator<<(ConstGSStr255Param s)			{ StringCat(buf, s, maxCharLen+1); return *this; }
		PStr& operator<<(const char *s)					{ StringCat(buf, s, maxCharLen+1); return *this; }
		PStr& operator<<(long n);						
		PStr& operator<<(short n)						{ return (*this << (long) n); }
		PStr& operator<<(char c)						{ if (buf[0] < maxCharLen) buf[++buf[0]] = c; return *this; }
		PStr& operator<<(unsigned char c)				{ if (buf[0] < maxCharLen) buf[++buf[0]] = c; return *this; }
		//PStr& operator<<(float_param f);				// NOT IMPLEMENTED!
		//PStr& operator<<(double_param d);				// NOT IMPLEMENTED!
		
		/* - Searching
		*/
		int Find(char ch) const							{ return Find(1, ch); }
		int Find(Uint8 start, char ch) const;
		int ReverseFind(char ch) const					{ return ReverseFind(GetLength(), ch); }
		int ReverseFind(Uint8 start, char ch) const;
		
		/* - Substrings
		*/
		PStr Left(Uint8 count) const						{ Uint8 len = GetLength(); if (count > len) count = len; return PStr<maxCharLen>(&buf[1], count); }
		PStr Right(Uint8 count) const					{ Uint8 len = GetLength(); if (count > len) count = len; return PStr<maxCharLen>(&buf[len - count + 1], count); }
		PStr Mid(Uint8 start, Uint8 count = 255) const;
		
		/* - Formatted output
		*/
		Uint8 Format(ConstGSStr255Param format, ...);
		Uint8 Format(const char *format, ...);
};


template <size_t maxCharLen>
PStr<maxCharLen>& PStr<maxCharLen>::operator<<(long n)
{
	PStr<15> s;
	s.Format("%ld", n);
	StringCat(buf, s, maxCharLen+1);
	return *this; 
}

template <size_t maxCharLen>
int PStr<maxCharLen>::Find(Uint8 start, char ch) const
{
	if (start > 0)
		for (Uint8 i = start; i <= GetLength(); ++i)
			if (buf[i] == ch) return i;
	return 0;
}

template <size_t maxCharLen>
int PStr<maxCharLen>::ReverseFind(Uint8 start, char ch) const
{
	if (start > GetLength())
		start = GetLength();
	for (Uint8 i = start; i > 0; --i)
		if (buf[i] == ch) return i;
	return 0;
}

template <size_t maxCharLen>
PStr<maxCharLen> PStr<maxCharLen>::Mid(Uint8 start, Uint8 count) const
{
	if (start > GetLength())
		count = 0;
	else if (start + count - 1 > GetLength())
		count = GetLength() - start + 1;
	
	return PStr<maxCharLen>(&buf[start], count);
}

template <size_t maxCharLen>
Uint8 PStr<maxCharLen>::Format(ConstGSStr255Param format, ...)
{
	va_list ap;
	va_start(ap, format);

	char szFormat[256];
	StringCopy(format, szFormat, 256);

	this->buf[0] = vsprintf((char*) &this->buf[1], szFormat, ap);

	va_end(ap);
	return this->buf[0];
}

template <size_t maxCharLen>
Uint8 PStr<maxCharLen>::Format(const char *format, ...)
{
	va_list ap;
	va_start(ap, format);

	this->buf[0] = vsprintf((char*) &this->buf[1], format, ap);

	va_end(ap);
	return this->buf[0];
}



////////////////////////////////////////////////////////////////////////////////
// - CStr<>

template <size_t maxCharLen>
class CStr : public TDebugObject {
	private:
		char buf[maxCharLen+1 + ((maxCharLen+1)%2)];
	
	public:
		/* - Constructors
		*/
		CStr()											{ buf[0] = 0; }
		CStr(const CStr &s)								{ StringCopy(s.buf, buf, maxCharLen+1); }
		CStr(ConstGSStr255Param s)						{ StringCopy(s, buf, maxCharLen+1); }
		CStr(const char *s)								{ StringCopy(s, buf, maxCharLen+1); }
		CStr(const void *s, size_t size)				{ StringCopy(s, size, buf, maxCharLen+1); }
		// TODO template <size_t maxCharLen>
		CStr(const PStr<maxCharLen>& s)					{ StringCopy(s, buf, maxCharLen+1); }
		
		/* - Assignment operators
		*/
		CStr& operator=(const CStr& s)					{ StringCopy(s.buf, buf, maxCharLen+1); return *this; }
		CStr& operator=(ConstGSStr255Param s)			{ StringCopy(s, buf, maxCharLen+1); return *this; }
		CStr& operator=(const char *s)					{ StringCopy(s, buf, maxCharLen+1); return *this; }
		
		// TODO template <size_t maxCharLen>
		CStr& operator=(const PStr<maxCharLen>& s)		{ StringCopy(s, buf, maxCharLen+1); return *this; }
		
		/* - Casts
		*/
		operator char *()								{ return buf; }
		operator const char *() const					{ return buf; }

		/* - String length
		*/
		size_t GetLength() const						{ return strlen(buf); }
		static size_t GetMaxLength()					{ return maxCharLen; }
		void SetLength(size_t len)						{ if (VERIFYN(kChris, len <= maxCharLen)) buf[len] = '\0'; }
		void Truncate(size_t len)						{ if (len <= maxCharLen) buf[len] = '\0'; }
		Bool8 IsEmpty() const							{ return buf[0] == '\0'; }
		void Clear()									{ buf[0] = '\0'; }
		
		/* - Subscript operators
		*/
		#if 0
		// Both Mac and Win compilers find these operators ambiguous when
		// you say aString[i], due to being able to implicitly cast to char*.
		char& operator[](size_t i)						{ return buf[i]; }
		char operator[](size_t i) const					{ return buf[i]; }
		#endif
		
		/* - Comparison operators
		*/
		Bool8 operator==(ConstGSStr255Param s) const 	{ return StringEqualIgnoringCase(buf, s); }
		Bool8 operator!=(ConstGSStr255Param s) const 	{ return !StringEqualIgnoringCase(buf, s); }
		Bool8 operator==(const char *s) const			{ return StringEqualIgnoringCase(buf, s); }
		Bool8 operator!=(const char *s) const			{ return !StringEqualIgnoringCase(buf, s); }
		Bool8 operator==(char c) const					{ return buf[0] == c && buf[1] == '\0'; }
		Bool8 operator!=(char c) const					{ return buf[0] != c || buf[1] != '\0'; }
		Bool8 operator<(ConstGSStr255Param s) const		{ return StringCompare(buf, s) < 0; }
		Bool8 operator<(const char *s) const			{ return StringCompare(buf, s) < 0; }
		Bool8 operator==(const CStr &s) const			{ return s == buf; }
		
		/* - Append operators
		*/
		CStr& operator<<(ConstGSStr255Param s)			{ StringCat(buf, s, maxCharLen+1); return *this; }
		CStr& operator<<(const char *s)					{ StringCat(buf, s, maxCharLen+1); return *this; }
		CStr& operator<<(long n);						
		CStr& operator<<(short n)						{ return (*this << (long) n); }
		CStr& operator<<(char c)						{ size_t pos = strlen(buf); if (pos < maxCharLen) { buf[pos] = c; buf[pos+1] = '\0'; } return *this; }
		CStr& operator<<(unsigned char c)				{ size_t pos = strlen(buf); if (pos < maxCharLen) { buf[pos] = c; buf[pos+1] = '\0'; } return *this; }
		//CStr& operator<<(float_param f);				// NOT IMPLEMENTED!
		//CStr& operator<<(double_param d);				// NOT IMPLEMENTED!
		
		/* - Searching
		*/
		int Find(char ch) const							{ return Find(0, ch); }
		int Find(size_t start, char ch) const;
		int ReverseFind(char ch) const					{ return ReverseFind(GetLength() - 1, ch); }
		int ReverseFind(size_t start, char ch) const;
		
		/* - Substrings
		*/
		CStr Left(size_t count) const					{ size_t len = GetLength(); if (count > len) count = len; return CStr<maxCharLen>(&buf[0], count); }
		CStr Right(size_t count) const					{ size_t len = GetLength(); if (count > len) count = len; return CStr<maxCharLen>(&buf[len - count], count); }
		CStr Mid(size_t start, size_t count = 1024) const;
		
		/* - Formatted output
		*/
		int Format(ConstGSStr255Param format, ...);
		int Format(const char *format, ...);

		/* - Debugging
		*/
		DECLARE_CLASS_DEBUGGING
};

template <size_t maxCharLen>
CStr<maxCharLen>& CStr<maxCharLen>::operator<<(long n)
{ 
	#if _WINDOWS
	
		char sz[12];
		_itoa(n, sz, 10);
	
		StringCat(buf, sz, maxCharLen+1);
		return *this;
		
	#else
	
		Str15 s; 
		NumToString(n, (GSStringPtr) s); 
		StringCat(buf, s, maxCharLen+1); 
		return *this; 
	#endif
}

template <size_t maxCharLen>
int CStr<maxCharLen>::Find(size_t start, char ch) const
{
	int i; const char *p;
	
	for (i = (int) start, p = &buf[i]; i <= maxCharLen && *p != '\0'; i++, p++)
		if (*p == ch) return i;
	return -1;
}

template <size_t maxCharLen>
int CStr<maxCharLen>::ReverseFind(size_t start, char ch) const
{
	int i; const char *p;
	
	for (i = (int) start, p = &buf[i]; i >= 0 && *p != '\0'; i--, p--)
		if (*p == ch) return i;
	return -1;
}

template <size_t maxCharLen>
CStr<maxCharLen> CStr<maxCharLen>::Mid(size_t start, size_t count) const
{
	if (start > GetLength())
		count = 0;
	else if (start + count - 1 > GetLength())
		count = GetLength() - start + 1;
	
	return CStr<maxCharLen>(&buf[start], count);
}

template <size_t maxCharLen>
int CStr<maxCharLen>::Format(ConstGSStr255Param format, ...)
{
	int result;
	va_list ap;
	va_start(ap, format);

	char szFormat[256];
	StringCopy(format, szFormat, 256);

	result = vsprintf(this->buf, szFormat, ap);

	va_end(ap);
	return result;
}

template <size_t maxCharLen>
int CStr<maxCharLen>::Format(const char *format, ...)
{
	int result;
	va_list ap;
	va_start(ap, format);

	result = vsprintf(this->buf, format, ap);

	va_end(ap);
	return result;
}


////////////////////////////////////////////////////////////////////////////////

#define STRINGTYPE_INTERFACE(maxCharLen) typedef PStr<maxCharLen> PStr##maxCharLen

typedef PStr<255>	PStr255;
typedef PStr<63>	PStr63;
typedef PStr<31>	PStr31;
typedef PStr<27>	PStr27;
typedef PStr<20>	PStr20;
typedef PStr<15>	PStr15;
typedef PStr<8>		PStr8;
typedef PStr<7>		PStr7;

typedef CStr<512>	CStr512;
typedef CStr<256>	CStr256;
typedef CStr<255>	CStr255;
typedef CStr<63>	CStr63;
typedef CStr<31>	CStr31;
typedef CStr<27>	CStr27;
typedef CStr<20>	CStr20;
typedef CStr<15>	CStr15;
typedef CStr<8>		CStr8;
typedef CStr<7>		CStr7;

typedef PStr255		PString;


#endif  // __cplusplus

/*============================================================================*/
/*============================================================================*/


// This should NOT be here, but numerous files rely on it,
//  and I don't have time to fix them all up now.  MFH 12/2004
#if __cplusplus
#include "GSString.X.h"
#endif  // __cplusplus


#endif  // _GSSTRING_
