Introduce NSRegularExpression support for libicu versions prior to 4.4,

which don't provide the UText interface to regular expressions.


git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@34345 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
wlux 2011-12-22 12:52:56 +00:00
parent 4c75f12273
commit 42ffcb55bf
2 changed files with 279 additions and 4 deletions

View file

@ -1,4 +1,14 @@
2011-12-22 Wolfgang Lux <wolgang.lux@gmail.com> 2011-12-22 Wolfgang Lux <wolfgang.lux@gmail.com>
* Source/NSRegularExpression.m (-initWithPattern:options:error:,
-pattern, setupRegex, -enumerateMatchesInString:options:range:,
FAKE_BLOCK_HACK, -replaceMatchesInString:options:range:,
-stringByReplacingMatchesInString:options:range:withTemplate:,
replacementStringForResult:inString:offset:template:): Introduce
support for libicu versions prior to 4.4, which don't provide the
UText interface to regular expressions.
2011-12-22 Wolfgang Lux <wolfgang.lux@gmail.com>
* Source/NSSocketPort.m (+portNumber:onHost:forceAddress:listener): * Source/NSSocketPort.m (+portNumber:onHost:forceAddress:listener):
Fix an uninitialized variable bug, which could lead to returning Fix an uninitialized variable bug, which could lead to returning

View file

@ -1,4 +1,4 @@
/** Implementation of NSRegualrExpression for GNUStep /** Implementation of NSRegularExpression for GNUStep
Copyright (C) 2010 Free Software Foundation, Inc. Copyright (C) 2010 Free Software Foundation, Inc.
@ -28,7 +28,14 @@
#if GS_USE_ICU == 1 #if GS_USE_ICU == 1
#include "unicode/uregex.h" #include "unicode/uregex.h"
// FIXME It would be nice to use autoconf for checking whether uregex_openUText
// is defined. However the naive check using AC_CHECK_FUNCS(uregex_openUText)
// wonn't work because libicu internally renames all entry points with some cpp
// magic.
#if (U_ICU_VERSION_MAJOR_NUM > 4 || (U_ICU_VERSION_MAJOR_NUM == 4 && U_ICU_VERSION_MINOR_NUM >= 4)) #if (U_ICU_VERSION_MAJOR_NUM > 4 || (U_ICU_VERSION_MAJOR_NUM == 4 && U_ICU_VERSION_MINOR_NUM >= 4))
#define HAVE_UREGEX_OPENUTEXT 1
#endif
#define NSRegularExpressionWorks #define NSRegularExpressionWorks
@ -94,6 +101,7 @@ NSRegularExpressionOptionsToURegexpFlags(NSRegularExpressionOptions opts)
error: e] autorelease]; error: e] autorelease];
} }
#if HAVE_UREGEX_OPENUTEXT
- (id) initWithPattern: (NSString*)aPattern - (id) initWithPattern: (NSString*)aPattern
options: (NSRegularExpressionOptions)opts options: (NSRegularExpressionOptions)opts
error: (NSError**)e error: (NSError**)e
@ -131,6 +139,42 @@ NSRegularExpressionOptionsToURegexpFlags(NSRegularExpressionOptions opts)
utext_close(t); utext_close(t);
return [str autorelease]; return [str autorelease];
} }
#else
- (id) initWithPattern: (NSString*)aPattern
options: (NSRegularExpressionOptions)opts
error: (NSError**)e
{
int32_t length = [aPattern length];
uint32_t flags = NSRegularExpressionOptionsToURegexpFlags(opts);
UParseError pe = {0};
UErrorCode s = 0;
TEMP_BUFFER(buffer, length);
[aPattern getCharacters: buffer range: NSMakeRange(0, length)];
regex = uregex_open(buffer, length, flags, &pe, &s);
if (U_FAILURE(s))
{
// FIXME: Do something sensible with the error parameter.
[self release];
return nil;
}
options = opts;
return self;
}
- (NSString*) pattern
{
UErrorCode s = 0;
int32_t length;
const unichar *pattern = uregex_pattern(regex, &length, &s);
if (U_FAILURE(s))
{
return nil;
}
return [NSString stringWithCharacters: pattern length: length];
}
#endif
static UBool static UBool
callback(const void *context, int32_t steps) callback(const void *context, int32_t steps)
@ -154,6 +198,7 @@ callback(const void *context, int32_t steps)
* NSRegularExpression, is stateful, and sharing this state between threads * NSRegularExpression, is stateful, and sharing this state between threads
* would break concurrent calls. * would break concurrent calls.
*/ */
#if HAVE_UREGEX_OPENUTEXT
static URegularExpression * static URegularExpression *
setupRegex(URegularExpression *regex, setupRegex(URegularExpression *regex,
NSString *string, NSString *string,
@ -187,6 +232,42 @@ setupRegex(URegularExpression *regex,
} }
return r; return r;
} }
#else
static URegularExpression *
setupRegex(URegularExpression *regex,
NSString *string,
unichar *buffer,
int32_t length,
NSMatchingOptions options,
NSRange range,
GSRegexBlock block)
{
UErrorCode s = 0;
URegularExpression *r = uregex_clone(regex, &s);
[string getCharacters: buffer range: NSMakeRange(0, length)];
if (options & NSMatchingReportProgress)
{
uregex_setMatchCallback(r, callback, block, &s);
}
uregex_setText(r, buffer, length, &s);
uregex_setRegion(r, range.location, range.location+range.length, &s);
if (options & NSMatchingWithoutAnchoringBounds)
{
uregex_useAnchoringBounds(r, FALSE, &s);
}
if (options & NSMatchingWithTransparentBounds)
{
uregex_useTransparentBounds(r, TRUE, &s);
}
if (U_FAILURE(s))
{
uregex_close(r);
return NULL;
}
return r;
}
#endif
static uint32_t static uint32_t
prepareResult(NSRegularExpression *regex, prepareResult(NSRegularExpression *regex,
@ -220,6 +301,7 @@ prepareResult(NSRegularExpression *regex,
return flags; return flags;
} }
#if HAVE_UREGEX_OPENUTEXT
- (void) enumerateMatchesInString: (NSString*)string - (void) enumerateMatchesInString: (NSString*)string
options: (NSMatchingOptions)opts options: (NSMatchingOptions)opts
range: (NSRange)range range: (NSRange)range
@ -275,6 +357,65 @@ prepareResult(NSRegularExpression *regex,
utext_close(&txt); utext_close(&txt);
uregex_close(r); uregex_close(r);
} }
#else
- (void) enumerateMatchesInString: (NSString*)string
options: (NSMatchingOptions)opts
range: (NSRange)range
usingBlock: (GSRegexBlock)block
{
UErrorCode s = 0;
BOOL stop = NO;
int32_t length = [string length];
URegularExpression *r;
NSUInteger groups = [self numberOfCaptureGroups] + 1;
NSRange ranges[groups];
TEMP_BUFFER(buffer, length);
r = setupRegex(regex, string, buffer, length, opts, range, block);
// Should this throw some kind of exception?
if (NULL == r)
{
return;
}
if (opts & NSMatchingAnchored)
{
if (uregex_lookingAt(r, -1, &s) && (0 == s))
{
// FIXME: Factor all of this out into prepareResult()
uint32_t flags;
NSTextCheckingResult *result;
flags = prepareResult(self, r, ranges, groups, &s);
result = [NSTextCheckingResult
regularExpressionCheckingResultWithRanges: ranges
count: groups
regularExpression: self];
CALL_BLOCK(block, result, flags, &stop);
}
}
else
{
while (!stop && uregex_findNext(r, &s) && (0 == s))
{
uint32_t flags;
NSTextCheckingResult *result;
flags = prepareResult(self, r, ranges, groups, &s);
result = [NSTextCheckingResult
regularExpressionCheckingResultWithRanges: ranges
count: groups
regularExpression: self];
CALL_BLOCK(block, result, flags, &stop);
}
}
if (opts & NSMatchingCompleted)
{
CALL_BLOCK(block, nil, NSMatchingCompleted, &stop);
}
uregex_close(r);
}
#endif
/* The remaining methods are all meant to be wrappers around the primitive /* The remaining methods are all meant to be wrappers around the primitive
* method that takes a block argument. Unfortunately, this is not really * method that takes a block argument. Unfortunately, this is not really
@ -373,6 +514,7 @@ prepareResult(NSRegularExpression *regex,
# ifdef __clang__ # ifdef __clang__
# warning Your compiler would support blocks if you added -fblocks to your OBJCFLAGS # warning Your compiler would support blocks if you added -fblocks to your OBJCFLAGS
# endif # endif
#if HAVE_UREGEX_OPENUTEXT
#define FAKE_BLOCK_HACK(failRet, code) \ #define FAKE_BLOCK_HACK(failRet, code) \
UErrorCode s = 0;\ UErrorCode s = 0;\
UText txt = UTEXT_INITIALIZER;\ UText txt = UTEXT_INITIALIZER;\
@ -395,6 +537,31 @@ prepareResult(NSRegularExpression *regex,
}\ }\
utext_close(&txt);\ utext_close(&txt);\
uregex_close(r); uregex_close(r);
#else
#define FAKE_BLOCK_HACK(failRet, code) \
UErrorCode s = 0;\
BOOL stop = NO;\
uint32_t length = [string length];\
URegularExpression *r;\
TEMP_BUFFER(buffer, length);\
r = setupRegex(regex, string, buffer, length, opts, range, 0);\
if (NULL == r) { return failRet; }\
if (opts & NSMatchingAnchored)\
{\
if (uregex_lookingAt(r, -1, &s) && (0==s))\
{\
code\
}\
}\
else\
{\
while (!stop && uregex_findNext(r, &s) && (s == 0))\
{\
code\
}\
}\
uregex_close(r);
#endif
- (NSUInteger) numberOfMatchesInString: (NSString*)string - (NSUInteger) numberOfMatchesInString: (NSString*)string
options: (NSMatchingOptions)opts options: (NSMatchingOptions)opts
@ -468,6 +635,7 @@ prepareResult(NSRegularExpression *regex,
#endif #endif
#if HAVE_UREGEX_OPENUTEXT
- (NSUInteger) replaceMatchesInString: (NSMutableString*)string - (NSUInteger) replaceMatchesInString: (NSMutableString*)string
options: (NSMatchingOptions)opts options: (NSMatchingOptions)opts
range: (NSRange)range range: (NSRange)range
@ -552,6 +720,104 @@ prepareResult(NSRegularExpression *regex,
utext_close(&replacement); utext_close(&replacement);
return ret; return ret;
} }
#else
- (NSUInteger) replaceMatchesInString: (NSMutableString*)string
options: (NSMatchingOptions)opts
range: (NSRange)range
withTemplate: (NSString*)template
{
// FIXME: We're computing a value that is most likely ignored in an
// expensive way.
NSInteger results = [self numberOfMatchesInString: string
options: opts
range: range];
UErrorCode s = 0;
uint32_t length = [string length];
uint32_t replLength = [template length];
unichar replacement[replLength];
int32_t outLength;
unichar *output;
NSString *out;
URegularExpression *r;
TEMP_BUFFER(buffer, length);
r = setupRegex(regex, string, buffer, length, opts, range, 0);
[template getCharacters: replacement range: NSMakeRange(0, replLength)];
outLength = uregex_replaceAll(r, replacement, replLength, NULL, 0, &s);
s = 0;
output = NSZoneMalloc(0, outLength * sizeof(unichar));
uregex_replaceAll(r, replacement, replLength, output, outLength, &s);
out =
[[NSString alloc] initWithCharactersNoCopy: output
length: outLength
freeWhenDone: YES];
[string setString: out];
RELEASE(out);
return results;
}
- (NSString*) stringByReplacingMatchesInString: (NSString*)string
options: (NSMatchingOptions)opts
range: (NSRange)range
withTemplate: (NSString*)template
{
UErrorCode s = 0;
uint32_t length = [string length];
URegularExpression *r;
uint32_t replLength = [template length];
unichar replacement[replLength];
int32_t outLength;
unichar *output;
TEMP_BUFFER(buffer, length);
r = setupRegex(regex, string, buffer, length, opts, range, 0);
[template getCharacters: replacement range: NSMakeRange(0, replLength)];
outLength = uregex_replaceAll(r, replacement, replLength, NULL, 0, &s);
s = 0;
output = NSZoneMalloc(0, outLength * sizeof(unichar));
uregex_replaceAll(r, replacement, replLength, output, outLength, &s);
return AUTORELEASE([[NSString alloc] initWithCharactersNoCopy: output
length: outLength
freeWhenDone: YES]);
}
- (NSString*) replacementStringForResult: (NSTextCheckingResult*)result
inString: (NSString*)string
offset: (NSInteger)offset
template: (NSString*)template
{
UErrorCode s = 0;
NSRange range = [result range];
URegularExpression *r;
uint32_t replLength = [template length];
unichar replacement[replLength];
int32_t outLength;
unichar *output;
TEMP_BUFFER(buffer, range.length);
r = setupRegex(regex,
[string substringWithRange: range],
buffer,
range.length,
0,
NSMakeRange(0, range.length),
0);
[template getCharacters: replacement range: NSMakeRange(0, replLength)];
outLength = uregex_replaceFirst(r, replacement, replLength, NULL, 0, &s);
s = 0;
output = NSZoneMalloc(0, outLength * sizeof(unichar));
uregex_replaceFirst(r, replacement, replLength, output, outLength, &s);
return AUTORELEASE([[NSString alloc] initWithCharactersNoCopy: output
length: outLength
freeWhenDone: YES]);
}
#endif
- (NSRegularExpressionOptions) options - (NSRegularExpressionOptions) options
{ {
@ -624,8 +890,7 @@ prepareResult(NSRegularExpression *regex,
return self; return self;
} }
@end @end
#endif //U_ICU_VERSION_MAJOR_NUM > 4 || (U_ICU_VERSION_MAJOR_NUM == 4 && U_ICU_VERSION_MINOR_NUM >= 4)) #endif //GS_ICU == 1
#endif //HAV_ICU
#ifndef NSRegularExpressionWorks #ifndef NSRegularExpressionWorks
#import "Foundation/NSRegularExpression.h" #import "Foundation/NSRegularExpression.h"