File:  [Apple Darwin 0.x] / objc / NXString.m
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs
Tue Apr 24 19:13:57 2018 UTC (8 years, 2 months ago) by root
Branches: MAIN, Apple
CVS tags: HEAD, Darwin03, Darwin01
Darwin 0.1 In-kernel Objective-C runtime

/*
 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
 *
 * @APPLE_LICENSE_HEADER_START@
 * 
 * "Portions Copyright (c) 1999 Apple Computer, Inc.  All Rights
 * Reserved.  This file contains Original Code and/or Modifications of
 * Original Code as defined in and that are subject to the Apple Public
 * Source License Version 1.0 (the 'License').  You may not use this file
 * except in compliance with the License.  Please obtain a copy of the
 * License at http://www.apple.com/publicsource and read it before using
 * this file.
 * 
 * The Original Code and all software distributed under the License are
 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
 * License for the specific language governing rights and limitations
 * under the License."
 * 
 * @APPLE_LICENSE_HEADER_END@
 */
/*
	NXString.m
	Copyright 1991 NeXT, Inc.
	Responsibility: Ali Ozer
*/

#ifndef KERNEL
#ifdef SHLIB
#import "shlib.h"
#endif SHLIB

#import <mach/mach.h>

#import "NXStringPrivate.h"
#import <streams/streams.h>
#import <streams/streamsextra.h>
#import <stdio.h>
#import "error.h"

/* Separate zone for ref counted strings... */
static NXZone *theStringZone = NULL;

NXZone *_NXStringZone (void)
{
  return theStringZone;
}

static void objectPrintfProc(NXStream *stream, void *item, void *procData)
{
    if ([(id)item respondsTo:@selector(writeToStream:)]) {
	[(id)item writeToStream:stream];
    } else {
	NXPutc(stream, '%'); NXPutc(stream, '@');
    }
}

void _NXStringErrorRaise (int errorCode, const char *errorMsg)
{
    extern void _NXLogError(const char *format, ...);
    _NXLogError( "NXString error %d: %s", errorCode, errorMsg);
    NX_RAISE (errorCode, errorMsg, 0);
}


@implementation NXString

+ initialize
{
    if (theStringZone == NULL) {
#if 1
	/* Using a separate string zone seems to hurt more than it helps now.
	   ??? However, we need to solve the copyFromZone: problem... */
	theStringZone = NXDefaultMallocZone();
#else
	theStringZone = NXCreateZone(vm_page_size, vm_page_size, YES);
	NXNameZone (theStringZone, "String Zone");
#endif
	NXRegisterPrintfProc('@', objectPrintfProc, NULL);
    }
    return self;
}

- (unichar *)allocateCharacterBuffer:(unsigned)nChars
{
    return NX_CHARALLOC([self zone], nChars);
}

- initFromCharactersNoCopy:(unichar *)chars length:(unsigned)len
{
    return [super init];
}

- init
{
    return [self initFromCharactersNoCopy:NULL length:0];
}

- initFromCharacters:(const unichar *)chars length:(unsigned)len;
{
    unichar *buffer = [self allocateCharacterBuffer:len];
    NX_CHARCOPY (chars, buffer, len);
    return [self initFromCharactersNoCopy:buffer length:len];
}

- initFromString:string
{
    NXRange range = {0, [string length]};
    return [self initFromString:string range:range];
}

- initFromString:string range:(NXRange)range
{
    unichar *buffer = [self allocateCharacterBuffer:RNGLEN(range)];
    [string getCharacters:buffer range:range];
    return [self initFromCharactersNoCopy:buffer length:RNGLEN(range)];
}

// The starting size for the buffer when reading from a stream, if no other clues about the desired size
// or the stream size are provided...

#define INITIALLENGTH 16

- initFromStream:(NXStream *)stream untilOneOf:(NXCharacterSet *)set maxLength:(unsigned int)maxLen
{
#if CHARS_ARE_EIGHT_BIT
    return [self initFromCStringStream:stream untilOneOf:set maxLength:maxLen];
#else
#warning initFromStream:untilOneOf:maxLength: not implemented for Unicode
    _NXStringErrorRaise (NXStringInternalError, "initFromStream:untilOneOf:maxLength: not implemented for Unicode");
    return nil;
#endif
}

- initFromCStringStream:(NXStream *)stream untilOneOf:(NXCharacterSet *)set maxLength:(unsigned int)maxLen
{
    volatile unsigned int readLen = 0;
    volatile unsigned int charsLen = MIN(maxLen, INITIALLENGTH);
    unichar *volatile chars = NULL;
    int chRead;
   
    if (stream->flags & NX_CANSEEK) {	// Try to fine tune the initial buffer size

	long curLoc = NXTell(stream);
	if (!set) {		// If no set, then length is determined by maxLen or stream size
	    NXSeek (stream, 0, NX_FROMEND);
	    charsLen = (NXTell(stream) - curLoc);
	    if (charsLen > maxLen) charsLen = maxLen;
	} else {		// Otherwise we have to look at every character to determine how many we'll read
	    charsLen = 0;
	    while (!NXAtEOS(stream) && (charsLen < maxLen) && ![set characterIsMember:(unichar)NXGetc(stream)]) charsLen++;
	}
	NXSeek (stream, curLoc, NX_FROMSTART);
	
    }

    if ((chars = [self allocateCharacterBuffer:charsLen])) {
    
	NX_DURING
    
	    // Seems like AtEOS is set after we attempt to read the last character.
	    // ??? Thus the !NXAtEOS is pretty useless down here...
	
	    while (!NXAtEOS(stream) && (readLen < maxLen) && ((chRead = NXGetc(stream)) != EOF)) {
		unichar ch = (unichar)chRead;
		if (set && [set characterIsMember:ch]) {
		    NXUngetc(stream);
		    break;
		}
		if (charsLen == readLen) {
		    unichar *newChars;
		    if ((charsLen *= 2) > maxLen) charsLen = maxLen;
		    newChars = [self allocateCharacterBuffer:charsLen];
		    NX_CHARCOPY ((unichar *)chars, newChars, readLen);
		    free ((unichar *)chars);
		    chars = newChars;
		}
		chars[readLen++] = ch;
	    }
    
	NX_HANDLER

	    free ((unichar *)chars);
	    NX_RERAISE ();
    
	NX_ENDHANDLER

    }

    return [self initFromCharactersNoCopy:(unichar *)chars length:readLen];
}

- initFromFormat:(NXString *)format, ...
{
    va_list argList;

    va_start (argList, format);
    self = [self initFromFormat:format withArgList:argList];
    va_end (argList);
    
    return self;
}

- initFromFormat:(NXString *)format withArgList:(va_list)argList
{
    int maxLen, len;
    unsigned formatLen = [format cStringLength] + 1;	// Including terminating zero
    char *bytes;
    NXStream *stream = NXOpenSmallMemory(NX_WRITEONLY);
    char tmpBuf[MAXTMPBUFFERLEN], *formatChars;

    formatChars = (formatLen > MAXTMPBUFFERLEN) ? NXZoneMalloc(NXDefaultMallocZone(), formatLen * sizeof(char)) : tmpBuf;
    [format getCString:formatChars];
    NXVPrintf(stream, formatChars, argList);
    NXFlush(stream);
    NXGetMemoryBuffer(stream, &bytes, &len, &maxLen);
    self = [self initFromCString:bytes length:len];
    NXCloseMemory(stream, NX_FREEBUFFER);
    if (formatChars != tmpBuf) free(formatChars);

    return self;
}


/* Byte oriented methods */

- initFromCString:(const char *)bytes
{
    return [self initFromCString:bytes length:strlen(bytes)];
}

- initFromCString:(const char *)bytes length:(unsigned)length
{
    unichar *buffer = NULL;
    unsigned cnt;

    if (length && bytes && *bytes) {
        buffer = [self allocateCharacterBuffer:length];
        for (cnt = 0; cnt < length; cnt++) {
            buffer[cnt] = bytes[cnt];
        }
    }
    return [self initFromCharactersNoCopy:buffer length:length];
}

- (void)getCString:(char *)buffer
{
    [self getCString:buffer maxLength:NX_MAX_STRING_LENGTH range:(NXRange){0, [self length]} remainingRange:NULL];
}

- (void)getCString:(char *)buffer maxLength:(unsigned)bytes
{
    [self getCString:buffer maxLength:bytes range:(NXRange){0, [self length]} remainingRange:NULL];
}    

- (void)getCString:(char *)buffer maxLength:(unsigned)bytes range:(NXRange)range remainingRange:(NXRange *)leftover
{
#if CHARS_ARE_EIGHT_BIT
    NXRange desiredRange = range;

    if (RNGLEN(range) > bytes) RNGLEN(range) = bytes;
    [self getCharacters:(unichar *)buffer range:range];
    buffer[RNGLEN(range)] = 0;

    if (leftover) {
	RNGLOC(*leftover) = RNGLOC(desiredRange) + RNGLEN(range);
	RNGLEN(*leftover) = RNGLEN(desiredRange) - RNGLEN(range);
    }
#else
#warning getCString:maxLength:range:remainingRange: not implemented for Unicode
    _NXStringErrorRaise (NXStringInternalError, "getCString:maxLength:range:remainingRange: not implemented for Unicode");
#if 0
    NXRange processedRange;
    unichar tmpBuf[MAXTMPBUFFERLEN];
    unsigned uCnt = 0, cCnt = 0;
    
    if (RNGLOC(range) + RNGLEN(range) > [self length]) BOUNDSERROR;

    processedRange = range;
    if (RNGLEN(processedRange) > MAXTMPBUFFERLEN) RNGLEN(processedRange) = MAXTMPBUFFERLEN;

    [self getCharacters:tmpBuf range:range];

    while (uCnt < RNGLEN(range)) {
	unichar ch = uStr[RNGLOC(range) + uCnt];
	if (cCnt < bytes) {	// ??? This check will have to be smarter
	    buffer[cCnt] = (ch > 0x0ff) ? NX_BADBYTE : ch;
	} else {
	    break;
	}
	uCnt++;
	cCnt++;
    }
    buffer[cCnt] = 0;
#endif
#endif
}

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

- (unsigned)cStringLength
{
#if CHARS_ARE_EIGHT_BIT
    return [self length];
#else
#warning cStringLength not implemented for Unicode
    _NXStringErrorRaise (NXStringInternalError, "cStringLength not implemented for Unicode");
    return 0;
#endif
}

- (char *)cStringCopy
{
    char *str = NX_BYTEALLOC (NXDefaultMallocZone(), [self cStringLength] + 1);
    [self getCString:str];
    return str;
}

- (NXAtom)uniqueCStringCopy
{
    char tmpBuf[MAXTMPBUFFERLEN], *str;
    NXAtom unique;
    unsigned int len = [self cStringLength] + 1;
    
    str = (len > MAXTMPBUFFERLEN) ? NX_BYTEALLOC(NXDefaultMallocZone(), len) : tmpBuf;
    [self getCString:str];
    unique = NXUniqueString (str);
    if (str != tmpBuf) free (str);    

    return unique;
}

- (unichar)characterAt:(unsigned)pos
{
    [self subclassResponsibility:_cmd];
    return 0;
}

- (void)getCharacters:(unichar *)buffer range:(NXRange)range
{
    unsigned int cnt;
    
    for (cnt = 0; cnt < RNGLEN(range); cnt++) {
        buffer[cnt] = [self characterAt:RNGLOC(range) + cnt];
    }
}

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

/* Comparision and find stuff */

// Compare the two character strings (whose lengths are given in firstLen & secondLen)
// according to the flags in flagMask.

// ??? Unicode string compares work differently: As characters are compared and found to be unequal,
// they are normalized. Thus if "o" and "O" are compared and found unequal, they are normalized
// (depending on flagMask), and compared again. This normalization might include case conversion,
// floating diacritics, etc.

NXComparisonResult NXCompareCharacters (const unichar *first, const unichar *second, unsigned firstLen, unsigned secondLen, unsigned flagMask, void *table)
{
    unsigned cnt = 0, compareLen = MIN(firstLen, secondLen);
    BOOL caseInsensitive = (flagMask & NX_CASE_INSENSITIVE) ? YES : NO;

    while (cnt < compareLen) {
	unichar ch1 = first[cnt], ch2 = second[cnt];
	if (caseInsensitive) {	// Don't worry about unrolling this into two loops...
	    if (ch1 >= 'a' && ch1 <= 'z') ch1 += 'A' - 'a';
	    if (ch2 >= 'a' && ch2 <= 'z') ch2 += 'A' - 'a';
	}
	if (ch1 < ch2) return NX_OrderedAscending;
	else if (ch1 > ch2) return NX_OrderedDescending;
	else cnt++;
    }
    return (firstLen < secondLen) ? NX_OrderedAscending : ((firstLen > secondLen) ? NX_OrderedDescending : NX_OrderedSame);
}

// Find findStr of len findStrLen in inStr of inStrLen. If flagMask contains NX_BACKWARDS_SEARCH,
// then look at inStr starting from the last valid character.
// See Unicode related warning under NXCompareCharacters().

NXRange NXFindCharacters (const unichar *findStr, const unichar *inStr, unsigned findStrLen, unsigned inStrLen, unsigned flagMask, void *table)
{
    int step;
    unsigned fromLoc, toLoc, cnt;	// fromLoc and toLoc are inclusive
    BOOL found = NO, done = NO;
    BOOL caseInsensitive = (flagMask & NX_CASE_INSENSITIVE) ? YES : NO;
    NXRange range = {NX_STRING_NOT_FOUND, 0};

    if (findStrLen > inStrLen) {	// ??? This can't be here for correct Unicode compares
	return range;
    }
    
    if (flagMask & NX_BACKWARDS_SEARCH) {
        fromLoc = inStrLen - findStrLen;	// Inclusive
        toLoc = 0;
    } else {       
        fromLoc = 0;
        toLoc = inStrLen - findStrLen;		// Inclusive
    }

    step = (fromLoc <= toLoc) ? 1 : -1;
    cnt = fromLoc;
    do {
        unsigned int chCnt;
        for (chCnt = 0; chCnt < findStrLen; chCnt++) {
	    unichar ch1 = findStr[chCnt], ch2 = inStr[chCnt + cnt];
	    if (caseInsensitive) {
		if (ch1 >= 'a' && ch1 <= 'z') ch1 += 'A' - 'a';
		if (ch2 >= 'a' && ch2 <= 'z') ch2 += 'A' - 'a';
	    }
            if (ch1 != ch2) {
                break;
            }
        }
        if (chCnt == findStrLen) {
            found = done = YES;
	    RNGLOC(range) = cnt;
	    RNGLEN(range) = findStrLen;
        } else if (cnt == toLoc) {
	    done = YES;
	} else {
            cnt += step;
        }
    } while (!done);

    return range;
}

unsigned NXHashCharacters(const unichar *characters, unsigned length)
{
    unsigned int h = length, cnt;

    if (length > MAXSTRINGLENFORHASHING) {
	length = MAXSTRINGLENFORHASHING;
    }
    
    for (cnt = 0; cnt < length; cnt++) {
	h <<= 4;
	h += (unsigned int)characters[cnt];
	h ^= (h >> 24);
    }
    
    return h;
}

- (BOOL)isEqual:string
{
    static Class stringClass = Nil;
    
    if (stringClass == Nil) stringClass = [NXString class];
    
    return (self == string) ||
	([string isKindOf: stringClass] &&
#if CHARS_ARE_EIGHT_BIT
	 ([self cStringLength] == [string cStringLength]) &&
#endif
	 ([self compare:string] == NX_OrderedSame));
}

- (NXComparisonResult)compare:string
{
    return [self compare:string mask:0 table:NULL];
}

- (NXComparisonResult)compare:string mask:(unsigned int)options table:(void *)table
{
    if (![string isKindOf:[NXString class]]) {
	return NX_OrderedAscending;	// ???
    } else {
	unsigned ownLength = [self length], otherLength = [string length];
	unichar ownBuffer[COMPARELENGTH], otherBuffer[COMPARELENGTH];
	NXRange ownRange = {0, 0}, otherRange = {0, 0};
	NXComparisonResult res = NX_OrderedSame;
    
	while (1) {
	    RNGLEN(ownRange) = MIN(ownLength - RNGLOC(ownRange), COMPARELENGTH);	
	    RNGLEN(otherRange) = MIN(otherLength - RNGLOC(otherRange), COMPARELENGTH);	
	    if (RNGLEN(ownRange) == 0 && RNGLEN(otherRange) == 0) return NX_OrderedSame;
	    [self getCharacters:ownBuffer range:ownRange];
	    [string getCharacters:otherBuffer range:otherRange];
	    if ((res = NXCompareCharacters(ownBuffer, otherBuffer, RNGLEN(ownRange), RNGLEN(otherRange), options, table)) != NX_OrderedSame) return res;
	    RNGLOC(ownRange) += RNGLEN(ownRange);
	    RNGLOC(otherRange) += RNGLEN(otherRange);
	}
    }
}

- (NXRange)findString:(NXString *)string
{
    NXRange range = {0, [self length]};
    return [self findString:string range:range mask:0 table:NULL];
}

- (NXRange)findString:(NXString *)findStr range:(NXRange)fRange mask:(unsigned int)options table:(void *)table
{
    int step;
    unsigned fromLoc, toLoc, cnt, findStrLen, len;	// fromLoc and toLoc are inclusive
    BOOL found = NO, done = NO;
    BOOL caseInsensitive = (options & NX_CASE_INSENSITIVE) ? YES : NO;
    NXRange range = {NX_STRING_NOT_FOUND, 0};
    unichar tmpBuf[MAXTMPBUFFERLEN], *findBuf;

    findStrLen = [findStr length];
    len = [self length];

    if (findStrLen > RNGLEN(fRange)) {	// ??? This can't be here for correct Unicode compares
	return range;
    }
    
    findBuf = (findStrLen > MAXTMPBUFFERLEN) ? NX_CHARALLOC(NXDefaultMallocZone(), findStrLen) : tmpBuf;
    [findStr getCharacters:findBuf];
      
    if (options & NX_BACKWARDS_SEARCH) {
        fromLoc = RNGLOC(fRange) + RNGLEN(fRange) - findStrLen;
        toLoc = RNGLOC(fRange);
    } else {       
        fromLoc = RNGLOC(fRange);
        toLoc = RNGLOC(fRange) + RNGLEN(fRange) - findStrLen;
    }

    step = (fromLoc <= toLoc) ? 1 : -1;
    cnt = fromLoc;
    do {
        unsigned int chCnt;
        for (chCnt = 0; chCnt < findStrLen; chCnt++) {
	    unichar ch1 = findBuf[chCnt], ch2 = [self characterAt:chCnt + cnt];
	    if (caseInsensitive) {
		if (ch1 >= 'a' && ch1 <= 'z') ch1 += 'A' - 'a';
		if (ch2 >= 'a' && ch2 <= 'z') ch2 += 'A' - 'a';
	    }
            if (ch1 != ch2) {
                break;
            }
        }
        if (chCnt == findStrLen) {
            found = done = YES;
	    RNGLOC(range) = cnt;
	    RNGLEN(range) = findStrLen;
        } else if (cnt == toLoc) {
	    done = YES;
	} else {
            cnt += step;
        }
    } while (!done);

    if (findBuf != tmpBuf) free(findBuf);

    return range;
}

- (unsigned)findCharacter:(unichar)ch
{
    NXRange range = {0, [self length]};
    return [self findCharacter:ch range:range mask:0 table:NULL];
}

- (unsigned)findCharacter:(unichar)ch range:(NXRange)fRange mask:(unsigned int)options table:(void *)table
{
    NXString *string = [[NXReadOnlyString alloc] initFromCharactersNoCopy:&ch length:1 freeWhenDone:NO];
    NXRange result = [self findString:string range:fRange mask:options table:NULL];
    [string free];
    return RNGLOC(result);
}

- (unsigned)findOneOf:(NXCharacterSet *)set
{
    NXRange range = {0, [self length]};
    return [self findOneOf:set range:range mask:0 table:NULL];
}

// ??? How should we deal with the CASEINSENSITIVE flag? Probably we shouldn't care...

- (unsigned)findOneOf:(NXCharacterSet *)set range:(NXRange)fRange mask:(unsigned int)options table:(void *)table
{
    int step;
    unsigned fromLoc, toLoc, cnt, len;	// fromLoc and toLoc are inclusive
    BOOL found = NO, done = NO;

    len = [self length];

    if (options & NX_BACKWARDS_SEARCH) {
        fromLoc = RNGLOC(fRange) + RNGLEN(fRange) - 1;
        toLoc = RNGLOC(fRange);
    } else {       
        fromLoc = RNGLOC(fRange);
        toLoc = RNGLOC(fRange) + RNGLEN(fRange) - 1;
    }

    step = (fromLoc <= toLoc) ? 1 : -1;
    cnt = fromLoc;
 
    do {
        unichar ch = [self characterAt:cnt];
	if ([set characterIsMember:ch]) {
	    done = found = YES;
        } else if (cnt == toLoc) {
	    done = YES;
	} else {
            cnt += step;
        }
    } while (!done);

    return found ? cnt : NX_STRING_NOT_FOUND;
}

- (unsigned)hash
{
    unichar buffer[MAXSTRINGLENFORHASHING];
    unsigned len = MIN([self length], MAXSTRINGLENFORHASHING);
    NXRange range = {0, len};
    
    [self getCharacters:buffer range:range];
    return NXHashCharacters(buffer, [self length]);
}

- (NXString *)copySubstring:(NXRange)range
{
    return [self copySubstring:range fromZone:[self zone]];
}

- (NXString *)copySubstring:(NXRange)range fromZone:(NXZone *)zone
{
    if (RNGLOC(range) + RNGLEN(range) > [self length]) BOUNDSERROR;
    if (RNGLOC(range) == 0 && RNGLEN(range) == [self length]) {
	return [self copyFromZone:zone];
    } else {
	id newObject = [[self class] allocFromZone:zone];
	unichar *chars = [newObject allocateCharacterBuffer:RNGLEN(range)];
	[self getCharacters:chars range:range];
	return [newObject initFromCharactersNoCopy:chars length:RNGLEN(range)];
    }
}

- immutableCopy
{
    return [self immutableCopyFromZone:[self zone]];
}

- immutableCopyFromZone:(NXZone *)zone
{
    return [self copyFromZone:zone];
}

- mutableCopy
{
    return [self mutableCopyFromZone:[self zone]];
}

- mutableCopyFromZone:(NXZone *)zone
{
    return [[NXReadWriteString allocFromZone:zone] initFromString:self];
}

- (void)writeToStream:(NXStream *)stream
{
#if CHARS_ARE_EIGHT_BIT
    [self writeCStringToStream:stream];
#else
#warning writeToStream: not implemented for Unicode
    _NXStringErrorRaise (NXStringInternalError, "writeToStream: not implemented for Unicode");
#endif
}

#define WRITEBUFFERLEN 1024

- (void)writeCStringToStream:(NXStream *)stream
{
    char buf[WRITEBUFFERLEN+1];
    NXRange range = {0, [self length]};

    while (RNGLEN(range) > 0) {
	NXRange remainingRange;
	[self getCString:buf maxLength:WRITEBUFFERLEN range:range remainingRange:&remainingRange];
	NXWrite (stream, buf, NX_LENGTH(range) - NX_LENGTH(remainingRange));
	range = remainingRange;
    }
}

- (void)printForDebugger:(NXStream *)stream
{
    unsigned int cnt, length = [self length];
    
    NXPrintf (stream, "%s, length %d: ", [[self class] name], length);
    
    for (cnt = 0; cnt < length; cnt++) {
        unichar ch = [self characterAt:cnt];
	NXPrintf (stream, (ch >= ' ' && ch < 127) ? "%c" : "<0x%x>", ch);
    }
    NXFlush (stream);
}

#define TOOLONGLIMIT 200
#define EACHSECTION 80

- (void)_print
{
    unsigned int cnt = 0, length = [self length], breakAt = (length > TOOLONGLIMIT) ? EACHSECTION : UINT_MAX;
    
    fprintf (stderr, "%s, length %d: ", [[self class] name], length);
    
    while (cnt < length) {
        unichar ch = [self characterAt:cnt];
	fprintf (stderr, (ch >= ' ' && ch < 127) ? "%c" : "<0x%x>", ch);
	if (++cnt == breakAt) {
	    cnt = length - EACHSECTION;
	    fprintf (stderr, "...");
	}
    }
    fprintf (stderr, "\n");
}


#ifndef DONT_USE_OLD_NXSTRING_NAMES

/* Compatibility stuff. These are 2.x/3.0 methods which should be preserved for 3.x but removed in 4.0.
*/

- initFromStream:(NXStream *)stream uptoLength:(unsigned)length orUntilOneOf:(NXCharacterSet *)set
{
    return [self initFromStream:stream untilOneOf:set maxLength:length];
}

- initFromByteStream:(NXStream *)stream uptoLength:(unsigned)length orUntilOneOf:(NXCharacterSet *)set
{
    return [self initFromCStringStream:stream untilOneOf:set maxLength:length];
}

- (void)getCString:(char *)buffer range:(NXStringRange)range
{
    [self getCString:buffer maxLength:NX_MAX_STRING_LENGTH range:range remainingRange:NULL];
}

- (void)getCString:(char *)buffer length:(unsigned)bytes
{
    [self getCString:buffer maxLength:bytes];
}

- (void)getCString:(char *)buffer length:(unsigned)bytes range:(NXStringRange)range
{
    [self getCString:buffer maxLength:bytes range:range remainingRange:NULL];
}

- (NXComparisionResult)compare:(NXString *)string mask:(unsigned int)options
{
    return [self compare:string mask:options table:NULL];
}

- (NXComparisionResult)compare:(NXString *)string mask:(unsigned int)options usingTable:(void *)table
{
    return [self compare:string mask:options table:table];    
}

- (NXStringRange)find:(NXString *)string
{
    return [self findString:string];
}

- (NXStringRange)find:(NXString *)string range:(NXStringRange)range
{
    return [self findString:string range:range mask:0 table:NULL];
}

- (NXStringRange)find:(NXString *)string mask:(unsigned int)options
{
    return [self findString:string range:(NXRange){0, [self length]} mask:options table:NULL];
} 

- (NXStringRange)find:(NXString *)string range:(NXStringRange)range mask:(unsigned int)options usingTable:(void *)table
{
    return [self findString:string range:range mask:options table:table];
}

- (unsigned)findOneOf:(NXCharacterSet *)set range:(NXStringRange)range
{
    return [self findOneOf:set range:range mask:0 table:NULL];
}

- (unsigned)findOneOf:(NXCharacterSet *)set mask:(unsigned int)options
{
    return [self findOneOf:set range:(NXRange){0, [self length]} mask:options table:NULL];
}

- (unsigned)findOneOf:(NXCharacterSet *)set range:(NXStringRange)range mask:(unsigned int)options usingTable:(void *)table
{
    return [self findOneOf:set range:range mask:options table:table];
}

- (unsigned)findCharacter:(unichar)ch range:(NXStringRange)range
{
    return [self findCharacter:ch range:range mask:0 table:NULL];
}

- (unsigned)findCharacter:(unichar)ch mask:(unsigned int)options
{
    return [self findCharacter:ch range:(NXRange){0, [self length]} mask:options table:NULL];
}

- (unsigned)findCharacter:(unichar)ch range:(NXStringRange)range mask:(unsigned int)options usingTable:(void *)table
{
    return [self findCharacter:ch range:range mask:options table:table];
}

- (unichar *)createCharacterBuffer:(unsigned)nChars
{
    return [self allocateCharacterBuffer:nChars];
}

- (void)writeBytesToStream:(NXStream *)stream
{
    return [self writeCStringToStream:stream];
}

#endif DONT_USE_OLD_NXSTRING_NAMES

@end
#endif /* KERNEL */

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.