mirror of
https://github.com/gnustep/libs-base.git
synced 2025-04-22 00:11:04 +00:00
internal 8bit encoding in not latin1 and uni_tolower() is therefore not usable. git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@35386 72102866-910b-0410-8b05-ffd578937521
1152 lines
26 KiB
C
1152 lines
26 KiB
C
/* Implementation of composite character sequence functions for GNUSTEP
|
|
Copyright (C) 1999 Free Software Foundation, Inc.
|
|
|
|
Written by: Richard Frith-Macdonald <richard@brainstorm.co.uk>
|
|
Date: May 1999
|
|
Based on code by: Stevo Crvenkovski <stevo@btinternet.com>
|
|
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)
|
|
{
|
|
#if GSEQ_O == GSEQ_CS || GSEQ_S == GSEQ_CS
|
|
if (GSPrivateDefaultCStringEncoding() == NSISOLatin1StringEncoding)
|
|
{
|
|
/* Using latin1 internally, rather than native encoding,
|
|
* so we can't use native tolower() function.
|
|
*/
|
|
for (i = 0; i < end; i++)
|
|
{
|
|
unichar c1 = uni_tolower((unichar)sBuf[i]);
|
|
unichar c2 = uni_tolower((unichar)oBuf[i]);
|
|
|
|
if (c1 < c2)
|
|
return NSOrderedAscending;
|
|
if (c1 > c2)
|
|
return NSOrderedDescending;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* We are not using latin1 encoding internally, so we trust
|
|
* that the internal encoding matches the native encoding
|
|
* and the native tolower() function will work.
|
|
*/
|
|
for (i = 0; i < end; i++)
|
|
{
|
|
#if GSEQ_S == GSEQ_CS
|
|
unichar c1 = tolower(sBuf[i]);
|
|
#else
|
|
unichar c1 = uni_tolower((unichar)sBuf[i]);
|
|
#endif
|
|
#if GSEQ_O == GSEQ_CS
|
|
unichar c2 = tolower(oBuf[i]);
|
|
#else
|
|
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++)
|
|
{
|
|
unichar c1 = uni_tolower((unichar)sBuf[i]);
|
|
unichar c2 = uni_tolower((unichar)oBuf[i]);
|
|
|
|
if (c1 < c2)
|
|
return NSOrderedAscending;
|
|
if (c1 > c2)
|
|
return NSOrderedDescending;
|
|
}
|
|
#endif
|
|
}
|
|
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
|
|
|