/* 
   NSString.m

   Copyright (C) 1995, 1996 Ovidiu Predescu and Mircea Oancea.
   All rights reserved.

   Author: Mircea Oancea <mircea@jupiter.elcom.pub.ro>

   This file is part of libFoundation.

   Permission to use, copy, modify, and distribute this software and its
   documentation for any purpose and without fee is hereby granted, provided
   that the above copyright notice appear in all copies and that both that
   copyright notice and this permission notice appear in supporting
   documentation.

   We disclaim all warranties with regard to this software, including all
   implied warranties of merchantability and fitness, in no event shall
   we be liable for any special, indirect or consequential damages or any
   damages whatsoever resulting from loss of use, data or profits, whether in
   an action of contract, negligence or other tortious action, arising out of
   or in connection with the use or performance of this software.
*/

#include <stdio.h>
#include <ctype.h>

#include <Foundation/common.h>
#include <Foundation/NSArray.h>
#include <Foundation/NSAutoreleasePool.h>
#include <Foundation/NSData.h>
#include <Foundation/NSDictionary.h>
#include <Foundation/NSCoder.h>
#include <Foundation/NSURL.h>
#include <Foundation/NSURLHandle.h>
#include <Foundation/NSException.h>
#include <Foundation/exceptions/StringExceptions.h>
#include <Foundation/exceptions/GeneralExceptions.h>
#include <Foundation/PropertyListParser.h>

#include <Foundation/NSCharacterSet.h>
#include <Foundation/NSString.h>
#include <Foundation/NSThread.h>
#include <Foundation/NSNotification.h>
#include <Foundation/NSConcreteString.h>
#include <Foundation/NSPathUtilities.h>
#include <Foundation/NSByteOrder.h>

#include "PrivateThreadData.h"
#include "NSObject+PropLists.h"

#include <locale.h>

#include <netinet/in.h>

int NSConvertUTF16toUTF8(unichar             **sourceStart,
                         const unichar       *sourceEnd, 
                         unsigned char       **targetStart,
                         const unsigned char *targetEnd);
int NSConvertUTF8toUTF16(unsigned char **sourceStart, unsigned char *sourceEnd, 
                         unichar **targetStart, const unichar *targetEnd);

id NSInitStringWithData(NSString *self, NSData *data,
                        NSStringEncoding encoding);

NSData *dataUsingEncoding(NSString *self,
                          NSStringEncoding encoding, BOOL flag);
/* 

General ideas in NSString class cluster implementation

The NSString class is an abstract class that uses only unicode representation
and handles in an inefficient manner since it operates on abstract strings
accessing characters one by one using characterAtIndex: method.

Currently there is only one abstract subclass of classes designed to implement
ANSI C strings in the default encoding provided by the operating system 
(assumed ASCII or ASCII extension like NEXTSTEP). This type of strings are called NS8BitString since they uses characters (usually represented on 8 bits)
for immutable classes and NSMutable8BitString for mutable ones respectively. 
This tree of classes is implemented based on `__compact8BitBytes' method
that returns a pointer to the internal representation of the string as char[],
with all characters compact, with no gap.

Unicode and encodings will be supported in the future when I will know
how to handle the following (If you know about these please send me a message)
	- convert between different encodings
	- convert characters to upper/lower cases
	- handle composed character sequences

So for the time being only NS8BitString/NSMutable8BitString are used but their
use in the future will be limited to ...WithCString... methods and the strings
generated by the compiler with @"" construct (which should generate unicode 
ones some day in the future).

There is another problem: methods like initWithCharacters... and 
initWithCString assume that the underlying support is 16Bit respectively 8Bit
but it is sent to an instance allocated with [NSString alloc]. So we make 
NSString alloc method to return a temporary string that will allocate and 
initialize the concrete class that will hold the character in initWith... 
methods. This class is NSTemporaryString. Thus one must use constructs like
	var = [[NSString alloc] initWith...]
	var = [NSString stringWith...]
but not
	var = [NSString alloc]
	[var initWith...]
since the second line will return an instance different from the one in var.

*/

#define USE_SINGLE8BITSTRING 1
// #define HAS_UNICODE_STRING 1

/***************************
 * NSString abstract class
 ***************************/

#if USE_SINGLE8BITSTRING 
static id Single8BitStringStore[256];
static Class Single8BitStringClass = Nil;

static inline id _getSingle8BitString(unsigned char _byte) {
    register id str;
    
    if (Single8BitStringClass == Nil) {
        Single8BitStringClass = [NSCharacter8BitString class];
        memset(Single8BitStringStore, 0, sizeof(Single8BitStringStore));
    }
    
    if ((str = Single8BitStringStore[(int)_byte]) == nil) {
        str = [[Single8BitStringClass allocWithZone:nil]
                                      initWithCString:(char *)&_byte length:1];
        Single8BitStringStore[(unsigned int)_byte] = str;
#if DEBUG && 0
        printf("%s: add str[%p] for char %c\n", __PRETTY_FUNCTION__,
               str, _byte);
#endif
    }
    return str;
}
#endif

@implementation NSString

static Class NSStringClass = Nil;

+ (void)initialize
{
    const char *cstr;

    if (NSStringClass == Nil)
        NSStringClass = [NSString class];

#ifndef __WIN32__
    /* required for toupper/tolower to work with umlauts */
    if ((cstr = getenv("LC_CTYPE")))
        setlocale(LC_CTYPE, cstr);
    if ((cstr = getenv("LC_COLLATE")))
        setlocale(LC_COLLATE, cstr);
#endif
    
    NSUserName();
}

/* Getting a string's length */

- (unsigned int)length
{
    [self subclassResponsibility:_cmd];
    return 0;
}

/* Accessing characters	*/

- (unichar)characterAtIndex:(unsigned int)index
{
    [self subclassResponsibility:_cmd];
    return 0;
}

- (void)getCharacters:(unichar*)buffer
{
    NSRange range = {0, [self length]};
    [self getCharacters:buffer range:range];
}

- (void)getCharacters:(unichar *)buffer range:(NSRange)aRange
{
    register unsigned int i = 0;
    IMP imp = [self methodForSelector:@selector(characterAtIndex:)];

    if (aRange.location + aRange.length > [self length]) {
	[[[IndexOutOfRangeException alloc] 
	    initWithFormat:@"range (%d,%d) in string %x of length %d",
	    	aRange.location, aRange.length, self, [self length]] raise];
    }
    
    for (i = 0; i < aRange.length; i++) {
	buffer[i] = (unichar)(long)(*imp)(self, @selector(characterAtIndex:), 
	    aRange.location + i);
    }
}

/* Combining strings */	

- (NSString *)stringByAppendingString:(NSString *)aString
{
    unichar  *buf;
    unsigned len1, len2;
    NSString *s;
    
    len1 = [self length];
    len2 = [aString length];
    
    if (len2 == 0)
	return [[self copy] autorelease];
    
    buf = calloc(len1 + len2 + 1, sizeof(unichar));
    [self    getCharacters:buf];
    [aString getCharacters:&(buf[len1])];
    buf[len1 + len2] = 0;
    s = [NSStringClass stringWithCharacters:buf length:(len1 + len2)];
    free(buf);
    return s;
}

- (NSString*)stringByAppendingFormat:(NSString*)format,...
{
    NSMutableString *string = [self mutableCopy];
    va_list va;
    
    va_start(va, format);
    [string appendFormat:format arguments:va];
    va_end(va);
    return AUTORELEASE(string);
}

- (NSString*)stringByAppendingFormat:(NSString*)format 
  arguments:(va_list)argList
{
    NSMutableString *string = [self mutableCopy];

    [string appendFormat:format arguments:argList];
    return AUTORELEASE(string);
}

- (NSString*)stringByPrependingString:(NSString*)aString
{
    return [aString stringByAppendingString:self];
}

- (NSString*)stringByPrependingFormat:(NSString*)format,...
{
    NSString *string;
    va_list va;

    va_start(va, format);
    string = Avsprintf(format, va);
    va_end(va);

    return [string stringByAppendingString:self];
}

- (NSString*)stringByPrependingFormat:(NSString*)format 
  arguments:(va_list)argList
{
    NSString *string = Avsprintf(format, argList);

    return [string stringByAppendingString:self];
}

/* Dividing strings */

- (NSArray *)componentsSeparatedByString:(NSString *)separator
{
    unsigned int first = 0, last = 0;
    unsigned int slen;
    NSMutableArray *components;

    if ((slen = [separator length]) == 0)
        return [NSArray arrayWithObject:self];

    if ([self length] == 0)
        return [NSArray arrayWithObject:self];
    
    components = [NSMutableArray arrayWithCapacity:16];

    while ((first = [self indexOfString:separator fromIndex:last]) !=NSNotFound) {
	NSRange  range;
        NSString *substring;

        range.location = last;
        range.length   = (first - last);
        substring = [self substringWithRange:range];

	[components addObject:substring];
	last = first + slen;
    }
    
    if ([self length] >= last) {
	NSString *lastComponent;
        
        lastComponent = [self substringFromIndex:last];
	[components addObject:lastComponent];
    }
    return components;
}

- (NSString *)substringWithRange:(NSRange)aRange
{
    unichar * buf;
    id rc;

    if (aRange.location + aRange.length > [self length] )
	[[[IndexOutOfRangeException alloc]
	    initWithFormat:@"range (%d,%d) in string %x of length %d",
	    	aRange.location, aRange.length, self, [self length]] raise];

    if (aRange.length == 0)
	return @"";

    buf = MallocAtomic(sizeof(unichar) * (aRange.length + 1));
    [self getCharacters:buf range:aRange];
    rc = AUTORELEASE([[NSStringClass alloc]
                           initWithCharactersNoCopy:buf
                           length:aRange.length
                           freeWhenDone:YES]);
    return rc;
}

- (NSString *)substringFromRange:(NSRange)aRange
{
    return [self substringWithRange:aRange];
}

- (NSString *)substringFromIndex:(unsigned int)index
{
    NSRange range;
    
    range.location = index;
    range.length   = [self length]; //- index
    if (range.length < index) {
	[[[IndexOutOfRangeException alloc] 
	    initWithFormat:@"index %d in string %x of length %d",
	    	index, self, [self length]] raise];
    }
    range.length -= index;
    
    return [self substringWithRange:range];
}

- (NSString*)substringToIndex:(unsigned int)index
{
    NSRange range = {0, index};

    return [self substringWithRange:range];
}

- (NSString *)stringByTrimmingCharactersInSet:(NSCharacterSet *)_set
{
    unsigned len;
    unichar  *buf;
    unsigned idx;
    unsigned ridx;
    BOOL (*isMem)(id,SEL,unichar);
    
    if ((len = [self length]) == 0)
        return [[self copy] autorelease];
	
    buf = calloc(len + 1, sizeof(unichar));
    [self getCharacters:buf];
    
    isMem = (void *)[_set methodForSelector:@selector(characterIsMember:)];
    
    for (idx = 0; 
	 (idx < len) && isMem(_set,@selector(characterIsMember:),buf[idx]); 
	 idx++)
	;
    for (ridx = len-1; 
	 (ridx >= idx) && isMem(_set,@selector(characterIsMember:),buf[ridx]);
	 ridx--)
	;
    
    self = [NSStringClass stringWithCharacters:&(buf[idx]) 
			  length:((ridx+1) - idx)];
    free(buf);
    return self;
}

/* Finding characters and substrings */

- (NSRange)rangeOfCharacterFromSet:(NSCharacterSet*)aSet
{
    NSRange range = {0, [self length]};

    return [self rangeOfCharacterFromSet:aSet options:0 range:range];
}

- (NSRange)rangeOfCharacterFromSet:(NSCharacterSet*)aSet
  options:(unsigned int)mask
{
    NSRange range = {0, [self length]};

    return [self rangeOfCharacterFromSet:aSet options:mask range:range];
}

- (NSRange)rangeOfCharacterFromSet:(NSCharacterSet*)aSet
  options:(unsigned int)mask range:(NSRange)aRange
{
    // UNICODE 
    // ENCODINGS - this code applies to the system's default encoding
    SEL characterIsMemberSel = @selector(characterIsMember:);
    IMP imp = [aSet methodForSelector:characterIsMemberSel];

    if (NSMaxRange(aRange) > [self length])
	[[[IndexOutOfRangeException alloc]
	    initWithFormat:@"range %@ not in string 0x%08x of length %d",
	    NSStringFromRange(aRange), self, [self length]] raise];

    if (mask & NSBackwardsSearch) {
        int i;
        
	for (i = aRange.length - 1; i >= aRange.location; i--) {
	    unichar c = [self characterAtIndex:i];

	    if ((*imp)(aSet, characterIsMemberSel, c) ||
		((mask & NSCaseInsensitiveSearch)
		 && ((islower(c)
		      && (*imp)(aSet, characterIsMemberSel, toupper(c)))
		     || (isupper(c)
			 && (*imp)(aSet, characterIsMemberSel, tolower(c)))))) {
		return NSMakeRange(i, 1);
	    }
	}
    }
    else {
        unsigned int i, max;
        max = NSMaxRange(aRange);
	for (i = aRange.location; i < max; i++) {
	    unichar c = [self characterAtIndex:i];

	    if ((*imp)(aSet, characterIsMemberSel, c) ||
		((mask & NSCaseInsensitiveSearch) &&
		 ((islower(c)
		  && (*imp)(aSet, characterIsMemberSel, toupper(c)))
		 || (isupper(c)
		     && (*imp)(aSet, characterIsMemberSel, tolower(c)))))) {
		return NSMakeRange(i, 1);
	    }
	}
    }

    return NSMakeRange(NSNotFound, 0);
}

- (NSRange)rangeOfString:(NSString*)string
{
    NSRange range = {0, [self length]};

    return [self rangeOfString:string options:0 range:range];
}

- (NSRange)rangeOfString:(NSString*)string options:(unsigned int)mask
{
    NSRange range = {0, [self length]};

    return [self rangeOfString:string options:mask range:range];
}

- (NSRange)rangeOfString:(NSString*)aString
  options:(unsigned int)mask range:(NSRange)aRange
{
    // UNICODE 
    // ENCODINGS - this code applies to the system's default encoding
    // islower needs to be replaced with proper NSCharacterSet calls (speed?)
    unsigned int i, a;
    NSRange range;

    if (aRange.location + aRange.length > [self length]) {
	[[[IndexOutOfRangeException alloc]
	    initWithFormat:@"range (%d,%d) in string %x of length %d",
	    	aRange.location, aRange.length, self, [self length]] raise];
    }
    
    a = [aString length];
    
    if (a == 0 || aRange.length < a)
	return NSMakeRange(0,0);

    if (mask & NSAnchoredSearch)  {
	range.location = aRange.location +
	    ((mask & NSBackwardsSearch) ? aRange.length - a : 0);
	range.length = a;
	
	if ([self compare:aString options:mask range:range] == NSOrderedSame)
	    return range;
	else
	    return NSMakeRange(NSNotFound, 0);
    }

    if (mask & NSBackwardsSearch) {	
	if (mask & NSCaseInsensitiveSearch) {
	    // Backward case insensitive
	    unichar cf;
            int n;
            
            cf = [aString characterAtIndex: 0 ];
	    cf = islower(cf) ? toupper(cf) : cf;
	    for (n = aRange.length - a; n >= 0; n--) {
		unichar ca = cf;
		unichar cm = [self characterAtIndex:n + aRange.location ];

		cm = islower(cm) ? toupper(cm) : cm;

		if (cm != ca)
		    continue;
		for (i = 1; i < a; i++) {
		    cm = [self characterAtIndex:n + i + aRange.location ];
		    ca = [aString characterAtIndex:i];
		    cm = islower(cm) ? toupper(cm) : cm;
		    ca = islower(ca) ? toupper(ca) : ca;
		    if (cm != ca)
			break;
		}
		if (i == a) {
		    range.location = aRange.location + n;
		    range.length = a;
		    return range;
		}
	    }
	}
	else {
	    // Backward case sensitive
            int n;
            
	    for (n = aRange.length - a; n >= 0; n--) {
		if ([self characterAtIndex:n + aRange.location]
			!= [aString characterAtIndex:0])
		    continue;
		for (i = 1; i < a; i++)
		    if ([self characterAtIndex:(n + i + aRange.location)]
			    != [aString characterAtIndex: i] )
			break;
		if (i == a) {
		    range.location = aRange.location + n;
		    range.length = a;
		    return range;
		}
	    }
	}
    }
    else {
	if (mask & NSCaseInsensitiveSearch) {
	    // Forward case insensitive
            unsigned int n;
	    unichar      cf;
            
            cf = [aString characterAtIndex: n];
	    cf = islower(cf) ? toupper(cf) : cf;
	    for (n = 0; n + a <= aRange.length; n++) {
		unichar ca = cf;
		unichar cm = [self characterAtIndex: n + aRange.location ];

		cm = islower(cm) ? toupper(cm) : cm;
		
		if (cm != ca)
		    continue;
		for (i = 1; i < a; i++) {
		    cm = [self characterAtIndex:n + i + aRange.location];
		    ca = [aString characterAtIndex:i];
		    cm = islower(cm) ? toupper(cm) : cm;
		    ca = islower(ca) ? toupper(ca) : ca;
		    if (cm != ca)
			break;
		}
		if (i == a) {
		    range.location = aRange.location + n;
		    range.length = a;
		    return range;
		}
	    }
	}
	else {
	    // Forward case sensitive
            unsigned int n;
	    for (n = 0; n + a <= aRange.length; n++) {
		if ([self characterAtIndex:n + aRange.location]
			!= [aString characterAtIndex: 0] )
		    continue;
		for (i = 1; i < a; i++)
		    if ([self characterAtIndex:n + i + aRange.location]
			    != [aString characterAtIndex:i])
			break;
		if (i == a) {
		    range.location = aRange.location + n;
		    range.length = a;
		    return range;
		}
	    }
	}
    }
    
    range.location = NSNotFound;
    range.length   = 0;
    return range;
}

- (unsigned int)indexOfString:(NSString *)substring
{
    NSRange range = {0, [self length]};
    
    range = [self rangeOfString:substring options:0 range:range];
    return range.length ? range.location : NSNotFound;
}

- (unsigned int)indexOfString:(NSString*)substring fromIndex:(unsigned)index
{
    NSRange range = {index, [self length]-index};
    
    range = [self rangeOfString:substring options:0 range:range];
    return range.length ? range.location : NSNotFound;
}

- (unsigned int)indexOfString:(NSString*)substring range:(NSRange)range
{
    range = [self rangeOfString:substring options:0 range:range];
    return range.length ? range.location : NSNotFound;
}

/* Determining composed character sequences */

- (NSRange)rangeOfComposedCharacterSequenceAtIndex:(unsigned int)anIndex
{
    NSRange range;
    unsigned int length = [self length];
    
    if (anIndex >= length) {
	[[[IndexOutOfRangeException alloc] 
	    initWithFormat:@"index %d out of range in string %x of length %d",
	    	anIndex, self, length] raise];
    }
    // UNICODE
    range.location = anIndex;
    range.length = 1;
    return range;
}

/* Converting string contents into a property list */

- (id)propertyList
{
    return NSParsePropertyListFromString(self);
}

- (NSMutableDictionary*)propertyListFromStringsFileFormat
{
    return NSParseStringsFromString(self);
}

/* Identifying and comparing strings */

- (NSComparisonResult)caseInsensitiveCompare:(NSString*)aString
{
    NSRange range = {0, [self length]};
    
    return [self compare:aString options:NSCaseInsensitiveSearch range:range];
}

- (NSComparisonResult)compare:(id)aString
{
    NSRange range = {0, [self length]};
    
    return [self compare:aString options:0 range:range];
}

- (NSComparisonResult)compare:(NSString*)aString options:(unsigned int)mask
{
    NSRange range = {0, [self length]};
    
    return [self compare:aString options:mask range:range];
}

- (NSComparisonResult)compare:(NSString*)aString
  options:(unsigned int)mask range:(NSRange)aRange
{
    // UNICODE
    // ENCODINGS - this code applies to the system's default encoding
    unsigned int i, n, a;

    if (NSMaxRange(aRange) > [self length]) {
      [[[IndexOutOfRangeException alloc] initWithFormat:@"range %@ in string %x of length %d",
	    	NSStringFromRange(aRange), self, [self length]] raise];
    }
    
    a = [aString length];
    n = MIN(a, aRange.length);

    if (mask & NSCaseInsensitiveSearch) {
      for (i = 0; i < n; i++) {
	      unichar cm = [self characterAtIndex:i + aRange.location];
	      unichar ca = [aString characterAtIndex:i];

	      cm = islower(cm) ? toupper(cm) : cm;
	      ca = islower(ca) ? toupper(ca) : ca;

	      if (cm < ca)
	        return NSOrderedAscending;
	      if (cm > ca)
	        return NSOrderedDescending;
      }
    }
    else {
      for (i = 0; i < n; i++) {
        if ([self characterAtIndex:i + aRange.location] <
            [aString characterAtIndex:i])
          return NSOrderedAscending;
        if ([self characterAtIndex:i + aRange.location] >
            [aString characterAtIndex:i])
          return NSOrderedDescending;
      }
    }

    if (aRange.length < a)
      return NSOrderedAscending;
    if (aRange.length > a)
      return NSOrderedDescending;

    return NSOrderedSame;
}

- (BOOL)hasPrefix:(NSString *)aString
{
    int mLen = [self length];
    int aLen = [aString length];
    NSRange range = {0, aLen};

#if DEBUG
    if (aString == nil) {
       NSLog(@"NOTE: [%@ hasPrefix:nil] does not work on MacOSX !", aString);
#if 0 && DEBUG
#  warning ABORT CODE ENABLED - do not deploy!
       abort();
#endif
    }
#endif
    
    if (aLen == 0)
        return NO;
    
    if (aLen > mLen)
	return NO;
    
    return [self compare:aString options:0 range:range] == NSOrderedSame;
}

- (BOOL)hasSuffix:(NSString*)aString
{
    int mLen = [self length];
    int aLen = [aString length];
    NSRange range = {mLen-aLen, aLen};
    
    if (aLen == 0)
        return NO;
    
    if (aLen > mLen)
	return NO;
    
    return [self compare:aString options:0 range:range] == NSOrderedSame;
}

- (BOOL)isEqual:(id)aString
{
    register Class clazz;
    register BOOL  i;
    NSRange range;
    
    if (self == aString)
	return YES;
    else if (aString == nil)
	return NO;
    
    if (NSStringClass == Nil)
        NSStringClass = [NSString class];
    
    i = NO;
    for (clazz = *(id *)aString; clazz; clazz = class_get_super_class(clazz)) {
	if (clazz == NSStringClass) {
	    i = YES;
	    break;
	}
    }
    if (i == NO)
	return NO;
    
    range.location = 0;
    range.length   = [self length];
    return [self compare:aString options:0 range:range] == NSOrderedSame;
}

- (BOOL)isEqualToString:(NSString*)aString
{
    NSRange range;
    
    if (self == aString)
	return YES;
    else if (aString == nil)
	return NO;
    
    range.location = 0;
    range.length   = [self length];
    return [self compare:aString options:0 range:range] == NSOrderedSame;
}

- (unsigned)hash
{
    unsigned hash = 0, hash2;
    int i, n = [self length];

    for(i = 0; i < n; i++) {
        hash <<= 4;
	// UNICODE - must use a for independent of composed characters
        hash += [self characterAtIndex:i];
        if((hash2 = hash & 0xf0000000))
            hash ^= (hash2 >> 24) ^ hash2;
    }

    return hash;
}

/* Getting a shared prefix */

- (NSString *)commonPrefixWithString:(NSString*)aString
  options:(unsigned int)mask
{
    NSRange range = {0, 0};
    int mLen;
    int aLen;
    int i;
    
    mLen = [self    length];
    aLen = [aString length];
    if ((mLen == 0) || (aLen == 0)) return @"";
    
    for (i = 0; (i < mLen) && (i < aLen); i++) {
	unichar c1, c2;
        
        c1 = [self characterAtIndex:i];
        c2 = [self characterAtIndex:i];
        
        if (mask & NSCaseInsensitiveSearch) {
            // ENCODINGS - this code applies to the system's default encoding
            c1 = tolower(c1);
            c2 = tolower(c2);
        }
        
        if (c1 != c2)
            break;
    }
    
    range.length = i;
    return [self substringWithRange:range];
}

/* Changing case */

- (NSString *)capitalizedString
{
    // UNICODE
    // ENCODINGS - this code applies to the system's default encoding
    int i;
    BOOL f = YES;
    int length = [self cStringLength];
    unichar* buf = MallocAtomic(sizeof(unichar) * (length + 1));

    for (i = 0; i < length; i++) {
	unichar c = [self characterAtIndex:i];

	if (isspace(c))
	    f = YES;

	if (f) {
	    buf[i] = islower(c) ? toupper(c) : c;
	    f = NO;
	}
	else
	    buf[i] = isupper(c) ? tolower(c) : c;
    }
    buf[i] = 0;

    return AUTORELEASE([[NSStringClass alloc]
                             initWithCharactersNoCopy:buf
                             length:length
                             freeWhenDone:YES]);
}

- (NSString *)lowercaseString
{
    // UNICODE
    // ENCODINGS - this code applies to the system's default encoding
    int i;
    int length = [self cStringLength];
    unichar* buf = MallocAtomic(sizeof(unichar) * (length+1));

    for (i = 0; i < length; i++) {
	unichar c = [self characterAtIndex:i];
        
	buf[i] = isupper(c) ? tolower(c) : c;
    }
    buf[i] = 0;

    return AUTORELEASE([[NSStringClass alloc]
                             initWithCharactersNoCopy:buf
                             length:length
                             freeWhenDone:YES]);
}

- (NSString *)uppercaseString
{
    // UNICODE
    // ENCODINGS - this code applies to the system's default encoding
    int i;
    int length = [self cStringLength];
    unichar* buf = MallocAtomic(sizeof(unichar) * (length+1));

    for (i = 0; i < length; i++) {
	unichar c = [self characterAtIndex:i];
	buf[i] = islower(c) ? toupper(c) : c;
    }

    buf[i] = 0;

    return AUTORELEASE([[NSStringClass alloc]
                             initWithCharactersNoCopy:buf
                             length:length
                             freeWhenDone:YES]);
}

/* Getting C strings */

- (const char *)cString
{
    // UNICODE
    // ENCODINGS
    [self subclassResponsibility:_cmd];
    return NULL;
}

- (unsigned int)cStringLength
{
    // UNICODE
    // ENCODINGS
    [self subclassResponsibility:_cmd];
    return 0;
}

- (const char *)UTF8String
{
    NSData        *d;
    unsigned      dlen;
    unsigned char *cstr;
    
    if ((d = [self dataUsingEncoding:NSUTF8StringEncoding]) == nil)
        return NULL;
    
    if ((dlen = [d length]) == 0) {
        static unsigned char c = '\0';
        return (const char *)&c;
    }
    
    cstr = NSZoneMallocAtomic([self zone], sizeof(unsigned char) * (dlen + 1));
    [d getBytes:cstr];
    cstr[dlen] = '\0';
#if !LIB_FOUNDATION_BOEHM_GC
    [NSAutoreleasedPointer autoreleasePointer:cstr];
#endif
    return (const char *)cstr;
}

- (void)getCString:(char *)buffer
{
    NSRange range = {0, [self length]};
    
    [self getCString:buffer maxLength:NSMaximumStringLength
          range:range remainingRange:NULL];
    buffer[range.length] = '\0';
}

- (void)getCString:(char*)buffer maxLength:(unsigned int)maxLength
{
    NSRange range = {0, [self length]};
    
    [self getCString:buffer maxLength:maxLength
          range:range remainingRange:NULL];
    buffer[range.length] = '\0';
}

- (void)getCString:(char*)buffer maxLength:(unsigned int)maxLength
  range:(NSRange)aRange remainingRange:(NSRange*)leftoverRange
{
    unsigned int toMove, i, cLength;
    unichar (*charAtIndex)(id,SEL,int);

    charAtIndex = (void*)[self methodForSelector:@selector(characterAtIndex:)];
    
    toMove  = MIN(maxLength, aRange.length);
    cLength = [self cStringLength];
    
    if (aRange.location + aRange.length > cLength) {
	[[[IndexOutOfRangeException alloc]
	    initWithFormat:@"range (%d,%d) in string %x of length %d",
	    	aRange.location, aRange.length, self, cLength] raise];
    }

    if (leftoverRange) {
	leftoverRange->location = aRange.location + toMove;
	leftoverRange->length = cLength - leftoverRange->location;
    }
    for (i = 0; i < toMove; i++) {
        buffer[i] = charAtIndex(self, @selector(characterAtIndex:),
                                aRange.location + i);
    }
    if (toMove < maxLength)
	buffer[toMove] = '\0';
}

/* Getting numeric values */

- (double)doubleValue
{
    // UNICODE
    // ENCODINGS
    double   val = 0.0;
    unsigned len;
    char     *str;
    
    len = [self cStringLength];
    if (len == 0)
        return 0.0;
    if ((str = malloc(len + 1)) == NULL)
        return 0.0;
    
    [self getCString:str]; str[len] = '\0';
    sscanf(str ? str : "", " %lf ", &val);
    free(str);
    return val;
}

- (float)floatValue
{
    // UNICODE
    // ENCODINGS
    float    val = 0;
    unsigned len;
    char     *str;
    
    if ((len = [self cStringLength]) == 0)
        return 0.0;
    if ((str = malloc(len + 1)) == NULL)
        return 0.0;
    
    [self getCString:str]; str[len] = '\0';
    sscanf(str ? str : "", " %f ", &val);
    free(str);
    return val;
}

- (int)intValue
{
    // UNICODE
    // ENCODINGS
    int      val = 0;
    unsigned len;
    char     *str;
    
    if ((len = [self cStringLength]) == 0)
        return 0;
    if ((str = malloc(len + 1)) == NULL)
        return 0;
    [self getCString:str]; str[len] = '\0';
    sscanf(str ? str : "", " %d ", &val);
    free(str);
    return val;
}

/* Working with encodings */

+ (NSStringEncoding *)availableStringEncodings
{
    // UNICODE
    // ENCODINGS
    static NSStringEncoding availableEncodings[] = {
	NSASCIIStringEncoding,
        NSISOLatin1StringEncoding,
        NSISOLatin9StringEncoding,
        NSUTF8StringEncoding,
        NSUnicodeStringEncoding,
	0
    };
    
    return availableEncodings;
}

+ (NSStringEncoding)defaultCStringEncoding
{
    // UNICODE
    // ENCODINGS
#if USE_LATIN9
    return NSISOLatin9StringEncoding;
#else
    return NSISOLatin1StringEncoding;
#endif
}

+ (NSString *)localizedNameOfStringEncoding:(NSStringEncoding)encoding
{
    switch(encoding) {
	case NSASCIIStringEncoding:     return @"NSASCIIStringEncoding";
	case NSNEXTSTEPStringEncoding:  return @"NSNEXTSTEPStringEncoding";
	case NSUTF8StringEncoding:      return @"NSUTF8StringEncoding";
	case NSISOLatin1StringEncoding: return @"NSISOLatin1StringEncoding";
	case NSISOLatin9StringEncoding: return @"NSISOLatin9StringEncoding";
	case NSSymbolStringEncoding:    return @"NSSymbolStringEncoding";
	case NSShiftJISStringEncoding:  return @"NSShiftJISStringEncoding";
	case NSISOLatin2StringEncoding: return @"NSISOLatin2StringEncoding";
	case NSUnicodeStringEncoding:   return @"NSUnicodeStringEncoding";
	case NSWinLatin1StringEncoding: return @"NSWinLatin1StringEncoding";
        case NSISO2022JPStringEncoding: return @"NSISO2022JPStringEncoding";

        case NSWindowsCP1251StringEncoding:
	    return @"NSWindowsCP1251StringEncoding";
        case NSWindowsCP1252StringEncoding:
	    return @"NSWindowsCP1252StringEncoding";
        case NSWindowsCP1253StringEncoding:
	    return @"NSWindowsCP1253StringEncoding";
        case NSWindowsCP1254StringEncoding:
	    return @"NSWindowsCP1254StringEncoding";
        case NSWindowsCP1250StringEncoding:
	    return @"NSWindowsCP1250StringEncoding";
	    
	case NSNonLossyASCIIStringEncoding:
	    return @"NSNonLossyASCIIStringEncoding";
	case NSJapaneseEUCStringEncoding:
	    return @"NSJapaneseEUCStringEncoding";
	case NSAdobeStandardCyrillicStringEncoding:
	    return @"NSAdobeStandardCyrillicStringEncoding";
	default: 
	    return @"Invalid encoding";
    }
}

- (BOOL)canBeConvertedToEncoding:(NSStringEncoding)encoding
{
    id data;
    data = [self dataUsingEncoding:encoding allowLossyConversion:NO];
    return data ? YES : NO;
}

- (NSData *)dataUsingEncoding:(NSStringEncoding)encoding
{
    return [self dataUsingEncoding:encoding allowLossyConversion:NO];
}

- (NSData *)dataUsingEncoding:(NSStringEncoding)encoding
  allowLossyConversion:(BOOL)flag
{
    return dataUsingEncoding(self, encoding, flag);
}

- (NSStringEncoding)fastestEncoding
{
    // UNICODE
    // ENCODINGS
    return NSISOLatin1StringEncoding;
}

- (NSStringEncoding)smallestEncoding
{
    // UNICODE
    // ENCODINGS
    return NSISOLatin1StringEncoding;
}

- (BOOL)getBytes:(void*)bytes maxLength:(unsigned int)maxLength
  inEncoding:(NSStringEncoding)encoding
  allowLossesInConversion:(BOOL)allowLossesInConversion
  fromRange:(NSRange)fromRange
  usedRange:(NSRange*)usedRange
  remainingRange:(NSRange*)remainingRange
{
    // UNICODE
    // ENCODINGS
    [self notImplemented:_cmd];
    return NO;
}

/* Writing to a file */

- (BOOL)writeToFile:(NSString *)path atomically:(BOOL)flag
{
    // UNICODE - remove this
    NSData *data;
    data = [self dataUsingEncoding:[NSStringClass defaultCStringEncoding]];
    //data = [NSData dataWithBytes:[self cString] length:[self length]];
    return writeToFile(path, data, flag);
}

/* Encoding methods */

- (void)encodeWithCoder:(NSCoder *)aCoder
{
    int     length;
    unichar *buf;
    
    length = [self length];
    buf    = MallocAtomic(sizeof(unichar) * length);
    
    [self getCharacters:buf];
    [aCoder encodeValueOfObjCType:@encode(int)     at:&length];
    [aCoder encodeArrayOfObjCType:@encode(unichar) count:length at:buf];
    lfFree(buf);
}

- (id)initWithCoder:(NSCoder *)aDecoder
{
    unichar* buf;
    int length;

    [aDecoder decodeValueOfObjCType:@encode(int) at:&length];
    buf = MallocAtomic (sizeof(unichar) * length);
    [aDecoder decodeArrayOfObjCType:@encode(unichar) count:length at:buf];

    self = AUTORELEASE(self);
    return [self initWithCharactersNoCopy:buf
                 length:length
                 freeWhenDone:YES];
}

/* NSCopying methods */

- (id)copyWithZone:(NSZone *)zone
{
    if (NSStringClass == Nil)
        NSStringClass = [NSString class];
    
    return RETAIN(self);
    // return [[NSStringClass allocWithZone:zone] initWithString:self];
}

/* NSMutableCopying methods */

- (id)mutableCopyWithZone:(NSZone*)zone
{
    return [[NSMutableString allocWithZone:zone] initWithString:self];
}

/* NSObject protocol */

- (NSString *)stringRepresentation
{
    /*
      an implementation of this method must quote the string for
      use in property lists.
    */
    return [self subclassResponsibility:_cmd];
}

- (NSString *)description
{
    return self;
}

@end /* NSString */

/*********************************
 * NSMutableString abstract class
 *********************************/

@implementation NSMutableString

/*
 * Modifying a string 
 */

- (void)appendFormat:(NSString*)format,...
{
    va_list va;

    va_start(va, format);
    [self appendFormat:format arguments:va];
    va_end(va);
}

- (void)appendFormat:(NSString*)format arguments:(va_list)argList;
{
    // FIX : Vsprinf(self, format, argList)
    [self appendString:Avsprintf(format, argList)];
}

- (void)appendString:(NSString*)aString
{
    NSRange range = {[self length], 0};

    [self replaceCharactersInRange:range withString:aString];
}

- (void)prependFormat:(NSString*)format,...
{
    NSRange range = {0, 0};
    va_list va;

    va_start(va, format);
    [self replaceCharactersInRange:range
	withString:Avsprintf(format, va)];
    va_end(va);
}

- (void)prependFormat:(NSString*)format arguments:(va_list)argList
{
    NSRange range = {0, 0};

    [self replaceCharactersInRange:range
	withString:Avsprintf(format, argList)];
}

- (void)prependString:(NSString*)aString
{
    NSRange range = {0, 0};

    [self replaceCharactersInRange:range withString:aString];
}

- (void)deleteCharactersInRange:(NSRange)range
{
    [self replaceCharactersInRange:range withString:nil];
}

- (void)insertString:(NSString*)aString atIndex:(unsigned)index
{
    NSRange range = {index, 0};

    [self replaceCharactersInRange:range withString:aString];
}

- (void)setString:(NSString*)aString
{
    NSRange range = {0, [self length]};

    [self replaceCharactersInRange:range withString:aString];
}

- (void)replaceCharactersInRange:(NSRange)aRange
  withString:(NSString*)aString
{
    [self subclassResponsibility:_cmd];
}

- (id)copyWithZone:(NSZone*)zone
{
    if (NSStringClass == Nil)
        NSStringClass = [NSString class];
    return [[NSStringClass allocWithZone:zone] initWithString:self];
}

@end /* NSMutableString */

/*********************************
 * NSString creation methods
 *********************************/

@implementation NSString(NSStringCreation)

+ (id)allocWithZone:(NSZone *)zone
{
    static Class NSTemporaryStringClass = Nil;
    if (NSStringClass == Nil)
        NSStringClass = [NSString class];
    if (NSTemporaryStringClass == Nil)
        NSTemporaryStringClass = [NSTemporaryString class];
    
    return (self == NSStringClass) ? 
	[NSTemporaryStringClass allocWithZone:zone] 
	: NSAllocateObject(self, 0, zone);
}

+ (id)localizedStringWithFormat:(NSString*)format,...
{
    va_list va;
    NSString* string;
    
    va_start(va, format);
    string = AUTORELEASE([[self alloc] initWithFormat:format arguments:va]);
    va_end(va);
    return string;
}

+ (id)string
{
    return @"";
}

+ (id)stringWithCharacters:(const unichar*)chars
  length:(unsigned int)length
{
    return AUTORELEASE([[self alloc] initWithCharacters:chars length:length]);
}

+ (id)stringWithCharactersNoCopy:(unichar*)chars	
  length:(unsigned int)length freeWhenDone:(BOOL)flag
{
    return AUTORELEASE([[self alloc] initWithCharactersNoCopy:chars 
                                     length:length freeWhenDone:flag]);
}

+ (id)stringWithString:(NSString*)aString
{
    return [self stringWithCString:[aString cString]];
}

+ (id)stringWithCString:(const char*)byteString
{
    return AUTORELEASE([[self alloc] initWithCString:byteString]);
}

+ (id)stringWithUTF8String:(const char *)bytes
{
    register unsigned char *p;
    for (p = (unsigned char *)bytes; *p; p++) {
        if (*p > 127)
            return AUTORELEASE([[self alloc] initWithUTF8String:bytes]);
    }
    return [self stringWithCString:bytes];
}

+ (NSString *)stringWithCString:(const char*)byteString
  length:(unsigned int)length
{
    return AUTORELEASE([[self alloc]
                           initWithCString:byteString length:length]);
}

+ (NSString *)stringWithCStringNoCopy:(char*)byteString
  length:(unsigned int)length freeWhenDone:(BOOL)flag
{
    return AUTORELEASE([[self alloc] initWithCStringNoCopy:byteString
                                     length:length freeWhenDone:flag]);
}

+ (id)stringWithCStringNoCopy:(char*)byteString
  freeWhenDone:(BOOL)flag
{
    return AUTORELEASE([[self alloc] initWithCStringNoCopy:byteString
                                     freeWhenDone:flag]);
}

+ (id)stringWithFormat:(NSString*)format,...
{
    va_list va;
    NSString* string;
    
    va_start(va, format);
    string = AUTORELEASE([[self alloc] initWithFormat:format arguments:va]);
    va_end(va);
    return string;
}

+ (id)stringWithFormat:(NSString *)format arguments:(va_list)argList
{
    return AUTORELEASE([[self alloc] initWithFormat:format
                                     arguments:argList]);
}

+ (id)stringWithContentsOfFile:(NSString *)path
{
    return AUTORELEASE([[self alloc] initWithContentsOfFile:path]);
}
+ (id)stringWithContentsOfURL:(NSURL *)_url
{
    return AUTORELEASE([[self alloc] initWithContentsOfURL:_url]);
}

@end /* NSString(NSStringCreation) */

@implementation NSString(GSAdditions)

- (NSString *)stringWithoutPrefix:(NSString *)_prefix
{
    return ([self hasPrefix:_prefix])
        ? [self substringFromIndex:[_prefix length]]
        : [[self copy] autorelease];
}

- (NSString *)stringWithoutSuffix:(NSString *)_suffix
{
    return ([self hasSuffix:_suffix])
        ? [self substringToIndex:([self length] - [_suffix length])]
        : [[self copy] autorelease];
}

- (NSString *)stringByReplacingString:(NSString *)_orignal
  withString:(NSString *)_replacement
{
    /* very slow solution .. */
    
    if ([self indexOfString:_orignal] == NSNotFound)
        return [[self copy] autorelease];
    
    return [[self componentsSeparatedByString:_orignal]
                  componentsJoinedByString:_replacement];
}

static NSCharacterSet *whiteSpaceSet = nil;
static BOOL (*isWhiteSpaceSetMem)(id, SEL, unichar);

- (NSString *)stringByTrimmingLeadWhiteSpaces
{
    /* can't we share the implementation of lead and tail?! It is 98% similiar */
    unsigned len;
    unichar  *buf;
    unsigned idx;
    
    if (whiteSpaceSet == nil) {
	whiteSpaceSet = [[NSCharacterSet whitespaceAndNewlineCharacterSet] retain];
	isWhiteSpaceSetMem = (void *)
	    [whiteSpaceSet methodForSelector:@selector(characterIsMember:)];
    }
    
    if ((len = [self length]) == 0)
        return @"";
    
    buf = calloc(len + 1, sizeof(unichar));
    [self getCharacters:buf];
        
    for (idx = 0; 
	 (idx < len) && isWhiteSpaceSetMem(whiteSpaceSet,
					   @selector(characterIsMember:),
					   buf[idx]); 
	 idx++)
	;
    
    self = [NSStringClass stringWithCharacters:&(buf[idx]) length:(len - idx)];
    free(buf);
    return self;
}
- (NSString *)stringByTrimmingTailWhiteSpaces
{
    unichar      *buf;
    unsigned int idx;
    unsigned     len;

    if (whiteSpaceSet == nil) {
	whiteSpaceSet = [[NSCharacterSet whitespaceAndNewlineCharacterSet] retain];
	isWhiteSpaceSetMem = (void *)
	    [whiteSpaceSet methodForSelector:@selector(characterIsMember:)];
    }
    
    if ((len = [self length]) == 0)
        return @"";
    
    buf = calloc(len + 2, sizeof(unichar));
    [self getCharacters:buf];
        
    for (idx = (len - 1); 
	 (idx >= 0) && isWhiteSpaceSetMem(whiteSpaceSet, 
					  @selector(characterIsMember:), buf[idx]);
	 idx--)
        ;
    
    self = [NSStringClass stringWithCharacters:buf length:(idx + 1)];
    free(buf);
    return self;
}

- (NSString *)stringByTrimmingLeadSpaces
{
    unsigned int len;
    unsigned int idx;
    unichar  *buf;
    
    if ((len = [self length]) == 0)
        return @"";
        
    buf = calloc(len + 2, sizeof(unichar));
    [self getCharacters:buf];
        
    for (idx = 0; (idx < len) && isspace(buf[idx]); idx++)
        ;
        
    self = [NSStringClass stringWithCharacters:&(buf[idx]) length:(len - idx)];
    if (buf) free(buf);
    return self;
}
- (NSString *)stringByTrimmingTailSpaces
{
    unsigned len;
    unichar *buf;
    int     idx;
    
    if ((len = [self length]) == 0)
        return @"";
        
    buf = calloc(len + 2, sizeof(unichar));
    [self getCharacters:buf];
        
    for (idx = (len - 1); (idx >= 0) && isspace(buf[idx]); idx--)
        ;
        
    self = [NSStringClass stringWithCharacters:buf length:(idx + 1)];
    if (buf) free(buf);
    return self;
}

- (NSString *)stringByTrimmingWhiteSpaces
{
    return [[self stringByTrimmingTailWhiteSpaces]
                  stringByTrimmingLeadWhiteSpaces];
}
- (NSString *)stringByTrimmingSpaces
{
    return [[self stringByTrimmingTailSpaces]
                  stringByTrimmingLeadSpaces];
}

@end /* NSString(GSAdditions) */

@implementation NSMutableString(GNUstepCompatibility)

- (void)trimLeadSpaces
{
    [self setString:[self stringByTrimmingLeadSpaces]];
}
- (void)trimTailSpaces
{
    [self setString:[self stringByTrimmingTailSpaces]];
}
- (void)trimSpaces
{
    [self setString:[self stringByTrimmingSpaces]];
}

@end /* NSMutableString(GNUstepCompatibility) */

@implementation NSMutableString(NSStringCreation)

+ (id)allocWithZone:(NSZone *)zone
{
    return (self == [NSMutableString class]) ? 
	[NSMutableTemporaryString allocWithZone:zone] 
	: NSAllocateObject(self, 0, zone);
}

+ (id)stringWithCapacity:(unsigned int)capacity
{
    return AUTORELEASE([[self alloc] initWithCapacity:capacity]);
}
+ (id)string
{
    return [self stringWithCapacity:0];
}

@end /* NSMutableString(NSStringCreation) */

/****************************
 * Initializing strings
 ****************************/

@implementation NSMutableString(NSStringInitialization)

- (id)initWithCapacity:(unsigned int)capacity
{
    [self subclassResponsibility:_cmd];
    return nil;
}

- (id)initWithCharacters:(const unichar *)chars length:(unsigned int)length
{
    unsigned char *buffer;
    unsigned int  i, j;
    BOOL isLower8BitEqual = NO;
    BOOL isLower7BitEqual = NO;
    unsigned int convertCount = 0;
    
    switch ([NSStringClass defaultCStringEncoding]) {
        case NSISOLatin1StringEncoding:
            isLower8BitEqual = YES;
            break;
        case NSASCIIStringEncoding:
        case NSUTF8StringEncoding:
            isLower7BitEqual = YES;
            break;
    }
    
    /* scan whether this is a non-8-bit- string ... */
    for (i = 0; i < length; i++) {
        //NSMutableString *s;
        
#if !HAS_UNICODE_STRING
	/* allow Euro char code (8364) */
	if (chars[i] == 8364) {
	    convertCount++;
	    continue;
	}
#endif
        if (isLower8BitEqual && (chars[i] < 256))
            /* valid 8-bit character in default encoding */
            continue;
        if (isLower7BitEqual && (chars[i] < 128))
            /* valid 7-bit character in default encoding */
            continue;
        
#if HAS_UNICODE_STRING
        s = [[NSMutableUnicodeString alloc]
                                     initWithCharacters:chars
                                     length:length];
        if (flag) {
            lfFree(chars);
            chars = NULL;
        }
#endif
        return [self notImplemented:_cmd];
    }
    
    buffer = MallocAtomic(length + (convertCount*3) + 1);
    
    for (i = 0, j = 0; i < length; i++, j++) {
#if !HAS_UNICODE_STRING
	if (chars[i] == 8364) {
	    buffer[j++] = 'E';
	    buffer[j++] = 'U';
	    buffer[j] = 'R';
	}
#endif
        buffer[j] = chars[i];
    }
    
    buffer[j] = '\0';
    self = [self initWithCString:(char *)buffer length:j];
    if (buffer) lfFree(buffer);
    return self;
}

- (id)initWithCharactersNoCopy:(unichar*)chars length:(unsigned int)length 
  freeWhenDone:(BOOL)flag
{
    unsigned char *buffer;
    unsigned int  i, j;
    BOOL isLower8BitEqual = NO;
    BOOL isLower7BitEqual = NO;
    unsigned int convertCount = 0;
    
    switch ([NSStringClass defaultCStringEncoding]) {
        case NSISOLatin1StringEncoding:
            isLower8BitEqual = YES;
            break;
        case NSASCIIStringEncoding:
        case NSUTF8StringEncoding:
        case NSISOLatin9StringEncoding:
            isLower7BitEqual = YES;
            break;
    }
    
    /* scan whether this is a non-8-bit- string ... */
    for (i = 0; i < length; i++) {
        //NSMutableString *s;
        
#if !HAS_UNICODE_STRING
	/* allow Euro char code (8364) */
	if (chars[i] == 8364) {
	    convertCount++;
	    continue;
	}
#endif
        if (isLower8BitEqual && (chars[i] < 256))
            /* valid 8-bit character in default encoding */
            continue;
        if (isLower7BitEqual && (chars[i] < 128))
            /* valid 7-bit character in default encoding */
            continue;
        
#if HAS_UNICODE_STRING
        s = [[NSMutableUTF16String alloc]
                                   initWithCharacters:chars
                                   length:length];
        if (flag) {
            lfFree(chars);
            chars = NULL;
        }
#endif
        return [self notImplemented:_cmd];
    }
    
    buffer = MallocAtomic(length + (convertCount*3) + 1);
    
    for (i = 0, j = 0; i < length; i++, j++) {
#if !HAS_UNICODE_STRING
	if (chars[i] == 8364) {
	    buffer[j++] = 'E';
	    buffer[j++] = 'U';
	    buffer[j] = 'R';
	}
#endif
        buffer[j] = chars[i];
    }

    
    buffer[j] = '\0';
    if (flag) {
        lfFree(chars);
        chars = NULL;
    }
    self = [self initWithCString:(char *)buffer length:j];
    if (buffer) lfFree(buffer);
    return self;
}

- (id)initWithCString:(const char*)byteString
{
    if (NSStringClass == Nil)
        NSStringClass = [NSString class];
    return [self initWithString:
                     AUTORELEASE([[NSStringClass alloc] 
                                     initWithCStringNoCopy:(char*)byteString
                                     freeWhenDone:NO])];
}

- (id)initWithCString:(const char*)byteString length:(unsigned int)length
{
    if (NSStringClass == Nil)
        NSStringClass = [NSString class];
    return [self initWithString:
                     AUTORELEASE([[NSStringClass alloc] 
                                     initWithCStringNoCopy:(char*)byteString
                                     length:length freeWhenDone:NO])];
}

- (id)initWithCStringNoCopy:(char*)byteString freeWhenDone:(BOOL)flag
{
    if (NSStringClass == Nil)
        NSStringClass = [NSString class];
    return [self initWithString:
                     AUTORELEASE([[NSStringClass alloc]
                                     initWithCStringNoCopy:byteString
                                     freeWhenDone:flag])];
}

- (id)initWithCStringNoCopy:(char*)byteString length:(unsigned int)length 
  freeWhenDone:(BOOL)flag
{
    if (NSStringClass == Nil)
        NSStringClass = [NSString class];
    return [self initWithString:
                     AUTORELEASE([[NSStringClass alloc]
                                     initWithCStringNoCopy:byteString
                                     length:length freeWhenDone:flag])];
}

- (id)initWithString:(NSString*)aString
{
    [self subclassResponsibility:_cmd];
    return nil;
}

- (id)initWithFormat:(NSString*)format, ...
{
    id str;
    va_list va;
    
    va_start(va, format);
    str = [self initWithFormat:format arguments:va];
    va_end(va);
    return str;
}

- (id)initWithFormat:(NSString*)format arguments:(va_list)argList
{
    return [self initWithString:Avsprintf(format, argList)];
}

- (id)initWithFormat:(NSString*)format
  locale:(NSDictionary*)dictionary, ...
{
    id str;
    va_list va;
    
    va_start(va, dictionary);
    str = [self initWithFormat:format arguments:va];
    va_end(va);
    return str;
}

- (id)initWithFormat:(NSString *)format 
  locale:(NSDictionary*)dictionary arguments:(va_list)argList
{
    return [self initWithFormat:format arguments:argList];
}

- (id)initWithData:(NSData *)data encoding:(NSStringEncoding)encoding
{
    /* NSMutableString */
    return NSInitStringWithData(self, data, encoding);
}

- (id)initWithContentsOfFile:(NSString *)path
{
    // UNICODE
    // ENCODINGS
    [self notImplemented:_cmd];
    return nil;
}

@end /* NSMutableString(NSStringInitialization) */

/****************************
 * Allocate concrete strings
 ****************************/
/*
 * Classes used for allocation of NSString concrete instances
 */

@implementation NSTemporaryString

static BOOL              isMultithreaded              = NO;
static NSTemporaryString *temporaryStringsPool        = nil;
static Class             NSInline8BitStringClass      = Nil;
static Class             NSShortInline8BitStringClass = Nil;

+ (void)initialize
{
    static BOOL initialized = NO;

    if (!initialized) {
	[[NSNotificationCenter defaultCenter]
	    addObserver:self
	    selector:@selector(taskNowMultiThreaded:)
	    name:NSWillBecomeMultiThreadedNotification
	    object:nil];
	initialized = YES;
    }
}

+ (void)taskNowMultiThreaded:notification
{
    PrivateThreadData* threadData = [[NSThread currentThread]
					_privateThreadData];

    [threadData setTemporaryStringsPool:temporaryStringsPool];
    temporaryStringsPool = nil;
    isMultithreaded = YES;
}

+ (id)allocWithZone:(NSZone*)zone
{
    NSTemporaryString* obj = nil;
    PrivateThreadData* threadData = nil;

    if (isMultithreaded) {
	threadData = [[NSThread currentThread] _privateThreadData];
	obj = [threadData temporaryString];
    }
    else {
	if (temporaryStringsPool) {
	    obj = temporaryStringsPool;
	    temporaryStringsPool = temporaryStringsPool->next;
	    obj->next = nil;
	}
    }

    if (!obj)
	obj = (id)NSAllocateObject(self, 0, zone);

    obj->_zone = zone;

    return obj;
}

- (void)dealloc
{
    fprintf (stderr, "ERROR: NSTemporaryString %s to be deallocated!\n", 
             isa->name);
    abort ();
}

static inline void _collectTemporary(NSTemporaryString *self)
{
    if (isMultithreaded) {
	[[[NSThread currentThread] _privateThreadData]
                    addTemporaryString:self];
    }
    else {
	if (self != temporaryStringsPool)
	    self->next = temporaryStringsPool;
	temporaryStringsPool = self;
    }
}

- (NSZone *)zone
{
    return _zone;
}

/*
 * Methods that return strings
 */

- (id)init
{
    id str = @"";

    _collectTemporary(self);
    return str;
}

- (id)initWithCharacters:(const unichar *)chars length:(unsigned int)length
{
    unsigned char         *buffer;
    register unsigned int i;
    BOOL isLower8BitEqual = NO;
    BOOL isLower7BitEqual = NO;

    if (length == 0) {
        _collectTemporary(self);
        return @"";
    }

    switch ([NSStringClass defaultCStringEncoding]) {
        case NSISOLatin1StringEncoding:
            isLower8BitEqual = YES;
            break;
        case NSASCIIStringEncoding:
        case NSUTF8StringEncoding:
            isLower7BitEqual = YES;
            break;
    }
    
    /* scan whether this is a non-8-bit- string ... */
    for (i = 0; i < length; i++) {
        NSString *s;
        
        if (isLower8BitEqual && (chars[i] < 256))
            /* valid 8-bit character in default encoding */
            continue;
        if (isLower7BitEqual && (chars[i] < 128))
            /* valid 7-bit character in default encoding */
            continue;
        
        s = [[NSInlineUTF16String allocForCapacity:(length + 1) zone:NULL]
                                  initWithCharacters:chars
                                  length:length];
        _collectTemporary(self);
        return s;
    }
    
    buffer = MallocAtomic(length + 1);
    
    for (i = 0; i < length; i++)
        buffer[i] = chars[i];
    
    buffer[length] = '\0';
    
    self = [self initWithCString:(char *)buffer length:length];
    if (buffer) lfFree(buffer);
    return self;
}

- (id)initWithCharactersNoCopy:(unichar *)chars
  length:(unsigned int)length freeWhenDone:(BOOL)flag
{
    unsigned char         *buffer;
    register unsigned int i;
    BOOL isLower8BitEqual = NO;
    BOOL isLower7BitEqual = NO;

    if (length == 0) {
        _collectTemporary(self);
        if (flag && chars != NULL) {
            lfFree(chars);
            chars = NULL;
        }
        return @"";
    }

    switch ([NSStringClass defaultCStringEncoding]) {
        case NSISOLatin1StringEncoding:
            isLower8BitEqual = YES;
            break;
        case NSASCIIStringEncoding:
        case NSUTF8StringEncoding:
            isLower7BitEqual = YES;
            break;
    }
    
    /* scan whether this is a non-8-bit- string ... */
    for (i = 0; i < length; i++) {
        NSString *s;

#if 0
        printf("chars[%d] %c %d\n", i, chars[i], chars[i]);
#endif
        
        if (isLower8BitEqual && (chars[i] < 256))
            /* valid 8-bit character in default encoding */
            continue;
        if (isLower7BitEqual && (chars[i] < 128))
            /* valid 7-bit character in default encoding */
            continue;
        
        s = [[NSInlineUTF16String allocForCapacity:(length + 1) zone:NULL]
                                  initWithCharacters:chars
                                  length:length];
        if (flag && (chars != NULL)) {
            lfFree(chars);
            chars = NULL;
        }
        _collectTemporary(self);
#if 0
        printf("%s: return s[%s]\n", __PRETTY_FUNCTION__, 
               [[[s class] description] cString]);
#endif
        return s;
    }
    
    buffer = MallocAtomic(length + 1);
    
    for (i = 0; i < length; i++)
        buffer[i] = chars[i];
    
    buffer[length] = '\0';
    if (flag && (chars != NULL)) {
        lfFree(chars);
        chars = NULL;
    }
    self = [self initWithCString:(char *)buffer length:length];
    if (buffer != NULL) lfFree(buffer);
    return self;
}

- (id)initWithCString:(const char *)byteString
{
    Class clazz;
    int length;
    id  str;
    
    if (NSInline8BitStringClass == Nil)
        NSInline8BitStringClass = [NSInline8BitString class];
    if (NSShortInline8BitStringClass == Nil)
        NSShortInline8BitStringClass = [NSShortInline8BitString class];
    
    length = Strlen(byteString);
    
    if (length == 0)
        return @"";
    
#if USE_SINGLE8BITSTRING    
    if (length == 1) {
        if ((str = _getSingle8BitString(*(unsigned char *)byteString))) {
            _collectTemporary(self);
            return RETAIN(str);
        }
    }
#endif    
    
    clazz = length < 255
        ? NSShortInline8BitStringClass
        : NSInline8BitStringClass;
    
    str = [[clazz allocForCapacity:length zone:_zone]
                  initWithCString:byteString length:length];
    
    _collectTemporary(self);
    return str;
}

- (id)initWithUTF8String:(const char *)byteString
{
    NSData *d;
    
    d = byteString
	? [NSData dataWithBytes:byteString length:strlen(byteString)]
	: nil;
    return [self initWithData:d encoding:NSUTF8StringEncoding];
}

- (id)initWithBytes:(void *)_bytes length:(unsigned)_length 
  encoding:(NSStringEncoding)_enc
{
    NSData *d;
    
    d = _bytes
	? [NSData dataWithBytes:_bytes length:_length]
	: nil;
    return [self initWithData:d encoding:_enc];
}
- (id)initWithBytesNoCopy:(void *)_bytes length:(unsigned)_length 
  encoding:(NSStringEncoding)_enc freeWhenDone:(BOOL)_fwd
{
    NSData *d;
    
    d = (_bytes != nil)
	? [[NSData alloc] initWithBytesNoCopy:_bytes length:_length
                          freeWhenDone:_fwd]
	: nil;
    self = [self initWithData:d encoding:_enc];
    [d release];
    return self;
}

- (id)initWithCString:(const char *)byteString length:(unsigned int)length
{
    Class clazz;
    id    str;

    if (length == 0) {
        _collectTemporary(self);
        return @"";
    }
#if USE_SINGLE8BITSTRING    
    if (length == 1) {
        if ((str = _getSingle8BitString(*(unsigned char *)byteString))) {
            _collectTemporary(self);
            return RETAIN(str);
        }
    }
#endif
    
    if (NSInline8BitStringClass == Nil)
        NSInline8BitStringClass = [NSInline8BitString class];
    if (NSShortInline8BitStringClass == Nil)
        NSShortInline8BitStringClass = [NSShortInline8BitString class];
    
    clazz = length < 255
        ? NSShortInline8BitStringClass
        : NSInline8BitStringClass;
    
    str = [[clazz allocForCapacity:length zone:_zone]
                  initWithCString:byteString length:length];

    _collectTemporary(self);
    return str;
}

- (id)initWithCStringNoCopy:(char*)byteString freeWhenDone:(BOOL)flag
{
    id str = flag
	? [NSOwned8BitString allocWithZone:_zone]
	: [NSNonOwned8BitString allocWithZone:_zone];

    str = [str initWithCString:byteString length:Strlen(byteString) copy:NO];
    _collectTemporary(self);
    return str;
}

- (id)initWithCStringNoCopy:(char *)byteString
  length:(unsigned int)length freeWhenDone:(BOOL)flag
{
    id str;

    str = flag
        ? [NSOwnedOpen8BitString    allocWithZone:_zone]
	: [NSNonOwnedOpen8BitString allocWithZone:_zone];
    
    str = [str initWithCString:byteString length:length copy:NO];
    _collectTemporary(self);
    return str;
}

- (id)initWithString:(NSString *)aString
{
    id str = [aString copyWithZone:_zone];
    _collectTemporary(self);
    return str;
}

- (id)initWithFormat:(NSString *)format, ...
{
    id str;
    va_list va;
    
    va_start(va, format);
    str = [self initWithFormat:format arguments:va];
    va_end(va);
    return str;
}

- (id)initWithFormat:(NSString *)format arguments:(va_list)argList
{
    id str = Avsprintf(format, argList);
    str = [str copyWithZone:_zone];
    _collectTemporary(self);
    return str;
}

- (id)initWithFormat:(NSString*)format
  locale:(NSDictionary*)dictionary, ...
{
    id str;
    va_list va;
    
    va_start(va, dictionary);
    str = [self initWithFormat:format arguments:va];
    va_end(va);
    return str;
}

- (id)initWithFormat:(NSString*)format 
  locale:(NSDictionary*)dictionary arguments:(va_list)argList
{
    return [self initWithFormat:format arguments:argList];
}

- (id)initWithData:(NSData *)data encoding:(NSStringEncoding)encoding
{
    /* NSTemporaryString */
    // UNICODE
    Class    clazz;
    id       str;
    unsigned len;
    
    len = [data length];
        
    clazz = Nil;

    if (encoding == NSUnicodeStringEncoding) {
        /* scan for characters > 255 ... (everything below is covered by L1) */
        const unichar *s;
        unsigned int  i, slen;
        
        s    = [data bytes];
        slen = len / 2;
        
        for (i = 0; i < slen; i++) {
            if (s[i] > 255) {
                /* use wide string ... */
                str = [NSInlineUTF16String allocForCapacity:slen zone:_zone];
                str = [str initWithCharacters:s length:slen];
                _collectTemporary(self);
                return str;
            }
        }
    }
    else if (encoding == NSISOLatin9StringEncoding) {
        const unsigned char *buf;
        unichar  *newBuf;
        unsigned int i;
        NSString *str;

        buf = [data bytes];
        newBuf = MallocAtomic((len + 1)* sizeof(unichar));
        
        for (i = 0; i < len; i++) { /* convert Euro sign */
            /* missing conversions for other latin9 signs */
            if (buf[i] == 164) {
                newBuf[i] = 8364;
            }
            else {
                newBuf[i] = buf[i];
            }
        }
        str = [NSInlineUTF16String allocForCapacity:len zone:[self zone]];
        str = [str initWithCharacters:newBuf length:len];
        
        lfFree(newBuf);
        _collectTemporary(self);
        return str;
    }
    else if (encoding == NSUTF8StringEncoding) {
        unichar       *buf16;
        unsigned char *start,   *end;
        unichar       *start16, *end16;
        int           result;
        
        buf16 = MallocAtomic((len + 1) * sizeof(unichar));
#if DEBUG
        NSCAssert(buf16,
                  @"couldn't allocate proper buffer of len %i", len);
#endif
        
        start   = (void *)[data bytes]; /* should I allocate a buffer ?? */
        end     = start + len;
        start16 = &(buf16[0]);
        end16   = start16 + len;
        
        result = NSConvertUTF8toUTF16(&start, end, &start16, end16);
        
        if (result == 2) { /* target exhausted */
            if (buf16) { lfFree(buf16); buf16 = NULL; }
            [NSException raise:@"UTFConversionException"
                         format:
                         @"couldn't convert UTF8 to UTF16, "
                         @"target buffer is to small !"];
        }
        else if (result == 1) { /* source exhausted */
            if (buf16) { lfFree(buf16); buf16 = NULL; }
            [NSException raise:@"UTFConversionException"
                         format:
                         @"couldn't convert UTF8 to UTF16, "
                         @"source buffer is to small "
                         @"(probably invalid input) !, data: %@", data];
        }
        else {
            /* length correct ? */
            unsigned int  i, slen;
            const unichar *s;

            s    = buf16;
            slen = (start16 - buf16);

            for (i = 0; i < slen; i++) {
                if (s[i] > 255) {
                    /* use wide string ... */
                    str = [NSInlineUTF16String allocForCapacity:slen
                                               zone:_zone];
                    str = [str initWithCharacters:s length:slen];
                    if (buf16) { lfFree(buf16); buf16 = NULL; }
                    _collectTemporary(self);

                    return str;
                }
            }
            
            if (buf16) { lfFree(buf16); buf16 = NULL; }
        }
    }
    
    if (clazz == Nil) {
        if (NSInline8BitStringClass == Nil)
            NSInline8BitStringClass = [NSInline8BitString class];
        if (NSShortInline8BitStringClass == Nil)
            NSShortInline8BitStringClass = [NSShortInline8BitString class];
        
        clazz = len < 255
            ? NSShortInline8BitStringClass
            : NSInline8BitStringClass;
    }
    len = [data length];
    str = [clazz allocForCapacity:len zone:_zone];
    str = NSInitStringWithData(str, data, encoding);
    _collectTemporary(self);
    return str;
}

- (id)initWithContentsOfFile:(NSString *)_path
{
    unsigned char *bytes = NULL;
    unsigned len;
    
    if ((bytes = NSReadContentsOfFile(_path, 1, &len))) {
        NSString *str;
        
        bytes[len] = '\0';
        
        if (len >= 2) {
            BOOL             isUnicode;
            enum NSByteOrder fbo;
            
            if (bytes[0] == 0xFF && bytes[1] == 0xFE) {
                isUnicode = YES;
                fbo = NS_LittleEndian;
            }
            else if (bytes[0] == 0xFE && bytes[1] == 0xFF) {
                isUnicode = YES;
                fbo = NS_BigEndian;
            }
            else
                isUnicode = NO;

            if (isUnicode) {
                unichar *chars;
                
                chars = (unichar *)&(bytes[2]);
                len   = ((len - 2) / 2);
                
                if (fbo != NSHostByteOrder()) {
                    unsigned i;
                    
                    /* IMPROVE THAT JUNK !!! */
                    for (i = 0; i < len; i++) {
                        unsigned char buf[2];
                        unsigned char t;
                        memcpy(buf, &(chars[i]), 2);
                        t = buf[0];
                        buf[0] = buf[1];
                        buf[1] = t;
                        memcpy(&(chars[i]), buf, 2);
                    }
                }
                
                str = [self initWithCharacters:chars length:len];
                if (bytes) free(bytes);
                return str;
            }
        }
        
        str = [[NSOwned8BitString allocWithZone:_zone] 
		                  initWithCString:(char *)bytes
                                  length:len copy:NO];
        
        _collectTemporary(self);
        return str;
    }    
    else {
        _collectTemporary(self);
        return nil;
    }
}

- (id)initWithContentsOfURL:(NSURL *)_url
{
    if ([_url isFileURL]) {
        return [self initWithContentsOfFile:[_url path]];
    }
    else if (_url == nil) {
        _collectTemporary(self);
        return nil;
    }
    else {
        NSURLHandle      *handle;
        NSData           *data;
        NSString         *mimeType;
        NSStringEncoding enc;
        
        handle   = [_url URLHandleUsingCache:NO];
        data     = [handle resourceData];
        mimeType = [[handle propertyForKey:@"content-type"] description];
        
        if ([mimeType length] > 0) {
            unsigned idx;

            enc = [NSStringClass defaultCStringEncoding];
            if ([mimeType hasPrefix:@"text/xml"])
                enc = NSUTF8StringEncoding;
            
            if ((idx = [mimeType indexOfString:@"charset="]) != NSNotFound) {
                NSString *cs;
                
                cs = [mimeType substringFromIndex:(idx + 8)];
                cs = [cs lowercaseString];
                if ([cs hasPrefix:@"utf-8"])
                    enc = NSUTF8StringEncoding;
                else if ([cs hasPrefix:@"iso-8859-1"])
                    enc = NSISOLatin1StringEncoding;
                else if ([cs hasPrefix:@"utf-16"])
                    enc = NSUnicodeStringEncoding;
                else if ([cs hasPrefix:@"ascii"])
                    enc = NSASCIIStringEncoding;
                else
                    NSLog(@"WARNING: cannot process content charset "
                          @"'%@' of URL '%@'", cs, [_url absoluteString]);
            }
        }
        else
            enc = [NSStringClass defaultCStringEncoding];
        
        return [self initWithData:data encoding:enc];
    }
}

@end /* NSTemporaryString */


@implementation NSMutableTemporaryString

static NSMutableTemporaryString *temporaryMutableStringsPool = nil;

+ (void)initialize
{
    static BOOL initialized = NO;

    if (!initialized) {
	[[NSNotificationCenter defaultCenter]
	    addObserver:self
	    selector:@selector(taskNowMultiThreaded:)
	    name:NSWillBecomeMultiThreadedNotification
	    object:nil];
	initialized = YES;
    }
}

+ (void)taskNowMultiThreaded:notification
{
    PrivateThreadData* threadData = [[NSThread currentThread]
					_privateThreadData];

    [threadData setTemporaryMutableStringsPool:temporaryMutableStringsPool];
    temporaryMutableStringsPool = nil;
    isMultithreaded = YES;
}

+ (id)allocWithZone:(NSZone*)zone
{
    NSMutableTemporaryString *obj = nil;
    PrivateThreadData        *threadData = nil;

    if (isMultithreaded) {
	threadData = [[NSThread currentThread] _privateThreadData];
	obj = [threadData temporaryMutableString];
    }
    else {
	if (temporaryMutableStringsPool) {
	    obj = temporaryMutableStringsPool;
	    temporaryMutableStringsPool = temporaryMutableStringsPool->next;
	    obj->next = nil;
	}
    }

    if (!obj)
	obj = (id)NSAllocateObject(self, 0, zone);

    obj->_zone = zone;

    return obj;
}

- (void)dealloc
{
    fprintf(stderr,"NSMutableTemporaryString %s to be deallocated!\n",isa->name);
    abort();
}

static inline void _collectMutableTemporary(NSMutableTemporaryString *self)
{
    if (isMultithreaded) {
	[[[NSThread currentThread] _privateThreadData]
                    addTemporaryMutableString:self];
    }
    else {
	if (self != temporaryMutableStringsPool)
	    self->next = temporaryMutableStringsPool;
	temporaryMutableStringsPool = self;
    }
}

/*
 * Methods that return strings
 */

- (id)initWithCapacity:(unsigned int)capacity
{
    id str = [[NSMutableSimple8BitString allocWithZone:_zone] 
	initWithCapacity:capacity];

    _collectMutableTemporary(self);
    return str;
}

- (id)init
{
    id str = [[NSMutableSimple8BitString allocWithZone:_zone] init];
    _collectMutableTemporary(self);
    return str;
}

- (id)initWithCString:(const char*)byteString
{
    int length = Strlen(byteString);
    id str = [[NSMutableSimple8BitString allocWithZone:_zone]
	    initWithCString:(char*)byteString length:length copy:YES];
    _collectMutableTemporary(self);
    return str;
}

- (id)initWithCString:(const char*)byteString length:(unsigned int)length
{
    id str = [[NSMutableSimple8BitString allocWithZone:_zone]
	    initWithCString:(char*)byteString length:length copy:YES];
    _collectMutableTemporary(self);
    return str;
}

- (id)initWithCStringNoCopy:(char*)byteString freeWhenDone:(BOOL)flag
{
    id str = [NSMutableSimple8BitString allocWithZone:_zone];
    
    str = [str initWithCString:byteString
	length:Strlen(byteString) copy:!flag];
    
    _collectMutableTemporary(self);
    return str;
}

- (id)initWithCStringNoCopy:(char*)byteString
  length:(unsigned int)length freeWhenDone:(BOOL)flag
{
    id str = [NSMutableSimple8BitString allocWithZone:_zone];
    
    str = [str initWithCString:byteString
	length:Strlen(byteString) copy:!flag];

    _collectMutableTemporary(self);
    return str;
}

- (id)initWithString:(NSString*)aString
{
    id str = [[NSMutableSimple8BitString allocWithZone:_zone] 
	initWithString:aString];
    
    _collectMutableTemporary(self);
    return str;
}

- (id)initWithFormat:(NSString*)format, ...
{
    id str;
    va_list va;
    
    va_start(va, format);
    str = [self initWithFormat:format arguments:va];
    va_end(va);
    return str;
}

- (id)initWithFormat:(NSString*)format arguments:(va_list)argList
{
    id str = [[NSMutableSimple8BitString allocWithZone:_zone] init];

    [str appendFormat:format arguments:argList];
    _collectMutableTemporary(self);
    return str;
}

- (id)initWithFormat:(NSString *)format
  locale:(NSDictionary *)dictionary, ...
{
    id str;
    va_list va;
    
    va_start(va, dictionary);
    str = [self initWithFormat:format arguments:va];
    va_end(va);
    return str;
}

- (id)initWithFormat:(NSString *)format 
  locale:(NSDictionary *)dictionary arguments:(va_list)argList
{
    return [self initWithFormat:format arguments:argList];
}

- (id)initWithData:(NSData *)data encoding:(NSStringEncoding)encoding
{
    /* NSMutableTemporaryString */
    // UNICODE
    id str;
    str = [NSMutableSimple8BitString allocWithZone:_zone];
    str = NSInitStringWithData(str, data, encoding);
    _collectMutableTemporary(self);
    return str;
}

- (id)initWithContentsOfFile:(NSString *)_path
{
    unsigned char *bytes = NULL;
    unsigned len;

    if ((bytes = NSReadContentsOfFile(_path, 1, &len))) {
        NSMutableString *str;
        
        bytes[len] = '\0';
        
        str = [[NSMutableSimple8BitString allocWithZone:_zone] 
		                          initWithCString:(char *)bytes
                                          length:len copy:NO];
        _collectMutableTemporary(self);
        return str;
    }    
    else {
        _collectMutableTemporary(self);
        return nil;
    }
}

@end /* NSMutableTemporaryString */

#include <Foundation/NSAutoreleasePool.h>

/*
 * Used for forcing linking of this category
 */

static void __dummyNSStringfile ()
{
    extern void __dummyNSStringFilePathfile();
    __dummyNSStringFilePathfile();
    __dummyNSStringfile();
}

/*
  Local Variables:
  c-basic-offset: 4
  tab-width: 8
  End:
*/
