Annotation of objc/NXString.m, revision 1.1.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.