Wired Foundation  2.0
A foundation framework for the Wired implementation on Mac OS X
RegexKitLite.m
00001 //
00002 //  RegexKitLite.m
00003 //  http://regexkit.sourceforge.net/
00004 //  Licensed under the terms of the BSD License, as specified below.
00005 //
00006 
00007 /*
00008  Copyright (c) 2008-2010, John Engelhart
00009  
00010  All rights reserved.
00011  
00012  Redistribution and use in source and binary forms, with or without
00013  modification, are permitted provided that the following conditions are met:
00014  
00015  * Redistributions of source code must retain the above copyright
00016  notice, this list of conditions and the following disclaimer.
00017  
00018  * Redistributions in binary form must reproduce the above copyright
00019  notice, this list of conditions and the following disclaimer in the
00020  documentation and/or other materials provided with the distribution.
00021  
00022  * Neither the name of the Zang Industries nor the names of its
00023  contributors may be used to endorse or promote products derived from
00024  this software without specific prior written permission.
00025  
00026  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00027  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00028  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
00029  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
00030  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
00031  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
00032  TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
00033  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
00034  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
00035  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00036  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00037 */
00038 
00039 #include <CoreFoundation/CFBase.h>
00040 #include <CoreFoundation/CFArray.h>
00041 #include <CoreFoundation/CFString.h>
00042 #import <Foundation/NSArray.h>
00043 #import <Foundation/NSDictionary.h>
00044 #import <Foundation/NSError.h>
00045 #import <Foundation/NSException.h>
00046 #import <Foundation/NSNotification.h>
00047 #import <Foundation/NSRunLoop.h>
00048 #ifdef    __OBJC_GC__
00049 #import <Foundation/NSGarbageCollector.h>
00050 #define RKL_STRONG_REF __strong
00051 #define RKL_GC_VOLATILE volatile
00052 #else  // __OBJC_GC__
00053 #define RKL_STRONG_REF
00054 #define RKL_GC_VOLATILE
00055 #endif // __OBJC_GC__
00056 
00057 #if (defined(TARGET_OS_EMBEDDED) && (TARGET_OS_EMBEDDED != 0)) || (defined(TARGET_OS_IPHONE) && (TARGET_OS_IPHONE != 0)) || (defined(MAC_OS_X_VERSION_MIN_REQUIRED) && (MAC_OS_X_VERSION_MIN_REQUIRED >= 1050))
00058 #include <objc/runtime.h>
00059 #else
00060 #include <objc/objc-runtime.h>
00061 #endif
00062 
00063 #include <libkern/OSAtomic.h>
00064 #include <mach-o/loader.h>
00065 #include <AvailabilityMacros.h>
00066 #include <dlfcn.h>
00067 #include <string.h>
00068 #include <stdarg.h>
00069 #include <stdlib.h>
00070 #include <stdio.h>
00071 
00072 #import "RegexKitLite.h"
00073 
00074 // If the gcc flag -mmacosx-version-min is used with, for example, '=10.2', give a warning that the libicucore.dylib is only available on >= 10.3.
00075 // If you are reading this comment because of this warning, this is to let you know that linking to /usr/lib/libicucore.dylib will cause your executable to fail on < 10.3.
00076 // You will need to build your own version of the ICU library and link to that in order for RegexKitLite to work successfully on < 10.3.  This is not simple.
00077 
00078 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1030
00079 #warning The ICU dynamic shared library, /usr/lib/libicucore.dylib, is only available on Mac OS X 10.3 and later.
00080 #warning You will need to supply a version of the ICU library to use RegexKitLite on Mac OS X 10.2 and earlier.
00081 #endif
00082 
00084 #pragma mark Compile time tunables
00085 
00086 #ifndef RKL_CACHE_SIZE
00087 #define RKL_CACHE_SIZE (13UL)
00088 #endif
00089 
00090 #if       RKL_CACHE_SIZE < 1
00091 #error RKL_CACHE_SIZE must be a non-negative number greater than 0.
00092 #endif // RKL_CACHE_SIZE < 1
00093 
00094 #ifndef RKL_FIXED_LENGTH
00095 #define RKL_FIXED_LENGTH (2048UL)
00096 #endif
00097 
00098 #if       RKL_FIXED_LENGTH < 1
00099 #error RKL_FIXED_LENGTH must be a non-negative number greater than 0.
00100 #endif // RKL_FIXED_LENGTH < 1
00101 
00102 #ifndef RKL_STACK_LIMIT
00103 #define RKL_STACK_LIMIT (128UL * 1024UL)
00104 #endif
00105 
00106 #if       RKL_STACK_LIMIT < 0
00107 #error RKL_STACK_LIMIT must be a non-negative number.
00108 #endif // RKL_STACK_LIMIT < 0
00109 
00110 #ifdef    RKL_APPEND_TO_ICU_FUNCTIONS
00111 #define RKL_ICU_FUNCTION_APPEND(x) _RKL_CONCAT(x, RKL_APPEND_TO_ICU_FUNCTIONS)
00112 #else  // RKL_APPEND_TO_ICU_FUNCTIONS
00113 #define RKL_ICU_FUNCTION_APPEND(x) x
00114 #endif // RKL_APPEND_TO_ICU_FUNCTIONS
00115 
00116 #if       defined(RKL_DTRACE) && (RKL_DTRACE != 0)
00117 #define _RKL_DTRACE_ENABLED 1
00118 #endif // defined(RKL_DTRACE) && (RKL_DTRACE != 0)
00119 
00120 // These are internal, non-public tunables.
00121 #define _RKL_FIXED_LENGTH                ((NSUInteger)RKL_FIXED_LENGTH)
00122 #define _RKL_STACK_LIMIT                 ((NSUInteger)RKL_STACK_LIMIT)
00123 #define _RKL_SCRATCH_BUFFERS             (5UL)
00124 #if       _RKL_SCRATCH_BUFFERS != 5
00125 #error _RKL_SCRATCH_BUFFERS is not tunable, it must be set to 5.
00126 #endif // _RKL_SCRATCH_BUFFERS != 5
00127 #define _RKL_PREFETCH_SIZE               (64UL)
00128 #define _RKL_DTRACE_REGEXUTF8_SIZE       (64UL)
00129 
00130 // A LRU Cache Set holds 4 lines, and the LRU algorithm uses 4 bits per line.
00131 // A LRU Cache Set has a type of RKLLRUCacheSet_t and is 16 bits wide (4 lines * 4 bits per line).
00132 // RKLLRUCacheSet_t must be initialized to a value of 0x0137 in order to work correctly.
00133 typedef uint16_t RKLLRUCacheSet_t;
00134 #define _RKL_LRU_CACHE_SET_INIT          ((RKLLRUCacheSet_t)0x0137U)
00135 #define _RKL_LRU_CACHE_SET_WAYS          (4UL)
00136 #if       _RKL_LRU_CACHE_SET_WAYS != 4
00137 #error _RKL_LRU_CACHE_SET_WAYS is not tunable, it must be set to 4.
00138 #endif // _RKL_LRU_CACHE_SET_WAYS != 4
00139 
00140 #define _RKL_REGEX_LRU_CACHE_SETS        ((NSUInteger)(RKL_CACHE_SIZE))
00141 #define _RKL_REGEX_CACHE_LINES           ((NSUInteger)((NSUInteger)(_RKL_REGEX_LRU_CACHE_SETS) * (NSUInteger)(_RKL_LRU_CACHE_SET_WAYS)))
00142 
00143 // Regex String Lookaside Cache parameters.
00144 #define _RKL_REGEX_LOOKASIDE_CACHE_BITS   (6UL)
00145 #if       _RKL_REGEX_LOOKASIDE_CACHE_BITS < 0
00146 #error _RKL_REGEX_LOOKASIDE_CACHE_BITS must be a non-negative number and is not intended to be user tunable.
00147 #endif // _RKL_REGEX_LOOKASIDE_CACHE_BITS < 0
00148 #define _RKL_REGEX_LOOKASIDE_CACHE_SIZE   (1LU << _RKL_REGEX_LOOKASIDE_CACHE_BITS)
00149 #define _RKL_REGEX_LOOKASIDE_CACHE_MASK  ((1LU << _RKL_REGEX_LOOKASIDE_CACHE_BITS) - 1LU)
00150 // RKLLookasideCache_t should be large enough to to hold the maximum number of cached regexes, or (RKL_CACHE_SIZE * _RKL_LRU_CACHE_SET_WAYS).
00151 #if       (RKL_CACHE_SIZE * _RKL_LRU_CACHE_SET_WAYS) <= (1 << 8)
00152 typedef uint8_t RKLLookasideCache_t;
00153 #elif     (RKL_CACHE_SIZE * _RKL_LRU_CACHE_SET_WAYS) <= (1 << 16)
00154 typedef uint16_t RKLLookasideCache_t;
00155 #else  // (RKL_CACHE_SIZE * _RKL_LRU_CACHE_SET_WAYS)  > (1 << 16)
00156 typedef uint32_t RKLLookasideCache_t;
00157 #endif // (RKL_CACHE_SIZE * _RKL_LRU_CACHE_SET_WAYS)
00158 
00160 #pragma mark -
00161 #pragma mark GCC / Compiler macros
00162 
00163 #if       defined (__GNUC__) && (__GNUC__ >= 4)
00164 #define RKL_ATTRIBUTES(attr, ...)        __attribute__((attr, ##__VA_ARGS__))
00165 #define RKL_EXPECTED(cond, expect)       __builtin_expect((long)(cond), (expect))
00166 #define RKL_PREFETCH(ptr)                __builtin_prefetch(ptr)
00167 #define RKL_PREFETCH_UNICHAR(ptr, off)   { const char *p = ((const char *)(ptr)) + ((off) * sizeof(UniChar)) + _RKL_PREFETCH_SIZE; RKL_PREFETCH(p); RKL_PREFETCH(p + _RKL_PREFETCH_SIZE); }
00168 #define RKL_HAVE_CLEANUP
00169 #define RKL_CLEANUP(func)                RKL_ATTRIBUTES(cleanup(func))
00170 #else  // defined (__GNUC__) && (__GNUC__ >= 4) 
00171 #define RKL_ATTRIBUTES(attr, ...)
00172 #define RKL_EXPECTED(cond, expect)       (cond)
00173 #define RKL_PREFETCH(ptr)
00174 #define RKL_PREFETCH_UNICHAR(ptr, off)
00175 #define RKL_CLEANUP(func)
00176 #endif // defined (__GNUC__) && (__GNUC__ >= 4) 
00177 
00178 #define RKL_STATIC_INLINE                         static __inline__ RKL_ATTRIBUTES(always_inline)
00179 #define RKL_ALIGNED(arg)                                            RKL_ATTRIBUTES(aligned(arg))
00180 #define RKL_UNUSED_ARG                                              RKL_ATTRIBUTES(unused)
00181 #define RKL_WARN_UNUSED                                             RKL_ATTRIBUTES(warn_unused_result)
00182 #define RKL_WARN_UNUSED_CONST                                       RKL_ATTRIBUTES(warn_unused_result, const)
00183 #define RKL_WARN_UNUSED_PURE                                        RKL_ATTRIBUTES(warn_unused_result, pure)
00184 #define RKL_WARN_UNUSED_SENTINEL                                    RKL_ATTRIBUTES(warn_unused_result, sentinel)
00185 #define RKL_NONNULL_ARGS(arg, ...)                                  RKL_ATTRIBUTES(nonnull(arg, ##__VA_ARGS__))
00186 #define RKL_WARN_UNUSED_NONNULL_ARGS(arg, ...)                      RKL_ATTRIBUTES(warn_unused_result, nonnull(arg, ##__VA_ARGS__))
00187 #define RKL_WARN_UNUSED_CONST_NONNULL_ARGS(arg, ...)                RKL_ATTRIBUTES(warn_unused_result, const, nonnull(arg, ##__VA_ARGS__))
00188 #define RKL_WARN_UNUSED_PURE_NONNULL_ARGS(arg, ...)                 RKL_ATTRIBUTES(warn_unused_result, pure, nonnull(arg, ##__VA_ARGS__))
00189 
00190 #if       defined (__GNUC__) && (__GNUC__ >= 4) && (__GNUC_MINOR__ >= 3)
00191 #define RKL_ALLOC_SIZE_NON_NULL_ARGS_WARN_UNUSED(as, nn, ...) RKL_ATTRIBUTES(warn_unused_result, nonnull(nn, ##__VA_ARGS__), alloc_size(as))
00192 #else  // defined (__GNUC__) && (__GNUC__ >= 4) && (__GNUC_MINOR__ >= 3)
00193 #define RKL_ALLOC_SIZE_NON_NULL_ARGS_WARN_UNUSED(as, nn, ...) RKL_ATTRIBUTES(warn_unused_result, nonnull(nn, ##__VA_ARGS__))
00194 #endif // defined (__GNUC__) && (__GNUC__ >= 4) && (__GNUC_MINOR__ >= 3)
00195 
00196 #ifdef    _RKL_DTRACE_ENABLED
00197 #define RKL_UNUSED_DTRACE_ARG
00198 #else  // _RKL_DTRACE_ENABLED
00199 #define RKL_UNUSED_DTRACE_ARG RKL_ATTRIBUTES(unused)
00200 #endif // _RKL_DTRACE_ENABLED
00201 
00203 #pragma mark -
00204 #pragma mark Assertion macros
00205 
00206 // These macros are nearly identical to their NSCParameterAssert siblings.
00207 // This is required because nearly everything is done while rkl_cacheSpinLock is locked.
00208 // We need to safely unlock before throwing any of these exceptions.
00209 // @try {} @finally {} significantly slows things down so it's not used.
00210 
00211 #define RKLCHardAbortAssert(c) do { int _c=(c); if(RKL_EXPECTED(!_c, 0L)) { NSLog(@"%@:%ld: Invalid parameter not satisfying: %s\n", [NSString stringWithUTF8String:__FILE__], (long)__LINE__, #c); abort(); } } while(0)
00212 #define RKLCAssertDictionary(d, ...) rkl_makeAssertDictionary(__PRETTY_FUNCTION__, __FILE__, __LINE__, (d), ##__VA_ARGS__)
00213 #define RKLCDelayedHardAssert(c, e, g) do { id *_e=(e); int _c=(c); if(RKL_EXPECTED(_e == NULL, 0L) || RKL_EXPECTED(*_e != NULL, 0L)) { goto g; } if(RKL_EXPECTED(!_c, 0L)) { *_e = RKLCAssertDictionary(@"Invalid parameter not satisfying: %s", #c); goto g; } } while(0)
00214 
00215 #ifdef    NS_BLOCK_ASSERTIONS
00216 #define RKLCAbortAssert(c)
00217 #define RKLCDelayedAssert(c, e, g)
00218 #define RKL_UNUSED_ASSERTION_ARG RKL_ATTRIBUTES(unused)
00219 #else  // NS_BLOCK_ASSERTIONS
00220 #define RKLCAbortAssert(c) RKLCHardAbortAssert(c)
00221 #define RKLCDelayedAssert(c, e, g) RKLCDelayedHardAssert(c, e, g)
00222 #define RKL_UNUSED_ASSERTION_ARG
00223 #endif // NS_BLOCK_ASSERTIONS
00224 
00225 #define RKL_EXCEPTION(e, f, ...)       [NSException exceptionWithName:(e) reason:rkl_stringFromClassAndMethod((self), (_cmd), (f), ##__VA_ARGS__) userInfo:NULL]
00226 #define RKL_RAISE_EXCEPTION(e, f, ...) [RKL_EXCEPTION(e, f, ##__VA_ARGS__) raise]
00227 
00229 #pragma mark -
00230 #pragma mark Utility functions and macros
00231 
00232 RKL_STATIC_INLINE BOOL NSRangeInsideRange(NSRange cin, NSRange win) RKL_WARN_UNUSED;
00233 RKL_STATIC_INLINE BOOL NSRangeInsideRange(NSRange cin, NSRange win) { return((((cin.location - win.location) <= win.length) && ((NSMaxRange(cin) - win.location) <= win.length)) ? YES : NO); }
00234 
00235 #define NSMakeRange(loc, len) ((NSRange){.location=(NSUInteger)(loc),      .length=(NSUInteger)(len)})
00236 #define CFMakeRange(loc, len) ((CFRange){.location=   (CFIndex)(loc),      .length=   (CFIndex)(len)})
00237 #define NSNotFoundRange       ((NSRange){.location=(NSUInteger)NSNotFound, .length=              0UL})
00238 #define NSMaxiumRange         ((NSRange){.location=                   0UL, .length=    NSUIntegerMax})
00239 // These values are used to help tickle improper usage.
00240 #define RKLIllegalRange       ((NSRange){.location=          NSIntegerMax, .length=     NSIntegerMax})
00241 #define RKLIllegalPointer     ((void * RKL_GC_VOLATILE)0xBAD0C0DE)
00242 
00244 #pragma mark -
00245 #pragma mark Exported NSString symbols for exception names, error domains, error keys, etc
00246 
00247 NSString * const RKLICURegexException                  = @"RKLICURegexException";
00248 
00249 NSString * const RKLICURegexErrorDomain                = @"RKLICURegexErrorDomain";
00250 
00251 NSString * const RKLICURegexEnumerationOptionsErrorKey = @"RKLICURegexEnumerationOptions";
00252 NSString * const RKLICURegexErrorCodeErrorKey          = @"RKLICURegexErrorCode";
00253 NSString * const RKLICURegexErrorNameErrorKey          = @"RKLICURegexErrorName";
00254 NSString * const RKLICURegexLineErrorKey               = @"RKLICURegexLine";
00255 NSString * const RKLICURegexOffsetErrorKey             = @"RKLICURegexOffset";
00256 NSString * const RKLICURegexPreContextErrorKey         = @"RKLICURegexPreContext";
00257 NSString * const RKLICURegexPostContextErrorKey        = @"RKLICURegexPostContext";
00258 NSString * const RKLICURegexRegexErrorKey              = @"RKLICURegexRegex";
00259 NSString * const RKLICURegexRegexOptionsErrorKey       = @"RKLICURegexRegexOptions";
00260 NSString * const RKLICURegexReplacedCountErrorKey      = @"RKLICURegexReplacedCount";
00261 NSString * const RKLICURegexReplacedStringErrorKey     = @"RKLICURegexReplacedString";
00262 NSString * const RKLICURegexReplacementStringErrorKey  = @"RKLICURegexReplacementString";
00263 NSString * const RKLICURegexSubjectRangeErrorKey       = @"RKLICURegexSubjectRange";
00264 NSString * const RKLICURegexSubjectStringErrorKey      = @"RKLICURegexSubjectString";
00265 
00266 // Used internally by rkl_userInfoDictionary to specify which arguments should be set in the NSError userInfo dictionary.
00267 enum {
00268   RKLUserInfoNone                    = 0UL,
00269   RKLUserInfoSubjectRange            = 1UL << 0,
00270   RKLUserInfoReplacedCount           = 1UL << 1,
00271   RKLUserInfoRegexEnumerationOptions = 1UL << 2,
00272 };
00273 typedef NSUInteger RKLUserInfoOptions;
00274 
00276 #pragma mark -
00277 #pragma mark Type / struct definitions
00278 
00279 // In general, the ICU bits and pieces here must exactly match the definition in the ICU sources.
00280 
00281 #define U_STRING_NOT_TERMINATED_WARNING -124
00282 #define U_ZERO_ERROR                       0
00283 #define U_INDEX_OUTOFBOUNDS_ERROR          8
00284 #define U_BUFFER_OVERFLOW_ERROR           15
00285 #define U_PARSE_CONTEXT_LEN               16
00286 
00287 typedef struct uregex uregex; // Opaque ICU regex type.
00288 
00289 typedef struct UParseError { // This must be exactly the same as the 'real' ICU declaration.
00290   int32_t line;
00291   int32_t offset;
00292   UniChar preContext[U_PARSE_CONTEXT_LEN];
00293   UniChar postContext[U_PARSE_CONTEXT_LEN];
00294 } UParseError;
00295 
00296 // For use with GCC's cleanup() __attribute__.
00297 enum {
00298   RKLLockedCacheSpinLock   = 1UL << 0,
00299   RKLUnlockedCacheSpinLock = 1UL << 1,
00300 };
00301 
00302 enum {
00303   RKLSplitOp                         = 1UL,
00304   RKLReplaceOp                       = 2UL,
00305   RKLRangeOp                         = 3UL,
00306   RKLArrayOfStringsOp                = 4UL,
00307   RKLArrayOfCapturesOp               = 5UL,
00308   RKLCapturesArrayOp                 = 6UL,
00309   RKLDictionaryOfCapturesOp          = 7UL,
00310   RKLArrayOfDictionariesOfCapturesOp = 8UL,
00311   RKLMaskOp                          = 0xFUL,
00312   RKLReplaceMutable                  = 1UL << 4,
00313   RKLSubcapturesArray                = 1UL << 5,
00314 };
00315 typedef NSUInteger RKLRegexOp;
00316 
00317 enum {
00318   RKLBlockEnumerationMatchOp   = 1UL,
00319   RKLBlockEnumerationReplaceOp = 2UL,
00320 };
00321 typedef NSUInteger RKLBlockEnumerationOp;
00322 
00323 typedef struct {
00324   RKL_STRONG_REF NSRange    * RKL_GC_VOLATILE ranges;
00325                  NSRange                      findInRange, remainingRange;
00326                  NSInteger                    capacity, found, findUpTo, capture, addedSplitRanges;
00327                  size_t                       size, stackUsed;
00328   RKL_STRONG_REF void      ** RKL_GC_VOLATILE rangesScratchBuffer;
00329   RKL_STRONG_REF void      ** RKL_GC_VOLATILE stringsScratchBuffer;
00330   RKL_STRONG_REF void      ** RKL_GC_VOLATILE arraysScratchBuffer;
00331   RKL_STRONG_REF void      ** RKL_GC_VOLATILE dictionariesScratchBuffer;
00332   RKL_STRONG_REF void      ** RKL_GC_VOLATILE keysScratchBuffer;
00333 } RKLFindAll;
00334 
00335 typedef struct {
00336                  CFStringRef               string;
00337                  CFHashCode                hash;
00338                  CFIndex                   length;
00339   RKL_STRONG_REF UniChar * RKL_GC_VOLATILE uniChar;
00340 } RKLBuffer;
00341 
00342 typedef struct {
00343                  CFStringRef                     regexString;
00344                  CFHashCode                      regexHash;
00345                  RKLRegexOptions                 options;
00346                  uregex                         *icu_regex;
00347                  NSInteger                       captureCount;
00348   
00349                  CFStringRef                     setToString;
00350                  CFHashCode                      setToHash;
00351                  CFIndex                         setToLength;
00352                  NSUInteger                      setToIsImmutable:1;
00353                  NSUInteger                      setToNeedsConversion:1;
00354   RKL_STRONG_REF const UniChar * RKL_GC_VOLATILE setToUniChar;
00355                  NSRange                         setToRange, lastFindRange, lastMatchRange;
00356 
00357                  RKLBuffer                      *buffer;
00358 } RKLCachedRegex;
00359 
00361 #pragma mark -
00362 #pragma mark Translation unit scope global variables
00363 
00364 static RKLLRUCacheSet_t     rkl_lruFixedBufferCacheSet = _RKL_LRU_CACHE_SET_INIT, rkl_lruDynamicBufferCacheSet = _RKL_LRU_CACHE_SET_INIT;
00365 static RKLBuffer            rkl_lruDynamicBuffer[_RKL_LRU_CACHE_SET_WAYS];
00366 static UniChar              rkl_lruFixedUniChar[_RKL_LRU_CACHE_SET_WAYS][_RKL_FIXED_LENGTH]; // This is the fixed sized UTF-16 conversion buffer.
00367 static RKLBuffer            rkl_lruFixedBuffer[_RKL_LRU_CACHE_SET_WAYS] = {{NULL, 0UL, 0L, &rkl_lruFixedUniChar[0][0]}, {NULL, 0UL, 0L, &rkl_lruFixedUniChar[1][0]}, {NULL, 0UL, 0L, &rkl_lruFixedUniChar[2][0]}, {NULL, 0UL, 0L, &rkl_lruFixedUniChar[3][0]}};
00368 static RKLCachedRegex       rkl_cachedRegexes[_RKL_REGEX_CACHE_LINES];
00369 #if       defined(__GNUC__) && (__GNUC__ == 4) && defined(__GNUC_MINOR__) && (__GNUC_MINOR__ == 2)
00370 static RKLCachedRegex * volatile rkl_lastCachedRegex; // XXX This is a work around for what appears to be a optimizer code generation bug in GCC 4.2.
00371 #else
00372 static RKLCachedRegex *rkl_lastCachedRegex;
00373 #endif // defined(__GNUC__) && (__GNUC__ == 4) && defined(__GNUC_MINOR__) && (__GNUC_MINOR__ == 2)
00374 static RKLLRUCacheSet_t     rkl_cachedRegexCacheSets[_RKL_REGEX_LRU_CACHE_SETS] = { [0 ... (_RKL_REGEX_LRU_CACHE_SETS - 1UL)] = _RKL_LRU_CACHE_SET_INIT };
00375 static RKLLookasideCache_t  rkl_regexLookasideCache[_RKL_REGEX_LOOKASIDE_CACHE_SIZE] RKL_ALIGNED(64);
00376 static OSSpinLock           rkl_cacheSpinLock = OS_SPINLOCK_INIT;
00377 static const UniChar        rkl_emptyUniCharString[1];                                // For safety, icu_regexes are 'set' to this when the string they were searched is cleared.
00378 static RKL_STRONG_REF void * RKL_GC_VOLATILE rkl_scratchBuffer[_RKL_SCRATCH_BUFFERS]; // Used to hold temporary allocations that are allocated via reallocf().
00379 
00381 #pragma mark -
00382 #pragma mark CFArray and CFDictionary call backs
00383 
00384 // These are used when running under manual memory management for the array that rkl_splitArray creates.
00385 // The split strings are created, but not autoreleased.  The (immutable) array is created using these callbacks, which skips the CFRetain() call, effectively transferring ownership to the CFArray object.
00386 // For each split string this saves the overhead of an autorelease, then an array retain, then an NSAutoreleasePool release. This is good for a ~30% speed increase.
00387 
00388 static void  rkl_CFCallbackRelease(CFAllocatorRef allocator RKL_UNUSED_ARG, const void *ptr) { CFRelease((CFTypeRef)ptr);                                                   }
00389 static const CFArrayCallBacks           rkl_transferOwnershipArrayCallBacks           =      { (CFIndex)0L, NULL, rkl_CFCallbackRelease, CFCopyDescription, CFEqual         };
00390 static const CFDictionaryKeyCallBacks   rkl_transferOwnershipDictionaryKeyCallBacks   =      { (CFIndex)0L, NULL, rkl_CFCallbackRelease, CFCopyDescription, CFEqual, CFHash };
00391 static const CFDictionaryValueCallBacks rkl_transferOwnershipDictionaryValueCallBacks =      { (CFIndex)0L, NULL, rkl_CFCallbackRelease, CFCopyDescription, CFEqual         };
00392 
00393 #ifdef    __OBJC_GC__
00394 
00395 #pragma mark -
00396 #pragma mark Low-level Garbage Collection aware memory/resource allocation utilities
00397 // If compiled with Garbage Collection, we need to be able to do a few things slightly differently.
00398 // The basic premiss is that under GC we use a trampoline function pointer which is set to a _start function to catch the first invocation.
00399 // The _start function checks if GC is running and then overwrites the function pointer with the appropriate routine.  Think of it as 'lazy linking'.
00400 
00401 enum { RKLScannedOption = NSScannedOption };
00402 
00403 // rkl_collectingEnabled uses objc_getClass() to get the NSGarbageCollector class, which doesn't exist on earlier systems.
00404 // This allows for graceful failure should we find ourselves running on an earlier version of the OS without NSGarbageCollector.
00405 static BOOL  rkl_collectingEnabled_first (void);
00406 static BOOL  rkl_collectingEnabled_yes   (void) { return(YES); }
00407 static BOOL  rkl_collectingEnabled_no    (void) { return(NO);  }
00408 static BOOL(*rkl_collectingEnabled)      (void) = rkl_collectingEnabled_first;
00409 static BOOL  rkl_collectingEnabled_first (void) {
00410   BOOL gcEnabled = ([objc_getClass("NSGarbageCollector") defaultCollector] != NULL) ? YES : NO;
00411   if(gcEnabled == YES) {
00412     // This section of code is required due to what I consider to be a fundamental design flaw in Cocoas GC system.
00413     // Earlier versions of "Garbage Collection Programming Guide" stated that (paraphrased) "all globals are automatically roots".
00414     // Current versions of the guide now include the following warning:
00415     //    "You may pass addresses of strong globals or statics into routines expecting pointers to object pointers (such as id* or NSError**)
00416     //     only if they have first been assigned to directly, rather than through a pointer dereference."
00417     // This is a surprisingly non-trivial condition to actually meet in practice and is a recipe for impossible to debug race condition bugs.
00418     // We just happen to be very, very, very lucky in the fact that we can initialize our root set before the first use.
00419     NSUInteger x = 0UL;
00420     for(x = 0UL; x < _RKL_SCRATCH_BUFFERS; x++)    { rkl_scratchBuffer[x]            = NSAllocateCollectable(16UL, 0UL); rkl_scratchBuffer[x]            = NULL; }
00421     for(x = 0UL; x < _RKL_LRU_CACHE_SET_WAYS; x++) { rkl_lruDynamicBuffer[x].uniChar = NSAllocateCollectable(16UL, 0UL); rkl_lruDynamicBuffer[x].uniChar = NULL; }
00422   }
00423   return((rkl_collectingEnabled = (gcEnabled == YES) ? rkl_collectingEnabled_yes : rkl_collectingEnabled_no)());
00424 }
00425 
00426 // rkl_realloc()
00427 static void   *rkl_realloc_first (RKL_STRONG_REF void ** RKL_GC_VOLATILE ptr, size_t size, NSUInteger flags);
00428 static void   *rkl_realloc_std   (RKL_STRONG_REF void ** RKL_GC_VOLATILE ptr, size_t size, NSUInteger flags RKL_UNUSED_ARG) { return((*ptr = reallocf(*ptr, size))); }
00429 static void   *rkl_realloc_gc    (RKL_STRONG_REF void ** RKL_GC_VOLATILE ptr, size_t size, NSUInteger flags)                { return((*ptr = NSReallocateCollectable(*ptr, (NSUInteger)size, flags))); }
00430 static void *(*rkl_realloc)      (RKL_STRONG_REF void ** RKL_GC_VOLATILE ptr, size_t size, NSUInteger flags) RKL_ALLOC_SIZE_NON_NULL_ARGS_WARN_UNUSED(2,1) = rkl_realloc_first;
00431 static void   *rkl_realloc_first (RKL_STRONG_REF void ** RKL_GC_VOLATILE ptr, size_t size, NSUInteger flags)                { if(rkl_collectingEnabled()==YES) { rkl_realloc = rkl_realloc_gc; } else { rkl_realloc = rkl_realloc_std; } return(rkl_realloc(ptr, size, flags)); }
00432 
00433 // rkl_free()
00434 static void *  rkl_free_first (RKL_STRONG_REF void ** RKL_GC_VOLATILE ptr);
00435 static void *  rkl_free_std   (RKL_STRONG_REF void ** RKL_GC_VOLATILE ptr) { if(*ptr != NULL) { free(*ptr); *ptr = NULL; } return(NULL); }
00436 static void *  rkl_free_gc    (RKL_STRONG_REF void ** RKL_GC_VOLATILE ptr) { if(*ptr != NULL) {             *ptr = NULL; } return(NULL); }
00437 static void *(*rkl_free)      (RKL_STRONG_REF void ** RKL_GC_VOLATILE ptr) RKL_NONNULL_ARGS(1) = rkl_free_first;
00438 static void   *rkl_free_first (RKL_STRONG_REF void ** RKL_GC_VOLATILE ptr) { if(rkl_collectingEnabled()==YES) { rkl_free = rkl_free_gc; } else { rkl_free = rkl_free_std; } return(rkl_free(ptr)); }
00439 
00440 // rkl_CFAutorelease()
00441 static id  rkl_CFAutorelease_first (CFTypeRef obj);
00442 static id  rkl_CFAutorelease_std   (CFTypeRef obj) { return([(id)obj autorelease]);  }
00443 static id  rkl_CFAutorelease_gc    (CFTypeRef obj) { return(NSMakeCollectable(obj)); }
00444 static id(*rkl_CFAutorelease)      (CFTypeRef obj) = rkl_CFAutorelease_first;
00445 static id  rkl_CFAutorelease_first (CFTypeRef obj) { return((rkl_CFAutorelease = (rkl_collectingEnabled()==YES) ? rkl_CFAutorelease_gc : rkl_CFAutorelease_std)(obj)); }
00446 
00447 // rkl_CreateStringWithSubstring()
00448 static id  rkl_CreateStringWithSubstring_first (id string, NSRange range);
00449 static id  rkl_CreateStringWithSubstring_std   (id string, NSRange range) { return((id)CFStringCreateWithSubstring(NULL, (CFStringRef)string, CFMakeRange((CFIndex)range.location, (CFIndex)range.length))); }
00450 static id  rkl_CreateStringWithSubstring_gc    (id string, NSRange range) { return([string substringWithRange:range]); }
00451 static id(*rkl_CreateStringWithSubstring)      (id string, NSRange range) RKL_WARN_UNUSED_NONNULL_ARGS(1) = rkl_CreateStringWithSubstring_first;
00452 static id  rkl_CreateStringWithSubstring_first (id string, NSRange range) { return((rkl_CreateStringWithSubstring = (rkl_collectingEnabled()==YES) ? rkl_CreateStringWithSubstring_gc : rkl_CreateStringWithSubstring_std)(string, range)); }
00453 
00454 // rkl_ReleaseObject()
00455 static id   rkl_ReleaseObject_first (id obj);
00456 static id   rkl_ReleaseObject_std   (id obj)                { CFRelease((CFTypeRef)obj); return(NULL); }
00457 static id   rkl_ReleaseObject_gc    (id obj RKL_UNUSED_ARG) {                            return(NULL); }
00458 static id (*rkl_ReleaseObject)      (id obj) RKL_NONNULL_ARGS(1) = rkl_ReleaseObject_first;
00459 static id   rkl_ReleaseObject_first (id obj)                { return((rkl_ReleaseObject = (rkl_collectingEnabled()==YES) ? rkl_ReleaseObject_gc : rkl_ReleaseObject_std)(obj)); }
00460 
00461 // rkl_CreateArrayWithObjects()
00462 static id  rkl_CreateArrayWithObjects_first (void **objects, NSUInteger count);
00463 static id  rkl_CreateArrayWithObjects_std   (void **objects, NSUInteger count) { return((id)CFArrayCreate(NULL, (const void **)objects, (CFIndex)count, &rkl_transferOwnershipArrayCallBacks)); }
00464 static id  rkl_CreateArrayWithObjects_gc    (void **objects, NSUInteger count) { return([NSArray arrayWithObjects:(const id *)objects count:count]); }
00465 static id(*rkl_CreateArrayWithObjects)      (void **objects, NSUInteger count) RKL_WARN_UNUSED_NONNULL_ARGS(1) = rkl_CreateArrayWithObjects_first;
00466 static id  rkl_CreateArrayWithObjects_first (void **objects, NSUInteger count) { return((rkl_CreateArrayWithObjects = (rkl_collectingEnabled()==YES) ? rkl_CreateArrayWithObjects_gc : rkl_CreateArrayWithObjects_std)(objects, count)); }
00467 
00468 // rkl_CreateAutoreleasedArray()
00469 static id  rkl_CreateAutoreleasedArray_first (void **objects, NSUInteger count);
00470 static id  rkl_CreateAutoreleasedArray_std   (void **objects, NSUInteger count) { return((id)rkl_CFAutorelease(rkl_CreateArrayWithObjects(objects, count))); }
00471 static id  rkl_CreateAutoreleasedArray_gc    (void **objects, NSUInteger count) { return(                      rkl_CreateArrayWithObjects(objects, count) ); }
00472 static id(*rkl_CreateAutoreleasedArray)      (void **objects, NSUInteger count) RKL_WARN_UNUSED_NONNULL_ARGS(1) = rkl_CreateAutoreleasedArray_first;
00473 static id  rkl_CreateAutoreleasedArray_first (void **objects, NSUInteger count) { return((rkl_CreateAutoreleasedArray = (rkl_collectingEnabled()==YES) ? rkl_CreateAutoreleasedArray_gc : rkl_CreateAutoreleasedArray_std)(objects, count)); }
00474 
00475 #else  // __OBJC_GC__ not defined
00476 
00477 #pragma mark -
00478 #pragma mark Low-level explicit memory/resource allocation utilities
00479 
00480 enum { RKLScannedOption = 0 };
00481 
00482 #define rkl_collectingEnabled() (NO)
00483 
00484 RKL_STATIC_INLINE void *rkl_realloc                   (void **ptr, size_t size, NSUInteger flags) RKL_ALLOC_SIZE_NON_NULL_ARGS_WARN_UNUSED(2,1);
00485 RKL_STATIC_INLINE void *rkl_free                      (void **ptr)                                RKL_NONNULL_ARGS(1);
00486 RKL_STATIC_INLINE id    rkl_CFAutorelease             (CFTypeRef obj)                             RKL_WARN_UNUSED_NONNULL_ARGS(1);
00487 RKL_STATIC_INLINE id    rkl_CreateAutoreleasedArray   (void **objects, NSUInteger count)          RKL_WARN_UNUSED_NONNULL_ARGS(1);
00488 RKL_STATIC_INLINE id    rkl_CreateArrayWithObjects    (void **objects, NSUInteger count)          RKL_WARN_UNUSED_NONNULL_ARGS(1);
00489 RKL_STATIC_INLINE id    rkl_CreateStringWithSubstring (id string, NSRange range)                  RKL_WARN_UNUSED_NONNULL_ARGS(1);
00490 RKL_STATIC_INLINE id    rkl_ReleaseObject             (id obj)                                    RKL_NONNULL_ARGS(1);
00491 
00492 RKL_STATIC_INLINE void *rkl_realloc                   (void **ptr, size_t size, NSUInteger flags RKL_UNUSED_ARG) { return((*ptr = reallocf(*ptr, size))); }
00493 RKL_STATIC_INLINE void *rkl_free                      (void **ptr)                                               { if(*ptr != NULL) { free(*ptr); *ptr = NULL; } return(NULL); }
00494 RKL_STATIC_INLINE id    rkl_CFAutorelease             (CFTypeRef obj)                                            { return([(id)obj autorelease]); }
00495 RKL_STATIC_INLINE id    rkl_CreateArrayWithObjects    (void **objects, NSUInteger count)                         { return((id)CFArrayCreate(NULL, (const void **)objects, (CFIndex)count, &rkl_transferOwnershipArrayCallBacks)); }
00496 RKL_STATIC_INLINE id    rkl_CreateAutoreleasedArray   (void **objects, NSUInteger count)                         { return(rkl_CFAutorelease(rkl_CreateArrayWithObjects(objects, count))); }
00497 RKL_STATIC_INLINE id    rkl_CreateStringWithSubstring (id string, NSRange range)                                 { return((id)CFStringCreateWithSubstring(NULL, (CFStringRef)string, CFMakeRange((CFIndex)range.location, (CFIndex)range.length))); }
00498 RKL_STATIC_INLINE id    rkl_ReleaseObject             (id obj)                                                   { CFRelease((CFTypeRef)obj); return(NULL); }
00499 
00500 #endif // __OBJC_GC__
00501 
00503 #pragma mark -
00504 #pragma mark ICU function prototypes
00505 
00506 // ICU functions.  See http://www.icu-project.org/apiref/icu4c/uregex_8h.html Tweaked slightly from the originals, but functionally identical.
00507 const char *RKL_ICU_FUNCTION_APPEND(u_errorName)              (                                                                                                                             int32_t  status) RKL_WARN_UNUSED_PURE;
00508 int32_t     RKL_ICU_FUNCTION_APPEND(u_strlen)                 (const UniChar *s)                                                                                                                             RKL_WARN_UNUSED_PURE_NONNULL_ARGS(1);
00509 int32_t     RKL_ICU_FUNCTION_APPEND(uregex_appendReplacement) (      uregex  *regexp,  const UniChar *replacementText, int32_t replacementLength, UniChar **destBuf, int32_t *destCapacity, int32_t *status) RKL_WARN_UNUSED_NONNULL_ARGS(1,2,4,5,6);
00510 int32_t     RKL_ICU_FUNCTION_APPEND(uregex_appendTail)        (      uregex  *regexp,                                                             UniChar **destBuf, int32_t *destCapacity, int32_t *status) RKL_WARN_UNUSED_NONNULL_ARGS(1,2,3,4);
00511 void        RKL_ICU_FUNCTION_APPEND(uregex_close)             (      uregex  *regexp)                                                                                                                        RKL_NONNULL_ARGS(1);
00512 int32_t     RKL_ICU_FUNCTION_APPEND(uregex_end)               (      uregex  *regexp,  int32_t groupNum,                                                                                    int32_t *status) RKL_WARN_UNUSED_NONNULL_ARGS(1,3);
00513 BOOL        RKL_ICU_FUNCTION_APPEND(uregex_find)              (      uregex  *regexp,  int32_t location,                                                                                    int32_t *status) RKL_WARN_UNUSED_NONNULL_ARGS(1,3);
00514 BOOL        RKL_ICU_FUNCTION_APPEND(uregex_findNext)          (      uregex  *regexp,                                                                                                       int32_t *status) RKL_WARN_UNUSED_NONNULL_ARGS(1,2);
00515 int32_t     RKL_ICU_FUNCTION_APPEND(uregex_groupCount)        (      uregex  *regexp,                                                                                                       int32_t *status) RKL_WARN_UNUSED_NONNULL_ARGS(1,2);
00516 uregex     *RKL_ICU_FUNCTION_APPEND(uregex_open)              (const UniChar *pattern, int32_t patternLength, RKLRegexOptions flags, UParseError *parseError,                               int32_t *status) RKL_WARN_UNUSED_NONNULL_ARGS(1,4,5);
00517 void        RKL_ICU_FUNCTION_APPEND(uregex_reset)             (      uregex  *regexp,  int32_t newIndex,                                                                                    int32_t *status) RKL_NONNULL_ARGS(1,3);
00518 void        RKL_ICU_FUNCTION_APPEND(uregex_setText)           (      uregex  *regexp,  const UniChar *text, int32_t textLength,                                                             int32_t *status) RKL_NONNULL_ARGS(1,2,4);
00519 int32_t     RKL_ICU_FUNCTION_APPEND(uregex_start)             (      uregex  *regexp,  int32_t groupNum,                                                                                    int32_t *status) RKL_WARN_UNUSED_NONNULL_ARGS(1,3);
00520 uregex     *RKL_ICU_FUNCTION_APPEND(uregex_clone)             (const uregex  *regexp,                                                                                                       int32_t *status) RKL_WARN_UNUSED_NONNULL_ARGS(1,2);
00521 
00523 #pragma mark -
00524 #pragma mark RegexKitLite internal, private function prototypes
00525 
00526 // Functions used for managing the 4-way set associative LRU cache and regex string hash lookaside cache.
00527 RKL_STATIC_INLINE NSUInteger      rkl_leastRecentlyUsedWayInSet                          (      NSUInteger      cacheSetsCount, const RKLLRUCacheSet_t cacheSetsArray[cacheSetsCount], NSUInteger set)                  RKL_WARN_UNUSED_NONNULL_ARGS(2);
00528 RKL_STATIC_INLINE void            rkl_accessCacheSetWay                                  (      NSUInteger      cacheSetsCount,       RKLLRUCacheSet_t cacheSetsArray[cacheSetsCount], NSUInteger set, NSUInteger way)  RKL_NONNULL_ARGS(2);
00529 RKL_STATIC_INLINE NSUInteger      rkl_regexLookasideCacheIndexForPointerAndOptions       (const void           *ptr,         RKLRegexOptions options)                                                                   RKL_WARN_UNUSED_NONNULL_ARGS(1);
00530 RKL_STATIC_INLINE void            rkl_setRegexLookasideCacheToCachedRegexForPointer      (const RKLCachedRegex *cachedRegex, const void *ptr)                                                                           RKL_NONNULL_ARGS(1,2);
00531 RKL_STATIC_INLINE RKLCachedRegex *rkl_cachedRegexFromRegexLookasideCacheForString        (const void           *ptr,         RKLRegexOptions options)                                                                   RKL_WARN_UNUSED_NONNULL_ARGS(1);
00532 RKL_STATIC_INLINE NSUInteger      rkl_makeCacheSetHash                                   (      CFHashCode      regexHash,   RKLRegexOptions options)                                                                   RKL_WARN_UNUSED;
00533 RKL_STATIC_INLINE NSUInteger      rkl_cacheSetForRegexHashAndOptions                     (      CFHashCode      regexHash,   RKLRegexOptions options)                                                                   RKL_WARN_UNUSED;
00534 RKL_STATIC_INLINE NSUInteger      rkl_cacheWayForCachedRegex                             (const RKLCachedRegex *cachedRegex)                                                                                            RKL_WARN_UNUSED_NONNULL_ARGS(1);
00535 RKL_STATIC_INLINE NSUInteger      rkl_cacheSetForCachedRegex                             (const RKLCachedRegex *cachedRegex)                                                                                            RKL_WARN_UNUSED_NONNULL_ARGS(1);
00536 RKL_STATIC_INLINE RKLCachedRegex *rkl_cachedRegexForCacheSetAndWay                       (      NSUInteger      cacheSet,    NSUInteger      cacheWay)                                                                  RKL_WARN_UNUSED;
00537 RKL_STATIC_INLINE RKLCachedRegex *rkl_cachedRegexForRegexHashAndOptionsAndWay            (      CFHashCode      regexHash,   RKLRegexOptions options, NSUInteger cacheWay)                                              RKL_WARN_UNUSED;
00538 RKL_STATIC_INLINE void            rkl_updateCachesWithCachedRegex                        (      RKLCachedRegex *cachedRegex, const void *ptr, int hitOrMiss RKL_UNUSED_DTRACE_ARG, int status RKL_UNUSED_DTRACE_ARG)    RKL_NONNULL_ARGS(1,2);
00539 RKL_STATIC_INLINE RKLCachedRegex *rkl_leastRecentlyUsedCachedRegexForRegexHashAndOptions (      CFHashCode      regexHash,   RKLRegexOptions options)                                                                   RKL_WARN_UNUSED;
00540 
00541 static RKLCachedRegex *rkl_getCachedRegex            (NSString *regexString, RKLRegexOptions options, NSError **error, id *exception)                                                                                                                            RKL_WARN_UNUSED_NONNULL_ARGS(1,4);
00542 static NSUInteger      rkl_setCachedRegexToString    (RKLCachedRegex *cachedRegex, const NSRange *range, int32_t *status, id *exception RKL_UNUSED_ASSERTION_ARG)                                                                                                    RKL_WARN_UNUSED_NONNULL_ARGS(1,2,3,4);
00543 static RKLCachedRegex *rkl_getCachedRegexSetToString (NSString *regexString, RKLRegexOptions options, NSString *matchString, NSUInteger *matchLengthPtr, NSRange *matchRange, NSError **error, id *exception, int32_t *status)                                   RKL_WARN_UNUSED_NONNULL_ARGS(1,3,4,5,7,8);
00544 static id              rkl_performDictionaryVarArgsOp(id self, SEL _cmd, RKLRegexOp regexOp, NSString *regexString, RKLRegexOptions options, NSInteger capture, id matchString, NSRange *matchRange, NSString *replacementString, NSError **error, void *result, id firstKey, va_list varArgsList) RKL_NONNULL_ARGS(1,2);
00545 static id              rkl_performRegexOp            (id self, SEL _cmd, RKLRegexOp regexOp, NSString *regexString, RKLRegexOptions options, NSInteger capture, id matchString, NSRange *matchRange, NSString *replacementString, NSError **error, void *result, NSUInteger captureKeysCount, id captureKeys[captureKeysCount], const int captureKeyIndexes[captureKeysCount]) RKL_NONNULL_ARGS(1,2);
00546 static void            rkl_handleDelayedAssert       (id self, SEL _cmd, id exception)                                                                                                                                                                           RKL_NONNULL_ARGS(3);
00547 
00548 static NSUInteger      rkl_search                    (RKLCachedRegex *cachedRegex, NSRange *searchRange, NSUInteger updateSearchRange, id *exception RKL_UNUSED_ASSERTION_ARG, int32_t *status)                        RKL_WARN_UNUSED_NONNULL_ARGS(1,2,4,5);
00549 
00550 static BOOL            rkl_findRanges                (RKLCachedRegex *cachedRegex, RKLRegexOp regexOp,      RKLFindAll *findAll, id *exception, int32_t *status)                                                       RKL_WARN_UNUSED_NONNULL_ARGS(1,3,4,5);
00551 static NSUInteger      rkl_growFindRanges            (RKLCachedRegex *cachedRegex, NSUInteger lastLocation, RKLFindAll *findAll, id *exception RKL_UNUSED_ASSERTION_ARG)                                               RKL_WARN_UNUSED_NONNULL_ARGS(1,3,4);
00552 static NSArray        *rkl_makeArray                 (RKLCachedRegex *cachedRegex, RKLRegexOp regexOp,      RKLFindAll *findAll, id *exception RKL_UNUSED_ASSERTION_ARG)                                               RKL_WARN_UNUSED_NONNULL_ARGS(1,3,4);
00553 static id              rkl_makeDictionary            (RKLCachedRegex *cachedRegex, RKLRegexOp regexOp,      RKLFindAll *findAll, NSUInteger captureKeysCount, id captureKeys[captureKeysCount], const int captureKeyIndexes[captureKeysCount], id *exception RKL_UNUSED_ASSERTION_ARG) RKL_WARN_UNUSED_NONNULL_ARGS(1,3,5,6);
00554 
00555 static NSString       *rkl_replaceString             (RKLCachedRegex *cachedRegex, id searchString, NSUInteger searchU16Length, NSString *replacementString, NSUInteger replacementU16Length, NSInteger *replacedCount, NSUInteger replaceMutable, id *exception, int32_t *status) RKL_WARN_UNUSED_NONNULL_ARGS(1,2,4,8,9);
00556 static int32_t         rkl_replaceAll                (RKLCachedRegex *cachedRegex, RKL_STRONG_REF const UniChar * RKL_GC_VOLATILE replacementUniChar, int32_t replacementU16Length, UniChar *replacedUniChar, int32_t replacedU16Capacity, NSInteger *replacedCount, int32_t *needU16Capacity, id *exception RKL_UNUSED_ASSERTION_ARG, int32_t *status) RKL_WARN_UNUSED_NONNULL_ARGS(1,2,4,6,7,8,9);
00557 
00558 static NSUInteger      rkl_isRegexValid              (id self, SEL _cmd, NSString *regex, RKLRegexOptions options, NSInteger *captureCountPtr, NSError **error) RKL_NONNULL_ARGS(1,2);
00559 
00560 static void            rkl_clearStringCache          (void);
00561 static void            rkl_clearBuffer               (RKLBuffer *buffer, NSUInteger freeDynamicBuffer) RKL_NONNULL_ARGS(1);
00562 static void            rkl_clearCachedRegex          (RKLCachedRegex *cachedRegex)                     RKL_NONNULL_ARGS(1);
00563 static void            rkl_clearCachedRegexSetTo     (RKLCachedRegex *cachedRegex)                     RKL_NONNULL_ARGS(1);
00564 
00565 static NSDictionary   *rkl_userInfoDictionary        (RKLUserInfoOptions userInfoOptions, NSString *regexString, RKLRegexOptions options, const UParseError *parseError, int32_t status, NSString *matchString, NSRange matchRange, NSString *replacementString, NSString *replacedString, NSInteger replacedCount, RKLRegexEnumerationOptions enumerationOptions, ...)                        RKL_WARN_UNUSED_SENTINEL;
00566 static NSError        *rkl_makeNSError               (RKLUserInfoOptions userInfoOptions, NSString *regexString, RKLRegexOptions options, const UParseError *parseError, int32_t status, NSString *matchString, NSRange matchRange, NSString *replacementString, NSString *replacedString, NSInteger replacedCount, RKLRegexEnumerationOptions enumerationOptions, NSString *errorDescription) RKL_WARN_UNUSED;
00567 
00568 static NSException    *rkl_NSExceptionForRegex       (NSString *regexString, RKLRegexOptions options, const UParseError *parseError, int32_t status) RKL_WARN_UNUSED_NONNULL_ARGS(1);
00569 static NSDictionary   *rkl_makeAssertDictionary      (const char *function, const char *file, int line, NSString *format, ...)                       RKL_WARN_UNUSED_NONNULL_ARGS(1,2,4);
00570 static NSString       *rkl_stringFromClassAndMethod  (id object, SEL selector, NSString *format, ...)                                                RKL_WARN_UNUSED_NONNULL_ARGS(3);
00571 
00572 RKL_STATIC_INLINE int32_t rkl_getRangeForCapture(RKLCachedRegex *cr, int32_t *s, int32_t c, NSRange *r) RKL_WARN_UNUSED_NONNULL_ARGS(1,2,4);
00573 RKL_STATIC_INLINE int32_t rkl_getRangeForCapture(RKLCachedRegex *cr, int32_t *s, int32_t c, NSRange *r) { uregex *re = cr->icu_regex; int32_t start = RKL_ICU_FUNCTION_APPEND(uregex_start)(re, c, s); if(RKL_EXPECTED((*s > U_ZERO_ERROR), 0L) || (start == -1)) { *r = NSNotFoundRange; } else { r->location = (NSUInteger)start; r->length = (NSUInteger)RKL_ICU_FUNCTION_APPEND(uregex_end)(re, c, s) - r->location; r->location += cr->setToRange.location; } return(*s); }
00574 
00575 RKL_STATIC_INLINE RKLFindAll rkl_makeFindAll(RKL_STRONG_REF NSRange * RKL_GC_VOLATILE r, NSRange fir, NSInteger c, size_t s, size_t su, RKL_STRONG_REF void ** RKL_GC_VOLATILE rsb, RKL_STRONG_REF void ** RKL_GC_VOLATILE ssb, RKL_STRONG_REF void ** RKL_GC_VOLATILE asb, RKL_STRONG_REF void ** RKL_GC_VOLATILE dsb, RKL_STRONG_REF void ** RKL_GC_VOLATILE ksb, NSInteger f, NSInteger cap, NSInteger fut) RKL_WARN_UNUSED_CONST;
00576 RKL_STATIC_INLINE RKLFindAll rkl_makeFindAll(RKL_STRONG_REF NSRange * RKL_GC_VOLATILE r, NSRange fir, NSInteger c, size_t s, size_t su, RKL_STRONG_REF void ** RKL_GC_VOLATILE rsb, RKL_STRONG_REF void ** RKL_GC_VOLATILE ssb, RKL_STRONG_REF void ** RKL_GC_VOLATILE asb, RKL_STRONG_REF void ** RKL_GC_VOLATILE dsb, RKL_STRONG_REF void ** RKL_GC_VOLATILE ksb, NSInteger f, NSInteger cap, NSInteger fut) { return(((RKLFindAll){ .ranges=r, .findInRange=fir, .remainingRange=fir, .capacity=c, .found=f, .findUpTo=fut, .capture=cap, .addedSplitRanges=0L, .size=s, .stackUsed=su, .rangesScratchBuffer=rsb, .stringsScratchBuffer=ssb, .arraysScratchBuffer=asb, .dictionariesScratchBuffer=dsb, .keysScratchBuffer=ksb})); }
00577 
00579 #pragma mark -
00580 #pragma mark RKL_FAST_MUTABLE_CHECK implementation
00581 
00582 #ifdef RKL_FAST_MUTABLE_CHECK
00583 // We use a trampoline function pointer to check at run time if the function __CFStringIsMutable is available.
00584 // If it is, the trampoline function pointer is replaced with the address of that function.
00585 // Otherwise, we assume the worst case that every string is mutable.
00586 // This hopefully helps to protect us since we're using an undocumented, non-public API call.
00587 // We will keep on working if it ever does go away, just with a bit less performance due to the overhead of mutable checks.
00588 
00589 static BOOL  rkl_CFStringIsMutable_first (CFStringRef str);
00590 static BOOL  rkl_CFStringIsMutable_yes   (CFStringRef str RKL_UNUSED_ARG) { return(YES); }
00591 static BOOL(*rkl_CFStringIsMutable)      (CFStringRef str) = rkl_CFStringIsMutable_first;
00592 static BOOL  rkl_CFStringIsMutable_first (CFStringRef str)                { if((rkl_CFStringIsMutable = (BOOL(*)(CFStringRef))dlsym(RTLD_DEFAULT, "__CFStringIsMutable")) == NULL) { rkl_CFStringIsMutable = rkl_CFStringIsMutable_yes; } return(rkl_CFStringIsMutable(str)); }
00593 #else  // RKL_FAST_MUTABLE_CHECK is not defined.  Assume that all strings are potentially mutable.
00594 #define rkl_CFStringIsMutable(s) (YES)
00595 #endif // RKL_FAST_MUTABLE_CHECK
00596 
00598 #pragma mark -
00599 #pragma mark iPhone / iPod touch low memory notification handler
00600 
00601 #if       defined(RKL_REGISTER_FOR_IPHONE_LOWMEM_NOTIFICATIONS) && (RKL_REGISTER_FOR_IPHONE_LOWMEM_NOTIFICATIONS == 1)
00602 
00603 // The next few lines are specifically for the iPhone to catch low memory conditions.
00604 // The basic idea is that rkl_RegisterForLowMemoryNotifications() is set to be run once by the linker at load time via __attribute((constructor)).
00605 // rkl_RegisterForLowMemoryNotifications() tries to find the iPhone low memory notification symbol.  If it can find it,
00606 // it registers with the default NSNotificationCenter to call the RKLLowMemoryWarningObserver class method +lowMemoryWarning:.
00607 // rkl_RegisterForLowMemoryNotifications() uses an atomic compare and swap to guarantee that it initializes exactly once.
00608 // +lowMemoryWarning tries to acquire the cache lock.  If it gets the lock, it clears the cache.  If it can't, it calls performSelector:
00609 // with a delay of half a second to try again.  This will hopefully prevent any deadlocks, such as a RegexKitLite request for
00610 // memory triggering a notification while the lock is held.
00611 
00612 static void rkl_RegisterForLowMemoryNotifications(void) RKL_ATTRIBUTES(used);
00613 
00614 @interface      RKLLowMemoryWarningObserver : NSObject +(void)lowMemoryWarning:(id)notification; @end
00615 @implementation RKLLowMemoryWarningObserver
00616 +(void)lowMemoryWarning:(id)notification {
00617   if(OSSpinLockTry(&rkl_cacheSpinLock)) { rkl_clearStringCache(); OSSpinLockUnlock(&rkl_cacheSpinLock); }
00618   else { [[RKLLowMemoryWarningObserver class] performSelector:@selector(lowMemoryWarning:) withObject:notification afterDelay:(NSTimeInterval)0.1]; }
00619 }
00620 @end
00621 
00622 static volatile int rkl_HaveRegisteredForLowMemoryNotifications = 0;
00623 
00624 __attribute__((constructor)) static void rkl_RegisterForLowMemoryNotifications(void) {
00625   _Bool   didSwap                   = false;
00626   void  **memoryWarningNotification = NULL;
00627 
00628   while((rkl_HaveRegisteredForLowMemoryNotifications == 0) && ((didSwap = OSAtomicCompareAndSwapIntBarrier(0, 1, &rkl_HaveRegisteredForLowMemoryNotifications)) == false)) { /* Allows for spurious CAS failures. */ }
00629   if(didSwap == true) {
00630     if((memoryWarningNotification = (void **)dlsym(RTLD_DEFAULT, "UIApplicationDidReceiveMemoryWarningNotification")) != NULL) {
00631       [[NSNotificationCenter defaultCenter] addObserver:[RKLLowMemoryWarningObserver class] selector:@selector(lowMemoryWarning:) name:(NSString *)*memoryWarningNotification object:NULL];
00632     }
00633   }
00634 }
00635 
00636 #endif // defined(RKL_REGISTER_FOR_IPHONE_LOWMEM_NOTIFICATIONS) && (RKL_REGISTER_FOR_IPHONE_LOWMEM_NOTIFICATIONS == 1)
00637 
00639 #pragma mark -
00640 #pragma mark DTrace functionality
00641 
00642 #ifdef    _RKL_DTRACE_ENABLED
00643 
00644 // compiledRegexCache(unsigned long eventID, const char *regexUTF8, int options, int captures, int hitMiss, int icuStatusCode, const char *icuErrorMessage, double *hitRate);
00645 // utf16ConversionCache(unsigned long eventID, unsigned int lookupResultFlags, double *hitRate, const void *string, unsigned long NSRange.location, unsigned long NSRange.length, long length);
00646 
00647 /*
00648 provider RegexKitLite {
00649  probe compiledRegexCache(unsigned long, const char *, unsigned int, int, int, int, const char *, double *);
00650  probe utf16ConversionCache(unsigned long, unsigned int, double *, const void *, unsigned long, unsigned long, long);
00651 };
00652  
00653 #pragma D attributes Unstable/Unstable/Common provider RegexKitLite provider
00654 #pragma D attributes Private/Private/Common   provider RegexKitLite module
00655 #pragma D attributes Private/Private/Common   provider RegexKitLite function
00656 #pragma D attributes Unstable/Unstable/Common provider RegexKitLite name
00657 #pragma D attributes Unstable/Unstable/Common provider RegexKitLite args
00658 */
00659 
00660 #define REGEXKITLITE_STABILITY "___dtrace_stability$RegexKitLite$v1$4_4_5_1_1_5_1_1_5_4_4_5_4_4_5"
00661 #define REGEXKITLITE_TYPEDEFS  "___dtrace_typedefs$RegexKitLite$v1"
00662 #define REGEXKITLITE_COMPILEDREGEXCACHE(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7) { __asm__ volatile(".reference " REGEXKITLITE_TYPEDEFS); __dtrace_probe$RegexKitLite$compiledRegexCache$v1$756e7369676e6564206c6f6e67$63686172202a$756e7369676e656420696e74$696e74$696e74$696e74$63686172202a$646f75626c65202a(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7); __asm__ volatile(".reference " REGEXKITLITE_STABILITY); }
00663 #define REGEXKITLITE_COMPILEDREGEXCACHE_ENABLED() __dtrace_isenabled$RegexKitLite$compiledRegexCache$v1()
00664 #define REGEXKITLITE_CONVERTEDSTRINGU16CACHE(arg0, arg1, arg2, arg3, arg4, arg5, arg6) { __asm__ volatile(".reference " REGEXKITLITE_TYPEDEFS); __dtrace_probe$RegexKitLite$utf16ConversionCache$v1$756e7369676e6564206c6f6e67$756e7369676e656420696e74$646f75626c65202a$766f6964202a$756e7369676e6564206c6f6e67$756e7369676e6564206c6f6e67$6c6f6e67(arg0, arg1, arg2, arg3, arg4, arg5, arg6); __asm__ volatile(".reference " REGEXKITLITE_STABILITY); }
00665 #define REGEXKITLITE_CONVERTEDSTRINGU16CACHE_ENABLED() __dtrace_isenabled$RegexKitLite$utf16ConversionCache$v1()
00666 
00667 extern void __dtrace_probe$RegexKitLite$compiledRegexCache$v1$756e7369676e6564206c6f6e67$63686172202a$756e7369676e656420696e74$696e74$696e74$696e74$63686172202a$646f75626c65202a(unsigned long, const char *, unsigned int, int, int, int, const char *, double *);
00668 extern int  __dtrace_isenabled$RegexKitLite$compiledRegexCache$v1(void);
00669 extern void __dtrace_probe$RegexKitLite$utf16ConversionCache$v1$756e7369676e6564206c6f6e67$756e7369676e656420696e74$646f75626c65202a$766f6964202a$756e7369676e6564206c6f6e67$756e7369676e6564206c6f6e67$6c6f6e67(unsigned long, unsigned int, double *, const void *, unsigned long, unsigned long, long);
00670 extern int  __dtrace_isenabled$RegexKitLite$utf16ConversionCache$v1(void);
00671 
00673 
00674 enum {
00675   RKLCacheHitLookupFlag           = 1 << 0,
00676   RKLConversionRequiredLookupFlag = 1 << 1,
00677   RKLSetTextLookupFlag            = 1 << 2,
00678   RKLDynamicBufferLookupFlag      = 1 << 3,
00679   RKLErrorLookupFlag              = 1 << 4,
00680   RKLEnumerationBufferLookupFlag  = 1 << 5,
00681 };
00682 
00683 #define rkl_dtrace_addLookupFlag(a,b) do { a |= (unsigned int)(b); } while(0)
00684 
00685 static char rkl_dtrace_regexUTF8[_RKL_REGEX_CACHE_LINES + 1UL][_RKL_DTRACE_REGEXUTF8_SIZE];
00686 static NSUInteger rkl_dtrace_eventID, rkl_dtrace_compiledCacheLookups, rkl_dtrace_compiledCacheHits, rkl_dtrace_conversionBufferLookups, rkl_dtrace_conversionBufferHits;
00687 
00688 #define rkl_dtrace_incrementEventID() do { rkl_dtrace_eventID++; } while(0)
00689 #define rkl_dtrace_incrementAndGetEventID(v) do { rkl_dtrace_eventID++; v = rkl_dtrace_eventID; } while(0)
00690 #define rkl_dtrace_compiledRegexCache(a0, a1, a2, a3, a4, a5) do { int _a3 = (a3); rkl_dtrace_compiledCacheLookups++; if(_a3 == 1) { rkl_dtrace_compiledCacheHits++; } if(RKL_EXPECTED(REGEXKITLITE_COMPILEDREGEXCACHE_ENABLED(), 0L)) { double hitRate = 0.0; if(rkl_dtrace_compiledCacheLookups > 0UL) { hitRate = ((double)rkl_dtrace_compiledCacheHits / (double)rkl_dtrace_compiledCacheLookups) * 100.0; } REGEXKITLITE_COMPILEDREGEXCACHE(rkl_dtrace_eventID, a0, a1, a2, _a3, a4, a5, &hitRate); } } while(0)
00691 #define rkl_dtrace_utf16ConversionCache(a0, a1, a2, a3, a4) do { unsigned int _a0 = (a0); if((_a0 & RKLConversionRequiredLookupFlag) != 0U) { rkl_dtrace_conversionBufferLookups++; if((_a0 & RKLCacheHitLookupFlag) != 0U) { rkl_dtrace_conversionBufferHits++; } } if(RKL_EXPECTED(REGEXKITLITE_CONVERTEDSTRINGU16CACHE_ENABLED(), 0L)) { double hitRate = 0.0; if(rkl_dtrace_conversionBufferLookups > 0UL) { hitRate = ((double)rkl_dtrace_conversionBufferHits / (double)rkl_dtrace_conversionBufferLookups) * 100.0; } REGEXKITLITE_CONVERTEDSTRINGU16CACHE(rkl_dtrace_eventID, _a0, &hitRate, a1, a2, a3, a4); } } while(0)
00692 #define rkl_dtrace_utf16ConversionCacheWithEventID(c0, a0, a1, a2, a3, a4) do { unsigned int _a0 = (a0); if((_a0 & RKLConversionRequiredLookupFlag) != 0U) { rkl_dtrace_conversionBufferLookups++; if((_a0 & RKLCacheHitLookupFlag) != 0U) { rkl_dtrace_conversionBufferHits++; } } if(RKL_EXPECTED(REGEXKITLITE_CONVERTEDSTRINGU16CACHE_ENABLED(), 0L)) { double hitRate = 0.0; if(rkl_dtrace_conversionBufferLookups > 0UL) { hitRate = ((double)rkl_dtrace_conversionBufferHits / (double)rkl_dtrace_conversionBufferLookups) * 100.0; } REGEXKITLITE_CONVERTEDSTRINGU16CACHE(c0, _a0, &hitRate, a1, a2, a3, a4); } } while(0)
00693 
00694 
00695 // \342\200\246 == UTF8 for HORIZONTAL ELLIPSIS, aka triple dots '...'
00696 #define RKL_UTF8_ELLIPSE "\342\200\246"
00697 
00698 // rkl_dtrace_getRegexUTF8 will copy the str argument to utf8Buffer using UTF8 as the string encoding.
00699 // If the utf8 encoding would take up more bytes than the utf8Buffers length, then the unicode character 'HORIZONTAL ELLIPSIS' ('...') is appended to indicate truncation occurred.
00700 static void rkl_dtrace_getRegexUTF8(CFStringRef str, char *utf8Buffer) RKL_NONNULL_ARGS(2);
00701 static void rkl_dtrace_getRegexUTF8(CFStringRef str, char *utf8Buffer) {
00702   if((str == NULL) || (utf8Buffer == NULL)) { return; }
00703   CFIndex maxLength = ((CFIndex)_RKL_DTRACE_REGEXUTF8_SIZE - 2L), maxBytes = (maxLength - (CFIndex)sizeof(RKL_UTF8_ELLIPSE) - 1L), stringU16Length = CFStringGetLength(str), usedBytes = 0L;
00704   CFStringGetBytes(str, CFMakeRange(0L, ((stringU16Length < maxLength) ? stringU16Length : maxLength)), kCFStringEncodingUTF8, (UInt8)'?', (Boolean)0, (UInt8 *)utf8Buffer, maxBytes, &usedBytes);
00705   if(usedBytes == maxBytes) { strncpy(utf8Buffer + usedBytes, RKL_UTF8_ELLIPSE, ((size_t)_RKL_DTRACE_REGEXUTF8_SIZE - (size_t)usedBytes) - 2UL); } else { utf8Buffer[usedBytes] = (char)0; }
00706 }
00707 
00708 #else  // _RKL_DTRACE_ENABLED
00709 
00710 #define rkl_dtrace_incrementEventID()
00711 #define rkl_dtrace_incrementAndGetEventID(v)
00712 #define rkl_dtrace_compiledRegexCache(a0, a1, a2, a3, a4, a5)
00713 #define rkl_dtrace_utf16ConversionCache(a0, a1, a2, a3, a4)
00714 #define rkl_dtrace_utf16ConversionCacheWithEventID(c0, a0, a1, a2, a3, a4)
00715 #define rkl_dtrace_getRegexUTF8(str, buf)
00716 #define rkl_dtrace_addLookupFlag(a,b)
00717 
00718 #endif // _RKL_DTRACE_ENABLED
00719 
00721 #pragma mark -
00722 #pragma mark RegexKitLite low-level internal functions
00723 #pragma mark -
00724 
00725 // The 4-way set associative LRU logic comes from Henry S. Warren Jr.'s Hacker's Delight, "revisions", 7-7 An LRU Algorithm:
00726 // http://www.hackersdelight.org/revisions.pdf
00727 // The functions rkl_leastRecentlyUsedWayInSet() and rkl_accessCacheSetWay() implement the cache functionality and are used
00728 // from a number of different places that need to perform caching (i.e., cached regex, cached UTF16 conversions, etc)
00729 
00730 #pragma mark 4-way set associative LRU functions
00731 
00732 RKL_STATIC_INLINE NSUInteger rkl_leastRecentlyUsedWayInSet(NSUInteger cacheSetsCount, const RKLLRUCacheSet_t cacheSetsArray[cacheSetsCount], NSUInteger set) {
00733   RKLCAbortAssert((cacheSetsArray != NULL) && ((NSInteger)cacheSetsCount > 0L) && (set < cacheSetsCount) && ((cacheSetsArray == rkl_cachedRegexCacheSets) ? set < _RKL_REGEX_LRU_CACHE_SETS : 1) && (((sizeof(unsigned int) - sizeof(RKLLRUCacheSet_t)) * 8) < (sizeof(unsigned int) * 8)));
00734   unsigned int cacheSet = (((unsigned int)cacheSetsArray[set]) << ((sizeof(unsigned int) - sizeof(RKLLRUCacheSet_t)) * 8)); // __builtin_clz takes an 'unsigned int' argument.  The rest is to ensure bit alignment regardless of 32/64/whatever.
00735   NSUInteger leastRecentlyUsed = ((NSUInteger)(3LU - (NSUInteger)((__builtin_clz((~(((cacheSet & 0x77777777U) + 0x77777777U) | cacheSet | 0x77777777U))) ) >> 2)));
00736   RKLCAbortAssert(leastRecentlyUsed < _RKL_LRU_CACHE_SET_WAYS);
00737   return(leastRecentlyUsed);
00738 }
00739 
00740 RKL_STATIC_INLINE void rkl_accessCacheSetWay(NSUInteger cacheSetsCount, RKLLRUCacheSet_t cacheSetsArray[cacheSetsCount], NSUInteger cacheSet, NSUInteger cacheWay) {
00741   RKLCAbortAssert((cacheSetsArray != NULL) && ((NSInteger)cacheSetsCount > 0L) && (cacheSet < cacheSetsCount) && (cacheWay < _RKL_LRU_CACHE_SET_WAYS) && ((cacheSetsArray == rkl_cachedRegexCacheSets) ? cacheSet < _RKL_REGEX_LRU_CACHE_SETS : 1));
00742   cacheSetsArray[cacheSet] = (RKLLRUCacheSet_t)(((cacheSetsArray[cacheSet] & (RKLLRUCacheSet_t)0xFFFFU) | (((RKLLRUCacheSet_t)0xFU) << (cacheWay * 4U))) & (~(((RKLLRUCacheSet_t)0x1111U) << (3U - cacheWay))));
00743 }
00744 
00745 #pragma mark Common, macro'ish compiled regular expression cache logic
00746 
00747 // These functions consolidate bits and pieces of code used to maintain, update, and access the 4-way set associative LRU cache and Regex Lookaside Cache.
00748 RKL_STATIC_INLINE NSUInteger      rkl_regexLookasideCacheIndexForPointerAndOptions  (const void           *ptr,       RKLRegexOptions options)                       { return(((((NSUInteger)(ptr)) >> 4) + options + (options >> 4)) & _RKL_REGEX_LOOKASIDE_CACHE_MASK); }
00749 RKL_STATIC_INLINE void            rkl_setRegexLookasideCacheToCachedRegexForPointer (const RKLCachedRegex *cachedRegex, const void *ptr)                             { rkl_regexLookasideCache[rkl_regexLookasideCacheIndexForPointerAndOptions(ptr, cachedRegex->options)] = (cachedRegex - rkl_cachedRegexes); }
00750 RKL_STATIC_INLINE RKLCachedRegex *rkl_cachedRegexFromRegexLookasideCacheForString   (const void           *ptr,       RKLRegexOptions options)                       { return(&rkl_cachedRegexes[rkl_regexLookasideCache[rkl_regexLookasideCacheIndexForPointerAndOptions(ptr, options)]]); }
00751 RKL_STATIC_INLINE NSUInteger      rkl_makeCacheSetHash                              (      CFHashCode      regexHash, RKLRegexOptions options)                       { return((NSUInteger)regexHash ^ (NSUInteger)options); }
00752 RKL_STATIC_INLINE NSUInteger      rkl_cacheSetForRegexHashAndOptions                (      CFHashCode      regexHash, RKLRegexOptions options)                       { return((rkl_makeCacheSetHash(regexHash, options) % _RKL_REGEX_LRU_CACHE_SETS)); }
00753 RKL_STATIC_INLINE NSUInteger      rkl_cacheWayForCachedRegex                        (const RKLCachedRegex *cachedRegex)                                              { return((cachedRegex - rkl_cachedRegexes) % _RKL_LRU_CACHE_SET_WAYS); }
00754 RKL_STATIC_INLINE NSUInteger      rkl_cacheSetForCachedRegex                        (const RKLCachedRegex *cachedRegex)                                              { return(rkl_cacheSetForRegexHashAndOptions(cachedRegex->regexHash, cachedRegex->options)); }
00755 RKL_STATIC_INLINE RKLCachedRegex *rkl_cachedRegexForCacheSetAndWay                  (      NSUInteger      cacheSet,  NSUInteger cacheWay)                           { return(&rkl_cachedRegexes[((cacheSet * _RKL_LRU_CACHE_SET_WAYS) + cacheWay)]); }
00756 RKL_STATIC_INLINE RKLCachedRegex *rkl_cachedRegexForRegexHashAndOptionsAndWay       (      CFHashCode      regexHash, RKLRegexOptions options, NSUInteger cacheWay)  { return(rkl_cachedRegexForCacheSetAndWay(rkl_cacheSetForRegexHashAndOptions(regexHash, options), cacheWay)); }
00757 
00758 RKL_STATIC_INLINE void rkl_updateCachesWithCachedRegex(RKLCachedRegex *cachedRegex, const void *ptr, int hitOrMiss RKL_UNUSED_DTRACE_ARG, int status RKL_UNUSED_DTRACE_ARG) {
00759   rkl_lastCachedRegex = cachedRegex;
00760   rkl_setRegexLookasideCacheToCachedRegexForPointer(cachedRegex, ptr);
00761   rkl_accessCacheSetWay(_RKL_REGEX_LRU_CACHE_SETS, rkl_cachedRegexCacheSets, rkl_cacheSetForCachedRegex(cachedRegex), rkl_cacheWayForCachedRegex(cachedRegex)); // Set the matching line as the most recently used.
00762   rkl_dtrace_compiledRegexCache(&rkl_dtrace_regexUTF8[(cachedRegex - rkl_cachedRegexes)][0], cachedRegex->options, (int)cachedRegex->captureCount, hitOrMiss, status, NULL);
00763 }
00764 
00765 RKL_STATIC_INLINE RKLCachedRegex *rkl_leastRecentlyUsedCachedRegexForRegexHashAndOptions(CFHashCode regexHash, RKLRegexOptions options) {
00766   NSUInteger cacheSet = rkl_cacheSetForRegexHashAndOptions(regexHash, options);
00767   return(rkl_cachedRegexForCacheSetAndWay(cacheSet, rkl_leastRecentlyUsedWayInSet(_RKL_REGEX_LRU_CACHE_SETS, rkl_cachedRegexCacheSets, cacheSet)));
00768 }
00769 
00770 #pragma mark Regular expression lookup function
00771 
00772 //  IMPORTANT!   This code is critical path code.  Because of this, it has been written for speed, not clarity.
00773 //  IMPORTANT!   Should only be called with rkl_cacheSpinLock already locked!
00774 //  ----------
00775 
00776 static RKLCachedRegex *rkl_getCachedRegex(NSString *regexString, RKLRegexOptions options, NSError **error, id *exception) {
00777   //  ----------   vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
00778   //  IMPORTANT!   This section of code is called almost every single time that any RegexKitLite functionality is used! It /MUST/ be very fast!
00779   //  ----------   vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
00780   
00781   RKLCachedRegex *cachedRegex = NULL;
00782   CFHashCode      regexHash   = 0UL;
00783   int32_t         status      = 0;
00784 
00785   RKLCDelayedAssert((rkl_cacheSpinLock != (OSSpinLock)0) && (regexString != NULL), exception, exitNow);
00786   
00787   // Fast path the common case where this regex is exactly the same one used last time.
00788   // The pointer equality test is valid under these circumstances since the cachedRegex->regexString is an immutable copy.
00789   // If the regexString argument is mutable, this test will fail, and we'll use the the slow path cache check below.
00790   if(RKL_EXPECTED(rkl_lastCachedRegex != NULL, 1L) && RKL_EXPECTED(rkl_lastCachedRegex->regexString == (CFStringRef)regexString, 1L) && RKL_EXPECTED(rkl_lastCachedRegex->options == options, 1L) && RKL_EXPECTED(rkl_lastCachedRegex->icu_regex != NULL, 1L)) {
00791     rkl_dtrace_compiledRegexCache(&rkl_dtrace_regexUTF8[(rkl_lastCachedRegex - rkl_cachedRegexes)][0], rkl_lastCachedRegex->options, (int)rkl_lastCachedRegex->captureCount, 1, 0, NULL);
00792     return(rkl_lastCachedRegex);
00793   }
00794 
00795   rkl_lastCachedRegex = NULL; // Make sure that rkl_lastCachedRegex is NULL in case there is some kind of error.
00796   cachedRegex         = rkl_cachedRegexFromRegexLookasideCacheForString(regexString, options); // Check the Regex Lookaside Cache to see if we can quickly find the correct Cached Regex for this regexString pointer + options.
00797   if((RKL_EXPECTED(cachedRegex->regexString == (CFStringRef)regexString, 1L) || (RKL_EXPECTED(cachedRegex->regexString != NULL, 1L) && RKL_EXPECTED(CFEqual((CFTypeRef)regexString, (CFTypeRef)cachedRegex->regexString) == YES, 1L))) && RKL_EXPECTED(cachedRegex->options == options, 1L) && RKL_EXPECTED(cachedRegex->icu_regex != NULL, 1L)) { goto foundMatch; } // There was a Regex Lookaside Cache hit, jump to foundMatch: to quickly return the result. A Regex Lookaside Cache hit allows us to bypass calling CFHash(), which is a decent performance win.
00798   else { cachedRegex = NULL; regexHash = CFHash((CFTypeRef)regexString); } // Regex Lookaside Cache miss.  We need to call CFHash() to determine the cache set for this regex.
00799 
00800   NSInteger cacheWay = 0L;                                                               // Check each way of the set that this regex belongs to.
00801   for(cacheWay = ((NSInteger)_RKL_LRU_CACHE_SET_WAYS - 1L); cacheWay > 0L; cacheWay--) { // Checking the ways in reverse (3, 2, 1, 0) finds a match "sooner" on average.
00802     cachedRegex = rkl_cachedRegexForRegexHashAndOptionsAndWay(regexHash, options, (NSUInteger)cacheWay);
00803     // Return the cached entry if it's a match. If regexString is mutable, the pointer equality test will fail, and CFEqual() is used to determine true equality with the immutable cachedRegex copy.  CFEqual() performs a slow character by character check.
00804     if(RKL_EXPECTED(cachedRegex->regexHash == regexHash, 0UL) && ((cachedRegex->regexString == (CFStringRef)regexString) || (RKL_EXPECTED(cachedRegex->regexString != NULL, 1L) && RKL_EXPECTED(CFEqual((CFTypeRef)regexString, (CFTypeRef)cachedRegex->regexString) == YES, 1L))) && RKL_EXPECTED(cachedRegex->options == options, 1L) && RKL_EXPECTED(cachedRegex->icu_regex != NULL, 1L)) {
00805     foundMatch: // Control can transfer here (from above) via a Regex Lookaside Cache hit.
00806       rkl_updateCachesWithCachedRegex(cachedRegex, regexString, 1, 0);
00807       return(cachedRegex);
00808     }
00809   }
00810 
00811   //  ----------   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
00812   //  IMPORTANT!   This section of code is called almost every single time that any RegexKitLite functionality is used! It /MUST/ be very fast!
00813   //  ----------   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
00814 
00815   // Code below this point is not as sensitive to speed since compiling a regular expression is an extremely expensive operation.
00816   // The regex was not found in the cache.  Get the cached regex for the least recently used line in the set, then clear the cached regex and create a new ICU regex in its place.
00817   cachedRegex = rkl_leastRecentlyUsedCachedRegexForRegexHashAndOptions(regexHash, options);
00818   rkl_clearCachedRegex(cachedRegex);
00819   
00820   if(RKL_EXPECTED((cachedRegex->regexString = CFStringCreateCopy(NULL, (CFStringRef)regexString)) == NULL, 0L)) { goto exitNow; } ; // Get a cheap immutable copy.
00821   rkl_dtrace_getRegexUTF8(cachedRegex->regexString, &rkl_dtrace_regexUTF8[(cachedRegex - rkl_cachedRegexes)][0]);
00822   cachedRegex->regexHash = regexHash;
00823   cachedRegex->options   = options;
00824   
00825   CFIndex                                        regexStringU16Length = CFStringGetLength(cachedRegex->regexString); // In UTF16 code units.
00826   UParseError                                    parseError           = (UParseError){-1, -1, {0}, {0}};
00827   RKL_STRONG_REF const UniChar * RKL_GC_VOLATILE regexUniChar         = NULL;
00828   
00829   if(RKL_EXPECTED(regexStringU16Length >= (CFIndex)INT_MAX, 0L)) { *exception = [NSException exceptionWithName:NSRangeException reason:@"Regex string length exceeds INT_MAX" userInfo:NULL]; goto exitNow; }
00830 
00831   // Try to quickly obtain regexString in UTF16 format.
00832   if((regexUniChar = CFStringGetCharactersPtr(cachedRegex->regexString)) == NULL) { // We didn't get the UTF16 pointer quickly and need to perform a full conversion in a temp buffer.
00833     RKL_STRONG_REF UniChar * RKL_GC_VOLATILE uniCharBuffer = NULL;
00834     if(((size_t)regexStringU16Length * sizeof(UniChar)) < (size_t)_RKL_STACK_LIMIT) { if(RKL_EXPECTED((uniCharBuffer = (RKL_STRONG_REF UniChar * RKL_GC_VOLATILE)alloca(                            (size_t)regexStringU16Length * sizeof(UniChar)     )) == NULL, 0L)) { goto exitNow; } } // Try to use the stack.
00835     else {                                                                            if(RKL_EXPECTED((uniCharBuffer = (RKL_STRONG_REF UniChar * RKL_GC_VOLATILE)rkl_realloc(&rkl_scratchBuffer[0], (size_t)regexStringU16Length * sizeof(UniChar), 0UL)) == NULL, 0L)) { goto exitNow; } } // Otherwise use the heap.
00836     CFStringGetCharacters(cachedRegex->regexString, CFMakeRange(0L, regexStringU16Length), uniCharBuffer); // Convert regexString to UTF16.
00837     regexUniChar = uniCharBuffer;
00838   }
00839   
00840   // Create the ICU regex.
00841   if(RKL_EXPECTED((cachedRegex->icu_regex = RKL_ICU_FUNCTION_APPEND(uregex_open)(regexUniChar, (int32_t)regexStringU16Length, options, &parseError, &status)) == NULL, 0L)) { goto exitNow; }
00842   if(RKL_EXPECTED(status <= U_ZERO_ERROR, 1L)) { cachedRegex->captureCount = (NSInteger)RKL_ICU_FUNCTION_APPEND(uregex_groupCount)(cachedRegex->icu_regex, &status); }
00843   if(RKL_EXPECTED(status <= U_ZERO_ERROR, 1L)) { rkl_updateCachesWithCachedRegex(cachedRegex, regexString, 0, status); }
00844   
00845 exitNow:
00846   if(RKL_EXPECTED(rkl_scratchBuffer[0] != NULL,         0L)) { rkl_scratchBuffer[0] = rkl_free(&rkl_scratchBuffer[0]); }
00847   if(RKL_EXPECTED(status                > U_ZERO_ERROR, 0L)) { rkl_clearCachedRegex(cachedRegex); cachedRegex = rkl_lastCachedRegex = NULL; if(error != NULL) { *error = rkl_makeNSError((RKLUserInfoOptions)RKLUserInfoNone, regexString, options, &parseError, status, NULL, NSNotFoundRange, NULL, NULL, 0L, (RKLRegexEnumerationOptions)RKLRegexEnumerationNoOptions, @"There was an error compiling the regular expression."); } }
00848   
00849 #ifdef    _RKL_DTRACE_ENABLED
00850   if(RKL_EXPECTED(cachedRegex == NULL, 1L)) { char regexUTF8[_RKL_DTRACE_REGEXUTF8_SIZE]; const char *err = NULL; if(status != U_ZERO_ERROR) { err = RKL_ICU_FUNCTION_APPEND(u_errorName)(status); } rkl_dtrace_getRegexUTF8((CFStringRef)regexString, regexUTF8); rkl_dtrace_compiledRegexCache(regexUTF8, options, -1, -1, status, err); }
00851 #endif // _RKL_DTRACE_ENABLED
00852   
00853   return(cachedRegex);
00854 }
00855 
00856 //  IMPORTANT!   This code is critical path code.  Because of this, it has been written for speed, not clarity.
00857 //  IMPORTANT!   Should only be called with rkl_cacheSpinLock already locked!
00858 //  ----------
00859 
00860 #pragma mark Set a cached regular expression to a NSStrings UTF-16 text
00861 
00862 static NSUInteger rkl_setCachedRegexToString(RKLCachedRegex *cachedRegex, const NSRange *range, int32_t *status, id *exception RKL_UNUSED_ASSERTION_ARG) {
00863   //  ----------   vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
00864   //  IMPORTANT!   This section of code is called almost every single time that any RegexKitLite functionality is used! It /MUST/ be very fast!
00865   //  ----------   vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
00866   
00867   RKLCDelayedAssert((cachedRegex != NULL) && (cachedRegex->setToString != NULL) && ((range != NULL) && (NSEqualRanges(*range, NSNotFoundRange) == NO)) && (status != NULL), exception, exitNow);
00868   RKL_STRONG_REF const UniChar * RKL_GC_VOLATILE stringUniChar = NULL;
00869 #ifdef _RKL_DTRACE_ENABLED
00870   unsigned int lookupResultFlags = 0U;
00871 #endif
00872   
00873   NSUInteger  useFixedBuffer = (cachedRegex->setToLength < (CFIndex)_RKL_FIXED_LENGTH) ? 1UL : 0UL;
00874   RKLBuffer  *buffer         = NULL;
00875   
00876   if(cachedRegex->setToNeedsConversion == 0U) {
00877     RKLCDelayedAssert((cachedRegex->setToUniChar != NULL) && (cachedRegex->buffer == NULL), exception, exitNow);
00878     if(RKL_EXPECTED((stringUniChar = (RKL_STRONG_REF const UniChar * RKL_GC_VOLATILE)CFStringGetCharactersPtr(cachedRegex->setToString)) == NULL, 0L)) { cachedRegex->setToUniChar = NULL; cachedRegex->setToRange = NSNotFoundRange; cachedRegex->setToNeedsConversion = 1U; }
00879     else { if(RKL_EXPECTED(cachedRegex->setToUniChar != stringUniChar, 0L)) { cachedRegex->setToRange = NSNotFoundRange; cachedRegex->setToUniChar = stringUniChar; } goto setRegexText; }
00880   }
00881 
00882   buffer = cachedRegex->buffer;
00883 
00884   RKLCDelayedAssert((buffer == NULL) ? 1 : (((buffer == &rkl_lruFixedBuffer[0])   || (buffer == &rkl_lruFixedBuffer[1])   || (buffer == &rkl_lruFixedBuffer[2])   || (buffer == &rkl_lruFixedBuffer[3])) ||
00885                                             ((buffer == &rkl_lruDynamicBuffer[0]) || (buffer == &rkl_lruDynamicBuffer[1]) || (buffer == &rkl_lruDynamicBuffer[2]) || (buffer == &rkl_lruDynamicBuffer[3]))), exception, exitNow);
00886   
00887   if((buffer != NULL) && RKL_EXPECTED(cachedRegex->setToString == buffer->string, 1L) && RKL_EXPECTED(cachedRegex->setToHash == buffer->hash, 1L) && RKL_EXPECTED(cachedRegex->setToLength == buffer->length, 1L)) {
00888     RKLCDelayedAssert((buffer->uniChar != NULL), exception, exitNow);
00889     rkl_dtrace_addLookupFlag(lookupResultFlags, RKLCacheHitLookupFlag | RKLConversionRequiredLookupFlag | (useFixedBuffer ? 0U : RKLDynamicBufferLookupFlag));
00890     if(cachedRegex->setToUniChar != buffer->uniChar) { cachedRegex->setToRange = NSNotFoundRange; cachedRegex->setToUniChar = buffer->uniChar; }
00891     goto setRegexText;
00892   }
00893 
00894   buffer              = NULL;
00895   cachedRegex->buffer = NULL;
00896 
00897   NSInteger cacheWay = 0L;
00898   for(cacheWay = ((NSInteger)_RKL_LRU_CACHE_SET_WAYS - 1L); cacheWay > 0L; cacheWay--) {
00899     if(useFixedBuffer) { buffer = &rkl_lruFixedBuffer[cacheWay]; } else { buffer = &rkl_lruDynamicBuffer[cacheWay]; }
00900     if(RKL_EXPECTED(cachedRegex->setToString == buffer->string, 1L) && RKL_EXPECTED(cachedRegex->setToHash == buffer->hash, 1L) && RKL_EXPECTED(cachedRegex->setToLength == buffer->length, 1L)) {
00901       RKLCDelayedAssert((buffer->uniChar != NULL), exception, exitNow);
00902       rkl_dtrace_addLookupFlag(lookupResultFlags, RKLCacheHitLookupFlag | RKLConversionRequiredLookupFlag | (useFixedBuffer ? 0U : RKLDynamicBufferLookupFlag));
00903       if(cachedRegex->setToUniChar != buffer->uniChar) { cachedRegex->setToRange = NSNotFoundRange; cachedRegex->setToUniChar = buffer->uniChar; }
00904       cachedRegex->buffer = buffer;
00905       goto setRegexText;
00906     }
00907   }
00908 
00909   buffer                    = NULL;
00910   cachedRegex->setToUniChar = NULL;
00911   cachedRegex->setToRange   = NSNotFoundRange;
00912   cachedRegex->buffer       = NULL;
00913   
00914   RKLCDelayedAssert((cachedRegex->setToNeedsConversion == 1U) && (cachedRegex->buffer == NULL), exception, exitNow);
00915   if(RKL_EXPECTED(cachedRegex->setToNeedsConversion == 1U, 1L) && RKL_EXPECTED((cachedRegex->setToUniChar = (RKL_STRONG_REF const UniChar * RKL_GC_VOLATILE)CFStringGetCharactersPtr(cachedRegex->setToString)) != NULL, 0L)) { cachedRegex->setToNeedsConversion = 0U; cachedRegex->setToRange = NSNotFoundRange; goto setRegexText; }
00916   
00917   rkl_dtrace_addLookupFlag(lookupResultFlags, RKLConversionRequiredLookupFlag | (useFixedBuffer ? 0U : RKLDynamicBufferLookupFlag));
00918 
00919   if(useFixedBuffer) { buffer = &rkl_lruFixedBuffer  [rkl_leastRecentlyUsedWayInSet(1UL, &rkl_lruFixedBufferCacheSet,   0UL)]; }
00920   else               { buffer = &rkl_lruDynamicBuffer[rkl_leastRecentlyUsedWayInSet(1UL, &rkl_lruDynamicBufferCacheSet, 0UL)]; }
00921 
00922   RKLCDelayedAssert((useFixedBuffer) ? ((buffer == &rkl_lruFixedBuffer[0])   || (buffer == &rkl_lruFixedBuffer[1])   || (buffer == &rkl_lruFixedBuffer[2])   || (buffer == &rkl_lruFixedBuffer[3])) :
00923                                        ((buffer == &rkl_lruDynamicBuffer[0]) || (buffer == &rkl_lruDynamicBuffer[1]) || (buffer == &rkl_lruDynamicBuffer[2]) || (buffer == &rkl_lruDynamicBuffer[3])), exception, exitNow);
00924   
00925   rkl_clearBuffer(buffer, 0UL);
00926 
00927   RKLCDelayedAssert((buffer->string == NULL) && (cachedRegex->setToString != NULL), exception, exitNow);
00928   if(RKL_EXPECTED((buffer->string = (CFStringRef)CFRetain((CFTypeRef)cachedRegex->setToString)) == NULL, 0L)) { goto exitNow; }
00929   buffer->hash   = cachedRegex->setToHash;
00930   buffer->length = cachedRegex->setToLength;
00931   
00932   if(useFixedBuffer == 0UL) {
00933     RKL_STRONG_REF void * RKL_GC_VOLATILE p = (RKL_STRONG_REF void * RKL_GC_VOLATILE)buffer->uniChar;
00934     if(RKL_EXPECTED((buffer->uniChar = (RKL_STRONG_REF UniChar * RKL_GC_VOLATILE)rkl_realloc(&p, ((size_t)buffer->length * sizeof(UniChar)), 0UL)) == NULL, 0L)) { goto exitNow; } // Resize the buffer.
00935   }
00936   
00937   RKLCDelayedAssert((buffer->string != NULL) && (buffer->uniChar != NULL), exception, exitNow);
00938   CFStringGetCharacters(buffer->string, CFMakeRange(0L, buffer->length), (UniChar *)buffer->uniChar); // Convert to a UTF16 string.
00939   
00940   cachedRegex->setToUniChar = buffer->uniChar;
00941   cachedRegex->setToRange   = NSNotFoundRange;
00942   cachedRegex->buffer       = buffer;
00943 
00944 setRegexText:
00945   if(buffer != NULL) { if(useFixedBuffer == 1UL) { rkl_accessCacheSetWay(1UL, &rkl_lruFixedBufferCacheSet, 0UL, (NSUInteger)(buffer - rkl_lruFixedBuffer)); } else { rkl_accessCacheSetWay(1UL, &rkl_lruDynamicBufferCacheSet, 0UL, (NSUInteger)(buffer - rkl_lruDynamicBuffer)); } }
00946 
00947   if(NSEqualRanges(cachedRegex->setToRange, *range) == NO) {
00948     RKLCDelayedAssert((cachedRegex->icu_regex != NULL) && (cachedRegex->setToUniChar != NULL) && (NSMaxRange(*range) <= (NSUInteger)cachedRegex->setToLength) && (cachedRegex->setToRange.length <= INT_MAX), exception, exitNow);
00949     cachedRegex->lastFindRange =  cachedRegex->lastMatchRange = NSNotFoundRange;
00950     cachedRegex->setToRange    = *range;
00951     RKL_ICU_FUNCTION_APPEND(uregex_setText)(cachedRegex->icu_regex, cachedRegex->setToUniChar + cachedRegex->setToRange.location, (int32_t)cachedRegex->setToRange.length, status);
00952     rkl_dtrace_addLookupFlag(lookupResultFlags, RKLSetTextLookupFlag);
00953     if(RKL_EXPECTED(*status > U_ZERO_ERROR, 0L)) { rkl_dtrace_addLookupFlag(lookupResultFlags, RKLErrorLookupFlag); goto exitNow; }
00954   }
00955   
00956   rkl_dtrace_utf16ConversionCache(lookupResultFlags, cachedRegex->setToString, cachedRegex->setToRange.location, cachedRegex->setToRange.length, cachedRegex->setToLength);
00957 
00958   return(1UL);
00959 
00960   //  ----------   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
00961   //  IMPORTANT!   This section of code is called almost every single time that any RegexKitLite functionality is used! It /MUST/ be very fast!
00962   //  ----------   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
00963   
00964 exitNow:
00965 #ifdef    _RKL_DTRACE_ENABLED
00966   rkl_dtrace_addLookupFlag(lookupResultFlags, RKLErrorLookupFlag); 
00967   if(cachedRegex != NULL) { rkl_dtrace_utf16ConversionCache(lookupResultFlags, cachedRegex->setToString, cachedRegex->setToRange.location, cachedRegex->setToRange.length, cachedRegex->setToLength); }
00968 #endif // _RKL_DTRACE_ENABLED
00969   if(cachedRegex != NULL) { cachedRegex->buffer = NULL; cachedRegex->setToRange = NSNotFoundRange; cachedRegex->lastFindRange = NSNotFoundRange; cachedRegex->lastMatchRange = NSNotFoundRange; }
00970   return(0UL);
00971 }
00972 
00973 //  IMPORTANT!   This code is critical path code.  Because of this, it has been written for speed, not clarity.
00974 //  IMPORTANT!   Should only be called with rkl_cacheSpinLock already locked!
00975 //  ----------
00976 
00977 #pragma mark Get a regular expression and set it to a NSStrings UTF-16 text
00978 
00979 static RKLCachedRegex *rkl_getCachedRegexSetToString(NSString *regexString, RKLRegexOptions options, NSString *matchString, NSUInteger *matchLengthPtr, NSRange *matchRange, NSError **error, id *exception, int32_t *status) {
00980   //  ----------   vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
00981   //  IMPORTANT!   This section of code is called almost every single time that any RegexKitLite functionality is used! It /MUST/ be very fast!
00982   //  ----------   vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
00983   
00984   RKLCachedRegex *cachedRegex = NULL;
00985   RKLCDelayedAssert((regexString != NULL) && (matchString != NULL) && (exception != NULL) && (status != NULL) && (matchLengthPtr != NULL), exception, exitNow);
00986 
00987   if(RKL_EXPECTED((cachedRegex = rkl_getCachedRegex(regexString, options, error, exception)) == NULL, 0L)) { goto exitNow; }
00988   RKLCDelayedAssert(((cachedRegex >= rkl_cachedRegexes) && ((cachedRegex - rkl_cachedRegexes) < (ssize_t)_RKL_REGEX_CACHE_LINES)) && (cachedRegex != NULL) && (cachedRegex->icu_regex != NULL) && (cachedRegex->regexString != NULL) && (cachedRegex->captureCount >= 0L) && (cachedRegex == rkl_lastCachedRegex), exception, exitNow);
00989 
00990   // Optimize the case where the string to search (matchString) is immutable and the setToString immutable copy is the same string with its reference count incremented.
00991   NSUInteger isSetTo     = ((cachedRegex->setToString      == (CFStringRef)matchString)) ? 1UL : 0UL;
00992   CFIndex    matchLength = ((cachedRegex->setToIsImmutable == 1U) && (isSetTo == 1UL))   ? cachedRegex->setToLength : CFStringGetLength((CFStringRef)matchString);
00993 
00994   *matchLengthPtr = (NSUInteger)matchLength;
00995   if(matchRange->length == NSUIntegerMax) { matchRange->length = (NSUInteger)matchLength; } // For convenience, allow NSUIntegerMax == string length.
00996   
00997   if(RKL_EXPECTED((NSUInteger)matchLength < NSMaxRange(*matchRange), 0L)) { goto exitNow; } // The match range is out of bounds for the string.  performRegexOp will catch and report the problem.
00998 
00999   RKLCDelayedAssert((isSetTo == 1UL) ? (cachedRegex->setToString != NULL) : 1, exception, exitNow);
01000 
01001   if(((cachedRegex->setToIsImmutable == 1U) ? isSetTo : (NSUInteger)((isSetTo == 1UL) && (cachedRegex->setToLength == matchLength) && (cachedRegex->setToHash == CFHash((CFTypeRef)matchString)))) == 0UL) {
01002     if(cachedRegex->setToString != NULL) { rkl_clearCachedRegexSetTo(cachedRegex); }
01003     
01004     cachedRegex->setToString          = (CFStringRef)CFRetain((CFTypeRef)matchString);
01005     RKLCDelayedAssert(cachedRegex->setToString != NULL, exception, exitNow);
01006     cachedRegex->setToUniChar         = CFStringGetCharactersPtr(cachedRegex->setToString);
01007     cachedRegex->setToNeedsConversion = (cachedRegex->setToUniChar == NULL) ? 1U : 0U;
01008     cachedRegex->setToIsImmutable     = (rkl_CFStringIsMutable(cachedRegex->setToString) == YES) ? 0U : 1U; // If RKL_FAST_MUTABLE_CHECK is not defined then setToIsImmutable will always be set to '0', or in other words mutable..
01009     cachedRegex->setToHash            = CFHash((CFTypeRef)cachedRegex->setToString);
01010     cachedRegex->setToRange           = NSNotFoundRange;
01011     cachedRegex->setToLength          = matchLength;
01012     
01013   }
01014   
01015   if(RKL_EXPECTED(rkl_setCachedRegexToString(cachedRegex, matchRange, status, exception) == 0UL, 0L)) { cachedRegex = NULL; if(*exception == NULL) { *exception = (id)RKLCAssertDictionary(@"Failed to set up UTF16 buffer."); } goto exitNow; }
01016   
01017 exitNow:
01018   return(cachedRegex);
01019   //  ----------   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
01020   //  IMPORTANT!   This section of code is called almost every single time that any RegexKitLite functionality is used! It /MUST/ be very fast!
01021   //  ----------   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
01022 }
01023 
01024 #pragma mark GCC cleanup __attribute__ functions that ensure the global rkl_cacheSpinLock is properly unlocked
01025 #ifdef    RKL_HAVE_CLEANUP
01026 
01027 // rkl_cleanup_cacheSpinLockStatus takes advantage of GCC's 'cleanup' variable attribute.  When an 'auto' variable with the 'cleanup' attribute goes out of scope,
01028 // GCC arranges to have the designated function called.  In this case, we make sure that if rkl_cacheSpinLock was locked that it was also unlocked.
01029 // If rkl_cacheSpinLock was locked, but the rkl_cacheSpinLockStatus unlocked flag was not set, we force rkl_cacheSpinLock unlocked with a call to OSSpinLockUnlock.
01030 // This is not a panacea for preventing mutex usage errors.  Old style ObjC exceptions will bypass the cleanup call, but newer C++ style ObjC exceptions should cause the cleanup function to be called during the stack unwind.
01031 
01032 // We do not depend on this cleanup function being called.  It is used only as an extra safety net.  It is probably a bug in RegexKitLite if it is ever invoked and forced to take some kind of protective action.
01033 
01034 volatile NSUInteger rkl_debugCacheSpinLockCount = 0UL;
01035 
01036 void        rkl_debugCacheSpinLock          (void)                                            RKL_ATTRIBUTES(used, noinline, visibility("default"));
01037 static void rkl_cleanup_cacheSpinLockStatus (volatile NSUInteger *rkl_cacheSpinLockStatusPtr) RKL_ATTRIBUTES(used);
01038 
01039 void rkl_debugCacheSpinLock(void) {
01040   rkl_debugCacheSpinLockCount++; // This is here primarily to prevent the optimizer from optimizing away the function.
01041 }
01042 
01043 static void rkl_cleanup_cacheSpinLockStatus(volatile NSUInteger *rkl_cacheSpinLockStatusPtr) {
01044   static NSUInteger didPrintForcedUnlockWarning = 0UL, didPrintNotLockedWarning = 0UL;
01045   NSUInteger        rkl_cacheSpinLockStatus     = *rkl_cacheSpinLockStatusPtr;
01046   
01047   if(RKL_EXPECTED((rkl_cacheSpinLockStatus & RKLUnlockedCacheSpinLock) == 0UL, 0L) && RKL_EXPECTED((rkl_cacheSpinLockStatus & RKLLockedCacheSpinLock) != 0UL, 1L)) {
01048     if(rkl_cacheSpinLock != (OSSpinLock)0) {
01049       if(didPrintForcedUnlockWarning == 0UL) { didPrintForcedUnlockWarning = 1UL; NSLog(@"[RegexKitLite] Unusual condition detected: Recorded that rkl_cacheSpinLock was locked, but for some reason it was not unlocked.  Forcibly unlocking rkl_cacheSpinLock. Set a breakpoint at rkl_debugCacheSpinLock to debug. This warning is only printed once."); }
01050       rkl_debugCacheSpinLock(); // Since this is an unusual condition, offer an attempt to catch it before we unlock.
01051       OSSpinLockUnlock(&rkl_cacheSpinLock);
01052     } else {
01053       if(didPrintNotLockedWarning    == 0UL) { didPrintNotLockedWarning    = 1UL; NSLog(@"[RegexKitLite] Unusual condition detected: Recorded that rkl_cacheSpinLock was locked, but for some reason it was not unlocked, yet rkl_cacheSpinLock is currently not locked? Set a breakpoint at rkl_debugCacheSpinLock to debug. This warning is only printed once."); }
01054       rkl_debugCacheSpinLock();
01055     }
01056   }
01057 }
01058 
01059 #endif // RKL_HAVE_CLEANUP
01060 
01061 // rkl_performDictionaryVarArgsOp is a front end to rkl_performRegexOp which converts a ', ...' varargs key/captures list and converts it in to a form that rkl_performRegexOp can use.
01062 // All error checking of arguments is handled by rkl_performRegexOp.
01063 
01064 #pragma mark Front end function that handles varargs and calls rkl_performRegexOp with the marshaled results
01065 
01066 static id rkl_performDictionaryVarArgsOp(id self, SEL _cmd, RKLRegexOp regexOp, NSString *regexString, RKLRegexOptions options, NSInteger capture, id matchString, NSRange *matchRange, NSString *replacementString, NSError **error, void *result, id firstKey, va_list varArgsList) {
01067   id         captureKeys[64];
01068   int        captureKeyIndexes[64];
01069   NSUInteger captureKeysCount = 0UL;
01070   
01071   if(varArgsList != NULL) {
01072     while(captureKeysCount < 62UL) {
01073       id  thisCaptureKey      = (captureKeysCount == 0) ? firstKey : va_arg(varArgsList, id);
01074       if(RKL_EXPECTED(thisCaptureKey == NULL, 0L)) { break; }
01075       int thisCaptureKeyIndex = va_arg(varArgsList, int);
01076       captureKeys[captureKeysCount]       = thisCaptureKey;
01077       captureKeyIndexes[captureKeysCount] = thisCaptureKeyIndex;
01078       captureKeysCount++;
01079     }
01080   }
01081   
01082   return(rkl_performRegexOp(self, _cmd, regexOp, regexString, options, capture, matchString, matchRange, replacementString, error, result, captureKeysCount, captureKeys, captureKeyIndexes));
01083 }
01084 
01085 //  IMPORTANT!   This code is critical path code.  Because of this, it has been written for speed, not clarity.
01086 //  ----------
01087 
01088 #pragma mark Primary internal function that Objective-C methods call to perform regular expression operations
01089 
01090 static id rkl_performRegexOp(id self, SEL _cmd, RKLRegexOp regexOp, NSString *regexString, RKLRegexOptions options, NSInteger capture, id matchString, NSRange *matchRange, NSString *replacementString, NSError **error, void *result, NSUInteger captureKeysCount, id captureKeys[captureKeysCount], const int captureKeyIndexes[captureKeysCount]) {
01091   volatile NSUInteger RKL_CLEANUP(rkl_cleanup_cacheSpinLockStatus) rkl_cacheSpinLockStatus = 0UL;
01092   
01093   NSUInteger replaceMutable = 0UL;
01094   RKLRegexOp maskedRegexOp  = (regexOp & RKLMaskOp);
01095   BOOL       dictionaryOp   = ((maskedRegexOp == RKLDictionaryOfCapturesOp) || (maskedRegexOp == RKLArrayOfDictionariesOfCapturesOp)) ? YES : NO;
01096   
01097   if((error != NULL) && (*error != NULL))                                            { *error = NULL; }
01098   
01099   if(RKL_EXPECTED(regexString == NULL, 0L))                                          { RKL_RAISE_EXCEPTION(NSInvalidArgumentException, @"The regular expression argument is NULL."); }
01100   if(RKL_EXPECTED(matchString == NULL, 0L))                                          { RKL_RAISE_EXCEPTION(NSInternalInconsistencyException, @"The match string argument is NULL."); }
01101   if(RKL_EXPECTED(matchRange  == NULL, 0L))                                          { RKL_RAISE_EXCEPTION(NSInternalInconsistencyException, @"The match range argument is NULL.");  }
01102   if((maskedRegexOp == RKLReplaceOp) && RKL_EXPECTED(replacementString == NULL, 0L)) { RKL_RAISE_EXCEPTION(NSInvalidArgumentException, @"The replacement string argument is NULL."); }
01103   if((dictionaryOp  == YES)          && RKL_EXPECTED(captureKeys       == NULL, 0L)) { RKL_RAISE_EXCEPTION(NSInvalidArgumentException, @"The keys argument is NULL.");               }
01104   if((dictionaryOp  == YES)          && RKL_EXPECTED(captureKeyIndexes == NULL, 0L)) { RKL_RAISE_EXCEPTION(NSInvalidArgumentException, @"The captures argument is NULL.");           }
01105   
01106   id              resultObject    = NULL, exception = NULL;
01107   int32_t         status          = U_ZERO_ERROR;
01108   RKLCachedRegex *cachedRegex     = NULL;
01109   NSUInteger      stringU16Length = 0UL, tmpIdx = 0UL;
01110   NSRange         stackRanges[2048];
01111   RKLFindAll      findAll;
01112   
01113   // IMPORTANT!   Once we have obtained the lock, code MUST exit via 'goto exitNow;' to unlock the lock!  NO EXCEPTIONS!
01114   // ----------
01115   OSSpinLockLock(&rkl_cacheSpinLock); // Grab the lock and get cache entry.
01116   rkl_cacheSpinLockStatus |= RKLLockedCacheSpinLock;
01117   rkl_dtrace_incrementEventID();
01118   
01119   if(RKL_EXPECTED((cachedRegex = rkl_getCachedRegexSetToString(regexString, options, matchString, &stringU16Length, matchRange, error, &exception, &status)) == NULL, 0L)) { stringU16Length = (NSUInteger)CFStringGetLength((CFStringRef)matchString); }
01120   if(RKL_EXPECTED(matchRange->length == NSUIntegerMax,           0L))                                        { matchRange->length = stringU16Length; } // For convenience.
01121   if(RKL_EXPECTED(stringU16Length     < NSMaxRange(*matchRange), 0L) && RKL_EXPECTED(exception == NULL, 1L)) { exception = (id)RKL_EXCEPTION(NSRangeException, @"Range or index out of bounds.");  goto exitNow; }
01122   if(RKL_EXPECTED(stringU16Length    >= (NSUInteger)INT_MAX,     0L) && RKL_EXPECTED(exception == NULL, 1L)) { exception = (id)RKL_EXCEPTION(NSRangeException, @"String length exceeds INT_MAX."); goto exitNow; }
01123   if(((maskedRegexOp == RKLRangeOp) || (maskedRegexOp == RKLArrayOfStringsOp)) && RKL_EXPECTED(cachedRegex != NULL, 1L) && (RKL_EXPECTED(capture < 0L, 0L) || RKL_EXPECTED(capture > cachedRegex->captureCount, 0L)) && RKL_EXPECTED(exception == NULL, 1L)) { exception = (id)RKL_EXCEPTION(NSInvalidArgumentException, @"The capture argument is not valid."); goto exitNow; }
01124 
01125   if((dictionaryOp == YES) && RKL_EXPECTED(cachedRegex != NULL, 1L) && RKL_EXPECTED(exception == NULL, 1L)) {
01126     for(tmpIdx = 0UL; tmpIdx < captureKeysCount; tmpIdx++) {
01127       if(RKL_EXPECTED(captureKeys[tmpIdx] == NULL, 0L)) { exception = (id)RKL_EXCEPTION(NSInvalidArgumentException, @"The capture key (key %lu of %lu) is NULL.", (unsigned long)(tmpIdx + 1UL), (unsigned long)captureKeysCount); break; }
01128       if((RKL_EXPECTED(captureKeyIndexes[tmpIdx] < 0, 0L) || RKL_EXPECTED(captureKeyIndexes[tmpIdx] > cachedRegex->captureCount, 0L))) { exception = (id)RKL_EXCEPTION(NSInvalidArgumentException, @"The capture argument %d (capture %lu of %lu) for key '%@' is not valid.", captureKeyIndexes[tmpIdx], (unsigned long)(tmpIdx + 1UL), (unsigned long)captureKeysCount, captureKeys[tmpIdx]); break; }
01129     }
01130   }
01131 
01132   if(RKL_EXPECTED(cachedRegex == NULL, 0L) || RKL_EXPECTED(status > U_ZERO_ERROR, 0L) || RKL_EXPECTED(exception != NULL, 0L)) { goto exitNow; }
01133   
01134   RKLCDelayedAssert(((cachedRegex >= rkl_cachedRegexes) && ((cachedRegex - rkl_cachedRegexes) < (ssize_t)_RKL_REGEX_CACHE_LINES)) && (cachedRegex != NULL) && (cachedRegex->icu_regex != NULL) && (cachedRegex->regexString != NULL) && (cachedRegex->captureCount >= 0L) && (cachedRegex->setToString != NULL) && (cachedRegex->setToLength >= 0L) && (cachedRegex->setToUniChar != NULL) && ((CFIndex)NSMaxRange(cachedRegex->setToRange) <= cachedRegex->setToLength), &exception, exitNow);
01135   RKLCDelayedAssert((cachedRegex->setToNeedsConversion == 0U) ? ((cachedRegex->setToNeedsConversion == 0U) && (cachedRegex->setToUniChar == CFStringGetCharactersPtr(cachedRegex->setToString))) : ((cachedRegex->buffer != NULL) && (cachedRegex->setToHash == cachedRegex->buffer->hash) && (cachedRegex->setToLength == cachedRegex->buffer->length) && (cachedRegex->setToUniChar == cachedRegex->buffer->uniChar)), &exception, exitNow);
01136   
01137   switch(maskedRegexOp) {
01138     case RKLRangeOp:
01139       if((RKL_EXPECTED(rkl_search(cachedRegex, matchRange, 0UL, &exception, &status) == NO, 0L)) || (RKL_EXPECTED(status > U_ZERO_ERROR, 0L))) { *(NSRange *)result = NSNotFoundRange; goto exitNow; }
01140       if(RKL_EXPECTED(capture == 0L, 1L)) { *(NSRange *)result = cachedRegex->lastMatchRange; } else { if(RKL_EXPECTED(rkl_getRangeForCapture(cachedRegex, &status, (int32_t)capture, (NSRange *)result) > U_ZERO_ERROR, 0L)) { goto exitNow; } }
01141       break;
01142       
01143     case RKLSplitOp:                         // Fall-thru...
01144     case RKLArrayOfStringsOp:                // Fall-thru...
01145     case RKLCapturesArrayOp:                 // Fall-thru...
01146     case RKLArrayOfCapturesOp:               // Fall-thru...
01147     case RKLDictionaryOfCapturesOp:          // Fall-thru...
01148     case RKLArrayOfDictionariesOfCapturesOp:
01149       findAll = rkl_makeFindAll(stackRanges, *matchRange, 2048L, (2048UL * sizeof(NSRange)), 0UL, &rkl_scratchBuffer[0], &rkl_scratchBuffer[1], &rkl_scratchBuffer[2], &rkl_scratchBuffer[3], &rkl_scratchBuffer[4], 0L, capture, (((maskedRegexOp == RKLCapturesArrayOp) || (maskedRegexOp == RKLDictionaryOfCapturesOp)) ? 1L : NSIntegerMax));
01150       
01151       if(RKL_EXPECTED(rkl_findRanges(cachedRegex, regexOp, &findAll, &exception, &status) == NO, 1L)) {
01152         if(RKL_EXPECTED(findAll.found == 0L, 0L)) { resultObject = (maskedRegexOp == RKLDictionaryOfCapturesOp) ? [NSDictionary dictionary] : [NSArray array]; }
01153         else {
01154           if(dictionaryOp == YES) { resultObject = rkl_makeDictionary (cachedRegex, regexOp, &findAll, captureKeysCount, captureKeys, captureKeyIndexes, &exception); }
01155           else                    { resultObject = rkl_makeArray      (cachedRegex, regexOp, &findAll, &exception); }
01156         }
01157       }
01158       
01159       for(tmpIdx = 0UL; tmpIdx < _RKL_SCRATCH_BUFFERS; tmpIdx++) { if(RKL_EXPECTED(rkl_scratchBuffer[tmpIdx] != NULL, 0L)) { rkl_scratchBuffer[tmpIdx] = rkl_free(&rkl_scratchBuffer[tmpIdx]); } }
01160 
01161       break;
01162 
01163     case RKLReplaceOp: resultObject = rkl_replaceString(cachedRegex, matchString, stringU16Length, replacementString, (NSUInteger)CFStringGetLength((CFStringRef)replacementString), (NSInteger *)result, (replaceMutable = (((regexOp & RKLReplaceMutable) != 0) ? 1UL : 0UL)), &exception, &status); break;
01164 
01165     default:           exception    = RKLCAssertDictionary(@"Unknown regexOp code."); break;
01166   }
01167   
01168 exitNow:
01169   OSSpinLockUnlock(&rkl_cacheSpinLock);
01170   rkl_cacheSpinLockStatus |= RKLUnlockedCacheSpinLock; // Warning about rkl_cacheSpinLockStatus never being read can be safely ignored.
01171   
01172   if(RKL_EXPECTED(status     > U_ZERO_ERROR, 0L) && RKL_EXPECTED(exception == NULL, 0L)) { exception = rkl_NSExceptionForRegex(regexString, options, NULL, status); } // If we had a problem, prepare an exception to be thrown.
01173   if(RKL_EXPECTED(exception != NULL,         0L))                                        { rkl_handleDelayedAssert(self, _cmd, exception);                          } // If there is an exception, throw it at this point.
01174   // If we're working on a mutable string and there were successful matches/replacements, then we still have work to do.
01175   // This is done outside the cache lock and with the objc replaceCharactersInRange:withString: method because Core Foundation
01176   // does not assert that the string we are attempting to update is actually a mutable string, whereas Foundation ensures
01177   // the object receiving the message is a mutable string and throws an exception if we're attempting to modify an immutable string.
01178   if(RKL_EXPECTED(replaceMutable == 1UL, 0L) && RKL_EXPECTED(*((NSInteger *)result) > 0L, 1L) && RKL_EXPECTED(status == U_ZERO_ERROR, 1L) && RKL_EXPECTED(resultObject != NULL, 1L)) { [matchString replaceCharactersInRange:*matchRange withString:resultObject]; }
01179   // If status < U_ZERO_ERROR, consider it an error, even though status < U_ZERO_ERROR is a 'warning' in ICU nomenclature.
01180   // status > U_ZERO_ERROR are an exception and handled above.
01181   // http://sourceforge.net/tracker/?func=detail&atid=990188&aid=2890810&group_id=204582
01182   if(RKL_EXPECTED(status  < U_ZERO_ERROR, 0L) && RKL_EXPECTED(resultObject == NULL, 0L) && (error != NULL)) {
01183     NSString *replacedString = NULL;
01184     NSInteger replacedCount = 0L;
01185     RKLUserInfoOptions userInfoOptions = RKLUserInfoNone;
01186     if((maskedRegexOp == RKLReplaceOp) && (result != NULL)) { userInfoOptions |= RKLUserInfoReplacedCount; replacedString = resultObject; replacedCount = *((NSInteger *)result); }
01187     if(matchRange != NULL) { userInfoOptions |= RKLUserInfoSubjectRange; }
01188     *error = rkl_makeNSError(userInfoOptions, regexString, options, NULL, status, matchString, (matchRange != NULL) ? *matchRange : NSNotFoundRange, replacementString, replacedString, replacedCount, (RKLRegexEnumerationOptions)RKLRegexEnumerationNoOptions, @"The ICU library returned an unexpected error.");
01189   }
01190   return(resultObject);
01191 }
01192 
01193 static void rkl_handleDelayedAssert(id self, SEL _cmd, id exception) {
01194   if(RKL_EXPECTED(exception != NULL, 1L)) {
01195     if([exception isKindOfClass:[NSException class]]) { [[NSException exceptionWithName:[exception name] reason:rkl_stringFromClassAndMethod(self, _cmd, [exception reason]) userInfo:[exception userInfo]] raise]; }
01196     else {
01197       id functionString = [exception objectForKey:@"function"], fileString = [exception objectForKey:@"file"], descriptionString = [exception objectForKey:@"description"], lineNumber = [exception objectForKey:@"line"];
01198       RKLCHardAbortAssert((functionString != NULL) && (fileString != NULL) && (descriptionString != NULL) && (lineNumber != NULL));
01199       [[NSAssertionHandler currentHandler] handleFailureInFunction:functionString file:fileString lineNumber:(NSInteger)[lineNumber longValue] description:descriptionString];
01200     }
01201   }
01202 }
01203 
01204 //  IMPORTANT!   This code is critical path code.  Because of this, it has been written for speed, not clarity.
01205 //  IMPORTANT!   Should only be called from rkl_performRegexOp() or rkl_findRanges().
01206 //  ----------
01207 
01208 #pragma mark Primary means of performing a search with a regular expression
01209 
01210 static NSUInteger rkl_search(RKLCachedRegex *cachedRegex, NSRange *searchRange, NSUInteger updateSearchRange, id *exception RKL_UNUSED_ASSERTION_ARG, int32_t *status) {
01211   NSUInteger foundMatch = 0UL;
01212 
01213   if((NSEqualRanges(*searchRange, cachedRegex->lastFindRange) == YES) && ((cachedRegex->lastMatchRange.length > 0UL) || (cachedRegex->lastMatchRange.location == (NSUInteger)NSNotFound))) { foundMatch = ((cachedRegex->lastMatchRange.location == (NSUInteger)NSNotFound) ? 0UL : 1UL);}
01214   else { // Only perform an expensive 'find' operation iff the current find range is different than the last find range.
01215     NSUInteger findLocation = (searchRange->location - cachedRegex->setToRange.location);
01216     RKLCDelayedAssert(((searchRange->location >= cachedRegex->setToRange.location)) && (NSRangeInsideRange(*searchRange, cachedRegex->setToRange) == YES) && (findLocation < INT_MAX) && (findLocation <= cachedRegex->setToRange.length), exception, exitNow);
01217     
01218     RKL_PREFETCH_UNICHAR(cachedRegex->setToUniChar, searchRange->location); // Spool up the CPU caches.
01219     
01220     // Using uregex_findNext can be a slight performance win.
01221     NSUInteger useFindNext = (RKL_EXPECTED(searchRange->location == (NSMaxRange(cachedRegex->lastMatchRange) + ((RKL_EXPECTED(cachedRegex->lastMatchRange.length == 0UL, 0L) && RKL_EXPECTED(cachedRegex->lastMatchRange.location < NSMaxRange(cachedRegex->setToRange), 0L)) ? 1UL : 0UL)), 1L) ? 1UL : 0UL);
01222 
01223     cachedRegex->lastFindRange = *searchRange;
01224     if(RKL_EXPECTED(useFindNext == 0UL, 0L)) { if(RKL_EXPECTED((RKL_ICU_FUNCTION_APPEND(uregex_find)    (cachedRegex->icu_regex, (int32_t)findLocation, status) == NO), 0L) || RKL_EXPECTED(*status > U_ZERO_ERROR, 0L)) { goto finishedFind; } }
01225     else {                                     if(RKL_EXPECTED((RKL_ICU_FUNCTION_APPEND(uregex_findNext)(cachedRegex->icu_regex,                        status) == NO), 0L) || RKL_EXPECTED(*status > U_ZERO_ERROR, 0L)) { goto finishedFind; } }
01226     foundMatch = 1UL; 
01227     
01228     if(RKL_EXPECTED(rkl_getRangeForCapture(cachedRegex, status, 0, &cachedRegex->lastMatchRange) > U_ZERO_ERROR, 0L)) { goto finishedFind; }
01229     RKLCDelayedAssert(NSRangeInsideRange(cachedRegex->lastMatchRange, *searchRange) == YES, exception, exitNow);
01230   }
01231   
01232 finishedFind:
01233   if(RKL_EXPECTED(*status > U_ZERO_ERROR, 0L)) { foundMatch = 0UL; cachedRegex->lastFindRange = NSNotFoundRange; }
01234   
01235   if(RKL_EXPECTED(foundMatch == 0UL, 0L)) { cachedRegex->lastFindRange = NSNotFoundRange; cachedRegex->lastMatchRange = NSNotFoundRange; if(RKL_EXPECTED(updateSearchRange == 1UL, 1L)) { *searchRange = NSMakeRange(NSMaxRange(*searchRange), 0UL); } }
01236   else {
01237     RKLCDelayedAssert(NSRangeInsideRange(cachedRegex->lastMatchRange, *searchRange) == YES, exception, exitNow);
01238     if(RKL_EXPECTED(updateSearchRange == 1UL, 1L)) {
01239       NSUInteger nextLocation = (NSMaxRange(cachedRegex->lastMatchRange) + ((RKL_EXPECTED(cachedRegex->lastMatchRange.length == 0UL, 0L) && RKL_EXPECTED(cachedRegex->lastMatchRange.location < NSMaxRange(cachedRegex->setToRange), 1L)) ? 1UL : 0UL)), locationDiff = nextLocation - searchRange->location;
01240       RKLCDelayedAssert((((locationDiff > 0UL) || ((locationDiff == 0UL) && (cachedRegex->lastMatchRange.location == NSMaxRange(cachedRegex->setToRange)))) && (locationDiff <= searchRange->length)), exception, exitNow);
01241       searchRange->location  = nextLocation;
01242       searchRange->length   -= locationDiff;
01243     }
01244   }
01245   
01246 #ifndef NS_BLOCK_ASSERTIONS
01247 exitNow:
01248 #endif
01249   return(foundMatch);
01250 }
01251 
01252 //  IMPORTANT!   This code is critical path code.  Because of this, it has been written for speed, not clarity.
01253 //  IMPORTANT!   Should only be called from rkl_performRegexOp() or rkl_performEnumerationUsingBlock().
01254 //  ----------
01255 
01256 #pragma mark Used to perform multiple searches at once and return the NSRange results in bulk
01257 
01258 static BOOL rkl_findRanges(RKLCachedRegex *cachedRegex, RKLRegexOp regexOp, RKLFindAll *findAll, id *exception, int32_t *status) {
01259   BOOL returnWithError = YES;
01260   RKLCDelayedAssert((((cachedRegex != NULL) && (cachedRegex->icu_regex != NULL) && (cachedRegex->setToUniChar != NULL) && (cachedRegex->captureCount >= 0L) && (cachedRegex->setToRange.location != (NSUInteger)NSNotFound)) && (status != NULL) && ((findAll != NULL) && (findAll->found == 0L) && (findAll->addedSplitRanges == 0L) && ((findAll->capacity >= 0L) && (((findAll->capacity > 0L) || (findAll->size > 0UL)) ? ((findAll->ranges != NULL) && (findAll->capacity > 0L) && (findAll->size > 0UL)) : 1)) && ((findAll->capture >= 0L) && (findAll->capture <= cachedRegex->captureCount)))), exception, exitNow);
01261   
01262   NSInteger  captureCount  = cachedRegex->captureCount, findAllRangeIndexOfLastNonZeroLength = 0L;
01263   NSUInteger lastLocation  = findAll->findInRange.location;
01264   RKLRegexOp maskedRegexOp = (regexOp & RKLMaskOp);
01265   NSRange    searchRange   = findAll->findInRange;
01266 
01267   for(findAll->found = 0L; (findAll->found < findAll->findUpTo) && ((findAll->found < findAll->capacity) || (findAll->found == 0L)); findAll->found++) {
01268     NSInteger loopCapture, shouldBreak = 0L;
01269 
01270     if(RKL_EXPECTED(findAll->found >= ((findAll->capacity - ((captureCount + 2L) * 4L)) - 4L), 0L)) { if(RKL_EXPECTED(rkl_growFindRanges(cachedRegex, lastLocation, findAll, exception) == 0UL, 0L)) { goto exitNow; } }
01271     
01272     RKLCDelayedAssert((searchRange.location != (NSUInteger)NSNotFound) && (NSRangeInsideRange(searchRange, cachedRegex->setToRange) == YES) && (NSRangeInsideRange(findAll->findInRange, cachedRegex->setToRange) == YES), exception, exitNow);
01273     
01274     // This fixes a 'bug' that is also present in ICU's uregex_split().  'Bug', in this case, means that the results of a split operation can differ from those that perl's split() creates for the same input.
01275     // "I|at|ice I eat rice" split using the regex "\b\s*" demonstrates the problem. ICU bug http://bugs.icu-project.org/trac/ticket/6826
01276     // ICU : "", "I", "|", "at", "|", "ice", "", "I", "", "eat", "", "rice" <- Results that RegexKitLite used to produce.
01277     // PERL:     "I", "|", "at", "|", "ice",     "I",     "eat",     "rice" <- Results that RegexKitLite now produces.
01278     do { if((rkl_search(cachedRegex, &searchRange, 1UL, exception, status) == NO) || (RKL_EXPECTED(*status > U_ZERO_ERROR, 0L))) { shouldBreak = 1L; } findAll->remainingRange = searchRange; }
01279     while(RKL_EXPECTED((cachedRegex->lastMatchRange.location - lastLocation) == 0UL, 0L) && RKL_EXPECTED(cachedRegex->lastMatchRange.length == 0UL, 0L) && (maskedRegexOp == RKLSplitOp) && RKL_EXPECTED(shouldBreak == 0L, 1L));
01280     if(RKL_EXPECTED(shouldBreak == 1L, 0L)) { break; }
01281 
01282     RKLCDelayedAssert((searchRange.location != (NSUInteger)NSNotFound) && (NSRangeInsideRange(searchRange, cachedRegex->setToRange) == YES) && (NSRangeInsideRange(findAll->findInRange, cachedRegex->setToRange) == YES) && (NSRangeInsideRange(searchRange, findAll->findInRange) == YES), exception, exitNow);
01283     RKLCDelayedAssert((NSRangeInsideRange(cachedRegex->lastFindRange, cachedRegex->setToRange) == YES) && (NSRangeInsideRange(cachedRegex->lastMatchRange, cachedRegex->setToRange) == YES) && (NSRangeInsideRange(cachedRegex->lastMatchRange, findAll->findInRange) == YES), exception, exitNow);
01284     RKLCDelayedAssert((findAll->ranges != NULL) && (findAll->found >= 0L) && (findAll->capacity >= 0L) && ((findAll->found + (captureCount + 3L) + 1L) < (findAll->capacity - 2L)), exception, exitNow);
01285     
01286     NSInteger findAllRangesIndexForCapture0 = findAll->found;
01287     switch(maskedRegexOp) {
01288       case RKLArrayOfStringsOp:
01289         if(findAll->capture == 0L) { findAll->ranges[findAll->found] = cachedRegex->lastMatchRange; } else { if(RKL_EXPECTED(rkl_getRangeForCapture(cachedRegex, status, (int32_t)findAll->capture, &findAll->ranges[findAll->found]) > U_ZERO_ERROR, 0L)) { goto exitNow; } }
01290         break;
01291         
01292       case RKLSplitOp:                         // Fall-thru...
01293       case RKLCapturesArrayOp:                 // Fall-thru...
01294       case RKLDictionaryOfCapturesOp:          // Fall-thru...
01295       case RKLArrayOfDictionariesOfCapturesOp: // Fall-thru...
01296       case RKLArrayOfCapturesOp:
01297         findAll->ranges[findAll->found] = ((maskedRegexOp == RKLSplitOp) ? NSMakeRange(lastLocation, cachedRegex->lastMatchRange.location - lastLocation) : cachedRegex->lastMatchRange);
01298 
01299         for(loopCapture = 1L; loopCapture <= captureCount; loopCapture++) {
01300           RKLCDelayedAssert((findAll->found >= 0L) && (findAll->found < (findAll->capacity - 2L)) && (loopCapture < INT_MAX), exception, exitNow);
01301           if(RKL_EXPECTED(rkl_getRangeForCapture(cachedRegex, status, (int32_t)loopCapture, &findAll->ranges[++findAll->found]) > U_ZERO_ERROR, 0L)) { goto exitNow; }
01302         }
01303         break;
01304         
01305       default: if(*exception == NULL) { *exception = RKLCAssertDictionary(@"Unknown regexOp."); } goto exitNow; break;
01306     }
01307     
01308     if(findAll->ranges[findAllRangesIndexForCapture0].length > 0UL) { findAllRangeIndexOfLastNonZeroLength = findAll->found + 1UL; }
01309     lastLocation = NSMaxRange(cachedRegex->lastMatchRange);
01310   }
01311   
01312   if(RKL_EXPECTED(*status > U_ZERO_ERROR, 0L)) { goto exitNow; }
01313   
01314   RKLCDelayedAssert((findAll->ranges != NULL) && (findAll->found >= 0L) && (findAll->found < (findAll->capacity - 2L)), exception, exitNow);
01315   if(maskedRegexOp == RKLSplitOp) {
01316     if(lastLocation != NSMaxRange(findAll->findInRange)) { findAll->addedSplitRanges++; findAll->ranges[findAll->found++] = NSMakeRange(lastLocation, NSMaxRange(findAll->findInRange) - lastLocation); findAllRangeIndexOfLastNonZeroLength = findAll->found; }
01317     findAll->found = findAllRangeIndexOfLastNonZeroLength;
01318   }
01319   
01320   RKLCDelayedAssert((findAll->ranges != NULL) && (findAll->found >= 0L) && (findAll->found < (findAll->capacity - 2L)), exception, exitNow);
01321   returnWithError = NO;
01322   
01323 exitNow:
01324   return(returnWithError);
01325 }
01326 
01327 //  IMPORTANT!   This code is critical path code.  Because of this, it has been written for speed, not clarity.
01328 //  IMPORTANT!   Should only be called from rkl_findRanges().
01329 //  ----------
01330 
01331 static NSUInteger rkl_growFindRanges(RKLCachedRegex *cachedRegex, NSUInteger lastLocation, RKLFindAll *findAll, id *exception RKL_UNUSED_ASSERTION_ARG) {
01332   NSUInteger didGrowRanges = 0UL;
01333   RKLCDelayedAssert((((cachedRegex != NULL) && (cachedRegex->captureCount >= 0L)) && ((findAll != NULL) && (findAll->capacity >= 0L) && (findAll->rangesScratchBuffer != NULL) && (findAll->found >= 0L) && (((findAll->capacity > 0L) || (findAll->size > 0UL) || (findAll->ranges != NULL)) ? ((findAll->capacity > 0L) && (findAll->size > 0UL) && (findAll->ranges != NULL) && (((size_t)findAll->capacity * sizeof(NSRange)) == findAll->size)) : 1))), exception, exitNow);
01334   
01335   // Attempt to guesstimate the required capacity based on: the total length needed to search / (length we've searched so far / ranges found so far).
01336   NSInteger newCapacity = (findAll->capacity + (findAll->capacity / 2L)), estimate = (NSInteger)((float)cachedRegex->setToLength / (((float)lastLocation + 1.0f) / ((float)findAll->found + 1.0f)));
01337   newCapacity = (((newCapacity + ((estimate > newCapacity) ? estimate : newCapacity)) / 2L) + ((cachedRegex->captureCount + 2L) * 4L) + 4L);
01338   
01339   NSUInteger                               needToCopy = ((*findAll->rangesScratchBuffer != findAll->ranges) && (findAll->ranges != NULL)) ? 1UL : 0UL; // If findAll->ranges is set to a stack allocation then we need to manually copy the data from the stack to the new heap allocation.
01340   size_t                                   newSize    = ((size_t)newCapacity * sizeof(NSRange));
01341   RKL_STRONG_REF NSRange * RKL_GC_VOLATILE newRanges  = NULL;
01342   
01343   if(RKL_EXPECTED((newRanges = (RKL_STRONG_REF NSRange * RKL_GC_VOLATILE)rkl_realloc((RKL_STRONG_REF void ** RKL_GC_VOLATILE)findAll->rangesScratchBuffer, newSize, 0UL)) == NULL, 0L)) { findAll->capacity = 0L; findAll->size = 0UL; findAll->ranges = NULL; *findAll->rangesScratchBuffer = rkl_free((RKL_STRONG_REF void ** RKL_GC_VOLATILE)findAll->rangesScratchBuffer); goto exitNow; } else { didGrowRanges = 1UL; }
01344   if(needToCopy == 1UL) { memcpy(newRanges, findAll->ranges, findAll->size); } // If necessary, copy the existing data to the new heap allocation.
01345   
01346   findAll->capacity = newCapacity;
01347   findAll->size     = newSize;
01348   findAll->ranges   = newRanges;
01349   
01350 exitNow:
01351   return(didGrowRanges);
01352 }
01353 
01354 //  IMPORTANT!   This code is critical path code.  Because of this, it has been written for speed, not clarity.
01355 //  IMPORTANT!   Should only be called from rkl_performRegexOp().
01356 //  ----------
01357 
01358 #pragma mark Convert bulk results from rkl_findRanges in to various NSArray types
01359 
01360 static NSArray *rkl_makeArray(RKLCachedRegex *cachedRegex, RKLRegexOp regexOp, RKLFindAll *findAll, id *exception RKL_UNUSED_ASSERTION_ARG) {
01361   NSUInteger  createdStringsCount = 0UL,   createdArraysCount = 0UL,  transferredStringsCount = 0UL;
01362   id         * RKL_GC_VOLATILE matchedStrings = NULL, * RKL_GC_VOLATILE subcaptureArrays = NULL, emptyString = @"";
01363   NSArray    * RKL_GC_VOLATILE resultArray    = NULL;
01364   
01365   RKLCDelayedAssert((cachedRegex != NULL) && ((findAll != NULL) && (findAll->found >= 0L) && (findAll->stringsScratchBuffer != NULL) && (findAll->arraysScratchBuffer != NULL)), exception, exitNow);
01366   
01367   size_t      matchedStringsSize = ((size_t)findAll->found * sizeof(id));
01368   CFStringRef setToString        = cachedRegex->setToString;
01369   
01370   if((findAll->stackUsed + matchedStringsSize) < (size_t)_RKL_STACK_LIMIT) { if(RKL_EXPECTED((matchedStrings = (id * RKL_GC_VOLATILE)alloca(matchedStringsSize))                                                                   == NULL, 0L)) { goto exitNow; } findAll->stackUsed += matchedStringsSize; }
01371   else {                                                                     if(RKL_EXPECTED((matchedStrings = (id * RKL_GC_VOLATILE)rkl_realloc(findAll->stringsScratchBuffer, matchedStringsSize, (NSUInteger)RKLScannedOption)) == NULL, 0L)) { goto exitNow; } }
01372   
01373   { // This sub-block (and its local variables) is here for the benefit of the optimizer.
01374     NSUInteger     found             = (NSUInteger)findAll->found;
01375     const NSRange *rangePtr          = findAll->ranges;
01376     id            *matchedStringsPtr = matchedStrings;
01377     
01378     for(createdStringsCount = 0UL; createdStringsCount < found; createdStringsCount++) {
01379       NSRange range = *rangePtr++;
01380       if(RKL_EXPECTED(((*matchedStringsPtr++ = RKL_EXPECTED(range.length == 0UL, 0L) ? emptyString : rkl_CreateStringWithSubstring((id)setToString, range)) == NULL), 0L)) { goto exitNow; }
01381     }
01382   }
01383   
01384   NSUInteger           arrayCount   = createdStringsCount;
01385   id * RKL_GC_VOLATILE arrayObjects = matchedStrings;
01386   
01387   if((regexOp & RKLSubcapturesArray) != 0UL) {
01388     RKLCDelayedAssert(((createdStringsCount % ((NSUInteger)cachedRegex->captureCount + 1UL)) == 0UL) && (createdArraysCount == 0UL), exception, exitNow);
01389     
01390     NSUInteger captureCount          = ((NSUInteger)cachedRegex->captureCount + 1UL);
01391     NSUInteger subcaptureArraysCount = (createdStringsCount / captureCount);
01392     size_t     subcaptureArraysSize  = ((size_t)subcaptureArraysCount * sizeof(id));
01393     
01394     if((findAll->stackUsed + subcaptureArraysSize) < (size_t)_RKL_STACK_LIMIT) { if(RKL_EXPECTED((subcaptureArrays = (id * RKL_GC_VOLATILE)alloca(subcaptureArraysSize))                                                                  == NULL, 0L)) { goto exitNow; } findAll->stackUsed += subcaptureArraysSize; }
01395     else {                                                                       if(RKL_EXPECTED((subcaptureArrays = (id * RKL_GC_VOLATILE)rkl_realloc(findAll->arraysScratchBuffer, subcaptureArraysSize, (NSUInteger)RKLScannedOption)) == NULL, 0L)) { goto exitNow; } }
01396     
01397     { // This sub-block (and its local variables) is here for the benefit of the optimizer.
01398       id *subcaptureArraysPtr = subcaptureArrays;
01399       id *matchedStringsPtr   = matchedStrings;
01400       
01401       for(createdArraysCount = 0UL; createdArraysCount < subcaptureArraysCount; createdArraysCount++) {
01402         if(RKL_EXPECTED((*subcaptureArraysPtr++ = rkl_CreateArrayWithObjects((void **)matchedStringsPtr, captureCount)) == NULL, 0L)) { goto exitNow; }
01403         matchedStringsPtr       += captureCount;
01404         transferredStringsCount += captureCount;
01405       }
01406     }
01407     
01408     RKLCDelayedAssert((transferredStringsCount == createdStringsCount), exception, exitNow);
01409     arrayCount   = createdArraysCount;
01410     arrayObjects = subcaptureArrays;
01411   }
01412   
01413   RKLCDelayedAssert((arrayObjects != NULL), exception, exitNow);
01414   resultArray = rkl_CreateAutoreleasedArray((void **)arrayObjects, (NSUInteger)arrayCount);
01415   
01416 exitNow:
01417   if(RKL_EXPECTED(resultArray == NULL, 0L) && (rkl_collectingEnabled() == NO)) { // If we did not create an array then we need to make sure that we release any objects we created.
01418     NSUInteger x;
01419     if(matchedStrings   != NULL) { for(x = transferredStringsCount; x < createdStringsCount; x++) { if((matchedStrings[x]  != NULL) && (matchedStrings[x] != emptyString)) { matchedStrings[x]   = rkl_ReleaseObject(matchedStrings[x]);   } } }
01420     if(subcaptureArrays != NULL) { for(x = 0UL;                     x < createdArraysCount;  x++) { if(subcaptureArrays[x] != NULL)                                        { subcaptureArrays[x] = rkl_ReleaseObject(subcaptureArrays[x]); } } }
01421   }
01422   
01423   return(resultArray);
01424 }
01425 
01426 //  IMPORTANT!   This code is critical path code.  Because of this, it has been written for speed, not clarity.
01427 //  IMPORTANT!   Should only be called from rkl_performRegexOp().
01428 //  ----------
01429 
01430 #pragma mark Convert bulk results from rkl_findRanges in to various NSDictionary types
01431 
01432 static id rkl_makeDictionary(RKLCachedRegex *cachedRegex, RKLRegexOp regexOp, RKLFindAll *findAll, NSUInteger captureKeysCount, id captureKeys[captureKeysCount], const int captureKeyIndexes[captureKeysCount], id *exception RKL_UNUSED_ASSERTION_ARG) {
01433   NSUInteger                      matchedStringIndex  = 0UL, createdStringsCount = 0UL, createdDictionariesCount = 0UL, matchedDictionariesCount = (findAll->found / (cachedRegex->captureCount + 1UL)), transferredDictionariesCount = 0UL;
01434   id           *  RKL_GC_VOLATILE matchedStrings      = NULL, * RKL_GC_VOLATILE matchedKeys = NULL, emptyString = @"";
01435   id              RKL_GC_VOLATILE returnObject        = NULL;
01436   NSDictionary ** RKL_GC_VOLATILE matchedDictionaries = NULL;
01437   
01438   RKLCDelayedAssert((cachedRegex != NULL) && ((findAll != NULL) && (findAll->found >= 0L) && (findAll->stringsScratchBuffer != NULL) && (findAll->dictionariesScratchBuffer != NULL) && (findAll->keysScratchBuffer != NULL) && (captureKeyIndexes != NULL)), exception, exitNow);
01439   
01440   CFStringRef setToString = cachedRegex->setToString;
01441   
01442   size_t      matchedStringsSize     = ((size_t)captureKeysCount * sizeof(void *));
01443   if((findAll->stackUsed + matchedStringsSize) < (size_t)_RKL_STACK_LIMIT) {      if(RKL_EXPECTED((matchedStrings      = (id           *  RKL_GC_VOLATILE)alloca(matchedStringsSize))                                                                             == NULL, 0L)) { goto exitNow; } findAll->stackUsed += matchedStringsSize; }
01444   else {                                                                          if(RKL_EXPECTED((matchedStrings      = (id           *  RKL_GC_VOLATILE)rkl_realloc(findAll->stringsScratchBuffer,      matchedStringsSize,      (NSUInteger)RKLScannedOption)) == NULL, 0L)) { goto exitNow; } }
01445   
01446   size_t      matchedKeysSize        = ((size_t)captureKeysCount * sizeof(void *));
01447   if((findAll->stackUsed + matchedKeysSize) < (size_t)_RKL_STACK_LIMIT) {         if(RKL_EXPECTED((matchedKeys         = (id           *  RKL_GC_VOLATILE)alloca(matchedKeysSize))                                                                                == NULL, 0L)) { goto exitNow; } findAll->stackUsed += matchedKeysSize; }
01448   else {                                                                          if(RKL_EXPECTED((matchedKeys         = (id           *  RKL_GC_VOLATILE)rkl_realloc(findAll->keysScratchBuffer,         matchedKeysSize,         (NSUInteger)RKLScannedOption)) == NULL, 0L)) { goto exitNow; } }
01449   
01450   size_t      matchedDictionariesSize = ((size_t)matchedDictionariesCount * sizeof(NSDictionary *));
01451   if((findAll->stackUsed + matchedDictionariesSize) < (size_t)_RKL_STACK_LIMIT) { if(RKL_EXPECTED((matchedDictionaries = (NSDictionary ** RKL_GC_VOLATILE)alloca(matchedDictionariesSize))                                                                        == NULL, 0L)) { goto exitNow; } findAll->stackUsed += matchedDictionariesSize; }
01452   else {                                                                          if(RKL_EXPECTED((matchedDictionaries = (NSDictionary ** RKL_GC_VOLATILE)rkl_realloc(findAll->dictionariesScratchBuffer, matchedDictionariesSize, (NSUInteger)RKLScannedOption)) == NULL, 0L)) { goto exitNow; } }
01453   
01454   { // This sub-block (and its local variables) is here for the benefit of the optimizer.
01455     NSUInteger     captureCount           = cachedRegex->captureCount;
01456     NSDictionary **matchedDictionariesPtr = matchedDictionaries;
01457     
01458     for(createdDictionariesCount = 0UL; createdDictionariesCount < matchedDictionariesCount; createdDictionariesCount++) {
01459       RKLCDelayedAssert(((createdDictionariesCount * captureCount) < (NSUInteger)findAll->found), exception, exitNow);
01460       RKL_STRONG_REF const NSRange * RKL_GC_VOLATILE rangePtr = &findAll->ranges[(createdDictionariesCount * (captureCount + 1UL))];
01461       for(matchedStringIndex = 0UL; matchedStringIndex < captureKeysCount; matchedStringIndex++) {
01462         NSRange range = rangePtr[captureKeyIndexes[matchedStringIndex]];
01463         if(RKL_EXPECTED(range.location != NSNotFound, 0L)) {
01464           if(RKL_EXPECTED(((matchedStrings[createdStringsCount] = RKL_EXPECTED(range.length == 0UL, 0L) ? emptyString : rkl_CreateStringWithSubstring((id)setToString, range)) == NULL), 0L)) { goto exitNow; }
01465           matchedKeys[createdStringsCount] = captureKeys[createdStringsCount];
01466           createdStringsCount++;
01467         }
01468       }
01469       RKLCDelayedAssert((matchedStringIndex <= captureCount), exception, exitNow);
01470       if(RKL_EXPECTED(((*matchedDictionariesPtr++ = (NSDictionary * RKL_GC_VOLATILE)CFDictionaryCreate(NULL, (const void **)matchedKeys, (const void **)matchedStrings, (CFIndex)createdStringsCount, &rkl_transferOwnershipDictionaryKeyCallBacks, &rkl_transferOwnershipDictionaryValueCallBacks)) == NULL), 0L)) { goto exitNow; }
01471       createdStringsCount = 0UL;
01472     }
01473   }
01474   
01475   if(createdDictionariesCount > 0UL) {
01476     if((regexOp & RKLMaskOp) == RKLArrayOfDictionariesOfCapturesOp) {
01477       RKLCDelayedAssert((matchedDictionaries != NULL) && (createdDictionariesCount > 0UL), exception, exitNow);
01478       if((returnObject = rkl_CreateAutoreleasedArray((void **)matchedDictionaries, createdDictionariesCount)) == NULL) { goto exitNow; }
01479       transferredDictionariesCount = createdDictionariesCount;
01480     } else {
01481       RKLCDelayedAssert((matchedDictionaries != NULL) && (createdDictionariesCount == 1UL), exception, exitNow);
01482       if((returnObject = rkl_CFAutorelease(matchedDictionaries[0])) == NULL) { goto exitNow; }
01483       transferredDictionariesCount = 1UL;
01484     }
01485   }
01486   
01487 exitNow:
01488   RKLCDelayedAssert((createdDictionariesCount <= transferredDictionariesCount) && ((transferredDictionariesCount > 0UL) ? (createdStringsCount == 0UL) : 1), exception, exitNow2);
01489 #ifndef NS_BLOCK_ASSERTIONS
01490 exitNow2:
01491 #endif
01492 
01493   if(rkl_collectingEnabled() == NO) { // Release any objects, if necessary.
01494     NSUInteger x;
01495     if(matchedStrings      != NULL) { for(x = 0UL;                          x < createdStringsCount;      x++) { if((matchedStrings[x]      != NULL) && (matchedStrings[x] != emptyString)) { matchedStrings[x]      = rkl_ReleaseObject(matchedStrings[x]);      } } }
01496     if(matchedDictionaries != NULL) { for(x = transferredDictionariesCount; x < createdDictionariesCount; x++) { if((matchedDictionaries[x] != NULL))                                       { matchedDictionaries[x] = rkl_ReleaseObject(matchedDictionaries[x]); } } }
01497   }
01498   
01499   return(returnObject);
01500 }
01501 
01502 //  IMPORTANT!   This code is critical path code.  Because of this, it has been written for speed, not clarity.
01503 //  IMPORTANT!   Should only be called from rkl_performRegexOp().
01504 //  ----------
01505 
01506 #pragma mark Perform "search and replace" operations on strings using ICUs uregex_*replace* functions
01507 
01508 static NSString *rkl_replaceString(RKLCachedRegex *cachedRegex, id searchString, NSUInteger searchU16Length, NSString *replacementString, NSUInteger replacementU16Length, NSInteger *replacedCountPtr, NSUInteger replaceMutable, id *exception, int32_t *status) {
01509   RKL_STRONG_REF UniChar       * RKL_GC_VOLATILE tempUniCharBuffer  = NULL;
01510   RKL_STRONG_REF const UniChar * RKL_GC_VOLATILE replacementUniChar = NULL;
01511   uint64_t           searchU16Length64  = (uint64_t)searchU16Length, replacementU16Length64 = (uint64_t)replacementU16Length;
01512   int32_t            resultU16Length    = 0, tempUniCharBufferU16Capacity = 0, needU16Capacity = 0;
01513   id RKL_GC_VOLATILE resultObject       = NULL;
01514   NSInteger          replacedCount      = -1L;
01515   
01516   if((RKL_EXPECTED(replacementU16Length64 >= (uint64_t)INT_MAX, 0L) || RKL_EXPECTED(((searchU16Length64 / 2ULL) + (replacementU16Length64 * 2ULL)) >= (uint64_t)INT_MAX, 0L))) { *exception = [NSException exceptionWithName:NSRangeException reason:@"Replacement string length exceeds INT_MAX." userInfo:NULL]; goto exitNow; }
01517 
01518   RKLCDelayedAssert((searchU16Length64 < (uint64_t)INT_MAX) && (replacementU16Length64 < (uint64_t)INT_MAX) && (((searchU16Length64 / 2ULL) + (replacementU16Length64 * 2ULL)) < (uint64_t)INT_MAX), exception, exitNow);
01519   
01520   // Zero order approximation of the buffer sizes for holding the replaced string or split strings and split strings pointer offsets.  As UTF16 code units.
01521   tempUniCharBufferU16Capacity = (int32_t)(16UL + (searchU16Length + (searchU16Length / 2UL)) + (replacementU16Length * 2UL));
01522   RKLCDelayedAssert((tempUniCharBufferU16Capacity < INT_MAX) && (tempUniCharBufferU16Capacity > 0), exception, exitNow);  
01523 
01524   // Buffer sizes converted from native units to bytes.
01525   size_t stackSize = 0UL, replacementSize = ((size_t)replacementU16Length * sizeof(UniChar)), tempUniCharBufferSize = ((size_t)tempUniCharBufferU16Capacity * sizeof(UniChar));
01526   
01527   // For the various buffers we require, we first try to allocate from the stack if we're not over the RKL_STACK_LIMIT.  If we are, switch to using the heap for the buffer.
01528   if((stackSize + tempUniCharBufferSize) < (size_t)_RKL_STACK_LIMIT) { if(RKL_EXPECTED((tempUniCharBuffer = (RKL_STRONG_REF UniChar * RKL_GC_VOLATILE)alloca(tempUniCharBufferSize))                                  == NULL, 0L)) { goto exitNow; } stackSize += tempUniCharBufferSize; }
01529   else                                                               { if(RKL_EXPECTED((tempUniCharBuffer = (RKL_STRONG_REF UniChar * RKL_GC_VOLATILE)rkl_realloc(&rkl_scratchBuffer[0], tempUniCharBufferSize, 0UL)) == NULL, 0L)) { goto exitNow; } }
01530   
01531   // Try to get the pointer to the replacement strings UTF16 data.  If we can't, allocate some buffer space, then covert to UTF16.
01532   if((replacementUniChar = CFStringGetCharactersPtr((CFStringRef)replacementString)) == NULL) {
01533     RKL_STRONG_REF UniChar * RKL_GC_VOLATILE uniCharBuffer = NULL;
01534     if((stackSize + replacementSize) < (size_t)_RKL_STACK_LIMIT) { if(RKL_EXPECTED((uniCharBuffer = (RKL_STRONG_REF UniChar * RKL_GC_VOLATILE)alloca(replacementSize))                                  == NULL, 0L)) { goto exitNow; } stackSize += replacementSize; } 
01535     else                                                         { if(RKL_EXPECTED((uniCharBuffer = (RKL_STRONG_REF UniChar * RKL_GC_VOLATILE)rkl_realloc(&rkl_scratchBuffer[1], replacementSize, 0UL)) == NULL, 0L)) { goto exitNow; } }
01536     CFStringGetCharacters((CFStringRef)replacementString, CFMakeRange(0L, replacementU16Length), uniCharBuffer); // Convert to a UTF16 string.
01537     replacementUniChar = uniCharBuffer;
01538   }
01539   
01540   resultU16Length = rkl_replaceAll(cachedRegex, replacementUniChar, (int32_t)replacementU16Length, tempUniCharBuffer, tempUniCharBufferU16Capacity, &replacedCount, &needU16Capacity, exception, status);
01541   RKLCDelayedAssert((resultU16Length <= tempUniCharBufferU16Capacity) && (needU16Capacity >= resultU16Length) && (needU16Capacity >= 0), exception, exitNow);
01542   if(RKL_EXPECTED((needU16Capacity + 4) >= INT_MAX, 0L)) { *exception = [NSException exceptionWithName:NSInternalInconsistencyException reason:@"Replaced string length exceeds INT_MAX." userInfo:NULL]; goto exitNow; }
01543   
01544   if(RKL_EXPECTED(*status == U_BUFFER_OVERFLOW_ERROR, 0L)) { // Our buffer guess(es) were too small.  Resize the buffers and try again.
01545     // rkl_replaceAll will turn a status of U_STRING_NOT_TERMINATED_WARNING in to a U_BUFFER_OVERFLOW_ERROR.
01546     // As an extra precaution, we pad out the amount needed by an extra four characters "just in case".
01547     // http://lists.apple.com/archives/Cocoa-dev/2010/Jan/msg01011.html
01548     needU16Capacity += 4;
01549     tempUniCharBufferSize = ((size_t)(tempUniCharBufferU16Capacity = needU16Capacity + 4) * sizeof(UniChar)); // Use needU16Capacity. Bug 2890810.
01550     if((stackSize + tempUniCharBufferSize) < (size_t)_RKL_STACK_LIMIT) { if(RKL_EXPECTED((tempUniCharBuffer = (RKL_STRONG_REF UniChar * RKL_GC_VOLATILE)alloca(tempUniCharBufferSize))                                  == NULL, 0L)) { goto exitNow; } stackSize += tempUniCharBufferSize; } // Warning about stackSize can be safely ignored.
01551     else                                                               { if(RKL_EXPECTED((tempUniCharBuffer = (RKL_STRONG_REF UniChar * RKL_GC_VOLATILE)rkl_realloc(&rkl_scratchBuffer[0], tempUniCharBufferSize, 0UL)) == NULL, 0L)) { goto exitNow; } }
01552     
01553     *status         = U_ZERO_ERROR; // Make sure the status var is cleared and try again.
01554     resultU16Length = rkl_replaceAll(cachedRegex, replacementUniChar, (int32_t)replacementU16Length, tempUniCharBuffer, tempUniCharBufferU16Capacity, &replacedCount, &needU16Capacity, exception, status);
01555     RKLCDelayedAssert((resultU16Length <= tempUniCharBufferU16Capacity) && (needU16Capacity >= resultU16Length) && (needU16Capacity >= 0), exception, exitNow);
01556   }
01557   
01558   // If status != U_ZERO_ERROR, consider it an error, even though status < U_ZERO_ERROR is a 'warning' in ICU nomenclature.
01559   // http://sourceforge.net/tracker/?func=detail&atid=990188&aid=2890810&group_id=204582
01560   if(RKL_EXPECTED(*status != U_ZERO_ERROR, 0L)) { goto exitNow; } // Something went wrong.
01561 
01562   RKLCDelayedAssert((replacedCount >= 0L), exception, exitNow);  
01563   if(RKL_EXPECTED(resultU16Length == 0, 0L)) { resultObject = @""; } // Optimize the case where the replaced text length == 0 with a @"" string.
01564   else if(RKL_EXPECTED((NSUInteger)resultU16Length == searchU16Length, 0L) && RKL_EXPECTED(replacedCount == 0L, 1L)) { // Optimize the case where the replacement == original by creating a copy. Very fast if self is immutable.
01565     if(replaceMutable == 0UL) { resultObject = rkl_CFAutorelease(CFStringCreateCopy(NULL, (CFStringRef)searchString)); } // .. but only if this is not replacing a mutable self.  Warning about potential leak can be safely ignored.
01566   } else { resultObject = rkl_CFAutorelease(CFStringCreateWithCharacters(NULL, tempUniCharBuffer, (CFIndex)resultU16Length)); } // otherwise, create a new string.  Warning about potential leak can be safely ignored.
01567   
01568   // If replaceMutable == 1UL, we don't do the replacement here.  We wait until after we return and unlock the cache lock.
01569   // This is because we may be trying to mutate an immutable string object.
01570   if((replaceMutable == 1UL) && RKL_EXPECTED(replacedCount > 0L, 1L)) { // We're working on a mutable string and there were successful matches with replaced text, so there's work to do.
01571     if(cachedRegex->buffer != NULL) { rkl_clearBuffer(cachedRegex->buffer, 0UL); cachedRegex->buffer = NULL; }
01572     NSUInteger  idx = 0UL;
01573     for(idx = 0UL; idx < _RKL_LRU_CACHE_SET_WAYS; idx++) {
01574       RKLBuffer *buffer = ((NSUInteger)cachedRegex->setToLength < _RKL_FIXED_LENGTH) ? &rkl_lruFixedBuffer[idx] : &rkl_lruDynamicBuffer[idx];
01575       if(RKL_EXPECTED(cachedRegex->setToString == buffer->string, 0L) && (cachedRegex->setToLength == buffer->length) && (cachedRegex->setToHash == buffer->hash)) { rkl_clearBuffer(buffer, 0UL); }
01576     }
01577     rkl_clearCachedRegexSetTo(cachedRegex); // Flush any cached information about this string since it will mutate.
01578   }
01579   
01580 exitNow:
01581   if(RKL_EXPECTED(status == NULL, 0L) || RKL_EXPECTED(*status != U_ZERO_ERROR, 0L) || RKL_EXPECTED(exception == NULL, 0L) || RKL_EXPECTED(*exception != NULL, 0L)) { replacedCount = -1L; }
01582   if(rkl_scratchBuffer[0] != NULL) { rkl_scratchBuffer[0] = rkl_free(&rkl_scratchBuffer[0]); }
01583   if(rkl_scratchBuffer[1] != NULL) { rkl_scratchBuffer[1] = rkl_free(&rkl_scratchBuffer[1]); }
01584   if(replacedCountPtr     != NULL) { *replacedCountPtr    = replacedCount;                   }
01585   return(resultObject);
01586 } // The two warnings about potential leaks can be safely ignored.
01587 
01588 //  IMPORTANT!   Should only be called from rkl_replaceString().
01589 //  ----------
01590 //  Modified version of the ICU libraries uregex_replaceAll() that keeps count of the number of replacements made.
01591 
01592 static int32_t rkl_replaceAll(RKLCachedRegex *cachedRegex, RKL_STRONG_REF const UniChar * RKL_GC_VOLATILE replacementUniChar, int32_t replacementU16Length, UniChar *replacedUniChar, int32_t replacedU16Capacity, NSInteger *replacedCount, int32_t *needU16Capacity, id *exception RKL_UNUSED_ASSERTION_ARG, int32_t *status) {
01593   int32_t    u16Length        = 0,   initialReplacedU16Capacity = replacedU16Capacity;
01594   NSUInteger bufferOverflowed = 0UL;
01595   NSInteger  replaced         = -1L;
01596   RKLCDelayedAssert((cachedRegex != NULL) && (replacementUniChar != NULL) && (replacedUniChar != NULL) && (replacedCount != NULL) && (needU16Capacity != NULL) && (status != NULL) && (replacementU16Length >= 0) && (replacedU16Capacity >= 0), exception, exitNow);
01597 
01598   cachedRegex->lastFindRange = cachedRegex->lastMatchRange = NSNotFoundRange; // Clear the cached find information for this regex so a subsequent find works correctly.
01599   RKL_ICU_FUNCTION_APPEND(uregex_reset)(cachedRegex->icu_regex, 0, status);
01600   
01601   // Work around for ICU uregex_reset() bug, see http://bugs.icu-project.org/trac/ticket/6545
01602   // http://sourceforge.net/tracker/index.php?func=detail&aid=2105213&group_id=204582&atid=990188
01603   if(RKL_EXPECTED(cachedRegex->setToRange.length == 0UL, 0L) && (*status == U_INDEX_OUTOFBOUNDS_ERROR)) { *status = U_ZERO_ERROR; }
01604   replaced = 0L;
01605   // This loop originally came from ICU source/i18n/uregex.cpp, uregex_replaceAll.
01606   // There is a bug in that code which causes the size of the buffer required for the replaced text to not be calculated correctly.
01607   // This contains a work around using the variable bufferOverflowed.
01608   // ICU bug: http://bugs.icu-project.org/trac/ticket/6656
01609   // http://sourceforge.net/tracker/index.php?func=detail&aid=2408447&group_id=204582&atid=990188
01610   while(RKL_ICU_FUNCTION_APPEND(uregex_findNext)(cachedRegex->icu_regex, status)) {
01611     replaced++;
01612     u16Length += RKL_ICU_FUNCTION_APPEND(uregex_appendReplacement)(cachedRegex->icu_regex, replacementUniChar, replacementU16Length, &replacedUniChar, &replacedU16Capacity, status);
01613     if(RKL_EXPECTED(*status == U_BUFFER_OVERFLOW_ERROR, 0L)) { bufferOverflowed = 1UL; *status = U_ZERO_ERROR; }
01614   }
01615   if(RKL_EXPECTED(*status == U_BUFFER_OVERFLOW_ERROR, 0L)) { bufferOverflowed = 1UL; *status = U_ZERO_ERROR; }
01616   if(RKL_EXPECTED(*status <= U_ZERO_ERROR, 1L))            { u16Length += RKL_ICU_FUNCTION_APPEND(uregex_appendTail)(cachedRegex->icu_regex, &replacedUniChar, &replacedU16Capacity, status); }
01617   
01618   // Try to work around a status of U_STRING_NOT_TERMINATED_WARNING.  For now, we treat it as a "Buffer Overflow" error.
01619   // As an extra precaution, in rkl_replaceString, we pad out the amount needed by an extra four characters "just in case".
01620   // http://lists.apple.com/archives/Cocoa-dev/2010/Jan/msg01011.html
01621   if(RKL_EXPECTED(*status == U_STRING_NOT_TERMINATED_WARNING, 0L)) { *status = U_BUFFER_OVERFLOW_ERROR; }
01622 
01623   // Check for status <= U_ZERO_ERROR (a 'warning' in ICU nomenclature) rather than just status == U_ZERO_ERROR.
01624   // Under just the right circumstances, status might be equal to U_STRING_NOT_TERMINATED_WARNING.  When this occurred,
01625   // rkl_replaceString would never get the U_BUFFER_OVERFLOW_ERROR status, and thus never grow the buffer to the size needed.
01626   // http://sourceforge.net/tracker/?func=detail&atid=990188&aid=2890810&group_id=204582
01627   if(RKL_EXPECTED(bufferOverflowed == 1UL, 0L) && RKL_EXPECTED(*status <= U_ZERO_ERROR, 1L)) { *status = U_BUFFER_OVERFLOW_ERROR; }
01628 
01629 #ifndef   NS_BLOCK_ASSERTIONS
01630 exitNow:
01631 #endif // NS_BLOCK_ASSERTIONS
01632   if(RKL_EXPECTED(replacedCount   != NULL, 1L)) { *replacedCount   = replaced;  }
01633   if(RKL_EXPECTED(needU16Capacity != NULL, 1L)) { *needU16Capacity = u16Length; } // Use needU16Capacity to return the number of characters that are needed for the completely replaced string. Bug 2890810.
01634   return(initialReplacedU16Capacity - replacedU16Capacity);                       // Return the number of characters of replacedUniChar that were used.
01635 }
01636 
01637 #pragma mark Internal function used to check if a regular expression is valid.
01638 
01639 static NSUInteger rkl_isRegexValid(id self, SEL _cmd, NSString *regex, RKLRegexOptions options, NSInteger *captureCountPtr, NSError **error) {
01640   volatile NSUInteger RKL_CLEANUP(rkl_cleanup_cacheSpinLockStatus) rkl_cacheSpinLockStatus = 0UL;
01641   
01642   RKLCachedRegex *cachedRegex    = NULL;
01643   NSUInteger      gotCachedRegex = 0UL;
01644   NSInteger       captureCount   = -1L;
01645   id              exception      = NULL;
01646   
01647   if((error != NULL) && (*error != NULL)) { *error = NULL; }
01648   if(RKL_EXPECTED(regex == NULL, 0L)) { RKL_RAISE_EXCEPTION(NSInvalidArgumentException, @"The regular expression argument is NULL."); }
01649   
01650   OSSpinLockLock(&rkl_cacheSpinLock);
01651   rkl_cacheSpinLockStatus |= RKLLockedCacheSpinLock;
01652   rkl_dtrace_incrementEventID();
01653   if(RKL_EXPECTED((cachedRegex = rkl_getCachedRegex(regex, options, error, &exception)) != NULL, 1L)) { gotCachedRegex = 1UL; captureCount = cachedRegex->captureCount; }
01654   cachedRegex = NULL;
01655   OSSpinLockUnlock(&rkl_cacheSpinLock);
01656   rkl_cacheSpinLockStatus |= RKLUnlockedCacheSpinLock; // Warning about rkl_cacheSpinLockStatus never being read can be safely ignored.
01657   
01658   if(captureCountPtr != NULL) { *captureCountPtr = captureCount; }
01659   if(RKL_EXPECTED(exception != NULL, 0L)) { rkl_handleDelayedAssert(self, _cmd, exception); }
01660   return(gotCachedRegex);
01661 }
01662 
01663 #pragma mark Functions used for clearing and releasing resources for various internal data structures
01664 
01665 static void rkl_clearStringCache(void) {
01666   RKLCAbortAssert(rkl_cacheSpinLock != (OSSpinLock)0);
01667   rkl_lastCachedRegex = NULL;
01668   NSUInteger x = 0UL;
01669   for(x = 0UL; x < _RKL_SCRATCH_BUFFERS;    x++) { if(rkl_scratchBuffer[x] != NULL) { rkl_scratchBuffer[x] = rkl_free(&rkl_scratchBuffer[x]); }  }
01670   for(x = 0UL; x < _RKL_REGEX_CACHE_LINES;  x++) { rkl_clearCachedRegex(&rkl_cachedRegexes[x]);                                                  }
01671   for(x = 0UL; x < _RKL_LRU_CACHE_SET_WAYS; x++) { rkl_clearBuffer(&rkl_lruFixedBuffer[x], 0UL); rkl_clearBuffer(&rkl_lruDynamicBuffer[x], 1UL); }
01672 }
01673 
01674 static void rkl_clearBuffer(RKLBuffer *buffer, NSUInteger freeDynamicBuffer) {
01675   RKLCAbortAssert(buffer != NULL);
01676   if(RKL_EXPECTED(buffer == NULL, 0L)) { return; }
01677   if(RKL_EXPECTED(freeDynamicBuffer == 1UL,  0L) && RKL_EXPECTED(buffer->uniChar != NULL, 1L)) { RKL_STRONG_REF void * RKL_GC_VOLATILE p = (RKL_STRONG_REF void * RKL_GC_VOLATILE)buffer->uniChar; buffer->uniChar = (RKL_STRONG_REF UniChar * RKL_GC_VOLATILE)rkl_free(&p); }
01678   if(RKL_EXPECTED(buffer->string    != NULL, 1L))                                              { CFRelease((CFTypeRef)buffer->string); buffer->string = NULL; }
01679   buffer->length = 0L;
01680   buffer->hash   = 0UL;
01681 }
01682 
01683 static void rkl_clearCachedRegex(RKLCachedRegex *cachedRegex) {
01684   RKLCAbortAssert(cachedRegex != NULL);
01685   if(RKL_EXPECTED(cachedRegex == NULL, 0L)) { return; }
01686   rkl_clearCachedRegexSetTo(cachedRegex);
01687   if(rkl_lastCachedRegex      == cachedRegex) { rkl_lastCachedRegex = NULL; }
01688   if(cachedRegex->icu_regex   != NULL)        { RKL_ICU_FUNCTION_APPEND(uregex_close)(cachedRegex->icu_regex); cachedRegex->icu_regex   = NULL; cachedRegex->captureCount = -1L;                               }
01689   if(cachedRegex->regexString != NULL)        { CFRelease((CFTypeRef)cachedRegex->regexString);                cachedRegex->regexString = NULL; cachedRegex->options      =  0U; cachedRegex->regexHash = 0UL; }
01690 }
01691 
01692 static void rkl_clearCachedRegexSetTo(RKLCachedRegex *cachedRegex) {
01693   RKLCAbortAssert(cachedRegex != NULL);
01694   if(RKL_EXPECTED(cachedRegex              == NULL, 0L)) { return; }
01695   if(RKL_EXPECTED(cachedRegex->icu_regex   != NULL, 1L)) { int32_t status = 0; RKL_ICU_FUNCTION_APPEND(uregex_setText)(cachedRegex->icu_regex, &rkl_emptyUniCharString[0], 0, &status); }
01696   if(RKL_EXPECTED(cachedRegex->setToString != NULL, 1L)) { CFRelease((CFTypeRef)cachedRegex->setToString); cachedRegex->setToString = NULL; }
01697   cachedRegex->lastFindRange    = cachedRegex->lastMatchRange       = cachedRegex->setToRange = NSNotFoundRange;
01698   cachedRegex->setToIsImmutable = cachedRegex->setToNeedsConversion = 0U;
01699   cachedRegex->setToUniChar     = NULL;
01700   cachedRegex->setToHash        = 0UL;
01701   cachedRegex->setToLength      = 0L;
01702   cachedRegex->buffer           = NULL;
01703 }
01704 
01705 #pragma mark Internal functions used to implement NSException and NSError functionality and userInfo NSDictionaries
01706 
01707 // Helps to keep things tidy.
01708 #define addKeyAndObject(objs, keys, i, k, o) ({id _o=(o), _k=(k); if((_o != NULL) && (_k != NULL)) { objs[i] = _o; keys[i] = _k; i++; } })
01709 
01710 static NSDictionary *rkl_userInfoDictionary(RKLUserInfoOptions userInfoOptions, NSString *regexString, RKLRegexOptions options, const UParseError *parseError, int32_t status, NSString *matchString, NSRange matchRange, NSString *replacementString, NSString *replacedString, NSInteger replacedCount, RKLRegexEnumerationOptions enumerationOptions, ...) {
01711   va_list varArgsList;
01712   va_start(varArgsList, enumerationOptions);
01713   if(regexString == NULL) { regexString = @"<NULL regex>"; }
01714 
01715   id objects[64], keys[64];
01716   NSUInteger count = 0UL;
01717   
01718   NSString * RKL_GC_VOLATILE errorNameString = [NSString stringWithUTF8String:RKL_ICU_FUNCTION_APPEND(u_errorName)(status)];
01719   
01720   addKeyAndObject(objects, keys, count, RKLICURegexRegexErrorKey,        regexString);
01721   addKeyAndObject(objects, keys, count, RKLICURegexRegexOptionsErrorKey, [NSNumber numberWithUnsignedInt:options]);
01722   addKeyAndObject(objects, keys, count, RKLICURegexErrorCodeErrorKey,    [NSNumber numberWithInt:status]);
01723   addKeyAndObject(objects, keys, count, RKLICURegexErrorNameErrorKey,    errorNameString);
01724 
01725   if(matchString                                            != NULL) { addKeyAndObject(objects, keys, count, RKLICURegexSubjectStringErrorKey,      matchString);                                             }  
01726   if((userInfoOptions & RKLUserInfoSubjectRange)            != 0UL)  { addKeyAndObject(objects, keys, count, RKLICURegexSubjectRangeErrorKey,       [NSValue valueWithRange:matchRange]);                     }
01727   if(replacementString                                      != NULL) { addKeyAndObject(objects, keys, count, RKLICURegexReplacementStringErrorKey,  replacementString);                                       }
01728   if(replacedString                                         != NULL) { addKeyAndObject(objects, keys, count, RKLICURegexReplacedStringErrorKey,     replacedString);                                          }
01729   if((userInfoOptions & RKLUserInfoReplacedCount)           != 0UL)  { addKeyAndObject(objects, keys, count, RKLICURegexReplacedCountErrorKey,      [NSNumber numberWithInteger:replacedCount]);              }
01730   if((userInfoOptions & RKLUserInfoRegexEnumerationOptions) != 0UL)  { addKeyAndObject(objects, keys, count, RKLICURegexEnumerationOptionsErrorKey, [NSNumber numberWithUnsignedInteger:enumerationOptions]); }
01731   
01732   if((parseError != NULL) && (parseError->line != -1)) {
01733     NSString *preContextString  = [NSString stringWithCharacters:&parseError->preContext[0]  length:(NSUInteger)RKL_ICU_FUNCTION_APPEND(u_strlen)(&parseError->preContext[0])];
01734     NSString *postContextString = [NSString stringWithCharacters:&parseError->postContext[0] length:(NSUInteger)RKL_ICU_FUNCTION_APPEND(u_strlen)(&parseError->postContext[0])];
01735     
01736     addKeyAndObject(objects, keys, count, RKLICURegexLineErrorKey,        [NSNumber numberWithInt:parseError->line]);
01737     addKeyAndObject(objects, keys, count, RKLICURegexOffsetErrorKey,      [NSNumber numberWithInt:parseError->offset]);
01738     addKeyAndObject(objects, keys, count, RKLICURegexPreContextErrorKey,  preContextString);
01739     addKeyAndObject(objects, keys, count, RKLICURegexPostContextErrorKey, postContextString);
01740     addKeyAndObject(objects, keys, count, @"NSLocalizedFailureReason",    ([NSString stringWithFormat:@"The error %@ occurred at line %d, column %d: %@<<HERE>>%@", errorNameString, parseError->line, parseError->offset, preContextString, postContextString]));
01741   } else {
01742     addKeyAndObject(objects, keys, count, @"NSLocalizedFailureReason",    ([NSString stringWithFormat:@"The error %@ occurred.", errorNameString]));
01743   }
01744   
01745   while(count < 62UL) { id obj = va_arg(varArgsList, id), key = va_arg(varArgsList, id); if((obj != NULL) && (key != NULL)) { addKeyAndObject(objects, keys, count, key, obj); } else { break; } }
01746   va_end(varArgsList);
01747   
01748   return([NSDictionary dictionaryWithObjects:&objects[0] forKeys:&keys[0] count:count]);
01749 }
01750 
01751 static NSError *rkl_makeNSError(RKLUserInfoOptions userInfoOptions, NSString *regexString, RKLRegexOptions options, const UParseError *parseError, int32_t status, NSString *matchString, NSRange matchRange, NSString *replacementString, NSString *replacedString, NSInteger replacedCount, RKLRegexEnumerationOptions enumerationOptions, NSString *errorDescription) {
01752   if(errorDescription == NULL) { errorDescription = (status == U_ZERO_ERROR) ? @"No description of this error is available." : [NSString stringWithFormat:@"ICU regular expression error #%d, %s.", status, RKL_ICU_FUNCTION_APPEND(u_errorName)(status)]; }
01753   return([NSError errorWithDomain:RKLICURegexErrorDomain code:(NSInteger)status userInfo:rkl_userInfoDictionary(userInfoOptions, regexString, options, parseError, status, matchString, matchRange, replacementString, replacedString, replacedCount, enumerationOptions, errorDescription, @"NSLocalizedDescription", NULL)]);
01754 }
01755 
01756 static NSException *rkl_NSExceptionForRegex(NSString *regexString, RKLRegexOptions options, const UParseError *parseError, int32_t status) {
01757   return([NSException exceptionWithName:RKLICURegexException reason:[NSString stringWithFormat:@"ICU regular expression error #%d, %s.", status, RKL_ICU_FUNCTION_APPEND(u_errorName)(status)] userInfo:rkl_userInfoDictionary((RKLUserInfoOptions)RKLUserInfoNone, regexString, options, parseError, status, NULL, NSNotFoundRange, NULL, NULL, 0L, (RKLRegexEnumerationOptions)RKLRegexEnumerationNoOptions, NULL)]);
01758 }
01759 
01760 static NSDictionary *rkl_makeAssertDictionary(const char *function, const char *file, int line, NSString *format, ...) {
01761   va_list varArgsList;
01762   va_start(varArgsList, format);
01763   NSString * RKL_GC_VOLATILE formatString   = [[[NSString alloc] initWithFormat:format arguments:varArgsList] autorelease];
01764   va_end(varArgsList);
01765   NSString * RKL_GC_VOLATILE functionString = [NSString stringWithUTF8String:function], *fileString = [NSString stringWithUTF8String:file];
01766   return([NSDictionary dictionaryWithObjectsAndKeys:formatString, @"description", functionString, @"function", fileString, @"file", [NSNumber numberWithInt:line], @"line", NSInternalInconsistencyException, @"exceptionName", NULL]);
01767 }
01768 
01769 static NSString *rkl_stringFromClassAndMethod(id object, SEL selector, NSString *format, ...) {
01770   va_list varArgsList;
01771   va_start(varArgsList, format);
01772   NSString * RKL_GC_VOLATILE formatString = [[[NSString alloc] initWithFormat:format arguments:varArgsList] autorelease];
01773   va_end(varArgsList);
01774   Class objectsClass = (object == NULL) ? NULL : [object class];
01775   return([NSString stringWithFormat:@"*** %c[%@ %@]: %@", (object == objectsClass) ? '+' : '-', (objectsClass == NULL) ? @"<NULL>" : NSStringFromClass(objectsClass), (selector == NULL) ? @":NULL:" : NSStringFromSelector(selector), formatString]);
01776 }
01777 
01778 #ifdef    _RKL_BLOCKS_ENABLED
01779 
01781 #pragma mark -
01782 #pragma mark Objective-C ^Blocks Support
01783 #pragma mark -
01784 
01785 
01786 // Prototypes
01787 
01788 static id rkl_performEnumerationUsingBlock(id self, SEL _cmd,
01789                                            RKLRegexOp regexOp, NSString *regexString, RKLRegexOptions options,
01790                                            id matchString, NSRange matchRange,
01791                                            RKLBlockEnumerationOp blockEnumerationOp, RKLRegexEnumerationOptions enumerationOptions,
01792                                            NSInteger *replacedCountPtr, NSUInteger *errorFreePtr,
01793                                            NSError **error,
01794                                            void (^stringsAndRangesBlock)(NSInteger capturedCount, NSString * const capturedStrings[capturedCount], const NSRange capturedStringRanges[capturedCount], volatile BOOL * const stop),
01795                                            NSString *(^replaceStringsAndRangesBlock)(NSInteger capturedCount, NSString * const capturedStrings[capturedCount], const NSRange capturedStringRanges[capturedCount], volatile BOOL * const stop)
01796                                            ) RKL_NONNULL_ARGS(1,2,4,6);
01797 
01798 // This is an object meant for internal use only.  It wraps and abstracts various functionality to simplify ^Blocks support.
01799 
01800 @interface RKLBlockEnumerationHelper : NSObject {
01801   @public
01802   RKLCachedRegex cachedRegex;
01803   RKLBuffer      buffer;
01804   RKL_STRONG_REF void * RKL_GC_VOLATILE scratchBuffer[_RKL_SCRATCH_BUFFERS];
01805   NSUInteger     needToFreeBufferUniChar:1;
01806 }
01807 - (id)initWithRegex:(NSString *)initRegexString options:(RKLRegexOptions)initOptions string:(NSString *)initString range:(NSRange)initRange error:(NSError **)initError;
01808 @end
01809 
01810 @implementation RKLBlockEnumerationHelper
01811 
01812 - (id)initWithRegex:(NSString *)initRegexString options:(RKLRegexOptions)initOptions string:(NSString *)initString range:(NSRange)initRange error:(NSError **)initError
01813 {
01814   volatile NSUInteger RKL_CLEANUP(rkl_cleanup_cacheSpinLockStatus) rkl_cacheSpinLockStatus = 0UL;
01815 
01816   int32_t         status               = U_ZERO_ERROR;
01817   id              exception            = NULL;
01818   RKLCachedRegex *retrievedCachedRegex = NULL;
01819 
01820 #ifdef _RKL_DTRACE_ENABLED
01821   NSUInteger      thisDTraceEventID    = 0UL;
01822   unsigned int    lookupResultFlags    = 0U;
01823 #endif
01824   
01825   if(RKL_EXPECTED((self = [super init]) == NULL, 0L)) { goto errorExit; }
01826 
01827   RKLCDelayedAssert((initRegexString != NULL) && (initString != NULL), &exception, errorExit);
01828 
01829   // IMPORTANT!   Once we have obtained the lock, code MUST exit via 'goto exitNow;' to unlock the lock!  NO EXCEPTIONS!
01830   // ----------
01831   OSSpinLockLock(&rkl_cacheSpinLock); // Grab the lock and get cache entry.
01832   rkl_cacheSpinLockStatus |= RKLLockedCacheSpinLock;
01833   rkl_dtrace_incrementAndGetEventID(thisDTraceEventID);
01834   
01835   if(RKL_EXPECTED((retrievedCachedRegex = rkl_getCachedRegex(initRegexString, initOptions, initError, &exception)) == NULL, 0L)) { goto exitNow; }
01836   RKLCDelayedAssert(((retrievedCachedRegex >= rkl_cachedRegexes) && ((retrievedCachedRegex - &rkl_cachedRegexes[0]) < (ssize_t)_RKL_REGEX_CACHE_LINES)) && (retrievedCachedRegex != NULL) && (retrievedCachedRegex->icu_regex != NULL) && (retrievedCachedRegex->regexString != NULL) && (retrievedCachedRegex->captureCount >= 0L) && (retrievedCachedRegex == rkl_lastCachedRegex), &exception, exitNow);
01837   
01838   if(RKL_EXPECTED(retrievedCachedRegex == NULL, 0L) || RKL_EXPECTED(status > U_ZERO_ERROR, 0L) || RKL_EXPECTED(exception != NULL, 0L)) { goto exitNow; }
01839 
01840   if(RKL_EXPECTED((cachedRegex.icu_regex   = RKL_ICU_FUNCTION_APPEND(uregex_clone)(retrievedCachedRegex->icu_regex, &status)) == NULL, 0L) || RKL_EXPECTED(status != U_ZERO_ERROR, 0L)) { goto exitNow; }
01841   if(RKL_EXPECTED((cachedRegex.regexString = (CFStringRef)CFRetain((CFTypeRef)retrievedCachedRegex->regexString))             == NULL, 0L))                                             { goto exitNow; }
01842   cachedRegex.options      = initOptions;
01843   cachedRegex.captureCount = retrievedCachedRegex->captureCount;
01844   cachedRegex.regexHash    = retrievedCachedRegex->regexHash;
01845 
01846   RKLCDelayedAssert((cachedRegex.icu_regex != NULL) && (cachedRegex.regexString != NULL) && (cachedRegex.captureCount >= 0L), &exception, exitNow);
01847 
01848 exitNow:
01849   if((rkl_cacheSpinLockStatus & RKLLockedCacheSpinLock) != 0UL) { // In case we arrive at exitNow: without obtaining the rkl_cacheSpinLock.
01850     OSSpinLockUnlock(&rkl_cacheSpinLock);
01851     rkl_cacheSpinLockStatus |= RKLUnlockedCacheSpinLock; // Warning about rkl_cacheSpinLockStatus never being read can be safely ignored.
01852   }
01853 
01854   if(RKL_EXPECTED(self == NULL, 0L) || RKL_EXPECTED(retrievedCachedRegex == NULL, 0L) || RKL_EXPECTED(cachedRegex.icu_regex == NULL, 0L) || RKL_EXPECTED(status != U_ZERO_ERROR, 0L) || RKL_EXPECTED(exception != NULL, 0L)) { goto errorExit; }
01855   retrievedCachedRegex = NULL; // Since we no longer hold the lock, ensure that nothing accesses the retrieved cache regex after this point.
01856 
01857   rkl_dtrace_addLookupFlag(lookupResultFlags, RKLEnumerationBufferLookupFlag);
01858 
01859   if(RKL_EXPECTED((buffer.string = CFStringCreateCopy(NULL, (CFStringRef)initString)) == NULL, 0L)) { goto errorExit; }
01860   buffer.hash   = CFHash((CFTypeRef)buffer.string);
01861   buffer.length = CFStringGetLength(buffer.string);
01862 
01863   if((buffer.uniChar = (UniChar *)CFStringGetCharactersPtr(buffer.string)) == NULL) {
01864     rkl_dtrace_addLookupFlag(lookupResultFlags, RKLConversionRequiredLookupFlag);
01865     if(RKL_EXPECTED((buffer.uniChar = (RKL_STRONG_REF UniChar * RKL_GC_VOLATILE)rkl_realloc((RKL_STRONG_REF void ** RKL_GC_VOLATILE)&buffer.uniChar, ((size_t)buffer.length * sizeof(UniChar)), 0UL)) == NULL, 0L)) { goto errorExit; } // Resize the buffer.
01866     needToFreeBufferUniChar = rkl_collectingEnabled() ? 0U : 1U;
01867     CFStringGetCharacters(buffer.string, CFMakeRange(0L, buffer.length), (UniChar *)buffer.uniChar); // Convert to a UTF16 string.
01868   }
01869 
01870   if(RKL_EXPECTED((cachedRegex.setToString = (CFStringRef)CFRetain((CFTypeRef)buffer.string)) == NULL, 0L)) { goto errorExit; }
01871   cachedRegex.setToHash    = buffer.hash;
01872   cachedRegex.setToLength  = buffer.length;
01873   cachedRegex.setToUniChar = buffer.uniChar;
01874   cachedRegex.buffer       = &buffer;
01875   
01876   RKLCDelayedAssert((cachedRegex.icu_regex != NULL) && (cachedRegex.setToUniChar != NULL) && (cachedRegex.setToLength < INT_MAX) && (NSMaxRange(initRange) <= (NSUInteger)cachedRegex.setToLength) && (NSMaxRange(initRange) < INT_MAX), &exception, errorExit);
01877   cachedRegex.lastFindRange = cachedRegex.lastMatchRange = NSNotFoundRange;
01878   cachedRegex.setToRange    = initRange;
01879   RKL_ICU_FUNCTION_APPEND(uregex_setText)(cachedRegex.icu_regex, cachedRegex.setToUniChar + cachedRegex.setToRange.location, (int32_t)cachedRegex.setToRange.length, &status);
01880   if(RKL_EXPECTED(status > U_ZERO_ERROR, 0L)) { goto errorExit; }
01881 
01882   rkl_dtrace_addLookupFlag(lookupResultFlags, RKLSetTextLookupFlag);
01883   rkl_dtrace_utf16ConversionCacheWithEventID(thisDTraceEventID, lookupResultFlags, initString, cachedRegex.setToRange.location, cachedRegex.setToRange.length, cachedRegex.setToLength);
01884 
01885   return(self);
01886 
01887 errorExit:
01888   if(RKL_EXPECTED(self      != NULL,         1L))                                        {  [self autorelease]; }
01889   if(RKL_EXPECTED(status     > U_ZERO_ERROR, 0L) && RKL_EXPECTED(exception == NULL, 0L)) {  exception = rkl_NSExceptionForRegex(initRegexString, initOptions, NULL, status); } // If we had a problem, prepare an exception to be thrown.
01890   if(RKL_EXPECTED(status     < U_ZERO_ERROR, 0L) && (initError != NULL))                 { *initError = rkl_makeNSError((RKLUserInfoOptions)RKLUserInfoNone, initRegexString, initOptions, NULL, status, initString, initRange, NULL, NULL, 0L, (RKLRegexEnumerationOptions)RKLRegexEnumerationNoOptions, @"The ICU library returned an unexpected error."); }
01891   if(RKL_EXPECTED(exception != NULL,         0L))                                        {  rkl_handleDelayedAssert(self, _cmd, exception); }
01892 
01893   return(NULL);
01894 }
01895 
01896 #ifdef    __OBJC_GC__
01897 - (void)finalize
01898 {
01899   rkl_clearCachedRegex(&cachedRegex);
01900   rkl_clearBuffer(&buffer, (needToFreeBufferUniChar != 0U) ? 1LU : 0LU);
01901   NSUInteger tmpIdx = 0UL; // The rkl_free() below is "probably" a no-op when GC is on, but better to be safe than sorry...
01902   for(tmpIdx = 0UL; tmpIdx < _RKL_SCRATCH_BUFFERS; tmpIdx++) { if(RKL_EXPECTED(scratchBuffer[tmpIdx] != NULL, 0L)) { scratchBuffer[tmpIdx] = rkl_free(&scratchBuffer[tmpIdx]); } }
01903   [super finalize];
01904 }
01905 #endif // __OBJC_GC__
01906   
01907 - (void)dealloc
01908 {
01909   rkl_clearCachedRegex(&cachedRegex);
01910   rkl_clearBuffer(&buffer, (needToFreeBufferUniChar != 0U) ? 1LU : 0LU);
01911   NSUInteger tmpIdx = 0UL;
01912   for(tmpIdx = 0UL; tmpIdx < _RKL_SCRATCH_BUFFERS; tmpIdx++) { if(RKL_EXPECTED(scratchBuffer[tmpIdx] != NULL, 0L)) { scratchBuffer[tmpIdx] = rkl_free(&scratchBuffer[tmpIdx]); } }
01913   [super dealloc];
01914 }
01915 
01916 @end
01917 
01918 //  IMPORTANT!   This code is critical path code.  Because of this, it has been written for speed, not clarity.
01919 //  ----------
01920 //
01921 //  Return value: BOOL. Per "Error Handling Programming Guide" wrt/ NSError, return NO on error / failure, and set *error to an NSError object.
01922 //  
01923 //  rkl_performEnumerationUsingBlock reference counted / manual memory management notes:
01924 //
01925 //  When running using reference counting, rkl_performEnumerationUsingBlock() creates a CFMutableArray called autoreleaseArray, which is -autoreleased.
01926 //  autoreleaseArray uses the rkl_transferOwnershipArrayCallBacks CFArray callbacks which do not perform a -retain/CFRetain() when objects are added, but do perform a -release/CFRelease() when an object is removed.
01927 //
01928 //  A special class, RKLBlockEnumerationHelper, is used to manage the details of creating a private instantiation of the ICU regex (via uregex_clone()) and setting up the details of the UTF-16 buffer required by the ICU regex engine.
01929 //  The instantiated RKLBlockEnumerationHelper is not autoreleased, but added to autoreleaseArray.  When rkl_performEnumerationUsingBlock() exits, it calls CFArrayRemoveAllValues(autoreleaseArray), which empties the array.
01930 //  This has the effect of immediately -releasing the instantiated RKLBlockEnumerationHelper object, and all the memory used to hold the ICU regex and UTF-16 conversion buffer.
01931 //  This means the memory is reclaimed immediately and we do not have to wait until the autorelease pool pops.
01932 //
01933 //  If we are performing a "string replacement" operation, we create a temporary NSMutableString named mutableReplacementString to hold the replaced strings results.  mutableReplacementString is also added to autoreleaseArray so that it
01934 //  can be properly released on an error.
01935 //
01936 //  Temporary strings that are created during the enumeration of matches are added to autoreleaseArray.
01937 //  The strings are added by doing a CFArrayReplaceValues(), which simultaneously releases the previous iterations temporary strings while adding the current iterations temporary strings to the array.
01938 //
01939 //  autoreleaseArray always has a reference to any "live" and in use objects. If anything "Goes Wrong", at any point, for any reason (ie, exception is thrown), autoreleaseArray is in the current NSAutoreleasePool
01940 //  and will automatically be released when that pool pops.  This ensures that we don't leak anything even when things go seriously sideways.  This also allows us to keep the total amount of memory in use
01941 //  down to a minimum, which can be substantial if the user is enumerating a large string, for example a regex of '\w+' on a 500K+ text file.
01942 //
01943 //  The only 'caveat' is that the user needs to -retain any strings that they want to use past the point at which their ^block returns.  Logically, it is as if the following takes place:
01944 //  
01945 //  for(eachMatchOfRegexInStringToSearch) {
01946 //    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
01947 //    callUsersBlock(capturedCount, capturedStrings, capturedStringRanges, stop);
01948 //    [pool release];
01949 //  }
01950 //
01951 //  But in reality, no NSAutoreleasePool is created, it's all slight of hand done via the CFMutableArray autoreleaseArray.
01952 //
01953 //  rkl_performEnumerationUsingBlock garbage collected / automatic memory management notes:
01954 //
01955 //  When RegexKitLite is built with -fobjc-gc or -fobjc-gc-only, and (in the case of -fobjc-gc) RegexKitLite determines that GC is active at execution time, then rkl_performEnumerationUsingBlock essentially
01956 //  skips all of the above reference counted autoreleaseArray stuff. 
01957 //
01958 //  rkl_performEnumerationUsingBlock and RKLRegexEnumerationReleaseStringReturnedByReplacementBlock notes
01959 //
01960 //  Under reference counting, this enumeration option allows the user to return a non-autoreleased string, and then have RegexKitLite send the object a -release message once it's done with it.
01961 //  The primary reason to do this is to immediately reclaim the memory used by the string holding the replacement text.
01962 //  Just in case the user returns one of the strings we passed via capturedStrings[], we check to see if the string return by the block is any of the strings we created and passed via capturedStrings[].
01963 //  If it is one of our strings, we do not send the string a -release since that would over release it.  It is assumed that the user will /NOT/ add a -retain to our strings in this case.
01964 //  Under GC, RKLRegexEnumerationReleaseStringReturnedByReplacementBlock is ignored and no -release messages are sent.
01965 //  
01966 
01967 #pragma mark Primary internal function that Objective-C ^Blocks related methods call to perform regular expression operations
01968 
01969 static id rkl_performEnumerationUsingBlock(id self, SEL _cmd,
01970                                            RKLRegexOp regexOp, NSString *regexString, RKLRegexOptions options,
01971                                            id matchString, NSRange matchRange,
01972                                            RKLBlockEnumerationOp blockEnumerationOp, RKLRegexEnumerationOptions enumerationOptions,
01973                                            NSInteger *replacedCountPtr, NSUInteger *errorFreePtr,
01974                                            NSError **error,
01975                                            void (^stringsAndRangesBlock)(NSInteger capturedCount, NSString * const capturedStrings[capturedCount], const NSRange capturedStringRanges[capturedCount], volatile BOOL * const stop),
01976                                            NSString *(^replaceStringsAndRangesBlock)(NSInteger capturedCount, NSString * const capturedStrings[capturedCount], const NSRange capturedStringRanges[capturedCount], volatile BOOL * const stop)) {
01977   NSMutableArray            * RKL_GC_VOLATILE autoreleaseArray              = NULL;
01978   RKLBlockEnumerationHelper * RKL_GC_VOLATILE blockEnumerationHelper        = NULL;
01979   NSMutableString           * RKL_GC_VOLATILE mutableReplacementString      = NULL;
01980   RKL_STRONG_REF UniChar    * RKL_GC_VOLATILE blockEnumerationHelperUniChar = NULL;
01981   NSUInteger    errorFree                = NO;
01982   id            exception                = NULL, returnObject  = NULL;
01983   CFRange       autoreleaseReplaceRange  = CFMakeRange(0L, 0L);
01984   int32_t       status                   = U_ZERO_ERROR;
01985   RKLRegexOp    maskedRegexOp            = (regexOp & RKLMaskOp);
01986   volatile BOOL shouldStop               = NO;
01987   NSInteger     replacedCount            = -1L;
01988   NSRange       lastMatchedRange         = NSNotFoundRange;
01989   NSUInteger    stringU16Length          = 0UL;
01990   
01991   BOOL performStringReplacement = (blockEnumerationOp == RKLBlockEnumerationReplaceOp) ? YES : NO;
01992   
01993   if((error != NULL) && (*error != NULL)) { *error = NULL; }
01994   
01995   if(RKL_EXPECTED(regexString == NULL, 0L)) { exception = (id)RKL_EXCEPTION(NSInvalidArgumentException,       @"The regular expression argument is NULL."); goto exitNow; }
01996   if(RKL_EXPECTED(matchString == NULL, 0L)) { exception = (id)RKL_EXCEPTION(NSInternalInconsistencyException, @"The match string argument is NULL.");       goto exitNow; }
01997 
01998   if((((enumerationOptions & RKLRegexEnumerationCapturedStringsNotRequired)              != 0UL) && ((enumerationOptions & RKLRegexEnumerationFastCapturedStringsXXX) != 0UL)) ||
01999      (((enumerationOptions & RKLRegexEnumerationReleaseStringReturnedByReplacementBlock) != 0UL) && (blockEnumerationOp != RKLBlockEnumerationReplaceOp)) ||
02000      ((enumerationOptions & (~((RKLRegexEnumerationOptions)(RKLRegexEnumerationCapturedStringsNotRequired | RKLRegexEnumerationReleaseStringReturnedByReplacementBlock | RKLRegexEnumerationFastCapturedStringsXXX)))) != 0UL)) {
02001     exception = (id)RKL_EXCEPTION(NSInvalidArgumentException, @"The RKLRegexEnumerationOptions argument is not valid.");
02002     goto exitNow;
02003   }
02004   
02005   stringU16Length = (NSUInteger)CFStringGetLength((CFStringRef)matchString);
02006   
02007   if(RKL_EXPECTED(matchRange.length == NSUIntegerMax,          1L)) { matchRange.length = stringU16Length; } // For convenience.
02008   if(RKL_EXPECTED(stringU16Length    < NSMaxRange(matchRange), 0L)) { exception = (id)RKL_EXCEPTION(NSRangeException, @"Range or index out of bounds.");  goto exitNow; }
02009   if(RKL_EXPECTED(stringU16Length   >= (NSUInteger)INT_MAX,    0L)) { exception = (id)RKL_EXCEPTION(NSRangeException, @"String length exceeds INT_MAX."); goto exitNow; }
02010   
02011   RKLCDelayedAssert((self != NULL) && (_cmd != NULL) && ((blockEnumerationOp == RKLBlockEnumerationMatchOp) ? (((regexOp == RKLCapturesArrayOp) || (regexOp == RKLSplitOp)) && (stringsAndRangesBlock != NULL) && (replaceStringsAndRangesBlock == NULL)) : 1) && ((blockEnumerationOp == RKLBlockEnumerationReplaceOp) ? ((regexOp == RKLCapturesArrayOp) && (stringsAndRangesBlock == NULL) && (replaceStringsAndRangesBlock != NULL)) : 1) , &exception, exitNow);
02012 
02013   if((rkl_collectingEnabled() == NO) && RKL_EXPECTED((autoreleaseArray = rkl_CFAutorelease(CFArrayCreateMutable(NULL, 0L, &rkl_transferOwnershipArrayCallBacks))) == NULL, 0L))          { goto exitNow; } // Warning about potential leak of Core Foundation object can be safely ignored.
02014   if(RKL_EXPECTED((blockEnumerationHelper = [[RKLBlockEnumerationHelper alloc] initWithRegex:regexString options:options string:matchString range:matchRange error:error]) == NULL, 0L)) { goto exitNow; } // Warning about potential leak of blockEnumerationHelper can be safely ignored.
02015   if(autoreleaseArray != NULL) { CFArrayAppendValue((CFMutableArrayRef)autoreleaseArray, blockEnumerationHelper); autoreleaseReplaceRange.location++; } // We do not autorelease blockEnumerationHelper, but instead add it to autoreleaseArray.
02016   
02017   if(performStringReplacement == YES) {
02018     if(RKL_EXPECTED((mutableReplacementString = [[NSMutableString alloc] init]) == NULL, 0L)) { goto exitNow; } // Warning about potential leak of mutableReplacementString can be safely ignored.
02019     if(autoreleaseArray != NULL) { CFArrayAppendValue((CFMutableArrayRef)autoreleaseArray, mutableReplacementString); autoreleaseReplaceRange.location++; } // We do not autorelease mutableReplacementString, but instead add it to autoreleaseArray.
02020   }
02021 
02022   // RKLBlockEnumerationHelper creates an immutable copy of the string to match (matchString) which we reference via blockEnumerationHelperString.  We use blockEnumerationHelperString when creating the captured strings from a match.
02023   // This protects us against the user mutating matchString while we are in the middle of enumerating matches.
02024   NSString           * RKL_GC_VOLATILE blockEnumerationHelperString = (NSString *)blockEnumerationHelper->buffer.string, ** RKL_GC_VOLATILE capturedStrings = NULL, *emptyString = @"";
02025   CFMutableStringRef * RKL_GC_VOLATILE fastCapturedStrings          = NULL;
02026   NSInteger  captureCountBlockArgument = (blockEnumerationHelper->cachedRegex.captureCount + 1L);
02027   size_t     capturedStringsCapacity   = ((size_t)captureCountBlockArgument + 4UL);
02028   size_t     capturedRangesCapacity    = (((size_t)captureCountBlockArgument + 4UL) * 5UL);
02029   NSRange   *capturedRanges            = NULL;
02030 
02031   lastMatchedRange              = NSMakeRange(matchRange.location, 0UL);
02032   blockEnumerationHelperUniChar = blockEnumerationHelper->buffer.uniChar;
02033   
02034   RKLCDelayedAssert((blockEnumerationHelperString != NULL) && (blockEnumerationHelperUniChar != NULL) && (captureCountBlockArgument > 0L) && (capturedStringsCapacity > 0UL) && (capturedRangesCapacity > 0UL), &exception, exitNow);
02035   
02036   if((capturedStrings = (NSString ** RKL_GC_VOLATILE)alloca(sizeof(NSString *) * capturedStringsCapacity)) == NULL) { goto exitNow; } // Space to hold the captured strings from a match.
02037   if((capturedRanges  = (NSRange *)                  alloca(sizeof(NSRange)    * capturedRangesCapacity))  == NULL) { goto exitNow; } // Space to hold the NSRanges of the captured strings from a match.
02038   
02039 #ifdef NS_BLOCK_ASSERTIONS
02040   { // Initialize the padded capturedStrings and capturedRanges to values that should tickle a fault if they are ever used.
02041     size_t idx = 0UL;
02042     for(idx = captureCountBlockArgument; idx < capturedStringsCapacity; idx++) { capturedStrings[idx] = (NSString *)RKLIllegalPointer; }
02043     for(idx = captureCountBlockArgument; idx < capturedRangesCapacity;  idx++) { capturedRanges[idx]  =             RKLIllegalRange;   }
02044   }
02045 #else
02046   { // Initialize all of the capturedStrings and capturedRanges to values that should tickle a fault if they are ever used.
02047     size_t idx = 0UL;
02048     for(idx = 0UL; idx < capturedStringsCapacity; idx++) { capturedStrings[idx] = (NSString *)RKLIllegalPointer; }
02049     for(idx = 0UL; idx < capturedRangesCapacity;  idx++) { capturedRanges[idx]  =             RKLIllegalRange;   }
02050   }
02051 #endif
02052   
02053   if((enumerationOptions & RKLRegexEnumerationFastCapturedStringsXXX) != 0UL) {
02054     RKLCDelayedAssert(((enumerationOptions & RKLRegexEnumerationCapturedStringsNotRequired) == 0UL), &exception, exitNow);
02055     size_t idx = 0UL;
02056     if((fastCapturedStrings = (CFMutableStringRef * RKL_GC_VOLATILE)alloca(sizeof(NSString *) * capturedStringsCapacity)) == NULL) { goto exitNow; } // Space to hold the "fast" captured strings from a match.
02057 
02058     for(idx = 0UL; idx < (size_t)captureCountBlockArgument; idx++) {
02059       if((fastCapturedStrings[idx] = CFStringCreateMutableWithExternalCharactersNoCopy(NULL, NULL, 0L, 0L, kCFAllocatorNull)) == NULL) { goto exitNow; }
02060       if(autoreleaseArray != NULL) { CFArrayAppendValue((CFMutableArrayRef)autoreleaseArray, fastCapturedStrings[idx]); autoreleaseReplaceRange.location++; } // We do not autorelease mutableReplacementString, but instead add it to autoreleaseArray.
02061       capturedStrings[idx] = (NSString *)fastCapturedStrings[idx];
02062     }
02063   }
02064 
02065   RKLFindAll findAll = rkl_makeFindAll(capturedRanges, matchRange, (NSInteger)capturedRangesCapacity, (capturedRangesCapacity * sizeof(NSRange)), 0UL, &blockEnumerationHelper->scratchBuffer[0], &blockEnumerationHelper->scratchBuffer[1], &blockEnumerationHelper->scratchBuffer[2], &blockEnumerationHelper->scratchBuffer[3], &blockEnumerationHelper->scratchBuffer[4], 0L, 0L, 1L);
02066   
02067   NSString ** RKL_GC_VOLATILE capturedStringsBlockArgument = NULL; // capturedStringsBlockArgument is what we pass to the 'capturedStrings[]' argument of the users ^block.  Will pass NULL if the user doesn't want the captured strings created automatically.
02068   if((enumerationOptions & RKLRegexEnumerationCapturedStringsNotRequired) == 0UL) { capturedStringsBlockArgument = capturedStrings; } // If the user wants the captured strings automatically created, set to capturedStrings.
02069   
02070   replacedCount = 0L;
02071   while(RKL_EXPECTED(rkl_findRanges(&blockEnumerationHelper->cachedRegex, regexOp, &findAll, &exception, &status) == NO, 1L) && RKL_EXPECTED(findAll.found > 0L, 1L) && RKL_EXPECTED(exception == NULL, 1L) && RKL_EXPECTED(status == U_ZERO_ERROR, 1L)) {
02072     if(performStringReplacement == YES) {
02073       NSUInteger lastMatchedMaxLocation = (lastMatchedRange.location + lastMatchedRange.length);
02074       NSRange    previousUnmatchedRange = NSMakeRange(lastMatchedMaxLocation, findAll.ranges[0].location - lastMatchedMaxLocation);
02075       RKLCDelayedAssert((NSMaxRange(previousUnmatchedRange) <= stringU16Length) && (NSRangeInsideRange(previousUnmatchedRange, matchRange) == YES), &exception, exitNow);
02076       if(RKL_EXPECTED(previousUnmatchedRange.length > 0UL, 1L)) { CFStringAppendCharacters((CFMutableStringRef)mutableReplacementString, blockEnumerationHelperUniChar + previousUnmatchedRange.location, (CFIndex)previousUnmatchedRange.length); }
02077     }
02078 
02079     findAll.found -= findAll.addedSplitRanges;
02080 
02081     NSInteger passCaptureCountBlockArgument = ((findAll.found == 0L) && (findAll.addedSplitRanges == 1L) && (maskedRegexOp == RKLSplitOp)) ? 1L : findAll.found, capturedStringsIdx = passCaptureCountBlockArgument;
02082     RKLCDelayedHardAssert(passCaptureCountBlockArgument <= captureCountBlockArgument, &exception, exitNow);
02083     if(capturedStringsBlockArgument != NULL) { // Only create the captured strings if the user has requested them.
02084       BOOL hadError = NO;                      // Loop over all the strings rkl_findRanges found.  If rkl_CreateStringWithSubstring() returns NULL due to an error, set returnBool to NO, and break out of the for() loop.
02085 
02086       for(capturedStringsIdx = 0L; capturedStringsIdx < passCaptureCountBlockArgument; capturedStringsIdx++) {
02087         RKLCDelayedHardAssert(capturedStringsIdx < captureCountBlockArgument, &exception, exitNow);
02088         if((enumerationOptions & RKLRegexEnumerationFastCapturedStringsXXX) != 0UL) {
02089           // Analyzer report of "Dereference of null pointer" can be safely ignored for the next line.  Bug filed: http://llvm.org/bugs/show_bug.cgi?id=6150
02090           CFStringSetExternalCharactersNoCopy(fastCapturedStrings[capturedStringsIdx], &blockEnumerationHelperUniChar[findAll.ranges[capturedStringsIdx].location], (CFIndex)findAll.ranges[capturedStringsIdx].length, (CFIndex)findAll.ranges[capturedStringsIdx].length);
02091         } else {
02092           if((capturedStrings[capturedStringsIdx] = (findAll.ranges[capturedStringsIdx].length == 0UL) ? emptyString : rkl_CreateStringWithSubstring(blockEnumerationHelperString, findAll.ranges[capturedStringsIdx])) == NULL) { hadError = YES; break; }
02093         }
02094       }
02095       if(((enumerationOptions & RKLRegexEnumerationFastCapturedStringsXXX) == 0UL) && RKL_EXPECTED(autoreleaseArray != NULL, 1L)) { CFArrayReplaceValues((CFMutableArrayRef)autoreleaseArray, autoreleaseReplaceRange, (const void **)capturedStrings, capturedStringsIdx); autoreleaseReplaceRange.length = capturedStringsIdx; } // Add to autoreleaseArray all the strings the for() loop created.
02096       if(RKL_EXPECTED(hadError == YES,  0L)) { goto exitNow; }           // hadError == YES will be set if rkl_CreateStringWithSubstring() returned NULL.
02097     }
02098     // For safety, set any capturedRanges and capturedStrings up to captureCountBlockArgument + 1 to values that indicate that they are not valid.
02099     // These values are chosen such that they should tickle any misuse by users.
02100     // capturedStringsIdx is initialized to passCaptureCountBlockArgument, but if capturedStringsBlockArgument != NULL, it is reset to 0 by the loop that creates strings.
02101     // If the loop that creates strings has an error, execution should transfer to exitNow and this will never get run.
02102     // Again, this is for safety for users that do not check the passed block argument 'captureCount' and instead depend on something like [regex captureCount].
02103     for(; capturedStringsIdx < captureCountBlockArgument + 1L; capturedStringsIdx++) { RKLCDelayedAssert((capturedStringsIdx < (NSInteger)capturedStringsCapacity) && (capturedStringsIdx < (NSInteger)capturedRangesCapacity), &exception, exitNow); capturedRanges[capturedStringsIdx] = RKLIllegalRange; capturedStrings[capturedStringsIdx] = (NSString *)RKLIllegalPointer; }
02104 
02105     RKLCDelayedAssert((passCaptureCountBlockArgument > 0L) && (NSMaxRange(capturedRanges[0]) <= stringU16Length) && (capturedRanges[0].location < NSIntegerMax) && (capturedRanges[0].length < NSIntegerMax), &exception, exitNow);
02106 
02107     switch(blockEnumerationOp) {
02108       case RKLBlockEnumerationMatchOp: stringsAndRangesBlock(passCaptureCountBlockArgument, capturedStringsBlockArgument, capturedRanges, &shouldStop); break;
02109 
02110       case RKLBlockEnumerationReplaceOp: {
02111           NSString *blockReturnedReplacementString = replaceStringsAndRangesBlock(passCaptureCountBlockArgument, capturedStringsBlockArgument, capturedRanges, &shouldStop);
02112     
02113           if(RKL_EXPECTED(blockReturnedReplacementString != NULL, 1L)) {
02114             CFStringAppend((CFMutableStringRef)mutableReplacementString, (CFStringRef)blockReturnedReplacementString);
02115             BOOL shouldRelease = (((enumerationOptions & RKLRegexEnumerationReleaseStringReturnedByReplacementBlock) != 0UL) && (capturedStringsBlockArgument != NULL) && (rkl_collectingEnabled() == NO)) ? YES : NO;
02116             if(shouldRelease == YES) { NSInteger idx = 0L; for(idx = 0L; idx < passCaptureCountBlockArgument; idx++) { if(capturedStrings[idx] == blockReturnedReplacementString) { shouldRelease = NO; break; } } }
02117             if(shouldRelease == YES) { [blockReturnedReplacementString release]; }
02118           }
02119       }
02120       break;
02121 
02122       default: exception = RKLCAssertDictionary(@"Unknown blockEnumerationOp code."); goto exitNow; break;
02123     }
02124     
02125     replacedCount++;    
02126     findAll.addedSplitRanges = 0L;                     // rkl_findRanges() expects findAll.addedSplitRanges to be 0 on entry.
02127     findAll.found            = 0L;                     // rkl_findRanges() expects findAll.found to be 0 on entry.
02128     findAll.findInRange      = findAll.remainingRange; // Ask rkl_findRanges() to search the part of the string after the current match.
02129     lastMatchedRange         = findAll.ranges[0];
02130 
02131     if(RKL_EXPECTED(shouldStop != NO, 0L)) { break; }
02132   }
02133   errorFree = YES;
02134   
02135 exitNow:
02136   if(RKL_EXPECTED(errorFree == NO, 0L)) { replacedCount = -1L; }
02137   if((blockEnumerationOp == RKLBlockEnumerationReplaceOp) && RKL_EXPECTED(errorFree == YES, 1L)) {
02138     RKLCDelayedAssert(replacedCount >= 0L, &exception, exitNow2);
02139     if(RKL_EXPECTED(replacedCount == 0UL, 0L)) {
02140       RKLCDelayedAssert((blockEnumerationHelper != NULL) && (blockEnumerationHelper->buffer.string != NULL), &exception, exitNow2);
02141       returnObject = rkl_CreateStringWithSubstring((id)blockEnumerationHelper->buffer.string, matchRange);
02142       if(rkl_collectingEnabled() == NO) { returnObject = rkl_CFAutorelease(returnObject); }
02143     }
02144     else {
02145       NSUInteger lastMatchedMaxLocation = (lastMatchedRange.location + lastMatchedRange.length);
02146       NSRange    previousUnmatchedRange = NSMakeRange(lastMatchedMaxLocation, NSMaxRange(matchRange) - lastMatchedMaxLocation);
02147       RKLCDelayedAssert((NSMaxRange(previousUnmatchedRange) <= stringU16Length) && (NSRangeInsideRange(previousUnmatchedRange, matchRange) == YES), &exception, exitNow2);
02148       
02149       if(RKL_EXPECTED(previousUnmatchedRange.length > 0UL, 1L)) { CFStringAppendCharacters((CFMutableStringRef)mutableReplacementString, blockEnumerationHelperUniChar + previousUnmatchedRange.location, (CFIndex)previousUnmatchedRange.length); }
02150       returnObject = rkl_CFAutorelease(CFStringCreateCopy(NULL, (CFStringRef)mutableReplacementString)); // Warning about potential leak of Core Foundation object can be safely ignored.
02151     }
02152   }
02153   
02154 #ifndef   NS_BLOCK_ASSERTIONS
02155 exitNow2:
02156 #endif // NS_BLOCK_ASSERTIONS
02157   if(RKL_EXPECTED(autoreleaseArray != NULL, 1L)) { CFArrayRemoveAllValues((CFMutableArrayRef)autoreleaseArray); } // Causes blockEnumerationHelper to be released immediately, freeing all of its resources (such as a large UTF-16 conversion buffer).
02158   if(RKL_EXPECTED(exception        != NULL, 0L)) { rkl_handleDelayedAssert(self, _cmd, exception);              } // If there is an exception, throw it at this point.
02159   if(((errorFree == NO) || ((errorFree == YES) && (returnObject == NULL))) && (error != NULL) && (*error == NULL)) {
02160     RKLUserInfoOptions  userInfoOptions = (RKLUserInfoSubjectRange | RKLUserInfoRegexEnumerationOptions);
02161     NSString           *replacedString  = NULL;
02162     if(blockEnumerationOp == RKLBlockEnumerationReplaceOp) { userInfoOptions |= RKLUserInfoReplacedCount; if(RKL_EXPECTED(errorFree == YES, 1L)) { replacedString = returnObject; } }
02163     *error = rkl_makeNSError(userInfoOptions, regexString, options, NULL, status, (blockEnumerationHelper != NULL) ? (blockEnumerationHelper->buffer.string != NULL) ? (NSString *)blockEnumerationHelper->buffer.string : matchString : matchString, matchRange, NULL, replacedString, replacedCount, enumerationOptions, @"An unexpected error occurred.");
02164   }
02165   if(replacedCountPtr != NULL) { *replacedCountPtr = replacedCount; }
02166   if(errorFreePtr     != NULL) { *errorFreePtr     = errorFree;     }
02167   return(returnObject);
02168 } // The two warnings about potential leaks can be safely ignored.
02169 
02170 #endif // _RKL_BLOCKS_ENABLED
02171 
02173 #pragma mark -
02174 #pragma mark Objective-C Public Interface
02175 #pragma mark -
02176 
02177 
02178 @implementation NSString (RegexKitLiteAdditions)
02179 
02180 #pragma mark +clearStringCache
02181 
02182 + (void)RKL_METHOD_PREPEND(clearStringCache)
02183 {
02184   volatile NSUInteger RKL_CLEANUP(rkl_cleanup_cacheSpinLockStatus) rkl_cacheSpinLockStatus = 0UL;
02185   OSSpinLockLock(&rkl_cacheSpinLock);
02186   rkl_cacheSpinLockStatus |= RKLLockedCacheSpinLock;
02187   rkl_clearStringCache();
02188   OSSpinLockUnlock(&rkl_cacheSpinLock);
02189   rkl_cacheSpinLockStatus |= RKLUnlockedCacheSpinLock; // Warning about rkl_cacheSpinLockStatus never being read can be safely ignored.
02190 }
02191 
02192 #pragma mark +captureCountForRegex:
02193 
02194 + (NSInteger)RKL_METHOD_PREPEND(captureCountForRegex):(NSString *)regex
02195 {
02196   NSInteger captureCount = -1L;
02197   rkl_isRegexValid(self, _cmd, regex, RKLNoOptions, &captureCount, NULL);
02198   return(captureCount);
02199 }
02200 
02201 + (NSInteger)RKL_METHOD_PREPEND(captureCountForRegex):(NSString *)regex options:(RKLRegexOptions)options error:(NSError **)error
02202 {
02203   NSInteger captureCount = -1L;
02204   rkl_isRegexValid(self, _cmd, regex, options,      &captureCount, error);
02205   return(captureCount);
02206 }
02207 
02208 #pragma mark -captureCount:
02209 
02210 - (NSInteger)RKL_METHOD_PREPEND(captureCount)
02211 {
02212   NSInteger captureCount = -1L;
02213   rkl_isRegexValid(self, _cmd, self, RKLNoOptions,  &captureCount, NULL);
02214   return(captureCount);
02215 }
02216 
02217 - (NSInteger)RKL_METHOD_PREPEND(captureCountWithOptions):(RKLRegexOptions)options error:(NSError **)error
02218 {
02219   NSInteger captureCount = -1L;
02220   rkl_isRegexValid(self, _cmd, self, options,       &captureCount, error);
02221   return(captureCount);
02222 }
02223 
02224 #pragma mark -componentsSeparatedByRegex:
02225 
02226 - (NSArray *)RKL_METHOD_PREPEND(componentsSeparatedByRegex):(NSString *)regex
02227 {
02228   NSRange range = NSMaxiumRange;
02229   return(rkl_performRegexOp(self, _cmd, (RKLRegexOp)RKLSplitOp, regex, RKLNoOptions, 0L, self, &range, NULL, NULL,  NULL, 0UL, NULL, NULL));
02230 }
02231 
02232 - (NSArray *)RKL_METHOD_PREPEND(componentsSeparatedByRegex):(NSString *)regex range:(NSRange)range
02233 {
02234   return(rkl_performRegexOp(self, _cmd, (RKLRegexOp)RKLSplitOp, regex, RKLNoOptions, 0L, self, &range, NULL, NULL,  NULL, 0UL, NULL, NULL));
02235 }
02236 
02237 - (NSArray *)RKL_METHOD_PREPEND(componentsSeparatedByRegex):(NSString *)regex options:(RKLRegexOptions)options range:(NSRange)range error:(NSError **)error
02238 {
02239   return(rkl_performRegexOp(self, _cmd, (RKLRegexOp)RKLSplitOp, regex, options,      0L, self, &range, NULL, error, NULL, 0UL, NULL, NULL));
02240 }
02241 
02242 #pragma mark -isMatchedByRegex:
02243 
02244 - (BOOL)RKL_METHOD_PREPEND(isMatchedByRegex):(NSString *)regex
02245 {
02246   NSRange result = NSNotFoundRange, range = NSMaxiumRange;
02247   rkl_performRegexOp(self, _cmd, (RKLRegexOp)RKLRangeOp, regex, RKLNoOptions, 0L, self, &range, NULL, NULL,  &result, 0UL, NULL, NULL);
02248   return((result.location == (NSUInteger)NSNotFound) ? NO : YES);
02249 }
02250 
02251 - (BOOL)RKL_METHOD_PREPEND(isMatchedByRegex):(NSString *)regex inRange:(NSRange)range
02252 {
02253   NSRange result = NSNotFoundRange;
02254   rkl_performRegexOp(self, _cmd, (RKLRegexOp)RKLRangeOp, regex, RKLNoOptions, 0L, self, &range, NULL, NULL,  &result, 0UL, NULL, NULL);
02255   return((result.location == (NSUInteger)NSNotFound) ? NO : YES);
02256 }
02257 
02258 - (BOOL)RKL_METHOD_PREPEND(isMatchedByRegex):(NSString *)regex options:(RKLRegexOptions)options inRange:(NSRange)range error:(NSError **)error
02259 {
02260   NSRange result = NSNotFoundRange;
02261   rkl_performRegexOp(self, _cmd, (RKLRegexOp)RKLRangeOp, regex, options,      0L, self, &range, NULL, error, &result, 0UL, NULL, NULL);
02262   return((result.location == (NSUInteger)NSNotFound) ? NO : YES);
02263 }
02264 
02265 #pragma mark -isRegexValid
02266 
02267 - (BOOL)RKL_METHOD_PREPEND(isRegexValid)
02268 {
02269   return(rkl_isRegexValid(self, _cmd, self, RKLNoOptions, NULL, NULL)  == 1UL ? YES : NO);
02270 }
02271 
02272 - (BOOL)RKL_METHOD_PREPEND(isRegexValidWithOptions):(RKLRegexOptions)options error:(NSError **)error
02273 {
02274   return(rkl_isRegexValid(self, _cmd, self, options,      NULL, error) == 1UL ? YES : NO);
02275 }
02276 
02277 #pragma mark -flushCachedRegexData
02278 
02279 - (void)RKL_METHOD_PREPEND(flushCachedRegexData)
02280 {
02281   volatile NSUInteger RKL_CLEANUP(rkl_cleanup_cacheSpinLockStatus) rkl_cacheSpinLockStatus = 0UL;
02282 
02283   CFIndex    selfLength = CFStringGetLength((CFStringRef)self);
02284   CFHashCode selfHash   = CFHash((CFTypeRef)self);
02285   
02286   OSSpinLockLock(&rkl_cacheSpinLock);
02287   rkl_cacheSpinLockStatus |= RKLLockedCacheSpinLock;
02288   rkl_dtrace_incrementEventID();
02289 
02290   NSUInteger idx;
02291   for(idx = 0UL; idx < _RKL_REGEX_CACHE_LINES; idx++) {
02292     RKLCachedRegex *cachedRegex = &rkl_cachedRegexes[idx];
02293     if((cachedRegex->setToString != NULL) && ( (cachedRegex->setToString == (CFStringRef)self) || ((cachedRegex->setToLength == selfLength) && (cachedRegex->setToHash == selfHash)) ) ) { rkl_clearCachedRegexSetTo(cachedRegex); }
02294   }
02295   for(idx = 0UL; idx < _RKL_LRU_CACHE_SET_WAYS; idx++) { RKLBuffer *buffer = &rkl_lruFixedBuffer[idx];   if((buffer->string != NULL) && ((buffer->string == (CFStringRef)self) || ((buffer->length == selfLength) && (buffer->hash == selfHash)))) { rkl_clearBuffer(buffer, 0UL); } }
02296   for(idx = 0UL; idx < _RKL_LRU_CACHE_SET_WAYS; idx++) { RKLBuffer *buffer = &rkl_lruDynamicBuffer[idx]; if((buffer->string != NULL) && ((buffer->string == (CFStringRef)self) || ((buffer->length == selfLength) && (buffer->hash == selfHash)))) { rkl_clearBuffer(buffer, 0UL); } }
02297 
02298   OSSpinLockUnlock(&rkl_cacheSpinLock);
02299   rkl_cacheSpinLockStatus |= RKLUnlockedCacheSpinLock; // Warning about rkl_cacheSpinLockStatus never being read can be safely ignored.
02300 }
02301 
02302 #pragma mark -rangeOfRegex:
02303 
02304 - (NSRange)RKL_METHOD_PREPEND(rangeOfRegex):(NSString *)regex
02305 {
02306   NSRange result = NSNotFoundRange, range = NSMaxiumRange;
02307   rkl_performRegexOp(self, _cmd, (RKLRegexOp)RKLRangeOp, regex, RKLNoOptions, 0L,      self, &range, NULL, NULL,  &result, 0UL, NULL, NULL);
02308   return(result);
02309 }
02310 
02311 - (NSRange)RKL_METHOD_PREPEND(rangeOfRegex):(NSString *)regex capture:(NSInteger)capture
02312 {
02313   NSRange result = NSNotFoundRange, range = NSMaxiumRange;
02314   rkl_performRegexOp(self, _cmd, (RKLRegexOp)RKLRangeOp, regex, RKLNoOptions, capture, self, &range, NULL, NULL,  &result, 0UL, NULL, NULL);
02315   return(result);
02316 }
02317 
02318 - (NSRange)RKL_METHOD_PREPEND(rangeOfRegex):(NSString *)regex inRange:(NSRange)range
02319 {
02320   NSRange result = NSNotFoundRange;
02321   rkl_performRegexOp(self, _cmd, (RKLRegexOp)RKLRangeOp, regex, RKLNoOptions, 0L,      self, &range, NULL, NULL,  &result, 0UL, NULL, NULL);
02322   return(result);
02323 }
02324 
02325 - (NSRange)RKL_METHOD_PREPEND(rangeOfRegex):(NSString *)regex options:(RKLRegexOptions)options inRange:(NSRange)range capture:(NSInteger)capture error:(NSError **)error
02326 {
02327   NSRange result = NSNotFoundRange;
02328   rkl_performRegexOp(self, _cmd, (RKLRegexOp)RKLRangeOp, regex, options,      capture, self, &range, NULL, error, &result, 0UL, NULL, NULL);
02329   return(result);
02330 }
02331 
02332 #pragma mark -stringByMatching:
02333 
02334 - (NSString *)RKL_METHOD_PREPEND(stringByMatching):(NSString *)regex
02335 {
02336   NSRange matchedRange = NSNotFoundRange, range = NSMaxiumRange;
02337   rkl_performRegexOp(self, _cmd, (RKLRegexOp)RKLRangeOp, regex, RKLNoOptions,      0L,      self, &range, NULL, NULL,  &matchedRange, 0UL, NULL, NULL);
02338   return((matchedRange.location == (NSUInteger)NSNotFound) ? NULL : rkl_CFAutorelease(CFStringCreateWithSubstring(NULL, (CFStringRef)self, CFMakeRange(matchedRange.location, matchedRange.length)))); // Warning about potential leak can be safely ignored.
02339 } // Warning about potential leak can be safely ignored.
02340 
02341 - (NSString *)RKL_METHOD_PREPEND(stringByMatching):(NSString *)regex capture:(NSInteger)capture
02342 {
02343   NSRange matchedRange = NSNotFoundRange, range = NSMaxiumRange;
02344   rkl_performRegexOp(self, _cmd, (RKLRegexOp)RKLRangeOp, regex, RKLNoOptions,      capture, self, &range, NULL, NULL,  &matchedRange, 0UL, NULL, NULL);
02345   return((matchedRange.location == (NSUInteger)NSNotFound) ? NULL : rkl_CFAutorelease(CFStringCreateWithSubstring(NULL, (CFStringRef)self, CFMakeRange(matchedRange.location, matchedRange.length)))); // Warning about potential leak can be safely ignored.
02346 } // Warning about potential leak can be safely ignored.
02347 
02348 - (NSString *)RKL_METHOD_PREPEND(stringByMatching):(NSString *)regex inRange:(NSRange)range
02349 {
02350   NSRange matchedRange = NSNotFoundRange;
02351   rkl_performRegexOp(self, _cmd, (RKLRegexOp)RKLRangeOp, regex, RKLNoOptions,      0L,      self, &range, NULL, NULL,  &matchedRange, 0UL, NULL, NULL);
02352   return((matchedRange.location == (NSUInteger)NSNotFound) ? NULL : rkl_CFAutorelease(CFStringCreateWithSubstring(NULL, (CFStringRef)self, CFMakeRange(matchedRange.location, matchedRange.length)))); // Warning about potential leak can be safely ignored.
02353 } // Warning about potential leak can be safely ignored.
02354 
02355 - (NSString *)RKL_METHOD_PREPEND(stringByMatching):(NSString *)regex options:(RKLRegexOptions)options inRange:(NSRange)range capture:(NSInteger)capture error:(NSError **)error
02356 {
02357   NSRange matchedRange = NSNotFoundRange;
02358   rkl_performRegexOp(self, _cmd, (RKLRegexOp)RKLRangeOp, regex, options,           capture, self, &range, NULL, error, &matchedRange, 0UL, NULL, NULL);
02359   return((matchedRange.location == (NSUInteger)NSNotFound) ? NULL : rkl_CFAutorelease(CFStringCreateWithSubstring(NULL, (CFStringRef)self, CFMakeRange(matchedRange.location, matchedRange.length)))); // Warning about potential leak can be safely ignored.
02360 } // Warning about potential leak can be safely ignored.
02361 
02362 #pragma mark -stringByReplacingOccurrencesOfRegex:
02363 
02364 - (NSString *)RKL_METHOD_PREPEND(stringByReplacingOccurrencesOfRegex):(NSString *)regex withString:(NSString *)replacement
02365 {
02366   NSRange searchRange = NSMaxiumRange;
02367   return(rkl_performRegexOp(self, _cmd, (RKLRegexOp)RKLReplaceOp, regex, RKLNoOptions, 0L, self, &searchRange, replacement, NULL,  NULL, 0UL, NULL, NULL));
02368 }
02369 
02370 - (NSString *)RKL_METHOD_PREPEND(stringByReplacingOccurrencesOfRegex):(NSString *)regex withString:(NSString *)replacement range:(NSRange)searchRange
02371 {
02372   return(rkl_performRegexOp(self, _cmd, (RKLRegexOp)RKLReplaceOp, regex, RKLNoOptions, 0L, self, &searchRange, replacement, NULL,  NULL, 0UL, NULL, NULL));
02373 }
02374 
02375 - (NSString *)RKL_METHOD_PREPEND(stringByReplacingOccurrencesOfRegex):(NSString *)regex withString:(NSString *)replacement options:(RKLRegexOptions)options range:(NSRange)searchRange error:(NSError **)error
02376 {
02377   return(rkl_performRegexOp(self, _cmd, (RKLRegexOp)RKLReplaceOp, regex, options,      0L, self, &searchRange, replacement, error, NULL, 0UL, NULL, NULL));
02378 }
02379 
02380 #pragma mark -componentsMatchedByRegex:
02381 
02382 - (NSArray *)RKL_METHOD_PREPEND(componentsMatchedByRegex):(NSString *)regex
02383 {
02384   NSRange searchRange = NSMaxiumRange;
02385   return(rkl_performRegexOp(self, _cmd, (RKLRegexOp)RKLArrayOfStringsOp, regex, RKLNoOptions, 0L,      self, &searchRange, NULL, NULL,  NULL, 0UL, NULL, NULL));
02386 }
02387 
02388 - (NSArray *)RKL_METHOD_PREPEND(componentsMatchedByRegex):(NSString *)regex capture:(NSInteger)capture
02389 {
02390   NSRange searchRange = NSMaxiumRange;
02391   return(rkl_performRegexOp(self, _cmd, (RKLRegexOp)RKLArrayOfStringsOp, regex, RKLNoOptions, capture, self, &searchRange, NULL, NULL,  NULL, 0UL, NULL, NULL));
02392 }
02393 
02394 - (NSArray *)RKL_METHOD_PREPEND(componentsMatchedByRegex):(NSString *)regex range:(NSRange)range
02395 {
02396   return(rkl_performRegexOp(self, _cmd, (RKLRegexOp)RKLArrayOfStringsOp, regex, RKLNoOptions, 0L,      self, &range,       NULL, NULL,  NULL, 0UL, NULL, NULL));
02397 }
02398 
02399 - (NSArray *)RKL_METHOD_PREPEND(componentsMatchedByRegex):(NSString *)regex options:(RKLRegexOptions)options range:(NSRange)range capture:(NSInteger)capture error:(NSError **)error
02400 {
02401   return(rkl_performRegexOp(self, _cmd, (RKLRegexOp)RKLArrayOfStringsOp, regex, options,      capture, self, &range,       NULL, error, NULL, 0UL, NULL, NULL));
02402 }
02403 
02404 #pragma mark -captureComponentsMatchedByRegex:
02405 
02406 - (NSArray *)RKL_METHOD_PREPEND(captureComponentsMatchedByRegex):(NSString *)regex
02407 {
02408   NSRange searchRange = NSMaxiumRange;
02409   return(rkl_performRegexOp(self, _cmd, (RKLRegexOp)RKLCapturesArrayOp, regex, RKLNoOptions, 0L, self, &searchRange, NULL, NULL,  NULL, 0UL, NULL, NULL));
02410 }
02411 
02412 - (NSArray *)RKL_METHOD_PREPEND(captureComponentsMatchedByRegex):(NSString *)regex range:(NSRange)range
02413 {
02414   return(rkl_performRegexOp(self, _cmd, (RKLRegexOp)RKLCapturesArrayOp, regex, RKLNoOptions, 0L, self, &range,       NULL, NULL,  NULL, 0UL, NULL, NULL));
02415 }
02416 
02417 - (NSArray *)RKL_METHOD_PREPEND(captureComponentsMatchedByRegex):(NSString *)regex options:(RKLRegexOptions)options range:(NSRange)range error:(NSError **)error
02418 {
02419   return(rkl_performRegexOp(self, _cmd, (RKLRegexOp)RKLCapturesArrayOp, regex, options,      0L, self, &range,       NULL, error, NULL, 0UL, NULL, NULL));
02420 }
02421 
02422 #pragma mark -arrayOfCaptureComponentsMatchedByRegex:
02423 
02424 - (NSArray *)RKL_METHOD_PREPEND(arrayOfCaptureComponentsMatchedByRegex):(NSString *)regex
02425 {
02426   NSRange searchRange = NSMaxiumRange;
02427   return(rkl_performRegexOp(self, _cmd, (RKLRegexOp)(RKLArrayOfCapturesOp | RKLSubcapturesArray), regex, RKLNoOptions, 0L, self, &searchRange, NULL, NULL,  NULL, 0UL, NULL, NULL));
02428 }
02429 
02430 - (NSArray *)RKL_METHOD_PREPEND(arrayOfCaptureComponentsMatchedByRegex):(NSString *)regex range:(NSRange)range
02431 {
02432   return(rkl_performRegexOp(self, _cmd, (RKLRegexOp)(RKLArrayOfCapturesOp | RKLSubcapturesArray), regex, RKLNoOptions, 0L, self, &range,       NULL, NULL,  NULL, 0UL, NULL, NULL));
02433 }
02434 
02435 - (NSArray *)RKL_METHOD_PREPEND(arrayOfCaptureComponentsMatchedByRegex):(NSString *)regex options:(RKLRegexOptions)options range:(NSRange)range error:(NSError **)error
02436 {
02437   return(rkl_performRegexOp(self, _cmd, (RKLRegexOp)(RKLArrayOfCapturesOp | RKLSubcapturesArray), regex, options,      0L, self, &range,       NULL, error, NULL, 0UL, NULL, NULL));
02438 }
02439 
02440 #pragma mark -dictionaryByMatchingRegex:
02441 
02442 - (NSDictionary *)RKL_METHOD_PREPEND(dictionaryByMatchingRegex):(NSString *)regex withKeysAndCaptures:(id)firstKey, ...
02443 {
02444   NSRange searchRange  = NSMaxiumRange;
02445   id      returnObject = NULL;
02446   va_list varArgsList;
02447   va_start(varArgsList, firstKey);
02448   returnObject = rkl_performDictionaryVarArgsOp(self, _cmd, (RKLRegexOp)RKLDictionaryOfCapturesOp, regex, (RKLRegexOptions)RKLNoOptions, 0L, self, &searchRange, NULL, NULL, NULL, firstKey, varArgsList);
02449   va_end(varArgsList);
02450   return(returnObject);
02451 }
02452 
02453 - (NSDictionary *)RKL_METHOD_PREPEND(dictionaryByMatchingRegex):(NSString *)regex range:(NSRange)range withKeysAndCaptures:(id)firstKey, ...
02454 {
02455   id returnObject = NULL;
02456   va_list varArgsList;
02457   va_start(varArgsList, firstKey);
02458   returnObject = rkl_performDictionaryVarArgsOp(self, _cmd, (RKLRegexOp)RKLDictionaryOfCapturesOp, regex, (RKLRegexOptions)RKLNoOptions, 0L, self, &range, NULL, NULL, NULL, firstKey, varArgsList);
02459   va_end(varArgsList);
02460   return(returnObject);
02461 }
02462 
02463 - (NSDictionary *)RKL_METHOD_PREPEND(dictionaryByMatchingRegex):(NSString *)regex options:(RKLRegexOptions)options range:(NSRange)range error:(NSError **)error withKeysAndCaptures:(id)firstKey, ...
02464 {
02465   id returnObject = NULL;
02466   va_list varArgsList;
02467   va_start(varArgsList, firstKey);
02468   returnObject = rkl_performDictionaryVarArgsOp(self, _cmd, (RKLRegexOp)RKLDictionaryOfCapturesOp, regex, options, 0L, self, &range, NULL, error, NULL, firstKey, varArgsList);
02469   va_end(varArgsList);
02470   return(returnObject);
02471 }
02472 
02473 - (NSDictionary *)RKL_METHOD_PREPEND(dictionaryByMatchingRegex):(NSString *)regex options:(RKLRegexOptions)options range:(NSRange)range error:(NSError **)error withFirstKey:(id)firstKey arguments:(va_list)varArgsList
02474 {
02475   return(rkl_performDictionaryVarArgsOp(self, _cmd, (RKLRegexOp)RKLDictionaryOfCapturesOp, regex, options, 0L, self, &range, NULL, error, NULL, firstKey, varArgsList));
02476 }
02477 
02478 - (NSDictionary *)RKL_METHOD_PREPEND(dictionaryByMatchingRegex):(NSString *)regex options:(RKLRegexOptions)options range:(NSRange)range error:(NSError **)error withKeys:(id *)keys forCaptures:(int *)captures count:(NSUInteger)count
02479 {
02480   return(rkl_performRegexOp(self, _cmd, (RKLRegexOp)RKLDictionaryOfCapturesOp, regex, options, 0L, self, &range, NULL, error, NULL, count, keys, captures));
02481 }
02482 
02483 #pragma mark -arrayOfDictionariesByMatchingRegex:
02484 
02485 - (NSArray *)RKL_METHOD_PREPEND(arrayOfDictionariesByMatchingRegex):(NSString *)regex withKeysAndCaptures:(id)firstKey, ...
02486 {
02487   NSRange searchRange  = NSMaxiumRange;
02488   id      returnObject = NULL;
02489   va_list varArgsList;
02490   va_start(varArgsList, firstKey);
02491   returnObject = rkl_performDictionaryVarArgsOp(self, _cmd, (RKLRegexOp)RKLArrayOfDictionariesOfCapturesOp, regex, (RKLRegexOptions)RKLNoOptions, 0L, self, &searchRange, NULL, NULL, NULL, firstKey, varArgsList);
02492   va_end(varArgsList);
02493   return(returnObject);
02494 }
02495 
02496 - (NSArray *)RKL_METHOD_PREPEND(arrayOfDictionariesByMatchingRegex):(NSString *)regex range:(NSRange)range withKeysAndCaptures:(id)firstKey, ...
02497 {
02498   id returnObject = NULL;
02499   va_list varArgsList;
02500   va_start(varArgsList, firstKey);
02501   returnObject = rkl_performDictionaryVarArgsOp(self, _cmd, (RKLRegexOp)RKLArrayOfDictionariesOfCapturesOp, regex, (RKLRegexOptions)RKLNoOptions, 0L, self, &range, NULL, NULL, NULL, firstKey, varArgsList);
02502   va_end(varArgsList);
02503   return(returnObject);
02504 }
02505 
02506 - (NSArray *)RKL_METHOD_PREPEND(arrayOfDictionariesByMatchingRegex):(NSString *)regex options:(RKLRegexOptions)options range:(NSRange)range error:(NSError **)error withKeysAndCaptures:(id)firstKey, ...
02507 {
02508   id returnObject = NULL;
02509   va_list varArgsList;
02510   va_start(varArgsList, firstKey);
02511   returnObject = rkl_performDictionaryVarArgsOp(self, _cmd, (RKLRegexOp)RKLArrayOfDictionariesOfCapturesOp, regex, options, 0L, self, &range, NULL, error, NULL, firstKey, varArgsList);
02512   va_end(varArgsList);
02513   return(returnObject);
02514 }
02515 
02516 - (NSArray *)RKL_METHOD_PREPEND(arrayOfDictionariesByMatchingRegex):(NSString *)regex options:(RKLRegexOptions)options range:(NSRange)range error:(NSError **)error withFirstKey:(id)firstKey arguments:(va_list)varArgsList
02517 {
02518   return(rkl_performDictionaryVarArgsOp(self, _cmd, (RKLRegexOp)RKLArrayOfDictionariesOfCapturesOp, regex, options, 0L, self, &range, NULL, error, NULL, firstKey, varArgsList));
02519 }
02520 
02521 - (NSArray *)RKL_METHOD_PREPEND(arrayOfDictionariesByMatchingRegex):(NSString *)regex options:(RKLRegexOptions)options range:(NSRange)range error:(NSError **)error withKeys:(id *)keys forCaptures:(int *)captures count:(NSUInteger)count
02522 {
02523   return(rkl_performRegexOp(self, _cmd, (RKLRegexOp)RKLArrayOfDictionariesOfCapturesOp, regex, options, 0L, self, &range, NULL, error, NULL, count, keys, captures));
02524 }
02525 
02526 #ifdef    _RKL_BLOCKS_ENABLED
02527 
02529 #pragma mark -
02530 #pragma mark ^Blocks Related NSString Methods
02531 
02532 #pragma mark -enumerateStringsMatchedByRegex:usingBlock:
02533 
02534 - (BOOL)RKL_METHOD_PREPEND(enumerateStringsMatchedByRegex):(NSString *)regex usingBlock:(void (^)(NSInteger captureCount, NSString * const capturedStrings[captureCount], const NSRange capturedRanges[captureCount], volatile BOOL * const stop))block
02535 {
02536   NSUInteger errorFree = NO;
02537   rkl_performEnumerationUsingBlock(self, _cmd, (RKLRegexOp)RKLCapturesArrayOp, regex, (RKLRegexOptions)RKLNoOptions, self, NSMaxiumRange, (RKLBlockEnumerationOp)RKLBlockEnumerationMatchOp, 0UL,                NULL, &errorFree, NULL,  block, NULL);
02538   return(errorFree == NO ? NO : YES);
02539 }
02540 
02541 - (BOOL)RKL_METHOD_PREPEND(enumerateStringsMatchedByRegex):(NSString *)regex options:(RKLRegexOptions)options inRange:(NSRange)range error:(NSError **)error enumerationOptions:(RKLRegexEnumerationOptions)enumerationOptions usingBlock:(void (^)(NSInteger captureCount, NSString * const capturedStrings[captureCount], const NSRange capturedRanges[captureCount], volatile BOOL * const stop))block
02542 {
02543   NSUInteger errorFree = NO;
02544   rkl_performEnumerationUsingBlock(self, _cmd, (RKLRegexOp)RKLCapturesArrayOp, regex, options,                       self, range,         (RKLBlockEnumerationOp)RKLBlockEnumerationMatchOp, enumerationOptions, NULL, &errorFree, error, block, NULL);
02545   return(errorFree == NO ? NO : YES);
02546 }
02547 
02548 #pragma mark -enumerateStringsSeparatedByRegex:usingBlock:
02549 
02550 - (BOOL)RKL_METHOD_PREPEND(enumerateStringsSeparatedByRegex):(NSString *)regex usingBlock:(void (^)(NSInteger captureCount, NSString * const capturedStrings[captureCount], const NSRange capturedRanges[captureCount], volatile BOOL * const stop))block
02551 {
02552   NSUInteger errorFree = NO;
02553   rkl_performEnumerationUsingBlock(self, _cmd, (RKLRegexOp)RKLSplitOp,         regex, (RKLRegexOptions)RKLNoOptions, self, NSMaxiumRange, (RKLBlockEnumerationOp)RKLBlockEnumerationMatchOp, 0UL,                NULL, &errorFree, NULL,  block, NULL);
02554   return(errorFree == NO ? NO : YES);
02555 }
02556 
02557 - (BOOL)RKL_METHOD_PREPEND(enumerateStringsSeparatedByRegex):(NSString *)regex options:(RKLRegexOptions)options inRange:(NSRange)range error:(NSError **)error enumerationOptions:(RKLRegexEnumerationOptions)enumerationOptions usingBlock:(void (^)(NSInteger captureCount, NSString * const capturedStrings[captureCount], const NSRange capturedRanges[captureCount], volatile BOOL * const stop))block
02558 {
02559   NSUInteger errorFree = NO;
02560   rkl_performEnumerationUsingBlock(self, _cmd, (RKLRegexOp)RKLSplitOp,         regex, options,                       self, range,         (RKLBlockEnumerationOp)RKLBlockEnumerationMatchOp, enumerationOptions, NULL, &errorFree, error, block, NULL);
02561   return(errorFree == NO ? NO : YES);  
02562 }
02563 
02564 #pragma mark -stringByReplacingOccurrencesOfRegex:usingBlock:
02565 
02566 - (NSString *)RKL_METHOD_PREPEND(stringByReplacingOccurrencesOfRegex):(NSString *)regex usingBlock:(NSString *(^)(NSInteger captureCount, NSString * const capturedStrings[captureCount], const NSRange capturedRanges[captureCount], volatile BOOL * const stop))block
02567 {
02568   return(rkl_performEnumerationUsingBlock(self, _cmd, (RKLRegexOp)RKLCapturesArrayOp, regex, (RKLRegexOptions)RKLNoOptions, self, NSMaxiumRange, (RKLBlockEnumerationOp)RKLBlockEnumerationReplaceOp, 0UL,                NULL, NULL, NULL,  NULL, block));
02569 }
02570 
02571 - (NSString *)RKL_METHOD_PREPEND(stringByReplacingOccurrencesOfRegex):(NSString *)regex options:(RKLRegexOptions)options inRange:(NSRange)range error:(NSError **)error enumerationOptions:(RKLRegexEnumerationOptions)enumerationOptions usingBlock:(NSString *(^)(NSInteger captureCount, NSString * const capturedStrings[captureCount], const NSRange capturedRanges[captureCount], volatile BOOL * const stop))block
02572 {
02573   return(rkl_performEnumerationUsingBlock(self, _cmd, (RKLRegexOp)RKLCapturesArrayOp, regex, options,                       self, range,         (RKLBlockEnumerationOp)RKLBlockEnumerationReplaceOp, enumerationOptions, NULL, NULL, error, NULL, block));
02574 }
02575 
02576 #endif // _RKL_BLOCKS_ENABLED
02577 
02578 @end
02579 
02581 #pragma mark -
02582 @implementation NSMutableString (RegexKitLiteAdditions)
02583 
02584 #pragma mark -replaceOccurrencesOfRegex:
02585 
02586 - (NSInteger)RKL_METHOD_PREPEND(replaceOccurrencesOfRegex):(NSString *)regex withString:(NSString *)replacement
02587 {
02588   NSRange    searchRange   = NSMaxiumRange;
02589   NSInteger replacedCount = -1L;
02590   rkl_performRegexOp(self, _cmd, (RKLRegexOp)(RKLReplaceOp | RKLReplaceMutable), regex, RKLNoOptions, 0L, self, &searchRange, replacement, NULL,  (void **)((void *)&replacedCount), 0UL, NULL, NULL);
02591   return(replacedCount);
02592 }
02593 
02594 - (NSInteger)RKL_METHOD_PREPEND(replaceOccurrencesOfRegex):(NSString *)regex withString:(NSString *)replacement range:(NSRange)searchRange
02595 {
02596   NSInteger replacedCount = -1L;
02597   rkl_performRegexOp(self, _cmd, (RKLRegexOp)(RKLReplaceOp | RKLReplaceMutable), regex, RKLNoOptions, 0L, self, &searchRange, replacement, NULL,  (void **)((void *)&replacedCount), 0UL, NULL, NULL);
02598   return(replacedCount);
02599 }
02600 
02601 - (NSInteger)RKL_METHOD_PREPEND(replaceOccurrencesOfRegex):(NSString *)regex withString:(NSString *)replacement options:(RKLRegexOptions)options range:(NSRange)searchRange error:(NSError **)error
02602 {
02603   NSInteger replacedCount = -1L;
02604   rkl_performRegexOp(self, _cmd, (RKLRegexOp)(RKLReplaceOp | RKLReplaceMutable), regex, options,      0L, self, &searchRange, replacement, error, (void **)((void *)&replacedCount), 0UL, NULL, NULL);
02605   return(replacedCount);
02606 }
02607 
02608 #ifdef    _RKL_BLOCKS_ENABLED
02609 
02611 #pragma mark -
02612 #pragma mark ^Blocks Related NSMutableString Methods
02613 
02614 #pragma mark -replaceOccurrencesOfRegex:usingBlock:
02615 
02616 - (NSInteger)RKL_METHOD_PREPEND(replaceOccurrencesOfRegex):(NSString *)regex usingBlock:(NSString *(^)(NSInteger captureCount, NSString * const capturedStrings[captureCount], const NSRange capturedRanges[captureCount], volatile BOOL * const stop))block
02617 {
02618   NSUInteger errorFree     = 0UL;
02619   NSInteger replacedCount  = -1L;
02620   NSString *replacedString = rkl_performEnumerationUsingBlock(self, _cmd, (RKLRegexOp)RKLCapturesArrayOp, regex, RKLNoOptions, self, NSMaxiumRange, (RKLBlockEnumerationOp)RKLBlockEnumerationReplaceOp, 0UL,                &replacedCount, &errorFree, NULL,  NULL, block);
02621   if((errorFree == YES) && (replacedCount > 0L)) { [self replaceCharactersInRange:NSMakeRange(0UL, [self length]) withString:replacedString]; }
02622   return(replacedCount);
02623 }
02624 
02625 - (NSInteger)RKL_METHOD_PREPEND(replaceOccurrencesOfRegex):(NSString *)regex options:(RKLRegexOptions)options inRange:(NSRange)range error:(NSError **)error enumerationOptions:(RKLRegexEnumerationOptions)enumerationOptions usingBlock:(NSString *(^)(NSInteger captureCount, NSString * const capturedStrings[captureCount], const NSRange capturedRanges[captureCount], volatile BOOL * const stop))block
02626 {
02627   NSUInteger errorFree     = 0UL;
02628   NSInteger replacedCount  = -1L;
02629   NSString *replacedString = rkl_performEnumerationUsingBlock(self, _cmd, (RKLRegexOp)RKLCapturesArrayOp, regex, options,      self, range,         (RKLBlockEnumerationOp)RKLBlockEnumerationReplaceOp, enumerationOptions, &replacedCount, &errorFree, error, NULL, block);
02630   if((errorFree == YES) && (replacedCount > 0L)) { [self replaceCharactersInRange:range withString:replacedString]; }
02631   return(replacedCount);
02632 }
02633 
02634 #endif // _RKL_BLOCKS_ENABLED
02635 
02636 @end
 All Classes