Annotation of objc/NXString.m, revision 1.1

1.1     ! root        1: /*
        !             2:  * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
        !             3:  *
        !             4:  * @APPLE_LICENSE_HEADER_START@
        !             5:  * 
        !             6:  * "Portions Copyright (c) 1999 Apple Computer, Inc.  All Rights
        !             7:  * Reserved.  This file contains Original Code and/or Modifications of
        !             8:  * Original Code as defined in and that are subject to the Apple Public
        !             9:  * Source License Version 1.0 (the 'License').  You may not use this file
        !            10:  * except in compliance with the License.  Please obtain a copy of the
        !            11:  * License at http://www.apple.com/publicsource and read it before using
        !            12:  * this file.
        !            13:  * 
        !            14:  * The Original Code and all software distributed under the License are
        !            15:  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
        !            16:  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
        !            17:  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
        !            18:  * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
        !            19:  * License for the specific language governing rights and limitations
        !            20:  * under the License."
        !            21:  * 
        !            22:  * @APPLE_LICENSE_HEADER_END@
        !            23:  */
        !            24: /*
        !            25:        NXString.m
        !            26:        Copyright 1991 NeXT, Inc.
        !            27:        Responsibility: Ali Ozer
        !            28: */
        !            29: 
        !            30: #ifndef KERNEL
        !            31: #ifdef SHLIB
        !            32: #import "shlib.h"
        !            33: #endif SHLIB
        !            34: 
        !            35: #import <mach/mach.h>
        !            36: 
        !            37: #import "NXStringPrivate.h"
        !            38: #import <streams/streams.h>
        !            39: #import <streams/streamsextra.h>
        !            40: #import <stdio.h>
        !            41: #import "error.h"
        !            42: 
        !            43: /* Separate zone for ref counted strings... */
        !            44: static NXZone *theStringZone = NULL;
        !            45: 
        !            46: NXZone *_NXStringZone (void)
        !            47: {
        !            48:   return theStringZone;
        !            49: }
        !            50: 
        !            51: static void objectPrintfProc(NXStream *stream, void *item, void *procData)
        !            52: {
        !            53:     if ([(id)item respondsTo:@selector(writeToStream:)]) {
        !            54:        [(id)item writeToStream:stream];
        !            55:     } else {
        !            56:        NXPutc(stream, '%'); NXPutc(stream, '@');
        !            57:     }
        !            58: }
        !            59: 
        !            60: void _NXStringErrorRaise (int errorCode, const char *errorMsg)
        !            61: {
        !            62:     extern void _NXLogError(const char *format, ...);
        !            63:     _NXLogError( "NXString error %d: %s", errorCode, errorMsg);
        !            64:     NX_RAISE (errorCode, errorMsg, 0);
        !            65: }
        !            66: 
        !            67: 
        !            68: @implementation NXString
        !            69: 
        !            70: + initialize
        !            71: {
        !            72:     if (theStringZone == NULL) {
        !            73: #if 1
        !            74:        /* Using a separate string zone seems to hurt more than it helps now.
        !            75:           ??? However, we need to solve the copyFromZone: problem... */
        !            76:        theStringZone = NXDefaultMallocZone();
        !            77: #else
        !            78:        theStringZone = NXCreateZone(vm_page_size, vm_page_size, YES);
        !            79:        NXNameZone (theStringZone, "String Zone");
        !            80: #endif
        !            81:        NXRegisterPrintfProc('@', objectPrintfProc, NULL);
        !            82:     }
        !            83:     return self;
        !            84: }
        !            85: 
        !            86: - (unichar *)allocateCharacterBuffer:(unsigned)nChars
        !            87: {
        !            88:     return NX_CHARALLOC([self zone], nChars);
        !            89: }
        !            90: 
        !            91: - initFromCharactersNoCopy:(unichar *)chars length:(unsigned)len
        !            92: {
        !            93:     return [super init];
        !            94: }
        !            95: 
        !            96: - init
        !            97: {
        !            98:     return [self initFromCharactersNoCopy:NULL length:0];
        !            99: }
        !           100: 
        !           101: - initFromCharacters:(const unichar *)chars length:(unsigned)len;
        !           102: {
        !           103:     unichar *buffer = [self allocateCharacterBuffer:len];
        !           104:     NX_CHARCOPY (chars, buffer, len);
        !           105:     return [self initFromCharactersNoCopy:buffer length:len];
        !           106: }
        !           107: 
        !           108: - initFromString:string
        !           109: {
        !           110:     NXRange range = {0, [string length]};
        !           111:     return [self initFromString:string range:range];
        !           112: }
        !           113: 
        !           114: - initFromString:string range:(NXRange)range
        !           115: {
        !           116:     unichar *buffer = [self allocateCharacterBuffer:RNGLEN(range)];
        !           117:     [string getCharacters:buffer range:range];
        !           118:     return [self initFromCharactersNoCopy:buffer length:RNGLEN(range)];
        !           119: }
        !           120: 
        !           121: // The starting size for the buffer when reading from a stream, if no other clues about the desired size
        !           122: // or the stream size are provided...
        !           123: 
        !           124: #define INITIALLENGTH 16
        !           125: 
        !           126: - initFromStream:(NXStream *)stream untilOneOf:(NXCharacterSet *)set maxLength:(unsigned int)maxLen
        !           127: {
        !           128: #if CHARS_ARE_EIGHT_BIT
        !           129:     return [self initFromCStringStream:stream untilOneOf:set maxLength:maxLen];
        !           130: #else
        !           131: #warning initFromStream:untilOneOf:maxLength: not implemented for Unicode
        !           132:     _NXStringErrorRaise (NXStringInternalError, "initFromStream:untilOneOf:maxLength: not implemented for Unicode");
        !           133:     return nil;
        !           134: #endif
        !           135: }
        !           136: 
        !           137: - initFromCStringStream:(NXStream *)stream untilOneOf:(NXCharacterSet *)set maxLength:(unsigned int)maxLen
        !           138: {
        !           139:     volatile unsigned int readLen = 0;
        !           140:     volatile unsigned int charsLen = MIN(maxLen, INITIALLENGTH);
        !           141:     unichar *volatile chars = NULL;
        !           142:     int chRead;
        !           143:    
        !           144:     if (stream->flags & NX_CANSEEK) {  // Try to fine tune the initial buffer size
        !           145: 
        !           146:        long curLoc = NXTell(stream);
        !           147:        if (!set) {             // If no set, then length is determined by maxLen or stream size
        !           148:            NXSeek (stream, 0, NX_FROMEND);
        !           149:            charsLen = (NXTell(stream) - curLoc);
        !           150:            if (charsLen > maxLen) charsLen = maxLen;
        !           151:        } else {                // Otherwise we have to look at every character to determine how many we'll read
        !           152:            charsLen = 0;
        !           153:            while (!NXAtEOS(stream) && (charsLen < maxLen) && ![set characterIsMember:(unichar)NXGetc(stream)]) charsLen++;
        !           154:        }
        !           155:        NXSeek (stream, curLoc, NX_FROMSTART);
        !           156:        
        !           157:     }
        !           158: 
        !           159:     if ((chars = [self allocateCharacterBuffer:charsLen])) {
        !           160:     
        !           161:        NX_DURING
        !           162:     
        !           163:            // Seems like AtEOS is set after we attempt to read the last character.
        !           164:            // ??? Thus the !NXAtEOS is pretty useless down here...
        !           165:        
        !           166:            while (!NXAtEOS(stream) && (readLen < maxLen) && ((chRead = NXGetc(stream)) != EOF)) {
        !           167:                unichar ch = (unichar)chRead;
        !           168:                if (set && [set characterIsMember:ch]) {
        !           169:                    NXUngetc(stream);
        !           170:                    break;
        !           171:                }
        !           172:                if (charsLen == readLen) {
        !           173:                    unichar *newChars;
        !           174:                    if ((charsLen *= 2) > maxLen) charsLen = maxLen;
        !           175:                    newChars = [self allocateCharacterBuffer:charsLen];
        !           176:                    NX_CHARCOPY ((unichar *)chars, newChars, readLen);
        !           177:                    free ((unichar *)chars);
        !           178:                    chars = newChars;
        !           179:                }
        !           180:                chars[readLen++] = ch;
        !           181:            }
        !           182:     
        !           183:        NX_HANDLER
        !           184: 
        !           185:            free ((unichar *)chars);
        !           186:            NX_RERAISE ();
        !           187:     
        !           188:        NX_ENDHANDLER
        !           189: 
        !           190:     }
        !           191: 
        !           192:     return [self initFromCharactersNoCopy:(unichar *)chars length:readLen];
        !           193: }
        !           194: 
        !           195: - initFromFormat:(NXString *)format, ...
        !           196: {
        !           197:     va_list argList;
        !           198: 
        !           199:     va_start (argList, format);
        !           200:     self = [self initFromFormat:format withArgList:argList];
        !           201:     va_end (argList);
        !           202:     
        !           203:     return self;
        !           204: }
        !           205: 
        !           206: - initFromFormat:(NXString *)format withArgList:(va_list)argList
        !           207: {
        !           208:     int maxLen, len;
        !           209:     unsigned formatLen = [format cStringLength] + 1;   // Including terminating zero
        !           210:     char *bytes;
        !           211:     NXStream *stream = NXOpenSmallMemory(NX_WRITEONLY);
        !           212:     char tmpBuf[MAXTMPBUFFERLEN], *formatChars;
        !           213: 
        !           214:     formatChars = (formatLen > MAXTMPBUFFERLEN) ? NXZoneMalloc(NXDefaultMallocZone(), formatLen * sizeof(char)) : tmpBuf;
        !           215:     [format getCString:formatChars];
        !           216:     NXVPrintf(stream, formatChars, argList);
        !           217:     NXFlush(stream);
        !           218:     NXGetMemoryBuffer(stream, &bytes, &len, &maxLen);
        !           219:     self = [self initFromCString:bytes length:len];
        !           220:     NXCloseMemory(stream, NX_FREEBUFFER);
        !           221:     if (formatChars != tmpBuf) free(formatChars);
        !           222: 
        !           223:     return self;
        !           224: }
        !           225: 
        !           226: 
        !           227: /* Byte oriented methods */
        !           228: 
        !           229: - initFromCString:(const char *)bytes
        !           230: {
        !           231:     return [self initFromCString:bytes length:strlen(bytes)];
        !           232: }
        !           233: 
        !           234: - initFromCString:(const char *)bytes length:(unsigned)length
        !           235: {
        !           236:     unichar *buffer = NULL;
        !           237:     unsigned cnt;
        !           238: 
        !           239:     if (length && bytes && *bytes) {
        !           240:         buffer = [self allocateCharacterBuffer:length];
        !           241:         for (cnt = 0; cnt < length; cnt++) {
        !           242:             buffer[cnt] = bytes[cnt];
        !           243:         }
        !           244:     }
        !           245:     return [self initFromCharactersNoCopy:buffer length:length];
        !           246: }
        !           247: 
        !           248: - (void)getCString:(char *)buffer
        !           249: {
        !           250:     [self getCString:buffer maxLength:NX_MAX_STRING_LENGTH range:(NXRange){0, [self length]} remainingRange:NULL];
        !           251: }
        !           252: 
        !           253: - (void)getCString:(char *)buffer maxLength:(unsigned)bytes
        !           254: {
        !           255:     [self getCString:buffer maxLength:bytes range:(NXRange){0, [self length]} remainingRange:NULL];
        !           256: }    
        !           257: 
        !           258: - (void)getCString:(char *)buffer maxLength:(unsigned)bytes range:(NXRange)range remainingRange:(NXRange *)leftover
        !           259: {
        !           260: #if CHARS_ARE_EIGHT_BIT
        !           261:     NXRange desiredRange = range;
        !           262: 
        !           263:     if (RNGLEN(range) > bytes) RNGLEN(range) = bytes;
        !           264:     [self getCharacters:(unichar *)buffer range:range];
        !           265:     buffer[RNGLEN(range)] = 0;
        !           266: 
        !           267:     if (leftover) {
        !           268:        RNGLOC(*leftover) = RNGLOC(desiredRange) + RNGLEN(range);
        !           269:        RNGLEN(*leftover) = RNGLEN(desiredRange) - RNGLEN(range);
        !           270:     }
        !           271: #else
        !           272: #warning getCString:maxLength:range:remainingRange: not implemented for Unicode
        !           273:     _NXStringErrorRaise (NXStringInternalError, "getCString:maxLength:range:remainingRange: not implemented for Unicode");
        !           274: #if 0
        !           275:     NXRange processedRange;
        !           276:     unichar tmpBuf[MAXTMPBUFFERLEN];
        !           277:     unsigned uCnt = 0, cCnt = 0;
        !           278:     
        !           279:     if (RNGLOC(range) + RNGLEN(range) > [self length]) BOUNDSERROR;
        !           280: 
        !           281:     processedRange = range;
        !           282:     if (RNGLEN(processedRange) > MAXTMPBUFFERLEN) RNGLEN(processedRange) = MAXTMPBUFFERLEN;
        !           283: 
        !           284:     [self getCharacters:tmpBuf range:range];
        !           285: 
        !           286:     while (uCnt < RNGLEN(range)) {
        !           287:        unichar ch = uStr[RNGLOC(range) + uCnt];
        !           288:        if (cCnt < bytes) {     // ??? This check will have to be smarter
        !           289:            buffer[cCnt] = (ch > 0x0ff) ? NX_BADBYTE : ch;
        !           290:        } else {
        !           291:            break;
        !           292:        }
        !           293:        uCnt++;
        !           294:        cCnt++;
        !           295:     }
        !           296:     buffer[cCnt] = 0;
        !           297: #endif
        !           298: #endif
        !           299: }
        !           300: 
        !           301: - (unsigned)length
        !           302: {
        !           303:     [self subclassResponsibility:_cmd];
        !           304:     return 0;
        !           305: }
        !           306: 
        !           307: - (unsigned)cStringLength
        !           308: {
        !           309: #if CHARS_ARE_EIGHT_BIT
        !           310:     return [self length];
        !           311: #else
        !           312: #warning cStringLength not implemented for Unicode
        !           313:     _NXStringErrorRaise (NXStringInternalError, "cStringLength not implemented for Unicode");
        !           314:     return 0;
        !           315: #endif
        !           316: }
        !           317: 
        !           318: - (char *)cStringCopy
        !           319: {
        !           320:     char *str = NX_BYTEALLOC (NXDefaultMallocZone(), [self cStringLength] + 1);
        !           321:     [self getCString:str];
        !           322:     return str;
        !           323: }
        !           324: 
        !           325: - (NXAtom)uniqueCStringCopy
        !           326: {
        !           327:     char tmpBuf[MAXTMPBUFFERLEN], *str;
        !           328:     NXAtom unique;
        !           329:     unsigned int len = [self cStringLength] + 1;
        !           330:     
        !           331:     str = (len > MAXTMPBUFFERLEN) ? NX_BYTEALLOC(NXDefaultMallocZone(), len) : tmpBuf;
        !           332:     [self getCString:str];
        !           333:     unique = NXUniqueString (str);
        !           334:     if (str != tmpBuf) free (str);    
        !           335: 
        !           336:     return unique;
        !           337: }
        !           338: 
        !           339: - (unichar)characterAt:(unsigned)pos
        !           340: {
        !           341:     [self subclassResponsibility:_cmd];
        !           342:     return 0;
        !           343: }
        !           344: 
        !           345: - (void)getCharacters:(unichar *)buffer range:(NXRange)range
        !           346: {
        !           347:     unsigned int cnt;
        !           348:     
        !           349:     for (cnt = 0; cnt < RNGLEN(range); cnt++) {
        !           350:         buffer[cnt] = [self characterAt:RNGLOC(range) + cnt];
        !           351:     }
        !           352: }
        !           353: 
        !           354: - (void)getCharacters:(unichar *)buffer
        !           355: {
        !           356:     NXRange range = {0, [self length]};
        !           357:     [self getCharacters:buffer range:range];
        !           358: }
        !           359: 
        !           360: /* Comparision and find stuff */
        !           361: 
        !           362: // Compare the two character strings (whose lengths are given in firstLen & secondLen)
        !           363: // according to the flags in flagMask.
        !           364: 
        !           365: // ??? Unicode string compares work differently: As characters are compared and found to be unequal,
        !           366: // they are normalized. Thus if "o" and "O" are compared and found unequal, they are normalized
        !           367: // (depending on flagMask), and compared again. This normalization might include case conversion,
        !           368: // floating diacritics, etc.
        !           369: 
        !           370: NXComparisonResult NXCompareCharacters (const unichar *first, const unichar *second, unsigned firstLen, unsigned secondLen, unsigned flagMask, void *table)
        !           371: {
        !           372:     unsigned cnt = 0, compareLen = MIN(firstLen, secondLen);
        !           373:     BOOL caseInsensitive = (flagMask & NX_CASE_INSENSITIVE) ? YES : NO;
        !           374: 
        !           375:     while (cnt < compareLen) {
        !           376:        unichar ch1 = first[cnt], ch2 = second[cnt];
        !           377:        if (caseInsensitive) {  // Don't worry about unrolling this into two loops...
        !           378:            if (ch1 >= 'a' && ch1 <= 'z') ch1 += 'A' - 'a';
        !           379:            if (ch2 >= 'a' && ch2 <= 'z') ch2 += 'A' - 'a';
        !           380:        }
        !           381:        if (ch1 < ch2) return NX_OrderedAscending;
        !           382:        else if (ch1 > ch2) return NX_OrderedDescending;
        !           383:        else cnt++;
        !           384:     }
        !           385:     return (firstLen < secondLen) ? NX_OrderedAscending : ((firstLen > secondLen) ? NX_OrderedDescending : NX_OrderedSame);
        !           386: }
        !           387: 
        !           388: // Find findStr of len findStrLen in inStr of inStrLen. If flagMask contains NX_BACKWARDS_SEARCH,
        !           389: // then look at inStr starting from the last valid character.
        !           390: // See Unicode related warning under NXCompareCharacters().
        !           391: 
        !           392: NXRange NXFindCharacters (const unichar *findStr, const unichar *inStr, unsigned findStrLen, unsigned inStrLen, unsigned flagMask, void *table)
        !           393: {
        !           394:     int step;
        !           395:     unsigned fromLoc, toLoc, cnt;      // fromLoc and toLoc are inclusive
        !           396:     BOOL found = NO, done = NO;
        !           397:     BOOL caseInsensitive = (flagMask & NX_CASE_INSENSITIVE) ? YES : NO;
        !           398:     NXRange range = {NX_STRING_NOT_FOUND, 0};
        !           399: 
        !           400:     if (findStrLen > inStrLen) {       // ??? This can't be here for correct Unicode compares
        !           401:        return range;
        !           402:     }
        !           403:     
        !           404:     if (flagMask & NX_BACKWARDS_SEARCH) {
        !           405:         fromLoc = inStrLen - findStrLen;       // Inclusive
        !           406:         toLoc = 0;
        !           407:     } else {       
        !           408:         fromLoc = 0;
        !           409:         toLoc = inStrLen - findStrLen;         // Inclusive
        !           410:     }
        !           411: 
        !           412:     step = (fromLoc <= toLoc) ? 1 : -1;
        !           413:     cnt = fromLoc;
        !           414:     do {
        !           415:         unsigned int chCnt;
        !           416:         for (chCnt = 0; chCnt < findStrLen; chCnt++) {
        !           417:            unichar ch1 = findStr[chCnt], ch2 = inStr[chCnt + cnt];
        !           418:            if (caseInsensitive) {
        !           419:                if (ch1 >= 'a' && ch1 <= 'z') ch1 += 'A' - 'a';
        !           420:                if (ch2 >= 'a' && ch2 <= 'z') ch2 += 'A' - 'a';
        !           421:            }
        !           422:             if (ch1 != ch2) {
        !           423:                 break;
        !           424:             }
        !           425:         }
        !           426:         if (chCnt == findStrLen) {
        !           427:             found = done = YES;
        !           428:            RNGLOC(range) = cnt;
        !           429:            RNGLEN(range) = findStrLen;
        !           430:         } else if (cnt == toLoc) {
        !           431:            done = YES;
        !           432:        } else {
        !           433:             cnt += step;
        !           434:         }
        !           435:     } while (!done);
        !           436: 
        !           437:     return range;
        !           438: }
        !           439: 
        !           440: unsigned NXHashCharacters(const unichar *characters, unsigned length)
        !           441: {
        !           442:     unsigned int h = length, cnt;
        !           443: 
        !           444:     if (length > MAXSTRINGLENFORHASHING) {
        !           445:        length = MAXSTRINGLENFORHASHING;
        !           446:     }
        !           447:     
        !           448:     for (cnt = 0; cnt < length; cnt++) {
        !           449:        h <<= 4;
        !           450:        h += (unsigned int)characters[cnt];
        !           451:        h ^= (h >> 24);
        !           452:     }
        !           453:     
        !           454:     return h;
        !           455: }
        !           456: 
        !           457: - (BOOL)isEqual:string
        !           458: {
        !           459:     static Class stringClass = Nil;
        !           460:     
        !           461:     if (stringClass == Nil) stringClass = [NXString class];
        !           462:     
        !           463:     return (self == string) ||
        !           464:        ([string isKindOf: stringClass] &&
        !           465: #if CHARS_ARE_EIGHT_BIT
        !           466:         ([self cStringLength] == [string cStringLength]) &&
        !           467: #endif
        !           468:         ([self compare:string] == NX_OrderedSame));
        !           469: }
        !           470: 
        !           471: - (NXComparisonResult)compare:string
        !           472: {
        !           473:     return [self compare:string mask:0 table:NULL];
        !           474: }
        !           475: 
        !           476: - (NXComparisonResult)compare:string mask:(unsigned int)options table:(void *)table
        !           477: {
        !           478:     if (![string isKindOf:[NXString class]]) {
        !           479:        return NX_OrderedAscending;     // ???
        !           480:     } else {
        !           481:        unsigned ownLength = [self length], otherLength = [string length];
        !           482:        unichar ownBuffer[COMPARELENGTH], otherBuffer[COMPARELENGTH];
        !           483:        NXRange ownRange = {0, 0}, otherRange = {0, 0};
        !           484:        NXComparisonResult res = NX_OrderedSame;
        !           485:     
        !           486:        while (1) {
        !           487:            RNGLEN(ownRange) = MIN(ownLength - RNGLOC(ownRange), COMPARELENGTH);        
        !           488:            RNGLEN(otherRange) = MIN(otherLength - RNGLOC(otherRange), COMPARELENGTH);  
        !           489:            if (RNGLEN(ownRange) == 0 && RNGLEN(otherRange) == 0) return NX_OrderedSame;
        !           490:            [self getCharacters:ownBuffer range:ownRange];
        !           491:            [string getCharacters:otherBuffer range:otherRange];
        !           492:            if ((res = NXCompareCharacters(ownBuffer, otherBuffer, RNGLEN(ownRange), RNGLEN(otherRange), options, table)) != NX_OrderedSame) return res;
        !           493:            RNGLOC(ownRange) += RNGLEN(ownRange);
        !           494:            RNGLOC(otherRange) += RNGLEN(otherRange);
        !           495:        }
        !           496:     }
        !           497: }
        !           498: 
        !           499: - (NXRange)findString:(NXString *)string
        !           500: {
        !           501:     NXRange range = {0, [self length]};
        !           502:     return [self findString:string range:range mask:0 table:NULL];
        !           503: }
        !           504: 
        !           505: - (NXRange)findString:(NXString *)findStr range:(NXRange)fRange mask:(unsigned int)options table:(void *)table
        !           506: {
        !           507:     int step;
        !           508:     unsigned fromLoc, toLoc, cnt, findStrLen, len;     // fromLoc and toLoc are inclusive
        !           509:     BOOL found = NO, done = NO;
        !           510:     BOOL caseInsensitive = (options & NX_CASE_INSENSITIVE) ? YES : NO;
        !           511:     NXRange range = {NX_STRING_NOT_FOUND, 0};
        !           512:     unichar tmpBuf[MAXTMPBUFFERLEN], *findBuf;
        !           513: 
        !           514:     findStrLen = [findStr length];
        !           515:     len = [self length];
        !           516: 
        !           517:     if (findStrLen > RNGLEN(fRange)) { // ??? This can't be here for correct Unicode compares
        !           518:        return range;
        !           519:     }
        !           520:     
        !           521:     findBuf = (findStrLen > MAXTMPBUFFERLEN) ? NX_CHARALLOC(NXDefaultMallocZone(), findStrLen) : tmpBuf;
        !           522:     [findStr getCharacters:findBuf];
        !           523:       
        !           524:     if (options & NX_BACKWARDS_SEARCH) {
        !           525:         fromLoc = RNGLOC(fRange) + RNGLEN(fRange) - findStrLen;
        !           526:         toLoc = RNGLOC(fRange);
        !           527:     } else {       
        !           528:         fromLoc = RNGLOC(fRange);
        !           529:         toLoc = RNGLOC(fRange) + RNGLEN(fRange) - findStrLen;
        !           530:     }
        !           531: 
        !           532:     step = (fromLoc <= toLoc) ? 1 : -1;
        !           533:     cnt = fromLoc;
        !           534:     do {
        !           535:         unsigned int chCnt;
        !           536:         for (chCnt = 0; chCnt < findStrLen; chCnt++) {
        !           537:            unichar ch1 = findBuf[chCnt], ch2 = [self characterAt:chCnt + cnt];
        !           538:            if (caseInsensitive) {
        !           539:                if (ch1 >= 'a' && ch1 <= 'z') ch1 += 'A' - 'a';
        !           540:                if (ch2 >= 'a' && ch2 <= 'z') ch2 += 'A' - 'a';
        !           541:            }
        !           542:             if (ch1 != ch2) {
        !           543:                 break;
        !           544:             }
        !           545:         }
        !           546:         if (chCnt == findStrLen) {
        !           547:             found = done = YES;
        !           548:            RNGLOC(range) = cnt;
        !           549:            RNGLEN(range) = findStrLen;
        !           550:         } else if (cnt == toLoc) {
        !           551:            done = YES;
        !           552:        } else {
        !           553:             cnt += step;
        !           554:         }
        !           555:     } while (!done);
        !           556: 
        !           557:     if (findBuf != tmpBuf) free(findBuf);
        !           558: 
        !           559:     return range;
        !           560: }
        !           561: 
        !           562: - (unsigned)findCharacter:(unichar)ch
        !           563: {
        !           564:     NXRange range = {0, [self length]};
        !           565:     return [self findCharacter:ch range:range mask:0 table:NULL];
        !           566: }
        !           567: 
        !           568: - (unsigned)findCharacter:(unichar)ch range:(NXRange)fRange mask:(unsigned int)options table:(void *)table
        !           569: {
        !           570:     NXString *string = [[NXReadOnlyString alloc] initFromCharactersNoCopy:&ch length:1 freeWhenDone:NO];
        !           571:     NXRange result = [self findString:string range:fRange mask:options table:NULL];
        !           572:     [string free];
        !           573:     return RNGLOC(result);
        !           574: }
        !           575: 
        !           576: - (unsigned)findOneOf:(NXCharacterSet *)set
        !           577: {
        !           578:     NXRange range = {0, [self length]};
        !           579:     return [self findOneOf:set range:range mask:0 table:NULL];
        !           580: }
        !           581: 
        !           582: // ??? How should we deal with the CASEINSENSITIVE flag? Probably we shouldn't care...
        !           583: 
        !           584: - (unsigned)findOneOf:(NXCharacterSet *)set range:(NXRange)fRange mask:(unsigned int)options table:(void *)table
        !           585: {
        !           586:     int step;
        !           587:     unsigned fromLoc, toLoc, cnt, len; // fromLoc and toLoc are inclusive
        !           588:     BOOL found = NO, done = NO;
        !           589: 
        !           590:     len = [self length];
        !           591: 
        !           592:     if (options & NX_BACKWARDS_SEARCH) {
        !           593:         fromLoc = RNGLOC(fRange) + RNGLEN(fRange) - 1;
        !           594:         toLoc = RNGLOC(fRange);
        !           595:     } else {       
        !           596:         fromLoc = RNGLOC(fRange);
        !           597:         toLoc = RNGLOC(fRange) + RNGLEN(fRange) - 1;
        !           598:     }
        !           599: 
        !           600:     step = (fromLoc <= toLoc) ? 1 : -1;
        !           601:     cnt = fromLoc;
        !           602:  
        !           603:     do {
        !           604:         unichar ch = [self characterAt:cnt];
        !           605:        if ([set characterIsMember:ch]) {
        !           606:            done = found = YES;
        !           607:         } else if (cnt == toLoc) {
        !           608:            done = YES;
        !           609:        } else {
        !           610:             cnt += step;
        !           611:         }
        !           612:     } while (!done);
        !           613: 
        !           614:     return found ? cnt : NX_STRING_NOT_FOUND;
        !           615: }
        !           616: 
        !           617: - (unsigned)hash
        !           618: {
        !           619:     unichar buffer[MAXSTRINGLENFORHASHING];
        !           620:     unsigned len = MIN([self length], MAXSTRINGLENFORHASHING);
        !           621:     NXRange range = {0, len};
        !           622:     
        !           623:     [self getCharacters:buffer range:range];
        !           624:     return NXHashCharacters(buffer, [self length]);
        !           625: }
        !           626: 
        !           627: - (NXString *)copySubstring:(NXRange)range
        !           628: {
        !           629:     return [self copySubstring:range fromZone:[self zone]];
        !           630: }
        !           631: 
        !           632: - (NXString *)copySubstring:(NXRange)range fromZone:(NXZone *)zone
        !           633: {
        !           634:     if (RNGLOC(range) + RNGLEN(range) > [self length]) BOUNDSERROR;
        !           635:     if (RNGLOC(range) == 0 && RNGLEN(range) == [self length]) {
        !           636:        return [self copyFromZone:zone];
        !           637:     } else {
        !           638:        id newObject = [[self class] allocFromZone:zone];
        !           639:        unichar *chars = [newObject allocateCharacterBuffer:RNGLEN(range)];
        !           640:        [self getCharacters:chars range:range];
        !           641:        return [newObject initFromCharactersNoCopy:chars length:RNGLEN(range)];
        !           642:     }
        !           643: }
        !           644: 
        !           645: - immutableCopy
        !           646: {
        !           647:     return [self immutableCopyFromZone:[self zone]];
        !           648: }
        !           649: 
        !           650: - immutableCopyFromZone:(NXZone *)zone
        !           651: {
        !           652:     return [self copyFromZone:zone];
        !           653: }
        !           654: 
        !           655: - mutableCopy
        !           656: {
        !           657:     return [self mutableCopyFromZone:[self zone]];
        !           658: }
        !           659: 
        !           660: - mutableCopyFromZone:(NXZone *)zone
        !           661: {
        !           662:     return [[NXReadWriteString allocFromZone:zone] initFromString:self];
        !           663: }
        !           664: 
        !           665: - (void)writeToStream:(NXStream *)stream
        !           666: {
        !           667: #if CHARS_ARE_EIGHT_BIT
        !           668:     [self writeCStringToStream:stream];
        !           669: #else
        !           670: #warning writeToStream: not implemented for Unicode
        !           671:     _NXStringErrorRaise (NXStringInternalError, "writeToStream: not implemented for Unicode");
        !           672: #endif
        !           673: }
        !           674: 
        !           675: #define WRITEBUFFERLEN 1024
        !           676: 
        !           677: - (void)writeCStringToStream:(NXStream *)stream
        !           678: {
        !           679:     char buf[WRITEBUFFERLEN+1];
        !           680:     NXRange range = {0, [self length]};
        !           681: 
        !           682:     while (RNGLEN(range) > 0) {
        !           683:        NXRange remainingRange;
        !           684:        [self getCString:buf maxLength:WRITEBUFFERLEN range:range remainingRange:&remainingRange];
        !           685:        NXWrite (stream, buf, NX_LENGTH(range) - NX_LENGTH(remainingRange));
        !           686:        range = remainingRange;
        !           687:     }
        !           688: }
        !           689: 
        !           690: - (void)printForDebugger:(NXStream *)stream
        !           691: {
        !           692:     unsigned int cnt, length = [self length];
        !           693:     
        !           694:     NXPrintf (stream, "%s, length %d: ", [[self class] name], length);
        !           695:     
        !           696:     for (cnt = 0; cnt < length; cnt++) {
        !           697:         unichar ch = [self characterAt:cnt];
        !           698:        NXPrintf (stream, (ch >= ' ' && ch < 127) ? "%c" : "<0x%x>", ch);
        !           699:     }
        !           700:     NXFlush (stream);
        !           701: }
        !           702: 
        !           703: #define TOOLONGLIMIT 200
        !           704: #define EACHSECTION 80
        !           705: 
        !           706: - (void)_print
        !           707: {
        !           708:     unsigned int cnt = 0, length = [self length], breakAt = (length > TOOLONGLIMIT) ? EACHSECTION : UINT_MAX;
        !           709:     
        !           710:     fprintf (stderr, "%s, length %d: ", [[self class] name], length);
        !           711:     
        !           712:     while (cnt < length) {
        !           713:         unichar ch = [self characterAt:cnt];
        !           714:        fprintf (stderr, (ch >= ' ' && ch < 127) ? "%c" : "<0x%x>", ch);
        !           715:        if (++cnt == breakAt) {
        !           716:            cnt = length - EACHSECTION;
        !           717:            fprintf (stderr, "...");
        !           718:        }
        !           719:     }
        !           720:     fprintf (stderr, "\n");
        !           721: }
        !           722: 
        !           723: 
        !           724: #ifndef DONT_USE_OLD_NXSTRING_NAMES
        !           725: 
        !           726: /* Compatibility stuff. These are 2.x/3.0 methods which should be preserved for 3.x but removed in 4.0.
        !           727: */
        !           728: 
        !           729: - initFromStream:(NXStream *)stream uptoLength:(unsigned)length orUntilOneOf:(NXCharacterSet *)set
        !           730: {
        !           731:     return [self initFromStream:stream untilOneOf:set maxLength:length];
        !           732: }
        !           733: 
        !           734: - initFromByteStream:(NXStream *)stream uptoLength:(unsigned)length orUntilOneOf:(NXCharacterSet *)set
        !           735: {
        !           736:     return [self initFromCStringStream:stream untilOneOf:set maxLength:length];
        !           737: }
        !           738: 
        !           739: - (void)getCString:(char *)buffer range:(NXStringRange)range
        !           740: {
        !           741:     [self getCString:buffer maxLength:NX_MAX_STRING_LENGTH range:range remainingRange:NULL];
        !           742: }
        !           743: 
        !           744: - (void)getCString:(char *)buffer length:(unsigned)bytes
        !           745: {
        !           746:     [self getCString:buffer maxLength:bytes];
        !           747: }
        !           748: 
        !           749: - (void)getCString:(char *)buffer length:(unsigned)bytes range:(NXStringRange)range
        !           750: {
        !           751:     [self getCString:buffer maxLength:bytes range:range remainingRange:NULL];
        !           752: }
        !           753: 
        !           754: - (NXComparisionResult)compare:(NXString *)string mask:(unsigned int)options
        !           755: {
        !           756:     return [self compare:string mask:options table:NULL];
        !           757: }
        !           758: 
        !           759: - (NXComparisionResult)compare:(NXString *)string mask:(unsigned int)options usingTable:(void *)table
        !           760: {
        !           761:     return [self compare:string mask:options table:table];    
        !           762: }
        !           763: 
        !           764: - (NXStringRange)find:(NXString *)string
        !           765: {
        !           766:     return [self findString:string];
        !           767: }
        !           768: 
        !           769: - (NXStringRange)find:(NXString *)string range:(NXStringRange)range
        !           770: {
        !           771:     return [self findString:string range:range mask:0 table:NULL];
        !           772: }
        !           773: 
        !           774: - (NXStringRange)find:(NXString *)string mask:(unsigned int)options
        !           775: {
        !           776:     return [self findString:string range:(NXRange){0, [self length]} mask:options table:NULL];
        !           777: } 
        !           778: 
        !           779: - (NXStringRange)find:(NXString *)string range:(NXStringRange)range mask:(unsigned int)options usingTable:(void *)table
        !           780: {
        !           781:     return [self findString:string range:range mask:options table:table];
        !           782: }
        !           783: 
        !           784: - (unsigned)findOneOf:(NXCharacterSet *)set range:(NXStringRange)range
        !           785: {
        !           786:     return [self findOneOf:set range:range mask:0 table:NULL];
        !           787: }
        !           788: 
        !           789: - (unsigned)findOneOf:(NXCharacterSet *)set mask:(unsigned int)options
        !           790: {
        !           791:     return [self findOneOf:set range:(NXRange){0, [self length]} mask:options table:NULL];
        !           792: }
        !           793: 
        !           794: - (unsigned)findOneOf:(NXCharacterSet *)set range:(NXStringRange)range mask:(unsigned int)options usingTable:(void *)table
        !           795: {
        !           796:     return [self findOneOf:set range:range mask:options table:table];
        !           797: }
        !           798: 
        !           799: - (unsigned)findCharacter:(unichar)ch range:(NXStringRange)range
        !           800: {
        !           801:     return [self findCharacter:ch range:range mask:0 table:NULL];
        !           802: }
        !           803: 
        !           804: - (unsigned)findCharacter:(unichar)ch mask:(unsigned int)options
        !           805: {
        !           806:     return [self findCharacter:ch range:(NXRange){0, [self length]} mask:options table:NULL];
        !           807: }
        !           808: 
        !           809: - (unsigned)findCharacter:(unichar)ch range:(NXStringRange)range mask:(unsigned int)options usingTable:(void *)table
        !           810: {
        !           811:     return [self findCharacter:ch range:range mask:options table:table];
        !           812: }
        !           813: 
        !           814: - (unichar *)createCharacterBuffer:(unsigned)nChars
        !           815: {
        !           816:     return [self allocateCharacterBuffer:nChars];
        !           817: }
        !           818: 
        !           819: - (void)writeBytesToStream:(NXStream *)stream
        !           820: {
        !           821:     return [self writeCStringToStream:stream];
        !           822: }
        !           823: 
        !           824: #endif DONT_USE_OLD_NXSTRING_NAMES
        !           825: 
        !           826: @end
        !           827: #endif /* KERNEL */

unix.superglobalmegacorp.com

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