/* Implementation of composite character sequence functions for GNUSTEP Copyright (C) 1999 Free Software Foundation, Inc. Written by: Richard Frith-Macdonald Date: May 1999 Based on code by: Stevo Crvenkovski Date: March 1997 This file is part of the GNUstep Base Library. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111 USA. */ /* * Warning - this contains hairy code - handle with care. * The first part of this file contains variable and constant definitions * plus inline function definitions for handling sequences of unicode * characters. It is bracketed in preprocessor conditionals so that it * is only ever included once. * The second part of the file contains inline function definitions that * are designed to be modified depending on the defined macros at the * point where they are included. This is meant to be included multiple * times so the same code can be used for NSString, and subclasses. */ #ifndef __GSeq_h_GNUSTEP_GSEQ_BASE_INCLUDE #define __GSeq_h_GNUSTEP_GSEQ_BASE_INCLUDE /* * Some standard selectors for frequently used methods. Set in NSString * +initialize or the GSString.m setup() function. */ static SEL caiSel = NULL; static SEL gcrSel = NULL; static SEL ranSel = NULL; /* * The maximum decompostion level for composite unicode characters. */ #define MAXDEC 18 /* * The structure definition for handling a unicode character sequence * for a single character. */ typedef struct { unichar *chars; NSUInteger count; NSUInteger capacity; BOOL normalized; } GSeqStruct; typedef GSeqStruct *GSeq; /* * A macro to define a GSeqStruct variable capable of holding a * unicode character sequence of the specified length. */ #define GSEQ_MAKE(BUF, SEQ, LEN) \ unichar BUF[LEN * MAXDEC + 1]; \ GSeqStruct SEQ = { BUF, LEN, LEN * MAXDEC, 0 } /* * A function to normalize a unicode character sequence ... produces a * sequence containing composed characters in a well defined order and * with a nul terminator as well as a character count. */ static inline void GSeq_normalize(GSeq seq) { NSUInteger count = seq->count; if (count) { unichar *source = seq->chars; unichar target[count*MAXDEC+1]; NSUInteger base = 0; /* * Pre-scan ... anything with a code under 0x00C0 is not a decomposable * character, so we don't need to expand it. * If there are no decomposable characters or composed sequences, the * sequence is already normalised and we don't need to make any changes. */ while (base < count) { if (source[base] >= 0x00C0) { break; } base++; } source[count] = (unichar)(0); if (base < count) { /* * Now expand decomposable characters into the long format. * Use the 'base' value to avoid re-checking characters which have * already been expanded. */ while (base < count) { unichar *spoint = &source[base]; unichar *tpoint = &target[base]; NSUInteger newbase = 0; do { unichar *dpoint = uni_is_decomp(*spoint); if (!dpoint) { *tpoint++ = *spoint; } else { while (*dpoint) { *tpoint++ = *dpoint++; } if (newbase <= 0) { newbase = (spoint - source) + 1; } } } while (*spoint++); count = tpoint - target; memcpy(&source[base], &target[base], 2*(count - base)); source[count] = (unichar)(0); if (newbase > 0) { base = newbase; } else { base = count; } } seq->count = count; /* * Now standardise ordering of all composed character sequences. */ if (count > 1) { BOOL notdone = YES; while (notdone) { unichar *first = seq->chars; unichar *second = first + 1; NSUInteger i; notdone = NO; for (i = 1; i < count; i++) { if (GSPrivateUniCop(*second)) { if (GSPrivateUniCop(*first) > GSPrivateUniCop(*second)) { unichar tmp = *first; *first = *second; *second = tmp; notdone = YES; } else if (GSPrivateUniCop(*first) == GSPrivateUniCop(*second)) { if (*first > *second) { unichar tmp = *first; *first = *second; *second = tmp; notdone = YES; } } } first++; second++; } } } } seq->normalized = YES; } } /* * A function to compare two unicode character sequences normalizing if * required. */ static inline NSComparisonResult GSeq_compare(GSeq s0, GSeq s1) { NSUInteger i; NSUInteger end; NSUInteger len0; NSUInteger len1; unichar *c0 = s0->chars; unichar *c1 = s1->chars; len0 = s0->count; len1 = s1->count; if (len0 == len1) { for (i = 0; i < len1; i++) { if (c0[i] != c1[i]) { break; } } if (i == len0) { return NSOrderedSame; } } if (s0->normalized == NO) GSeq_normalize(s0); if (s1->normalized == NO) GSeq_normalize(s1); len0 = s0->count; len1 = s1->count; if (len0 < len1) end = len0; else end = len1; for (i = 0; i < end; i++) { if (c0[i] < c1[i]) return NSOrderedAscending; if (c0[i] > c1[i]) return NSOrderedDescending; } if (len0 < len1) return NSOrderedAscending; if (len0 > len1) return NSOrderedDescending; return NSOrderedSame; } static inline void GSeq_lowercase(GSeq seq) { unichar *s = seq->chars; NSUInteger len = seq->count; NSUInteger i; for (i = 0; i < len; i++) s[i] = uni_tolower(s[i]); } static inline void GSeq_uppercase(GSeq seq) { unichar *s = seq->chars; NSUInteger len = seq->count; NSUInteger i; for (i = 0; i < len; i++) s[i] = uni_toupper(s[i]); } /* * Specify NSString, GSUString or GSCString */ #define GSEQ_NS 0 #define GSEQ_US 1 #define GSEQ_CS 2 /* * Definitions for bitmask of search options. These MUST match the * enumeration in NSString.h */ #define GSEQ_FCLS 3 #define GSEQ_BCLS 7 #define GSEQ_FLS 2 #define GSEQ_BLS 6 #define GSEQ_FCS 1 #define GSEQ_BCS 5 #define GSEQ_FS 0 #define GSEQ_BS 4 #define GSEQ_FCLAS 11 #define GSEQ_BCLAS 15 #define GSEQ_FLAS 10 #define GSEQ_BLAS 14 #define GSEQ_FCAS 9 #define GSEQ_BCAS 13 #define GESQ_FAS 8 #define GSEQ_BAS 12 #endif /* __GSeq_h_GNUSTEP_GSEQ_BASE_INCLUDE */ /* * Set up macros for dealing with 'self' on the basis of GSQ_S */ #if GSEQ_S == GSEQ_US #define GSEQ_ST GSStr #define GSEQ_SLEN s->_count #define GSEQ_SGETC(I) s->_contents.u[I] #define GSEQ_SGETR(B,R) memcpy(B, &s->_contents.u[R.location], 2*(R).length) #define GSEQ_SRANGE(I) (*srImp)((id)s, ranSel, I) #else #if GSEQ_S == GSEQ_CS #define GSEQ_ST GSStr #define GSEQ_SLEN s->_count #define GSEQ_SGETC(I) (unichar)s->_contents.c[I] #define GSEQ_SGETR(B,R) ( { \ NSUInteger _lcount = 0; \ while (_lcount < (R).length) \ { \ (B)[_lcount] = (unichar)s->_contents.c[(R).location + _lcount]; \ _lcount++; \ } \ } ) #define GSEQ_SRANGE(I) (NSRange){I,1} #else #define GSEQ_ST NSString* #define GSEQ_SLEN [s length] #define GSEQ_SGETC(I) (*scImp)(s, caiSel, I) #define GSEQ_SGETR(B,R) (*sgImp)(s, gcrSel, B, R) #define GSEQ_SRANGE(I) (*srImp)(s, ranSel, I) #endif #endif /* * Set up macros for dealing with 'other' string on the basis of GSQ_O */ #if GSEQ_O == GSEQ_US #define GSEQ_OT GSStr #define GSEQ_OLEN o->_count #define GSEQ_OGETC(I) o->_contents.u[I] #define GSEQ_OGETR(B,R) memcpy(B, &o->_contents.u[R.location], 2*(R).length) #define GSEQ_ORANGE(I) (*orImp)((id)o, ranSel, I) #else #if GSEQ_O == GSEQ_CS #define GSEQ_OT GSStr #define GSEQ_OLEN o->_count #define GSEQ_OGETC(I) (unichar)o->_contents.c[I] #define GSEQ_OGETR(B,R) ( { \ NSUInteger _lcount = 0; \ while (_lcount < (R).length) \ { \ (B)[_lcount] = (unichar)o->_contents.c[(R).location + _lcount]; \ _lcount++; \ } \ } ) #define GSEQ_ORANGE(I) (NSRange){I,1} #else #define GSEQ_OT NSString* #define GSEQ_OLEN [o length] #define GSEQ_OGETC(I) (*ocImp)(o, caiSel, I) #define GSEQ_OGETR(B,R) (*ogImp)(o, gcrSel, B, R) #define GSEQ_ORANGE(I) (*orImp)(o, ranSel, I) #endif #endif /* * If a string comparison function is required, implement it. */ #ifdef GSEQ_STRCOMP static NSComparisonResult GSEQ_STRCOMP(NSString *ss, NSString *os, NSUInteger mask, NSRange aRange) { GSEQ_ST s = (GSEQ_ST)ss; GSEQ_OT o = (GSEQ_OT)os; NSUInteger oLength; /* Length of other. */ #if 0 /* Range should be checked in calling code */ if (aRange.location > GSEQ_SLEN) [NSException raise: NSRangeException format: @"Invalid location."]; if (aRange.length > (GSEQ_SLEN - aRange.location)) [NSException raise: NSRangeException format: @"Invalid location+length."]; #endif oLength = GSEQ_OLEN; if (aRange.length == 0) { if (oLength == 0) { return NSOrderedSame; } return NSOrderedAscending; } else if (oLength == 0) { return NSOrderedDescending; } if (mask & NSLiteralSearch) { NSUInteger i; NSUInteger sLen = aRange.length; NSUInteger oLen = oLength; NSUInteger end; #if GSEQ_S == GSEQ_NS void (*sgImp)(NSString*, SEL, unichar*, NSRange); unichar sBuf[sLen]; #else #if GSEQ_S == GSEQ_US unichar *sBuf; #else unsigned char *sBuf; #endif #endif #if GSEQ_O == GSEQ_NS void (*ogImp)(NSString*, SEL, unichar*, NSRange); unichar oBuf[oLen]; #else #if GSEQ_O == GSEQ_US unichar *oBuf; #else unsigned char *oBuf; #endif #endif #if GSEQ_S == GSEQ_NS sgImp = (void (*)(NSString*,SEL,unichar*,NSRange)) [(id)s methodForSelector: gcrSel]; GSEQ_SGETR(sBuf, aRange); #else #if GSEQ_S == GSEQ_CS sBuf = &s->_contents.c[aRange.location]; #else sBuf = &s->_contents.u[aRange.location]; #endif #endif #if GSEQ_O == GSEQ_NS ogImp = (void (*)(NSString*,SEL,unichar*,NSRange)) [(id)o methodForSelector: gcrSel]; GSEQ_OGETR(oBuf, NSMakeRange(0, oLen)); #else #if GSEQ_O == GSEQ_CS oBuf = o->_contents.c; #else oBuf = o->_contents.u; #endif #endif if (oLen < sLen) end = oLen; else end = sLen; if (mask & NSCaseInsensitiveSearch) { for (i = 0; i < end; i++) { #if GSEQ_O == GSEQ_CS && GSEQ_S == GSEQ_CS char c1 = tolower(sBuf[i]); char c2 = tolower(oBuf[i]); #else unichar c1 = uni_tolower((unichar)sBuf[i]); unichar c2 = uni_tolower((unichar)oBuf[i]); #endif if (c1 < c2) return NSOrderedAscending; if (c1 > c2) return NSOrderedDescending; } } else { for (i = 0; i < end; i++) { #if GSEQ_O == GSEQ_CS && GSEQ_S == GSEQ_CS if (sBuf[i] < oBuf[i]) return NSOrderedAscending; if (sBuf[i] > oBuf[i]) return NSOrderedDescending; #else if ((unichar)sBuf[i] < (unichar)oBuf[i]) return NSOrderedAscending; if ((unichar)sBuf[i] > (unichar)oBuf[i]) return NSOrderedDescending; #endif } } if (sLen > oLen) return NSOrderedDescending; else if (sLen < oLen) return NSOrderedAscending; else return NSOrderedSame; } else { NSUInteger start = aRange.location; NSUInteger end = start + aRange.length; NSUInteger sLength = GSEQ_SLEN; NSUInteger sCount = start; NSUInteger oCount = 0; NSComparisonResult result; #if GSEQ_S == GSEQ_NS || GSEQ_S == GSEQ_US NSRange (*srImp)(NSString*, SEL, NSUInteger); #endif #if GSEQ_O == GSEQ_NS || GSEQ_O == GSEQ_US NSRange (*orImp)(NSString*, SEL, NSUInteger); #endif #if GSEQ_S == GSEQ_NS void (*sgImp)(NSString*, SEL, unichar*, NSRange); #endif #if GSEQ_O == GSEQ_NS void (*ogImp)(NSString*, SEL, unichar*, NSRange); #endif #if GSEQ_S == GSEQ_NS || GSEQ_S == GSEQ_US srImp = (NSRange (*)(NSString*, SEL, NSUInteger)) [(id)s methodForSelector: ranSel]; #endif #if GSEQ_O == GSEQ_NS || GSEQ_O == GSEQ_US orImp = (NSRange (*)(NSString*, SEL, NSUInteger)) [(id)o methodForSelector: ranSel]; #endif #if GSEQ_S == GSEQ_NS sgImp = (void (*)(NSString*, SEL, unichar*, NSRange)) [(id)s methodForSelector: gcrSel]; #endif #if GSEQ_O == GSEQ_NS ogImp = (void (*)(NSString*, SEL, unichar*, NSRange)) [(id)o methodForSelector: gcrSel]; #endif while (sCount < end) { if (oCount >= oLength) { return NSOrderedDescending; } else if (sCount >= sLength) { return NSOrderedAscending; } else { NSRange sRange = GSEQ_SRANGE(sCount); NSRange oRange = GSEQ_ORANGE(oCount); GSEQ_MAKE(sBuf, sSeq, sRange.length); GSEQ_MAKE(oBuf, oSeq, oRange.length); GSEQ_SGETR(sBuf, sRange); GSEQ_OGETR(oBuf, oRange); result = GSeq_compare(&sSeq, &oSeq); if (result != NSOrderedSame) { if (mask & NSCaseInsensitiveSearch) { GSeq_lowercase(&oSeq); GSeq_lowercase(&sSeq); result = GSeq_compare(&sSeq, &oSeq); if (result != NSOrderedSame) { return result; } } else { return result; } } sCount += sRange.length; oCount += oRange.length; } } if (oCount < oLength) return NSOrderedAscending; return NSOrderedSame; } } #undef GSEQ_STRCOMP #endif /* * If a string search function is required, implement it. */ #ifdef GSEQ_STRRANGE static NSRange GSEQ_STRRANGE(NSString *ss, NSString *os, NSUInteger mask, NSRange aRange) { GSEQ_ST s = (GSEQ_ST)ss; GSEQ_OT o = (GSEQ_OT)os; NSUInteger myIndex; NSUInteger myEndIndex; NSUInteger strLength; #if GSEQ_S == GSEQ_NS unichar (*scImp)(NSString*, SEL, NSUInteger); void (*sgImp)(NSString*, SEL, unichar*, NSRange); #endif #if GSEQ_O == GSEQ_NS unichar (*ocImp)(NSString*, SEL, NSUInteger); void (*ogImp)(NSString*, SEL, unichar*, NSRange); #endif #if GSEQ_S == GSEQ_NS || GSEQ_S == GSEQ_US NSRange (*srImp)(NSString*, SEL, NSUInteger); #endif #if GSEQ_O == GSEQ_NS || GSEQ_O == GSEQ_US NSRange (*orImp)(NSString*, SEL, NSUInteger); #endif #if 0 /* Check that the search range is reasonable */ NSUInteger myLength = GSEQ_SLEN; /* Range should be checked in calling code */ if (aRange.location > myLength) [NSException raise: NSRangeException format: @"Invalid location."]; if (aRange.length > (myLength - aRange.location)) [NSException raise: NSRangeException format: @"Invalid location+length."]; #endif /* Ensure the string can be found */ strLength = GSEQ_OLEN; if (strLength > aRange.length || strLength == 0) return (NSRange){NSNotFound, 0}; /* * Cache method implementations for getting characters and ranges */ #if GSEQ_S == GSEQ_NS scImp = (unichar (*)(NSString*,SEL,NSUInteger)) [(id)s methodForSelector: caiSel]; sgImp = (void (*)(NSString*,SEL,unichar*,NSRange)) [(id)s methodForSelector: gcrSel]; #endif #if GSEQ_O == GSEQ_NS ocImp = (unichar (*)(NSString*,SEL,NSUInteger)) [(id)o methodForSelector: caiSel]; ogImp = (void (*)(NSString*,SEL,unichar*,NSRange)) [(id)o methodForSelector: gcrSel]; #endif #if GSEQ_S == GSEQ_NS || GSEQ_S == GSEQ_US srImp = (NSRange (*)(NSString*,SEL,NSUInteger)) [(id)s methodForSelector: ranSel]; #endif #if GSEQ_O == GSEQ_NS || GSEQ_O == GSEQ_US orImp = (NSRange (*)(NSString*,SEL,NSUInteger)) [(id)o methodForSelector: ranSel]; #endif switch (mask) { case GSEQ_FCLS: case GSEQ_FCLAS: { unichar strFirstCharacter = GSEQ_OGETC(0); myIndex = aRange.location; myEndIndex = aRange.location + aRange.length - strLength; if (mask & NSAnchoredSearch) myEndIndex = myIndex; for (;;) { NSUInteger i = 1; unichar myCharacter = GSEQ_SGETC(myIndex); unichar strCharacter = strFirstCharacter; for (;;) { if ((myCharacter != strCharacter) && ((uni_tolower(myCharacter) != uni_tolower(strCharacter)))) break; if (i == strLength) return (NSRange){myIndex, strLength}; myCharacter = GSEQ_SGETC(myIndex + i); strCharacter = GSEQ_OGETC(i); i++; } if (myIndex == myEndIndex) break; myIndex++; } return (NSRange){NSNotFound, 0}; } case GSEQ_BCLS: case GSEQ_BCLAS: { unichar strFirstCharacter = GSEQ_OGETC(0); myIndex = aRange.location + aRange.length - strLength; myEndIndex = aRange.location; if (mask & NSAnchoredSearch) myEndIndex = myIndex; for (;;) { NSUInteger i = 1; unichar myCharacter = GSEQ_SGETC(myIndex); unichar strCharacter = strFirstCharacter; for (;;) { if ((myCharacter != strCharacter) && ((uni_tolower(myCharacter) != uni_tolower(strCharacter)))) break; if (i == strLength) return (NSRange){myIndex, strLength}; myCharacter = GSEQ_SGETC(myIndex + i); strCharacter = GSEQ_OGETC(i); i++; } if (myIndex == myEndIndex) break; myIndex--; } return (NSRange){NSNotFound, 0}; } case GSEQ_FLS: case GSEQ_FLAS: { unichar strFirstCharacter = GSEQ_OGETC(0); myIndex = aRange.location; myEndIndex = aRange.location + aRange.length - strLength; if (mask & NSAnchoredSearch) myEndIndex = myIndex; for (;;) { NSUInteger i = 1; unichar myCharacter = GSEQ_SGETC(myIndex); unichar strCharacter = strFirstCharacter; for (;;) { if (myCharacter != strCharacter) break; if (i == strLength) return (NSRange){myIndex, strLength}; myCharacter = GSEQ_SGETC(myIndex + i); strCharacter = GSEQ_OGETC(i); i++; } if (myIndex == myEndIndex) break; myIndex++; } return (NSRange){NSNotFound, 0}; } case GSEQ_BLS: case GSEQ_BLAS: { unichar strFirstCharacter = GSEQ_OGETC(0); myIndex = aRange.location + aRange.length - strLength; myEndIndex = aRange.location; if (mask & NSAnchoredSearch) myEndIndex = myIndex; for (;;) { NSUInteger i = 1; unichar myCharacter = GSEQ_SGETC(myIndex); unichar strCharacter = strFirstCharacter; for (;;) { if (myCharacter != strCharacter) break; if (i == strLength) return (NSRange){myIndex, strLength}; myCharacter = GSEQ_SGETC(myIndex + i); strCharacter = GSEQ_OGETC(i); i++; } if (myIndex == myEndIndex) break; myIndex--; } return (NSRange){NSNotFound, 0}; } case GSEQ_FCS: case GSEQ_FCAS: { NSUInteger strBaseLength; NSRange iRange; strBaseLength = [(NSString*)o _baseLength]; myIndex = aRange.location; myEndIndex = aRange.location + aRange.length - strBaseLength; if (mask & NSAnchoredSearch) myEndIndex = myIndex; iRange = GSEQ_ORANGE(0); if (iRange.length) { GSEQ_MAKE(iBuf, iSeq, iRange.length); GSEQ_OGETR(iBuf, iRange); GSeq_lowercase(&iSeq); for (;;) { NSRange sRange = GSEQ_SRANGE(myIndex); GSEQ_MAKE(sBuf, sSeq, sRange.length); GSEQ_SGETR(sBuf, sRange); GSeq_lowercase(&sSeq); if (GSeq_compare(&iSeq, &sSeq) == NSOrderedSame) { NSUInteger myCount = sRange.length; NSUInteger strCount = iRange.length; if (strCount >= strLength) { return (NSRange){myIndex, myCount}; } for (;;) { NSRange r0 = GSEQ_SRANGE(myIndex + myCount); GSEQ_MAKE(b0, s0, r0.length); NSRange r1 = GSEQ_ORANGE(strCount); GSEQ_MAKE(b1, s1, r1.length); GSEQ_SGETR(b0, r0); GSEQ_OGETR(b1, r1); if (GSeq_compare(&s0, &s1) != NSOrderedSame) { GSeq_lowercase(&s0); GSeq_lowercase(&s1); if (GSeq_compare(&s0, &s1) != NSOrderedSame) { break; } } myCount += r0.length; strCount += r1.length; if (strCount >= strLength) { return (NSRange){myIndex, myCount}; } } } myIndex += sRange.length; if (myIndex > myEndIndex) break; } } return (NSRange){NSNotFound, 0}; } case GSEQ_BCS: case GSEQ_BCAS: { NSUInteger strBaseLength; NSRange iRange; strBaseLength = [(NSString*)o _baseLength]; myIndex = aRange.location + aRange.length - strBaseLength; myEndIndex = aRange.location; if (mask & NSAnchoredSearch) myEndIndex = myIndex; iRange = GSEQ_ORANGE(0); if (iRange.length) { GSEQ_MAKE(iBuf, iSeq, iRange.length); GSEQ_OGETR(iBuf, iRange); GSeq_lowercase(&iSeq); for (;;) { NSRange sRange = GSEQ_SRANGE(myIndex); GSEQ_MAKE(sBuf, sSeq, sRange.length); GSEQ_SGETR(sBuf, sRange); GSeq_lowercase(&sSeq); if (GSeq_compare(&iSeq, &sSeq) == NSOrderedSame) { NSUInteger myCount = sRange.length; NSUInteger strCount = iRange.length; if (strCount >= strLength) { return (NSRange){myIndex, myCount}; } for (;;) { NSRange r0 = GSEQ_SRANGE(myIndex + myCount); GSEQ_MAKE(b0, s0, r0.length); NSRange r1 = GSEQ_ORANGE(strCount); GSEQ_MAKE(b1, s1, r1.length); GSEQ_SGETR(b0, r0); GSEQ_OGETR(b1, r1); if (GSeq_compare(&s0, &s1) != NSOrderedSame) { GSeq_lowercase(&s0); GSeq_lowercase(&s1); if (GSeq_compare(&s0, &s1) != NSOrderedSame) { break; } } myCount += r0.length; strCount += r1.length; if (strCount >= strLength) { return (NSRange){myIndex, myCount}; } } } if (myIndex <= myEndIndex) break; myIndex--; while (uni_isnonsp(GSEQ_SGETC(myIndex)) && (myIndex > 0)) myIndex--; } } return (NSRange){NSNotFound, 0}; } case GSEQ_BS: case GSEQ_BAS: { NSUInteger strBaseLength; NSRange iRange; strBaseLength = [(NSString*)o _baseLength]; myIndex = aRange.location + aRange.length - strBaseLength; myEndIndex = aRange.location; if (mask & NSAnchoredSearch) myEndIndex = myIndex; iRange = GSEQ_ORANGE(0); if (iRange.length) { GSEQ_MAKE(iBuf, iSeq, iRange.length); GSEQ_OGETR(iBuf, iRange); for (;;) { NSRange sRange = GSEQ_SRANGE(myIndex); GSEQ_MAKE(sBuf, sSeq, sRange.length); GSEQ_SGETR(sBuf, sRange); if (GSeq_compare(&iSeq, &sSeq) == NSOrderedSame) { NSUInteger myCount = sRange.length; NSUInteger strCount = iRange.length; if (strCount >= strLength) { return (NSRange){myIndex, myCount}; } for (;;) { NSRange r0 = GSEQ_SRANGE(myIndex + myCount); GSEQ_MAKE(b0, s0, r0.length); NSRange r1 = GSEQ_ORANGE(strCount); GSEQ_MAKE(b1, s1, r1.length); GSEQ_SGETR(b0, r0); GSEQ_OGETR(b1, r1); if (GSeq_compare(&s0, &s1) != NSOrderedSame) { break; } myCount += r0.length; strCount += r1.length; if (strCount >= strLength) { return (NSRange){myIndex, myCount}; } } } if (myIndex <= myEndIndex) break; myIndex--; while (uni_isnonsp(GSEQ_SGETC(myIndex)) && (myIndex > 0)) myIndex--; } } return (NSRange){NSNotFound, 0}; } case GSEQ_FS: case GESQ_FAS: default: { NSUInteger strBaseLength; NSRange iRange; strBaseLength = [(NSString*)o _baseLength]; myIndex = aRange.location; myEndIndex = aRange.location + aRange.length - strBaseLength; if (mask & NSAnchoredSearch) myEndIndex = myIndex; iRange = GSEQ_ORANGE(0); if (iRange.length) { GSEQ_MAKE(iBuf, iSeq, iRange.length); GSEQ_OGETR(iBuf, iRange); for (;;) { NSRange sRange = GSEQ_SRANGE(myIndex); GSEQ_MAKE(sBuf, sSeq, sRange.length); GSEQ_SGETR(sBuf, sRange); if (GSeq_compare(&iSeq, &sSeq) == NSOrderedSame) { NSUInteger myCount = sRange.length; NSUInteger strCount = iRange.length; if (strCount >= strLength) { return (NSRange){myIndex, myCount}; } for (;;) { NSRange r0 = GSEQ_SRANGE(myIndex + myCount); GSEQ_MAKE(b0, s0, r0.length); NSRange r1 = GSEQ_ORANGE(strCount); GSEQ_MAKE(b1, s1, r1.length); GSEQ_SGETR(b0, r0); GSEQ_OGETR(b1, r1); if (GSeq_compare(&s0, &s1) != NSOrderedSame) { break; } myCount += r0.length; strCount += r1.length; if (strCount >= strLength) { return (NSRange){myIndex, myCount}; } } } myIndex += sRange.length; if (myIndex > myEndIndex) break; } } return (NSRange){NSNotFound, 0}; } } return (NSRange){NSNotFound, 0}; } #undef GSEQ_STRRANGE #endif /* * Clean up macro namespace */ #ifdef GSEQ_S #undef GSEQ_SLEN #undef GSEQ_SGETC #undef GSEQ_SGETR #undef GSEQ_SRANGE #undef GSEQ_ST #undef GSEQ_S #endif #ifdef GSEQ_O #undef GSEQ_OLEN #undef GSEQ_OGETC #undef GSEQ_OGETR #undef GSEQ_ORANGE #undef GSEQ_OT #undef GSEQ_O #endif