//
// $Id: Text.h,v 1.13 2007/03/08 19:59:21 will_mason Exp $
//
// vi: set ft=objc:

/*
 * ObjectiveLib - a library of containers and algorithms for Objective-C
 *
 * Copyright (c) 2004-2007
 * Will Mason
 *
 * Portions:
 *
 * Copyright (c) 1994
 * Hewlett-Packard Company
 *
 * Copyright (c) 1996,1997
 * Silicon Graphics Computer Systems, Inc.
 *
 * Copyright (c) 1997
 * Moscow Center for SPARC Technology
 *
 * Copyright (c) 1999 
 * Boris Fomitchev
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 * You may contact the author at will_mason@users.sourceforge.net.
 */

#if !defined(TEXT_OL_GUARD)
#define TEXT_OL_GUARD

#include <ObjectiveLib/ObjectBase.h>
#if defined(OL_HAVE_INTTYPES_H)
#include <inttypes.h>
#else
#include <stdint.h>
#endif

/**
 * @defgroup Text
 *
 * Classes for storing and manipulating text. The text system of @b ObjectiveLib
 * uses Unicode to store its data, but it should not be considered a replacement
 * for full-featured internationalized text systems like that provided by
 * the International Components for Unicode provided by IBM. For example,
 * @b ObjectiveLib has no knowledge of code points, only code units. Therefore,
 * the meaning of surrogates is ignored, and malformed sequences can be
 * created, though this will certainly be rare. The consistent use of UTF-16 to
 * encode all text in @b ObjectiveLib is a great improvement over the almost
 * entirely random treatment of text in standard C, but its drawbacks should be
 * borne in mind.
 */

/**
 * The type of a character of text. Text is stored using the UTF-16 encoding.
 *
 * @ingroup Text
 */
typedef uint16_t olchar;

/**
 * @internal The underlying type used to store text
 */
struct _OLTextReference;

/**
 * @class OLText Text.h ObjectiveLib/Text.h
 *
 * A immutable piece of text. Text stored in an instance of OLText can be queried,
 * searched, converted to other encodings and subsequences can be extracted, but the
 * text itself cannot be changed. In order to mutate a piece of text an instance of
 * the class OLTextBuffer must be used, and then an immutable OLText object can be
 * derived.
 *
 * OLText objects maintain their data by reference counting. Therefore, copying a
 * piece of text is a very inexpensive operation, as the reference count is simply
 * incremented.
 *
 * @sa OLTextBuffer
 * @if OL_NO_OPENSTEP
 * @sa OLConstantString
 * @endif
 *
 * @ingroup Text
 */
@interface OLText :
#if defined(OL_NO_OPENSTEP)
    Object <OLStreamable>
#else
    NSObject <OLStreamable, NSCopying, NSCoding>
#endif
{
@protected
    /**
     * The opaque structure that holds the data
     */
    struct _OLTextReference* reference;
}

/**
 * Initialize the class. This for the runtime system to call. Please don't call
 * this method.
 */
#if defined(OL_NO_OPENSTEP)
+ (id) initialize;
#else
+ (void) initialize;
#endif

/**
 * Create and return a new text object. The text is encoded from the given encoding
 * @a enc to the internal encoding used by all text objects of UTF-16.
 * 
 * @note If OpenStep is present the returned object will be autoreleased before being returned.
 *
 * @if OL_NO_OPENSTEP
 * @exception OLInvalidArgumentException if the given encoding is not supported
 * @else
 * @exception NSInvalidArgumentException if the given encoding is not supported
 * @endif
 * @param bytes the bytes containing the text encoded with the given encoding
 * @param num the number of bytes
 * @param enc the encoding used for the data in @a bytes
 * @return a reference to the new text object
 */
+ (id) textWithBytes: (const uint8_t*)bytes count: (unsigned)num encoding: (const char*)enc;

/**
 * Create and return a new text object. The text in @a chs is assumed to be in the
 * default encoding for the platform. This locale is assumed to have been set by
 * a previous call to @c setlocale. The "C string" @a chs should be null-terminated.
 *
 * @note If OpenStep is present the returned object will be autoreleased before being returned.
 *
 * @param chs the characters to encode with UTF-16 and store
 * @return a reference to the new text object
 */
+ (id) textWithCString: (const char*)chs;

#if !defined(OL_NO_OPENSTEP)
/**
 * Create and return a new text object. The text is copied from the NSString
 * object. The returned text will be autoreleased before being returned.
 *
 * @param str the NSString to copy
 * @return a reference to the new text object
 */
+ (id) textWithNSString: (NSString*)str;
#endif

/**
 * Create and return a new text object. The given text object @a text is copied, meaning
 * that the reference count to its data is incremented.
 *
 * @note If OpenStep is present the returned object will be autoreleased before being returned.
 *
 * @param text the text to copy
 * @return a reference to the new text object
 */
+ (id) textWithText: (OLText*)text;

/**
 * @name Initializers and Deallocators
 */
/* @{ */

/**
 * Initialize a new text object. The text is empty.
 *
 * @return a reference to this text
 */
- (id) init;

/**
 * Initialize a new text object. The @a bytes given will be converted from the encoding
 * @a enc to UTF-16.
 *
 * @if OL_NO_OPENSTEP
 * @exception OLInvalidArgumentException if the given encoding is not supported
 * @else
 * @exception NSInvalidArgumentException if the given encoding is not supported
 * @endif
 * @param bytes the bytes containing the text encoded with the given encoding
 * @param num the number of bytes
 * @param enc the encoding used for the data in @a bytes
 * @return a reference to this text object
 */
- (id) initWithBytes: (const uint8_t*)bytes count: (unsigned)num encoding: (const char*)enc;

/**
 * Initialize a new text object. The new object will contain the characters pointed to
 * by the parameter @a chs.
 *
 * @param chs the characters to copy into the new text object
 * @param num the number of characters
 * @return a reference to this text object
 */
- (id) initWithChars: (const olchar*)chs count: (unsigned)num;

#if !defined(OL_NO_OPENSTEP)
/**
 * Initialize the text object. Creates a new text object from an archive and returns it.
 *
 * @post The text returned will be identical to the text saved to the archive
 * using the #encodeWithCoder: message.
 *
 * @param decoder the coder which will decode the archived text
 * @return a reference to this text object
 */
- (id) initWithCoder: (NSCoder*)decoder;
#endif

#if defined(OL_NO_OPENSTEP)
- (id) initWithConstantString: (OLConstantString*)str;
#endif

/**
 * Initialize the text object. The text in @a chs is assumed to be in the default encoding
 * for the platform. This locale is assumed to have been set by a previous call to
 * @c setlocale. The "C string" @a chs should be null-terminated.
 *
 * @param chs the characters to encode with UTF-16 and store
 * @return a reference to this text object
 */
- (id) initWithCString: (const char*)chs;

#if !defined(OL_NO_OPENSTEP)
- (id) initWithNSString: (NSString*)str;
#endif

/**
 * Initialize the text object. Creates a new text object from an object input stream.
 *
 * @post The text returned will be identical to the text saved to the stream
 * using the #writeSelfToStream: message.
 *
 * @param stream the input stream from which to read the text
 * @return a reference to this text object
 */
- (id) initWithObjectInStream: (OLObjectInStream*)stream;

/**
 * Initialize the text object. The given text object @a text is copied, meaning
 * that the reference count to its data is incremented.
 *
 * @param text the text to copy
 * @return a reference to this text object
 */
- (id) initWithText: (OLText*)text;

/**
 * Initialize the text object. A span of @a num characters is copied from the
 * given text object @a text starting at @a roff.
 *
 * @note The boundaries of the text object from which to copy are not checked,
 * meaning that if any character designated to be copied is not actually
 * controlled by the give text object, the results will be undefined.
 *
 * @param text the text object from which to copy characters
 * @param roff the beginning offset from which to copy
 * @param num the number of characters to copy
 * @return a reference to this text object
 */
- (id) initWithText: (OLText*)text offset: (unsigned)roff count: (unsigned)num;

/**
 * Reduce the reference count to the text by one and deallocate the memory
 * if the reference count becomes zero.
 */
#if defined(OL_NO_OPENSTEP)
- (id) free;
#else
- (void) dealloc;
#endif
/* @} */

/**
 * Return the character at @a index.
 *
 * @note If @a index is out of the range controlled by this object, the result will
 * be undefined.
 *
 * @param index the index of the character to return
 * @return the character at @a index
 */
- (olchar) at: (unsigned)index;

/**
 * Return the text encoded with the given encoding. The length of the returned array
 * will be placed in @a rc.
 *
 * @note The returned array must be freed with @c objc_free.
 *
 * @if OL_NO_OPENSTEP
 * @exception OLInvalidArgumentException if the given encoding is not supported
 * @else
 * @exception NSInvalidArgumentException if the given encoding is not supported
 * @endif
 * @param enc the encoding with which to encode the text
 * @param rc the length of the returned array
 * @return an array of encoded text
 */
- (uint8_t*) bytesWithEncoding: (const char*)enc returnedCount: (unsigned*)rc;

/**
 * Compare this object to another. OLText objects can be compared to other OLText objects,
 * to NSString objects under OpenStep and to OLConstantString objects if OpenStep is
 * not present. The two objects, if compatible, will be compared lexicographically.
 *
 * @param other the object to which to compare this one
 * @return a value greater than, equal to, or less than zero accoringly as this object
 * is greater than, equal to, or less than @a other
 */
- (int) compare: (id)other;

#if defined(OL_NO_OPENSTEP)
/**
 * Return a copy of this object. A new object is returned that refers to the same text
 * as this object. The reference count is merely incremented.
 *
 * @return a copy of this object
 */
- (id) copy;
#else
/**
 * Return a copy of this object. A new object is returned that refers to the same text
 * as this object. The reference count is merely incremented. The new object will be
 * allocated from @a zone.
 *
 * @param zone the zone from which to allocate new memory
 * @return a copy of this object
 */
- (id) copyWithZone: (NSZone*)zone;
#endif

/**
 * Return a "C string". The returned array is an array of bytes encoded with the default
 * encoding for the platform. This encoding should be set with a previous call to
 * @c setlocale. The returned array should not be freed by the caller.
 *
 * @return an array encoded with the default encoding
 */
- (const char*) cString;

/**
 * Return whether this text is empty.
 *
 * @return YES if the text is empty, NO otherwise
 */
- (BOOL) empty;

#if !defined(OL_NO_OPENSTEP)
/**
 * Encode the text. This should not be confused with the notion of "encoding" the text
 * in the sense of a "text encoding". Encoding in this context refers to the act of
 * saving the text to an archive. The text is saved to an archive using @a encoder. The
 * test can be retrieved from the archive using the initializer #initWithCoder:.
 *
 * @param encoder the coder which will save the text to the archive
 */
- (void) encodeWithCoder: (NSCoder*)encoder;
#endif

/**
 * Find a character. The character is searched for from the given offset.
 *
 * @note The starting offset is not checked to make sure it is within the
 * bounds of the text.
 *
 * @param ch the character for which to search
 * @param offset the offset from which to start
 * @return the index of the character or UINT_MAX if the character cannot be
 * found
 */
- (unsigned) findChar: (olchar)ch fromOffset: (unsigned)offset;

/**
 * Find a character not in a set. The characters of this text object are searched
 * until one is found that is not contained in the given set, @a text.
 *
 * @note The starting offset is not checked to make sure it is within the
 * bounds of the text.
 *
 * @param text the set of characters against which to compare
 * @param offset the starting offset in this text object of the search 
 * @return the index of the first character not in @a text or UINT_MAX if
 * all characters of @a text are contained in this text object
 */
- (unsigned) findFirstNotOf: (OLText*)text fromOffset: (unsigned)offset;

/**
 * Find a character of a set. The characters of this text object are searched
 * until one is found that is contained in the given set, @a text.
 *
 * @note The starting offset is not checked to make sure it is within the
 * bounds of the text.
 *
 * @param text the set of characters against which to compare
 * @param offset the starting offset in this text object of the search 
 * @return the index of the first character in @a text or UINT_MAX if
 * no characters of @a text are contained in this text object
 */
- (unsigned) findFirstOf: (OLText*)text fromOffset: (unsigned)offset;

/**
 * Find a character not in a set. The characters of this text object are searched
 * until one is found that is not contained in the given set, @a text. The search
 * begins at @a offset and proceeds backwards, towards the beginning of this
 * text object.
 *
 * @note The starting offset is not checked to make sure it is within the
 * bounds of the text.
 *
 * @param text the set of characters against which to compare
 * @param offset the starting offset in this text object of the search 
 * @return the index of the last character not in @a text or UINT_MAX if
 * all characters of @a text are contained in this text object
 */
- (unsigned) findLastNotOf: (OLText*)text fromOffset: (unsigned)offset;

/**
 * Find a character of a set. The characters of this text object are searched
 * until one is found that is contained in the given set, @a text. The search
 * begins at @a offset and proceeds backwards, towards the beginning of this
 * text object.
 *
 * @note The starting offset is not checked to make sure it is within the
 * bounds of the text.
 *
 * @param text the set of characters against which to compare
 * @param offset the starting offset in this text object of the search 
 * @return the index of the last character in @a text or UINT_MAX if
 * no characters of @a text are contained in this text object
 */
- (unsigned) findLastOf: (OLText*)text fromOffset: (unsigned)offset;

/**
 * Find a subsequence. This text object is searched until the subsequence
 * represented by @a text is found.
 *
 * @note The starting offset is not checked to make sure it is within the
 * bounds of the text.
 *
 * @param text the subsequence for which to search
 * @param offset the starting offset in this text object of the search
 * @return the beginning index of the subsequence or UINT_MAX if the subsequence
 * cannot be found
 */
- (unsigned) findText: (OLText*)text fromOffset: (unsigned)offset;

/**
 * Extract a range of characters. A range of characters from this text object is
 * copied to a buffer.
 *
 * @note No range checking is performed on the validity of the arguments passed.
 *
 * @param buffer the destination buffer
 * @param offset the starting offset
 * @param num the number of characters to copy
 */
- (void) getCharacters: (olchar*)buffer fromOffset: (unsigned)offset count: (unsigned)num;

/**
 * Return a hash code. The hash code for this text object is computed using #OLHash.
 *
 * @return the hash code
 */
- (unsigned) hash;

/**
 * Return whether this text object is equal to another one. This message returns YES if
 * #compare: returns zero.
 *
 * @param object the object to test
 * @return YES if @a object is equal to this text object
 */
- (BOOL) isEqual: (id)object;

/**
 * Return the length of the text. This is message returns the same value as #size.
 *
 * @return the length
 */
- (unsigned) length;

/**
 * Return the maximum size of a text object.
 *
 * @return the maximum size
 */
- (unsigned) maxSize;

/**
 * Return the text encoded with the given encoding. The resulting array will
 * be null-terminated.
 *
 * @note The returned array must be freed with @c objc_free.
 *
 * @if OL_NO_OPENSTEP
 * @exception OLInvalidArgumentException if the given encoding is not supported
 * @else
 * @exception NSInvalidArgumentException if the given encoding is not supported
 * @endif
 * @param enc the encoding with which to encode the text
 * @return an array of encoded text
 */
- (uint8_t*) nullTerminatedBytesWithEncoding: (const char*)enc;

/**
 * Find a character. The character is searched for from the given offset backwards,
 * towards the beginning of this text object.
 *
 * @note The starting offset is not checked to make sure it is within the
 * bounds of the text.
 *
 * @param ch the character for which to search
 * @param offset the offset from which to start
 * @return the last index of the character or UINT_MAX if the character cannot be
 * found
 */
- (unsigned) rfindChar: (olchar)ch fromOffset: (unsigned)offset;

/**
 * Return the size of the text. This is message returns the same value as #length.
 *
 * @return the size
 */
- (unsigned) size;

/**
 * Extract a subsequence. A new text object is created from the indicated subsequence
 * of this one.
 *
 * @note If OpenStep is present the returned object will be autoreleased before being returned.
 * Additionally, no range checking is performed on the validity of the arguments passed.
 *
 * @param offset the offset from which to start the new object
 * @param num the number of characters in the new object
 * @return a new text object that contains the indicated subsequence
 */
- (OLText*) substrFromOffset: (unsigned)offset count: (unsigned)num;

#if !defined(OL_NO_OPENSTEP)
/**
 * Convert this text object to an instance of NSString. The returned NSString is
 * autoreleased for being returned.
 *
 * @return a NSString that contains the text of this object
 */
- (NSString*) toNSString;
#endif

/**
 * Write this object to a stream. The text is written in a platform-neutral way and
 * may be recovered with the initializer #initWithObjectInStream:.
 *
 * @exception OLInputOutputException if there is an error writing to the stream
 * @param stream the stream to which to write
 */
- (void) writeSelfToStream: (OLObjectOutStream*)stream;

@end

/**
 * @class OLTextBuffer Text.h ObjectiveLib/Text.h
 *
 * A mutable buffer for manipulating text. OLTextBuffer is like a mutable version
 * of OLText. It is meant to be used when manipulating text, but not to be treated
 * as a mutable replacement for OLText. The usage model would be something like,
 * create a OLTextBuffer instance, build the desired sequence of characters, then
 * convert it to OLText with the #text method for general use, archiving or
 * streaming.
 *
 * @note Most of the methods that mutate the text buffer return a reference to the
 * buffer to enable chaining of mutations. For example,
 * @code
 * OLTextBuffer* buffer = [[OLTextBuffer alloc] init];
 * [buffer [[appendText: [OLText textWithCString: "You're cute"]] appendChar: OL_EXCLAMATION_CHAR]];
 * @endcode
 *
 * @sa OLText
 *
 * @ingroup Text
 */
@interface OLTextBuffer :
#if defined(OL_NO_OPENSTEP)
    Object
#else
    NSObject <NSCopying>
#endif
{
@protected
    /**
     * The array of characters under control of this object
     */
    olchar*     begin;

    /**
     * The size of the array
     */
    unsigned    size;

    /**
     * The capacity of the array
     */
    unsigned    capacity;
}

/**
 * Create and return a new, empty text buffer.
 *
 * @note If OpenStep is present the returned object will be autoreleased before being returned.
 *
 * @return a new text buffer
 */
+ (id) textBuffer;

/**
 * Create and return a new text buffer that holds a copy of the give text object.
 *
 * @note If OpenStep is present the returned object will be autoreleased before being returned.
 *
 * @param text the text to copy into this buffer
 * @return a new text buffer
 */
+ (id) textBufferWithText: (OLText*)text;

/**
 * @name Initializers and Deallocators
 */
/* @{ */

/**
 * Initialize a new text buffer. The resuling buffer contains no text. The buffer will
 * have an initial capacity of 32 characters. This will grow as needed.
 *
 * @return a reference to this text buffer
 */
- (id) init;

/**
 * Initialize a new text buffer. The resuling buffer contains no text. The buffer will
 * have an initial capacity of @a cap characters. This will grow as needed.
 *
 * @param cap the capacity with which to start
 * @return a reference to this text buffer
 */
- (id) initWithCapacity: (unsigned)cap;

/**
 * Initialize a new text buffer. The buffer will start with a copy of the given text.
 *
 * @param text the text to copy into the buffer
 * @return a reference to this text buffer
 */
- (id) initWithText: (OLText*)text;

/**
 * Free all memory allocated by this buffer and destroy the object.
 */
#if defined(OL_NO_OPENSTEP)
- (id) free;
#else
- (void) dealloc;
#endif
/* @} */

/**
 * Append a character. The given character will be appended to the current array.
 *
 * @param ch the character to append
 * @return a reference to this text buffer
 */
- (OLTextBuffer*) appendChar: (olchar)ch;

/**
 * Append some characters. A span of characters from the array @a chars starting at
 * offset @a offset and extending @a num characters will be appended to the current
 * array.
 *
 * @param chars the array from which to copy characters
 * @param offset the offset from which to start copying
 * @param num the number of characters to append
 * @return a reference to this text buffer
 */
- (OLTextBuffer*) appendChars: (const olchar*)chars fromOffset: (unsigned)offset count: (unsigned)num;

/**
 * Append a text object. All the characters of the given object will be appended to this
 * array.
 *
 * @param text the text to append
 * @return a reference to this text buffer
 */
- (OLTextBuffer*) appendText: (OLText*)text;

/**
 * Append another text buffer. All the characters of the given buffer will be appended to
 * this array.
 *
 * @param buffer the buffer to append
 * @return a reference to this text buffer
 */
- (OLTextBuffer*) appendTextBuffer: (OLTextBuffer*)buffer;

/**
 * Assign a character. The character at @a index is replaced.
 *
 * @note The index is not checked to make sure it is within the
 * bounds of the text buffer.
 *
 * @param index the index at which to replace the value of the character
 * @param ch the new character for @a index
 * @return a reference to this text buffer
 */
- (OLTextBuffer*) assignAt: (unsigned)index character: (olchar)ch;

/**
 * Return the character at @a index.
 *
 * @note If @a index is out of the range controlled by this object, the result will
 * be undefined.
 *
 * @param index the index of the character to return
 * @return the character at @a index
 */
- (olchar) at: (unsigned)index;

/**
 * Return the capacity of this buffer.
 *
 * @return the capacity
 */
- (unsigned) capacity;

/**
 * Erase all characters.
 */
- (void) clear;

/**
 * Compare this object to another. The two objects, if compatible, will be
 * compared lexicographically.
 *
 * @param other the object to which to compare this one
 * @return a value greater than, equal to, or less than zero accoringly as this object
 * is greater than, equal to, or less than @a other
 */
- (int) compare: (id)other;

#if defined(OL_NO_OPENSTEP)
/**
 * Return a copy of this text buffer.
 *
 * @return a copy
 */
- (id) copy;
#else
/**
 * Return a copy of this text buffer allocated with the given zone.
 *
 * @param zone the zone from which to allocate the new memory
 * @return a copy
 */
- (id) copyWithZone: (NSZone*)zone;
#endif

/**
 * Return whether this text buffer is empty.
 *
 * @return YES if the buffer is empty, NO if not
 */
- (BOOL) empty;

/**
 * Erase a character. The character at the given index will be erased and the indices of
 * all subsequent characters will be shifted down one position.
 *
 * @note If @a index is out of the range controlled by this object, the result will
 * be undefined.
 *
 * @param index the index at which to erase
 * @return a reference to this text buffer
 */
- (OLTextBuffer*) eraseAt: (unsigned)index;

/**
 * Erase a group of characters. The given number of characters starting at the given
 * offset will be removed.
 *
 * @note No bounds checking is performed on the input parameters.
 *
 * @param offset the offset from which to erase
 * @param num the number of characters to erase
 * @return a reference to this text buffer
 */
- (OLTextBuffer*) eraseFromOffset: (unsigned)offset count: (unsigned)num;

/**
 * Find a character. The character is searched for from the given offset.
 *
 * @note The starting offset is not checked to make sure it is within the
 * bounds of the text buffer.
 *
 * @param ch the character for which to search
 * @param offset the offset from which to start
 * @return the index of the character or UINT_MAX if the character cannot be
 * found
 */
- (unsigned) findChar: (olchar)ch fromOffset: (unsigned)offset;

/**
 * Find a character not in a set. The characters of this text buffer are searched
 * until one is found that is not contained in the given set, @a text.
 *
 * @note The starting offset is not checked to make sure it is within the
 * bounds of the text.
 *
 * @param text the set of characters against which to compare
 * @param offset the starting offset in this text object of the search 
 * @return the index of the first character not in @a text or UINT_MAX if
 * all characters of @a text are contained in this text object
 */
- (unsigned) findFirstNotOf: (OLText*)text fromOffset: (unsigned)offset;

/**
 * Find a character of a set. The characters of this text buffer are searched
 * until one is found that is contained in the given set, @a text.
 *
 * @note The starting offset is not checked to make sure it is within the
 * bounds of the text.
 *
 * @param text the set of characters against which to compare
 * @param offset the starting offset in this text object of the search 
 * @return the index of the first character in @a text or UINT_MAX if
 * no characters of @a text are contained in this text object
 */
- (unsigned) findFirstOf: (OLText*)text fromOffset: (unsigned)offset;

/**
 * Find a character not in a set. The characters of this text buffer are searched
 * until one is found that is not contained in the given set, @a text. The search
 * begins at @a offset and proceeds backwards, towards the beginning of this
 * text object.
 *
 * @note The starting offset is not checked to make sure it is within the
 * bounds of the text.
 *
 * @param text the set of characters against which to compare
 * @param offset the starting offset in this text object of the search 
 * @return the index of the last character not in @a text or UINT_MAX if
 * all characters of @a text are contained in this text object
 */
- (unsigned) findLastNotOf: (OLText*)text fromOffset: (unsigned)offset;

/**
 * Find a character of a set. The characters of this text buffer are searched
 * until one is found that is contained in the given set, @a text. The search
 * begins at @a offset and proceeds backwards, towards the beginning of this
 * text object.
 *
 * @note The starting offset is not checked to make sure it is within the
 * bounds of the text.
 *
 * @param text the set of characters against which to compare
 * @param offset the starting offset in this text object of the search 
 * @return the index of the last character in @a text or UINT_MAX if
 * no characters of @a text are contained in this text object
 */
- (unsigned) findLastOf: (OLText*)text fromOffset: (unsigned)offset;

/**
 * Find a subsequence. This text buffer is searched until the subsequence
 * represented by @a text is found.
 *
 * @note The starting offset is not checked to make sure it is within the
 * bounds of the text.
 *
 * @param text the subsequence for which to search
 * @param offset the starting offset in this text object of the search
 * @return the beginning index of the subsequence or UINT_MAX if the subsequence
 * cannot be found
 */
- (unsigned) findText: (OLText*)text fromOffset: (unsigned)offset;

/**
 * Extract a range of characters. A range of characters from this text buffer is
 * copied to a buffer.
 *
 * @note No range checking is performed on the validity of the arguments passed.
 *
 * @param buffer the destination buffer
 * @param offset the starting offset
 * @param num the number of characters to copy
 */
- (void) getCharacters: (olchar*)buffer fromOffset: (unsigned)offset count: (unsigned)num;

/**
 * Insert a character. The given character is inserted at the given offset and the
 * indices of all subsequent characters are shifted up by one.
 *
 * @note The offset for the insertion is not checked to determine whether it is
 * actually in the sequence controller by this text buffer.
 *
 * @param ch the character to insert
 * @param offset the offset at which to insert @a ch
 * @return a reference to this text buffer
 */
- (OLTextBuffer*) insertChar: (olchar)ch atOffset: (unsigned)offset;

/**
 * Insert an array of characters. The given number of haracters from the given
 * array are inserted from the given offset.
 *
 * @note No range checking is performed on the validity of the arguments passed.
 *
 * @param chars the array from which to copy characters
 * @param offset the index in @a chars from which to start copying
 * @param num the number of characters to insert
 * @return a reference to this text buffer
 */
- (OLTextBuffer*) insertChars: (const olchar*)chars atOffset: (unsigned)offset count: (unsigned)num;

/**
 * Insert a chunk of text. The given text is inserted into the buffer at the
 * given offset.
 *
 * @note The offset for the insertion is not checked to determine whether it is
 * actually in the sequence controller by this text buffer.
 *
 * @param text the text object to insert
 * @param offset the offset at which to insert the characters from @a text
 * @return a reference to this text buffer
 */
- (OLTextBuffer*) insertText: (OLText*)text atOffset: (unsigned)offset;

/**
 * Return whether this text buffer is equal to another one. This message returns YES if
 * #compare: returns zero.
 *
 * @param object the object to test
 * @return YES if @a object is equal to this text object
 */
- (BOOL) isEqual: (id)object;

/**
 * Return the length of the text buffer. This is message returns the same value as #size.
 * The number of characters controlled by the buffer is returned, not the capacity.
 *
 * @return the length
 */
- (unsigned) length;

/**
 * Replace a range of characters. The given number of characters are replaced from the
 * given offset with the given text object.
 *
 * @note None of the input parameters is checked to be sure that it actually refers to
 * a part of the text buffer that is under its conrol.
 *
 * @param offset the starting offset of the characters to replace
 * @param num the number of characters to replace
 * @param text the text to insert as a replacement
 * @return a reference to this text buffer
 */
- (OLTextBuffer*) replaceFromOffset: (unsigned)offset count: (unsigned)num withText: (OLText*)text;

/**
 * Ensure that the capacity of the text buffer is at least of a certain size. After sending
 * this message the capacity of the text buffer will be no less than the given value.
 *
 * @param cap the new desired capacity
 */
- (void) reserve: (unsigned)cap;

/**
 * Resize the text buffer. If the given size is greater than the current size,
 * not the current capacity, then the remainder will be filled with the given
 * character. If the give size is less than the current size, then the size will
 * be truncated.
 *
 * @param newLength the new size of the text buffer
 * @param ch the character with which to fill the empty space if the new size
 * is greater than the current size
 * @return a reference to this text buffer
 */
- (OLTextBuffer*) resize: (unsigned)newLength filledWith: (olchar)ch;

/**
 * Reverse the order of characters. After sending this message the characters
 * will be in reverse order from the order in which they were before.
 * @return a reference to this text buffer
 */
- (OLTextBuffer*) reverse;

/**
 * Find a character. The character is searched for from the given offset backwards,
 * towards the beginning of this text buffer.
 *
 * @note The starting offset is not checked to make sure it is within the
 * bounds of the text.
 *
 * @param ch the character for which to search
 * @param offset the offset from which to start
 * @return the last index of the character or UINT_MAX if the character cannot be
 * found
 */
- (unsigned) rfindChar: (olchar)ch fromOffset: (unsigned)offset;

/**
 * Return the size of the text buffer. This is message returns the same value as #length.
 * The number of characters controlled by the buffer is returned, not the capacity.
 *
 * @return the size
 */
- (unsigned) size;

/**
 * Extract a subsequence. A new text object is created from the indicated subsequence
 * of this one.
 *
 * @note If OpenStep is present the returned object will be autoreleased before being returned.
 *
 * @note No range checking is performed on the validity of the arguments passed.
 *
 * @param offset the offset from which to start the new object
 * @param num the number of characters in the new object
 * @return a new text object that contains the indicated subsequence
 */
- (OLText*) substrFromOffset: (unsigned)offset count: (unsigned)num;

/**
 * Return the text. All of the text controlled by this buffer will be used to
 * create a new text object.
 *
 * @note If OpenStep is present the returned object will be autoreleased before being returned.
 *
 * @return a text object that represents this buffer
 */
- (OLText*) text;

@end

#if defined(OL_NO_OPENSTEP)

/**
 * @class OLConstantString Text.h ObjectiveLib/Text.h
 *
 * The class used to store constant "strings" that can be directly instantiated
 * in code using the convention @"this is a constant". Instances of this class
 * that contain non-ASCII characters are not supported.
 *
 * @sa OLText, OLTextBuffer
 *
 * @ingroup Text
 */
@interface OLConstantString : Object
{
    /**
     * The character data
     */
    char*       c_string;

    /**
     * The length of the data
     */
    unsigned    len;
}

#if defined(__NEXT_RUNTIME__)
/**
 * Return the class object.
 *
 * @return a reference to the class object
 */
+ (id) class;

/**
 * Performed when the class is loaded into the runtime system. Please do not call
 * this method. It is for the use of the runtime system.
 */
+ (void) load;
#endif

/**
 * Free the memory associated with this object.
 */
- (id) free;

#if defined(__NEXT_RUNTIME__)
/**
 * Return the class object.
 *
 * @return a reference to the class object
 */
- (id) class;
#endif

/**
 * Compare this object to another. OLConstantString objects can be compared to
 * other OLConstantString objects and to OLText objects. The two objects, if
 * compatible, will be compared lexicographically.
 *
 * @param other the object to which to compare this one
 * @return a value greater than, equal to, or less than zero accoringly as this object
 * is greater than, equal to, or less than @a other
 */
- (int) compare: (id)other;

/**
 * Copy this object.
 *
 * @return a copy of this object
 */
- (id) copy;

/**
 * Return the array of characters controlled by this object.
 *
 * @return the controlled array
 */
- (const char*) cString;

/**
 * Return a hash code. The hash code for this text object is computed using #OLHash.
 *
 * @return the hash code
 */
- (unsigned) hash;

/**
 * Return whether this text object is equal to another one. This message returns YES if
 * #compare: returns zero.
 *
 * @param other the object to test
 * @return YES if @a object is equal to this text object
 */
- (BOOL) isEqual: (id)other;

/**
 * Return the length of the controlled sequence of characters.
 *
 * @return the length
 */
- (unsigned) length;

@end

#if defined(__NEXT_RUNTIME__)
/**
 * @internal The class object used to represent the class of OLConstantString
 */
extern struct objc_class _OLConstantStringClassReference;
#endif

#endif

#endif
