]> git.saurik.com Git - apple/icu.git/blobdiff - icuSources/i18n/rematch.cpp
ICU-400.37.tar.gz
[apple/icu.git] / icuSources / i18n / rematch.cpp
index 294833ec718b905675c22aaa8333956155f1f7d3..52190e268ab5ded1b49df2d861c6d9185748fc61 100644 (file)
@@ -1,15 +1,15 @@
-//
-//  file:  rematch.cpp    
-//
-//         Contains the implementation of class RegexMatcher,
-//         which is one of the main API classes for the ICU regular expression package.
-//
 /*
 **************************************************************************
-*   Copyright (C) 2002-2005 International Business Machines Corporation  *
+*   Copyright (C) 2002-2008 International Business Machines Corporation  *
 *   and others. All rights reserved.                                     *
 **************************************************************************
 */
+//
+//  file:  rematch.cpp
+//
+//         Contains the implementation of class RegexMatcher,
+//         which is one of the main API classes for the ICU regular expression package.
+//
 
 #include "unicode/utypes.h"
 #if !UCONFIG_NO_REGULAR_EXPRESSIONS
 
 U_NAMESPACE_BEGIN
 
+// Default limit for the size of the back track stack, to avoid system
+//    failures causedby heap exhaustion.  Units are in 32 bit words, not bytes.
+// This value puts ICU's limits higher than most other regexp implementations,
+//    which use recursion rather than the heap, and take more storage per
+//    backtrack point.
+//
+static const int32_t DEFAULT_BACKTRACK_STACK_CAPACITY = 8000000;
+
+// Time limit counter constant.
+//   Time limits for expression evaluation are in terms of quanta of work by
+//   the engine, each of which is 10,000 state saves.
+//   This constant determines that state saves per tick number.
+static const int32_t TIMER_INITIAL_VALUE = 10000;
+
 //-----------------------------------------------------------------------------
 //
 //   Constructor and Destructor
 //
 //-----------------------------------------------------------------------------
 RegexMatcher::RegexMatcher(const RegexPattern *pat)  { 
-    fPattern           = pat;
-    fPatternOwned      = NULL;
-    fInput             = NULL;
-    fTraceDebug        = FALSE;
-    fDeferredStatus    = U_ZERO_ERROR;
-    fStack             = new UVector32(fDeferredStatus); 
-    fData              = fSmallData;
-    fWordBreakItr      = NULL;
+    fDeferredStatus = U_ZERO_ERROR;
+    init(fDeferredStatus);
+    if (U_FAILURE(fDeferredStatus)) {
+        return;
+    }
     if (pat==NULL) {
         fDeferredStatus = U_ILLEGAL_ARGUMENT_ERROR;
         return;
     }
-    if (pat->fDataSize > (int32_t)(sizeof(fSmallData)/sizeof(int32_t))) {
-        fData = (int32_t *)uprv_malloc(pat->fDataSize * sizeof(int32_t)); 
-    }
-    if (fStack == NULL || fData == NULL) {
-        fDeferredStatus = U_MEMORY_ALLOCATION_ERROR;
-    }
-        
-    reset(*RegexStaticSets::gStaticSets->fEmptyString);
+    fPattern = pat;
+    init2(RegexStaticSets::gStaticSets->fEmptyString, fDeferredStatus);
 }
 
 
 
 RegexMatcher::RegexMatcher(const UnicodeString &regexp, const UnicodeString &input,
                            uint32_t flags, UErrorCode &status) {
-    UParseError    pe;
-    fPatternOwned      = RegexPattern::compile(regexp, flags, pe, status);
-    fPattern           = fPatternOwned;
-    fTraceDebug        = FALSE;
-    fDeferredStatus    = U_ZERO_ERROR;
-    fStack             = new UVector32(status); 
-    fData              = fSmallData;
-    fWordBreakItr      = NULL;
+    init(status);
     if (U_FAILURE(status)) {
         return;
     }
-    if (fPattern->fDataSize > (int32_t)(sizeof(fSmallData)/sizeof(int32_t))) {
-        fData = (int32_t *)uprv_malloc(fPattern->fDataSize * sizeof(int32_t)); 
-    }
-    if (fStack == NULL || fData == NULL) {
-        status = U_MEMORY_ALLOCATION_ERROR;
-    }
-    reset(input);
+    UParseError    pe;
+    fPatternOwned      = RegexPattern::compile(regexp, flags, pe, status);
+    fPattern           = fPatternOwned;
+    init2(input, status);
 }
 
 
 RegexMatcher::RegexMatcher(const UnicodeString &regexp, 
                            uint32_t flags, UErrorCode &status) {
-    UParseError    pe;
-    fTraceDebug        = FALSE;
-    fDeferredStatus    = U_ZERO_ERROR;
-    fStack             = new UVector32(status); 
-    fData              = fSmallData;
-    fPatternOwned      = RegexPattern::compile(regexp, flags, pe, status);
-    fPattern           = fPatternOwned;
-    fWordBreakItr      = NULL;
+    init(status);
     if (U_FAILURE(status)) {
         return;
     }
-
-    if (fPattern->fDataSize > (int32_t)(sizeof(fSmallData)/sizeof(int32_t))) {
-        fData = (int32_t *)uprv_malloc(fPattern->fDataSize * sizeof(int32_t)); 
-    }
-    if (fStack == NULL || fData == NULL) {
-        status = U_MEMORY_ALLOCATION_ERROR;
-    }
-    reset(*RegexStaticSets::gStaticSets->fEmptyString);
+    UParseError    pe;
+    fPatternOwned      = RegexPattern::compile(regexp, flags, pe, status);
+    fPattern           = fPatternOwned;
+    init2(RegexStaticSets::gStaticSets->fEmptyString, status);
 }
 
 
 
+
 RegexMatcher::~RegexMatcher() {
     delete fStack;
     if (fData != fSmallData) {
@@ -124,6 +109,79 @@ RegexMatcher::~RegexMatcher() {
     #endif
 }
 
+//
+//   init()   common initialization for use by all constructors.
+//            Initialize all fields, get the object into a consistent state.
+//            This must be done even when the initial status shows an error,
+//            so that the object is initialized sufficiently well for the destructor
+//            to run safely.
+//
+void RegexMatcher::init(UErrorCode &status) {
+    fPattern           = NULL;
+    fPatternOwned      = NULL;
+    fInput             = NULL;
+    fFrameSize         = 0;
+    fRegionStart       = 0;
+    fRegionLimit       = 0;
+    fAnchorStart       = 0;
+    fAnchorLimit       = 0;
+    fLookStart         = 0;
+    fLookLimit         = 0;
+    fActiveStart       = 0;
+    fActiveLimit       = 0;
+    fTransparentBounds = FALSE;
+    fAnchoringBounds   = TRUE;
+    fMatch             = FALSE;
+    fMatchStart        = 0;
+    fMatchEnd          = 0;
+    fLastMatchEnd      = -1;
+    fAppendPosition    = 0;
+    fHitEnd            = FALSE;
+    fRequireEnd        = FALSE;
+    fStack             = NULL;
+    fFrame             = NULL;
+    fTimeLimit         = 0;
+    fTime              = 0;
+    fTickCounter       = 0;
+    fStackLimit        = DEFAULT_BACKTRACK_STACK_CAPACITY;
+    fCallbackFn        = NULL;
+    fCallbackContext   = NULL;
+    fTraceDebug        = FALSE;
+    fDeferredStatus    = status;
+    fData              = fSmallData;
+    fWordBreakItr      = NULL;
+    
+    fStack             = new UVector32(status);
+    if (U_FAILURE(status)) {
+        fDeferredStatus = status;
+    }
+}
+
+//
+//  init2()   Common initialization for use by RegexMatcher constructors, part 2.
+//            This handles the common setup to be done after the Pattern is available.
+//
+void RegexMatcher::init2(const UnicodeString &input, UErrorCode &status) {
+    if (U_FAILURE(status)) {
+        fDeferredStatus = status;
+        return;
+    }
+
+    if (fPattern->fDataSize > (int32_t)(sizeof(fSmallData)/sizeof(int32_t))) {
+        fData = (int32_t *)uprv_malloc(fPattern->fDataSize * sizeof(int32_t)); 
+        if (fData == NULL) {
+            status = fDeferredStatus = U_MEMORY_ALLOCATION_ERROR;
+            return;
+        }
+    }
+
+    reset(input);
+    setStackLimit(DEFAULT_BACKTRACK_STACK_CAPACITY, status);
+    if (U_FAILURE(status)) {
+        fDeferredStatus = status;
+        return;
+    }
+}
 
 
 static const UChar BACKSLASH  = 0x5c;
@@ -149,11 +207,11 @@ RegexMatcher &RegexMatcher::appendReplacement(UnicodeString &dest,
     }
 
     // Copy input string from the end of previous match to start of current match
-    int32_t  len = fMatchStart-fLastReplaceEnd;
+    int32_t  len = fMatchStart-fAppendPosition;
     if (len > 0) {
-        dest.append(*fInput, fLastReplaceEnd, len);
+        dest.append(*fInput, fAppendPosition, len);
     }
-    fLastReplaceEnd = fMatchEnd;
+    fAppendPosition = fMatchEnd;
     
 
     // scan the replacement text, looking for substitutions ($n) and \escapes.
@@ -249,11 +307,13 @@ RegexMatcher &RegexMatcher::appendReplacement(UnicodeString &dest,
 //                   To the destination string, append everything following
 //                   the last match position from the input string.
 //
+//                   Note:  Match ranges do not affect appendTail or appendReplacement
+//
 //--------------------------------------------------------------------------------
 UnicodeString &RegexMatcher::appendTail(UnicodeString &dest) {
-    int32_t  len = fInput->length()-fMatchEnd;
+    int32_t  len = fInput->length() - fAppendPosition;
     if (len > 0) {
-        dest.append(*fInput, fMatchEnd, len);
+        dest.append(*fInput, fAppendPosition, len);
     }
     return dest;
 }
@@ -313,6 +373,9 @@ UBool RegexMatcher::find() {
     }
 
     int32_t startPos = fMatchEnd;
+    if (startPos==0) {
+        startPos = fActiveStart;
+    }
 
     if (fMatch) {
         // Save the position of any previous successful match.
@@ -321,8 +384,9 @@ UBool RegexMatcher::find() {
         if (fMatchStart == fMatchEnd) {
             // Previous match had zero length.  Move start position up one position
             //  to avoid sending find() into a loop on zero-length matches.
-            if (startPos == fInput->length()) {
+            if (startPos >= fActiveLimit) {
                 fMatch = FALSE;
+                fHitEnd = TRUE;
                 return FALSE;
             }
             startPos = fInput->moveIndex32(startPos, 1);
@@ -332,17 +396,20 @@ UBool RegexMatcher::find() {
             // A previous find() failed to match.  Don't try again.
             //   (without this test, a pattern with a zero-length match
             //    could match again at the end of an input string.)
+            fHitEnd = TRUE;
             return FALSE;
         }
     }
 
-    int32_t inputLen = fInput->length();
 
     // Compute the position in the input string beyond which a match can not begin, because
     //   the minimum length match would extend past the end of the input.
-    int32_t testLen  = inputLen - fPattern->fMinMatchLen;
+    //   Note:  some patterns that cannot match anything will have fMinMatchLength==Max Int.
+    //          Be aware of possible overflows if making changes here.
+    int32_t testLen  = fActiveLimit - fPattern->fMinMatchLen;
     if (startPos > testLen) {
         fMatch = FALSE;
+        fHitEnd = TRUE;
         return FALSE;
     }
 
@@ -355,7 +422,7 @@ UBool RegexMatcher::find() {
         // No optimization was found. 
         //  Try a match at each input position.
         for (;;) {
-            MatchAt(startPos, fDeferredStatus);
+            MatchAt(startPos, FALSE, fDeferredStatus);
             if (U_FAILURE(fDeferredStatus)) {
                 return FALSE;
             }
@@ -363,9 +430,10 @@ UBool RegexMatcher::find() {
                 return TRUE;
             }
             if (startPos >= testLen) {
+                fHitEnd = TRUE;
                 return FALSE;
             }
-            U16_FWD_1(inputBuf, startPos, inputLen);
+            U16_FWD_1(inputBuf, startPos, fActiveLimit);
             // Note that it's perfectly OK for a pattern to have a zero-length
             //   match at the end of a string, so we must make sure that the loop
             //   runs with startPos == testLen the last time through.
@@ -375,11 +443,11 @@ UBool RegexMatcher::find() {
     case START_START:
         // Matches are only possible at the start of the input string
         //   (pattern begins with ^ or \A)
-        if (startPos > 0) {
+        if (startPos > fActiveStart) {
             fMatch = FALSE;
             return FALSE;
         }
-        MatchAt(startPos, fDeferredStatus);
+        MatchAt(startPos, FALSE, fDeferredStatus);
         if (U_FAILURE(fDeferredStatus)) {
             return FALSE;
         }
@@ -392,10 +460,10 @@ UBool RegexMatcher::find() {
             U_ASSERT(fPattern->fMinMatchLen > 0);
             for (;;) {
                 int32_t pos = startPos;
-                U16_NEXT(inputBuf, startPos, inputLen, c);  // like c = inputBuf[startPos++];
+                U16_NEXT(inputBuf, startPos, fActiveLimit, c);  // like c = inputBuf[startPos++];
                 if (c<256 && fPattern->fInitialChars8->contains(c) ||
                     c>=256 && fPattern->fInitialChars->contains(c)) {
-                    MatchAt(pos, fDeferredStatus);
+                    MatchAt(pos, FALSE, fDeferredStatus);
                     if (U_FAILURE(fDeferredStatus)) {
                         return FALSE;
                     }
@@ -405,6 +473,7 @@ UBool RegexMatcher::find() {
                 }
                 if (pos >= testLen) {
                     fMatch = FALSE;
+                    fHitEnd = TRUE;
                     return FALSE;
                 }
             }
@@ -419,9 +488,9 @@ UBool RegexMatcher::find() {
             UChar32 theChar = fPattern->fInitialChar;
             for (;;) {
                 int32_t pos = startPos;
-                U16_NEXT(inputBuf, startPos, inputLen, c);  // like c = inputBuf[startPos++];
+                U16_NEXT(inputBuf, startPos, fActiveLimit, c);  // like c = inputBuf[startPos++];
                 if (c == theChar) {
-                    MatchAt(pos, fDeferredStatus);
+                    MatchAt(pos, FALSE, fDeferredStatus);
                     if (U_FAILURE(fDeferredStatus)) {
                         return FALSE;
                     }
@@ -431,6 +500,7 @@ UBool RegexMatcher::find() {
                 }
                 if (pos >= testLen) {
                     fMatch = FALSE;
+                    fHitEnd = TRUE;
                     return FALSE;
                 }
             }
@@ -440,40 +510,65 @@ UBool RegexMatcher::find() {
     case START_LINE:
         {
             UChar32  c;
-            if (startPos == 0) {
-                MatchAt(startPos, fDeferredStatus);
+            if (startPos == fAnchorStart) {
+                MatchAt(startPos, FALSE, fDeferredStatus);
                 if (U_FAILURE(fDeferredStatus)) {
                     return FALSE;
                 }
                 if (fMatch) {
                     return TRUE;
                 }
-                U16_NEXT(inputBuf, startPos, inputLen, c);  // like c = inputBuf[startPos++];
+                U16_NEXT(inputBuf, startPos, fActiveLimit, c);  // like c = inputBuf[startPos++];
             }
 
-            for (;;) {
-                c = inputBuf[startPos-1];
-                if (((c & 0x7f) <= 0x29) &&     // First quickly bypass as many chars as possible
-                    ((c<=0x0d && c>=0x0a) || c==0x85 ||c==0x2028 || c==0x2029 )) {
-                        if (c == 0x0d && startPos < inputLen && inputBuf[startPos] == 0x0a) {
-                            startPos++;
-                        }
-                        MatchAt(startPos, fDeferredStatus);
-                        if (U_FAILURE(fDeferredStatus)) {
-                            return FALSE;
-                        }
-                        if (fMatch) {
-                            return TRUE;
-                        }
+            if (fPattern->fFlags & UREGEX_UNIX_LINES) {
+               for (;;) {
+                    c = inputBuf[startPos-1];
+                    if (c == 0x0a) {
+                            MatchAt(startPos, FALSE, fDeferredStatus);
+                            if (U_FAILURE(fDeferredStatus)) {
+                                return FALSE;
+                            }
+                            if (fMatch) {
+                                return TRUE;
+                            }
+                    }
+                    if (startPos >= testLen) {
+                        fMatch = FALSE;
+                        fHitEnd = TRUE;
+                        return FALSE;
+                    }
+                    U16_NEXT(inputBuf, startPos, fActiveLimit, c);  // like c = inputBuf[startPos++];
+                    // Note that it's perfectly OK for a pattern to have a zero-length
+                    //   match at the end of a string, so we must make sure that the loop
+                    //   runs with startPos == testLen the last time through.
                 }
-                if (startPos >= testLen) {
-                    fMatch = FALSE;
-                    return FALSE;
+            } else {
+                for (;;) {
+                    c = inputBuf[startPos-1];
+                    if (((c & 0x7f) <= 0x29) &&     // First quickly bypass as many chars as possible
+                        ((c<=0x0d && c>=0x0a) || c==0x85 ||c==0x2028 || c==0x2029 )) {
+                            if (c == 0x0d && startPos < fActiveLimit && inputBuf[startPos] == 0x0a) {
+                                startPos++;
+                            }
+                            MatchAt(startPos, FALSE, fDeferredStatus);
+                            if (U_FAILURE(fDeferredStatus)) {
+                                return FALSE;
+                            }
+                            if (fMatch) {
+                                return TRUE;
+                            }
+                    }
+                    if (startPos >= testLen) {
+                        fMatch = FALSE;
+                        fHitEnd = TRUE;
+                        return FALSE;
+                    }
+                    U16_NEXT(inputBuf, startPos, fActiveLimit, c);  // like c = inputBuf[startPos++];
+                    // Note that it's perfectly OK for a pattern to have a zero-length
+                    //   match at the end of a string, so we must make sure that the loop
+                    //   runs with startPos == testLen the last time through.
                 }
-                U16_NEXT(inputBuf, startPos, inputLen, c);  // like c = inputBuf[startPos++];
-                // Note that it's perfectly OK for a pattern to have a zero-length
-                //   match at the end of a string, so we must make sure that the loop
-                //   runs with startPos == testLen the last time through.
             }
         }
 
@@ -495,13 +590,13 @@ UBool RegexMatcher::find(int32_t start, UErrorCode &status) {
         status = fDeferredStatus;
         return FALSE;
     }
-    int32_t inputLen = fInput->length();
-    if (start < 0 || start > inputLen) {
+    this->reset();                        // Note:  Reset() is specified by Java Matcher documentation.
+                                          //        This will reset the region to be the full input length.
+    if (start < fActiveStart || start > fActiveLimit) {
         status = U_INDEX_OUTOFBOUNDS_ERROR;
         return FALSE;
     }
-    this->reset();
-    fMatchEnd = start;
+    fMatchEnd = start;  
     return find();
 }
 
@@ -554,7 +649,35 @@ const UnicodeString &RegexMatcher::input() const {
 }
 
 
+//--------------------------------------------------------------------------------
+//
+//  hasAnchoringBounds()
+//
+//--------------------------------------------------------------------------------
+UBool RegexMatcher::hasAnchoringBounds() const {
+    return fAnchoringBounds;
+}
+
+
+//--------------------------------------------------------------------------------
+//
+//  hasTransparentBounds()
+//
+//--------------------------------------------------------------------------------
+UBool RegexMatcher::hasTransparentBounds() const {
+    return fTransparentBounds;
+}
+
+
 
+//--------------------------------------------------------------------------------
+//
+//  hitEnd()
+//
+//--------------------------------------------------------------------------------
+UBool RegexMatcher::hitEnd() const {
+    return fHitEnd;
+}
 
 //--------------------------------------------------------------------------------
 //
@@ -569,8 +692,8 @@ UBool RegexMatcher::lookingAt(UErrorCode &status) {
         status = fDeferredStatus;
         return FALSE;
     }
-    reset();
-    MatchAt(0, status);
+    resetPreserveRegion();
+    MatchAt(fActiveStart, FALSE, status);
     return fMatch;
 }
 
@@ -583,12 +706,12 @@ UBool RegexMatcher::lookingAt(int32_t start, UErrorCode &status) {
         status = fDeferredStatus;
         return FALSE;
     }
-    if (start < 0 || start > fInput->length()) {
+    reset();
+    if (start < fActiveStart || start > fActiveLimit) {
         status = U_INDEX_OUTOFBOUNDS_ERROR;
         return FALSE;
     }
-    reset();
-    MatchAt(start, status);
+    MatchAt(start, FALSE, status);
     return fMatch;
 }
 
@@ -607,10 +730,9 @@ UBool RegexMatcher::matches(UErrorCode &status) {
         status = fDeferredStatus;
         return FALSE;
     }
-    reset();
-    MatchAt(0, status);
-    UBool   success  = (fMatch && fMatchEnd==fInput->length());
-    return success;
+    resetPreserveRegion();
+    MatchAt(fActiveStart, TRUE, status);
+    return fMatch;
 }
 
 
@@ -622,24 +744,78 @@ UBool RegexMatcher::matches(int32_t start, UErrorCode &status) {
         status = fDeferredStatus;
         return FALSE;
     }
-    if (start < 0 || start > fInput->length()) {
+    reset();
+    if (start < fActiveStart || start > fActiveLimit) {
         status = U_INDEX_OUTOFBOUNDS_ERROR;
         return FALSE;
     }
-    reset();
-    MatchAt(start, status);
-    UBool   success  = (fMatch && fMatchEnd==fInput->length());
-    return success;
+    MatchAt(start, TRUE, status);
+    return fMatch;
 }
 
 
 
+//--------------------------------------------------------------------------------
+//
+//    pattern
+//
+//--------------------------------------------------------------------------------
 const RegexPattern &RegexMatcher::pattern() const {
     return *fPattern;
 }
 
 
 
+//--------------------------------------------------------------------------------
+//
+//    region
+//
+//--------------------------------------------------------------------------------
+RegexMatcher &RegexMatcher::region(int32_t start, int32_t limit, UErrorCode &status) {
+    if (U_FAILURE(status)) {
+        return *this;
+    }
+    if (start>limit || start<0 || limit<0 || limit>fInput->length()) {
+        status = U_ILLEGAL_ARGUMENT_ERROR;
+    }
+    this->reset();
+    fRegionStart = start;
+    fRegionLimit = limit;
+    fActiveStart = start;
+    fActiveLimit = limit;
+    if (!fTransparentBounds) {
+        fLookStart = start;
+        fLookLimit = limit;
+    }
+    if (fAnchoringBounds) {
+        fAnchorStart = start;
+        fAnchorLimit = limit;
+    }
+    return *this;
+}
+
+
+
+//--------------------------------------------------------------------------------
+//
+//    regionEnd
+//
+//--------------------------------------------------------------------------------
+int32_t RegexMatcher::regionEnd() const {
+    return fRegionLimit;
+}
+
+
+//--------------------------------------------------------------------------------
+//
+//    regionStart
+//
+//--------------------------------------------------------------------------------
+int32_t RegexMatcher::regionStart() const {
+    return fRegionStart;
+}
+
+
 //--------------------------------------------------------------------------------
 //
 //    replaceAll
@@ -654,7 +830,8 @@ UnicodeString RegexMatcher::replaceAll(const UnicodeString &replacement, UErrorC
         return *fInput;
     }
     UnicodeString destString;
-    for (reset(); find(); ) {
+    reset();
+    while (find()) {
         appendReplacement(destString, replacement, status);
         if (U_FAILURE(status)) {
             break;
@@ -693,6 +870,15 @@ UnicodeString RegexMatcher::replaceFirst(const UnicodeString &replacement, UErro
 }
 
 
+//--------------------------------------------------------------------------------
+//
+//     requireEnd
+//
+//--------------------------------------------------------------------------------
+UBool RegexMatcher::requireEnd() const {
+    return fRequireEnd;
+}
+
 
 //--------------------------------------------------------------------------------
 //
@@ -700,17 +886,34 @@ UnicodeString RegexMatcher::replaceFirst(const UnicodeString &replacement, UErro
 //
 //--------------------------------------------------------------------------------
 RegexMatcher &RegexMatcher::reset() {
+    fRegionStart    = 0;
+    fRegionLimit    = fInput->length();
+    fActiveStart    = 0;
+    fActiveLimit    = fRegionLimit;
+    fAnchorStart    = 0;
+    fAnchorLimit    = fRegionLimit;
+    fLookStart      = 0;
+    fLookLimit      = fRegionLimit;
+    resetPreserveRegion();
+    return *this;
+}
+
+
+
+void RegexMatcher::resetPreserveRegion() {
     fMatchStart     = 0;
     fMatchEnd       = 0;
     fLastMatchEnd   = -1;
-    fLastReplaceEnd = 0;
+    fAppendPosition = 0;
     fMatch          = FALSE;
+    fHitEnd         = FALSE;
+    fRequireEnd     = FALSE;
+    fTime           = 0;
+    fTickCounter    = TIMER_INITIAL_VALUE;
     resetStack();
-    return *this;
 }
 
 
-
 RegexMatcher &RegexMatcher::reset(const UnicodeString &input) {
     fInput          = &input;
     reset();
@@ -722,18 +925,18 @@ RegexMatcher &RegexMatcher::reset(const UnicodeString &input) {
     return *this;
 }
 
-RegexMatcher &RegexMatcher::reset(const UChar *) {
+/*RegexMatcher &RegexMatcher::reset(const UChar *) {
     fDeferredStatus = U_INTERNAL_PROGRAM_ERROR;
     return *this;
-}
+}*/
 
 
 RegexMatcher &RegexMatcher::reset(int32_t position, UErrorCode &status) {
     if (U_FAILURE(status)) {
         return *this;
     }
-    reset();
-    if (position < 0 || position >= fInput->length()) {
+    reset();       // Reset also resets the region to be the entire string.
+    if (position < 0 || position >= fActiveLimit) {
         status = U_INDEX_OUTOFBOUNDS_ERROR;
         return *this;
     }
@@ -778,18 +981,15 @@ int32_t  RegexMatcher::split(const UnicodeString &input,
         return 0;
     }
 
-
     //
     // Reset for the input text
     //
     reset(input);
-    int32_t   inputLen = input.length();
     int32_t   nextOutputStringStart = 0;
-    if (inputLen == 0) {
+    if (fActiveLimit == 0) {
         return 0;
     }
 
-
     //
     // Loop through the input text, searching for the delimiter pattern
     //
@@ -804,7 +1004,7 @@ int32_t  RegexMatcher::split(const UnicodeString &input,
             //    last capture group saved in favor of the unprocessed remainder of the
             //    input string.)
             i = destCapacity-1;
-            int32_t remainingLength = inputLen-nextOutputStringStart;
+            int32_t remainingLength = fActiveLimit-nextOutputStringStart;
             if (remainingLength > 0) {
                 dest[i].setTo(input, nextOutputStringStart, remainingLength);
             }
@@ -828,7 +1028,7 @@ int32_t  RegexMatcher::split(const UnicodeString &input,
                 dest[i] = group(groupNum, status);
             }
 
-            if (nextOutputStringStart == inputLen) {
+            if (nextOutputStringStart == fActiveLimit) {
                 // The delimiter was at the end of the string.  We're done.
                 break;
             }
@@ -838,7 +1038,7 @@ int32_t  RegexMatcher::split(const UnicodeString &input,
         {
             // We ran off the end of the input while looking for the next delimiter.
             // All the remaining text goes into the current output string.
-            dest[i].setTo(input, nextOutputStringStart, inputLen-nextOutputStringStart);
+            dest[i].setTo(input, nextOutputStringStart, fActiveLimit-nextOutputStringStart);
             break;
         }
     }
@@ -859,6 +1059,11 @@ int32_t RegexMatcher::start(UErrorCode &status) const {
 
 
 
+//--------------------------------------------------------------------------------
+//
+//     start(int32_t group, UErrorCode &status)
+//
+//--------------------------------------------------------------------------------
 int32_t RegexMatcher::start(int32_t group, UErrorCode &status) const {
     if (U_FAILURE(status)) {
         return -1;
@@ -889,6 +1094,146 @@ int32_t RegexMatcher::start(int32_t group, UErrorCode &status) const {
 
 
 
+//--------------------------------------------------------------------------------
+//
+//     useAnchoringBounds
+//
+//--------------------------------------------------------------------------------
+RegexMatcher &RegexMatcher::useAnchoringBounds(UBool b) {
+    fAnchoringBounds = b;
+    UErrorCode status = U_ZERO_ERROR;
+    region(fRegionStart, fRegionLimit, status); 
+    U_ASSERT(U_SUCCESS(status));
+    return *this;
+}
+
+
+//--------------------------------------------------------------------------------
+//
+//     useTransparentBounds
+//
+//--------------------------------------------------------------------------------
+RegexMatcher &RegexMatcher::useTransparentBounds(UBool b) {
+    fTransparentBounds = b;
+    UErrorCode status = U_ZERO_ERROR;
+    region(fRegionStart, fRegionLimit, status); 
+    U_ASSERT(U_SUCCESS(status));
+    return *this;
+}
+
+//--------------------------------------------------------------------------------
+//
+//     setTimeLimit
+//
+//--------------------------------------------------------------------------------
+void RegexMatcher::setTimeLimit(int32_t limit, UErrorCode &status) {
+    if (U_FAILURE(status)) {
+        return;
+    }
+    if (U_FAILURE(fDeferredStatus)) {
+        status = fDeferredStatus;
+        return;
+    }
+    if (limit < 0) {
+        status = U_ILLEGAL_ARGUMENT_ERROR;
+        return;
+    }
+    fTimeLimit = limit;
+}
+
+
+//--------------------------------------------------------------------------------
+//
+//     getTimeLimit
+//
+//--------------------------------------------------------------------------------
+int32_t RegexMatcher::getTimeLimit() const {
+    return fTimeLimit;
+}
+
+
+//--------------------------------------------------------------------------------
+//
+//     setStackLimit
+//
+//--------------------------------------------------------------------------------
+void RegexMatcher::setStackLimit(int32_t limit, UErrorCode &status) {
+    if (U_FAILURE(status)) {
+        return;
+    }
+    if (U_FAILURE(fDeferredStatus)) {
+        status = fDeferredStatus;
+        return;
+    }
+    if (limit < 0) {
+        status = U_ILLEGAL_ARGUMENT_ERROR;
+        return;
+    }
+    
+    // Reset the matcher.  This is needed here in case there is a current match
+    //    whose final stack frame (containing the match results, pointed to by fFrame) 
+    //    would be lost by resizing to a smaller stack size.
+    reset();
+    
+    if (limit == 0) {
+        // Unlimited stack expansion
+        fStack->setMaxCapacity(0);
+    } else {
+        // Change the units of the limit  from bytes to ints, and bump the size up
+        //   to be big enough to hold at least one stack frame for the pattern, 
+        //   if it isn't there already.
+        int32_t adjustedLimit = limit / sizeof(int32_t);
+        if (adjustedLimit < fPattern->fFrameSize) {
+            adjustedLimit = fPattern->fFrameSize;
+        }
+        fStack->setMaxCapacity(adjustedLimit);
+    }
+    fStackLimit = limit;
+}
+
+
+//--------------------------------------------------------------------------------
+//
+//     getStackLimit
+//
+//--------------------------------------------------------------------------------
+int32_t RegexMatcher::getStackLimit() const {
+    return fStackLimit;
+}
+
+
+//--------------------------------------------------------------------------------
+//
+//     setMatchCallback
+//
+//--------------------------------------------------------------------------------
+void RegexMatcher::setMatchCallback(URegexMatchCallback     *callback,
+                                    const void              *context,
+                                    UErrorCode              &status) {
+     if (U_FAILURE(status)) {
+         return;
+     }
+     fCallbackFn = callback;
+     fCallbackContext = context;
+}
+
+
+//--------------------------------------------------------------------------------
+//
+//     getMatchCallback
+//
+//--------------------------------------------------------------------------------
+void RegexMatcher::getMatchCallback(URegexMatchCallback   *&callback,
+                                  const void              *&context,
+                                  UErrorCode              &status) {
+    if (U_FAILURE(status)) {
+       return;
+    }
+    callback = fCallbackFn;
+    context  = fCallbackContext;
+}
+
+
 //================================================================================
 //
 //    Code following this point in this file is the internal
@@ -933,17 +1278,20 @@ REStackFrame *RegexMatcher::resetStack() {
 //
 //          parameters:   pos   - the current position in the input buffer
 //
+//              TODO:  double-check edge cases at region boundaries.
+//
 //--------------------------------------------------------------------------------
 UBool RegexMatcher::isWordBoundary(int32_t pos) {
     UBool isBoundary = FALSE;
     UBool cIsWord    = FALSE;
     
-    // Determine whether char c at current position is a member of the word set of chars.
-    // If we're off the end of the string, behave as though we're not at a word char.
-    if (pos < fInput->length()) {
+    if (pos >= fLookLimit) {
+        fHitEnd = TRUE;
+    } else {
+        // Determine whether char c at current position is a member of the word set of chars.
+        // If we're off the end of the string, behave as though we're not at a word char.
         UChar32  c = fInput->char32At(pos);
-        int8_t ctype = u_charType(c);
-        if (ctype==U_NON_SPACING_MARK || ctype==U_ENCLOSING_MARK) {
+        if (u_hasBinaryProperty(c, UCHAR_GRAPHEME_EXTEND) || u_charType(c) == U_FORMAT_CHAR) {
             // Current char is a combining one.  Not a boundary.
             return FALSE;
         }
@@ -955,13 +1303,13 @@ UBool RegexMatcher::isWordBoundary(int32_t pos) {
     UBool prevCIsWord = FALSE;
     int32_t prevPos = pos;
     for (;;) {
-        if (prevPos == 0) {
+        if (prevPos <= fLookStart) {
             break;
         }
         prevPos = fInput->moveIndex32(prevPos, -1);
         UChar32 prevChar = fInput->char32At(prevPos);
-        int8_t prevCType = u_charType(prevChar);
-        if (!(prevCType==U_NON_SPACING_MARK || prevCType==U_ENCLOSING_MARK)) {
+        if (!(u_hasBinaryProperty(prevChar, UCHAR_GRAPHEME_EXTEND)
+              || u_charType(prevChar) == U_FORMAT_CHAR)) {
             prevCIsWord = fPattern->fStaticSets[URX_ISWORD_SET]->contains(prevChar);
             break;
         }
@@ -982,40 +1330,90 @@ UBool RegexMatcher::isWordBoundary(int32_t pos) {
 UBool RegexMatcher::isUWordBoundary(int32_t pos) {
     UBool       returnVal = FALSE;
 #if UCONFIG_NO_BREAK_ITERATION==0
-    UErrorCode  status    = U_ZERO_ERROR;  
     
     // If we haven't yet created a break iterator for this matcher, do it now.
     if (fWordBreakItr == NULL) {
         fWordBreakItr = 
-            (RuleBasedBreakIterator *)BreakIterator::createWordInstance(Locale::getEnglish(), status);
-        if (U_FAILURE(status)) {
-            // TODO:  reliable error reporting for BI failures.
+            (RuleBasedBreakIterator *)BreakIterator::createWordInstance(Locale::getEnglish(), fDeferredStatus);
+        if (U_FAILURE(fDeferredStatus)) {
             return FALSE;
         }
         fWordBreakItr->setText(*fInput);
     }
 
-    returnVal = fWordBreakItr->isBoundary(pos);
+    if (pos >= fLookLimit) {
+        fHitEnd = TRUE;
+        returnVal = TRUE;   // With Unicode word rules, only positions within the interior of "real"
+                            //    words are not boundaries.  All non-word chars stand by themselves,
+                            //    with word boundaries on both sides.
+    } else {
+        returnVal = fWordBreakItr->isBoundary(pos);
+    }
 #endif
     return   returnVal;
 }
 
 //--------------------------------------------------------------------------------
 //
-//   StateSave      
+//   IncrementTime     This function is called once each TIMER_INITIAL_VALUE state
+//                     saves. Increment the "time" counter, and call the
+//                     user callback function if there is one installed.
+//
+//                     If the match operation needs to be aborted, either for a time-out
+//                     or because the user callback asked for it, just set an error status.
+//                     The engine will pick that up and stop in its outer loop.
+//
+//--------------------------------------------------------------------------------
+void RegexMatcher::IncrementTime(UErrorCode &status) {
+    fTickCounter = TIMER_INITIAL_VALUE;
+    fTime++;
+    if (fCallbackFn != NULL) {
+        if ((*fCallbackFn)(fCallbackContext, fTime) == FALSE) {
+            status = U_REGEX_STOPPED_BY_CALLER;
+            return;
+        }
+    }
+    if (fTimeLimit > 0 && fTime >= fTimeLimit) {
+        status = U_REGEX_TIME_OUT;
+    }
+}
+
+//--------------------------------------------------------------------------------
+//
+//   StateSave
 //       Make a new stack frame, initialized as a copy of the current stack frame.
 //       Set the pattern index in the original stack frame from the operand value
 //       in the opcode.  Execution of the engine continues with the state in
 //       the newly created stack frame
 //
 //       Note that reserveBlock() may grow the stack, resulting in the
-//       whole thing being relocated in memory.  
+//       whole thing being relocated in memory.
+//
+//    Parameters:
+//       fp           The top frame pointer when called.  At return, a new 
+//                    fame will be present
+//       savePatIdx   An index into the compiled pattern.  Goes into the original
+//                    (not new) frame.  If execution ever back-tracks out of the
+//                    new frame, this will be where we continue from in the pattern.
+//    Return
+//                    The new frame pointer.
 //
 //--------------------------------------------------------------------------------
-inline REStackFrame *RegexMatcher::StateSave(REStackFrame *fp, int32_t savePatIdx, int32_t frameSize, UErrorCode &status) {
+inline REStackFrame *RegexMatcher::StateSave(REStackFrame *fp, int32_t savePatIdx, UErrorCode &status) {
     // push storage for a new frame. 
-    int32_t *newFP = fStack->reserveBlock(frameSize, status);
-    fp = (REStackFrame *)(newFP - frameSize);  // in case of realloc of stack.
+    int32_t *newFP = fStack->reserveBlock(fFrameSize, status);
+    if (newFP == NULL) {
+        // Failure on attempted stack expansion.
+        //   Stack function set some other error code, change it to a more
+        //   specific one for regular expressions.
+        status = U_REGEX_STACK_OVERFLOW;
+        // We need to return a writable stack frame, so just return the
+        //    previous frame.  The match operation will stop quickly
+        //    because of the error status, after which the frame will never
+        //    be looked at again.
+        return fp;
+    }
+    fp = (REStackFrame *)(newFP - fFrameSize);  // in case of realloc of stack.
     
     // New stack frame = copy of old top frame.
     int32_t *source = (int32_t *)fp;
@@ -1027,17 +1425,24 @@ inline REStackFrame *RegexMatcher::StateSave(REStackFrame *fp, int32_t savePatId
         }
     }
     
+    fTickCounter--;
+    if (fTickCounter <= 0) {
+       IncrementTime(status);    // Re-initializes fTickCounter
+    }
     fp->fPatIdx = savePatIdx;
     return (REStackFrame *)newFP;
 }
-    
-            
+
+
 //--------------------------------------------------------------------------------
 //
 //   MatchAt      This is the actual matching engine.
 //
+//                  startIdx:    begin matching a this index.
+//                  toEnd:       if true, match must extend to end of the input region
+//
 //--------------------------------------------------------------------------------
-void RegexMatcher::MatchAt(int32_t startIdx, UErrorCode &status) {
+void RegexMatcher::MatchAt(int32_t startIdx, UBool toEnd, UErrorCode &status) {
     UBool       isMatch  = FALSE;      // True if the we have a match.
 
     int32_t     op;                    // Operation from the compiled pattern, split into
@@ -1072,17 +1477,16 @@ void RegexMatcher::MatchAt(int32_t startIdx, UErrorCode &status) {
     }
 
     //  Cache frequently referenced items from the compiled pattern
-    //  in local variables.
     //
     int32_t             *pat           = fPattern->fCompiledPat->getBuffer();
 
     const UChar         *litText       = fPattern->fLiteralText.getBuffer();
     UVector             *sets          = fPattern->fSets;
-    int32_t              inputLen      = fInput->length();
+
     const UChar         *inputBuf      = fInput->getBuffer();
 
+    fFrameSize = fPattern->fFrameSize;
     REStackFrame        *fp            = resetStack();
-    int32_t              frameSize     = fPattern->fFrameSize;
 
     fp->fPatIdx   = 0;
     fp->fInputIdx = startIdx;
@@ -1126,19 +1530,21 @@ void RegexMatcher::MatchAt(int32_t startIdx, UErrorCode &status) {
             // Force a backtrack.  In some circumstances, the pattern compiler
             //   will notice that the pattern can't possibly match anything, and will
             //   emit one of these at that point.
-            fp = (REStackFrame *)fStack->popFrame(frameSize);
+            fp = (REStackFrame *)fStack->popFrame(fFrameSize);
             break;
 
 
         case URX_ONECHAR:
-            if (fp->fInputIdx < inputLen) {
+            if (fp->fInputIdx < fActiveLimit) {
                 UChar32   c;
-                U16_NEXT(inputBuf, fp->fInputIdx, inputLen, c);
-                if (c == opValue) {           
+                U16_NEXT(inputBuf, fp->fInputIdx, fActiveLimit, c);
+                if (c == opValue) {
                     break;
                 }
+            } else {
+                fHitEnd = TRUE;
             }
-            fp = (REStackFrame *)fStack->popFrame(frameSize);
+            fp = (REStackFrame *)fStack->popFrame(fFrameSize);
             break;
 
 
@@ -1157,9 +1563,10 @@ void RegexMatcher::MatchAt(int32_t startIdx, UErrorCode &status) {
                 U_ASSERT(opType == URX_STRING_LEN);
                 U_ASSERT(stringLen >= 2);
 
-                if (fp->fInputIdx + stringLen > inputLen) {
+                if (fp->fInputIdx + stringLen > fActiveLimit) {
                     // No match.  String is longer than the remaining input text.
-                    fp = (REStackFrame *)fStack->popFrame(frameSize);
+                    fHitEnd = TRUE;          //   TODO:  See ticket 6074
+                    fp = (REStackFrame *)fStack->popFrame(fFrameSize);
                     break;
                 }
 
@@ -1177,7 +1584,7 @@ void RegexMatcher::MatchAt(int32_t startIdx, UErrorCode &status) {
                         }
                     } else {
                         // Match failed.
-                        fp = (REStackFrame *)fStack->popFrame(frameSize);
+                        fp = (REStackFrame *)fStack->popFrame(fFrameSize);
                         break;
                     }
                 }
@@ -1187,13 +1594,18 @@ void RegexMatcher::MatchAt(int32_t startIdx, UErrorCode &status) {
 
 
         case URX_STATE_SAVE:
-            fp = StateSave(fp, opValue, frameSize, status);
+            fp = StateSave(fp, opValue, status);
             break;
 
 
         case URX_END:
             // The match loop will exit via this path on a successful match,
             //   when we reach the end of the pattern.
+            if (toEnd && fp->fInputIdx != fActiveLimit) {
+                // The pattern matched, but not to the end of input.  Try some more.
+                fp = (REStackFrame *)fStack->popFrame(fFrameSize);
+                break;
+            }
             isMatch = TRUE;
             goto  breakFromLoop;
 
@@ -1203,110 +1615,177 @@ void RegexMatcher::MatchAt(int32_t startIdx, UErrorCode &status) {
             //             opValue+2 - the start of a capture group whose end
             //                          has not yet been reached (and might not ever be).
         case URX_START_CAPTURE:
-            U_ASSERT(opValue >= 0 && opValue < frameSize-3);
+            U_ASSERT(opValue >= 0 && opValue < fFrameSize-3);
             fp->fExtra[opValue+2] = fp->fInputIdx;
             break;
 
 
         case URX_END_CAPTURE:
-            U_ASSERT(opValue >= 0 && opValue < frameSize-3);
+            U_ASSERT(opValue >= 0 && opValue < fFrameSize-3);
             U_ASSERT(fp->fExtra[opValue+2] >= 0);            // Start pos for this group must be set.
             fp->fExtra[opValue]   = fp->fExtra[opValue+2];   // Tentative start becomes real.
             fp->fExtra[opValue+1] = fp->fInputIdx;           // End position
             U_ASSERT(fp->fExtra[opValue] <= fp->fExtra[opValue+1]);
             break;
 
-            
+
         case URX_DOLLAR:                   //  $, test for End of line
                                            //     or for position before new line at end of input
-            if (fp->fInputIdx < inputLen-2) {
+            if (fp->fInputIdx < fAnchorLimit-2) {
                 // We are no where near the end of input.  Fail.
-                fp = (REStackFrame *)fStack->popFrame(frameSize);
+                //   This is the common case.  Keep it first.
+                fp = (REStackFrame *)fStack->popFrame(fFrameSize);
                 break;
             }
-            if (fp->fInputIdx >= inputLen) {
+            if (fp->fInputIdx >= fAnchorLimit) {
                 // We really are at the end of input.  Success.
+                fHitEnd = TRUE;
+                fRequireEnd = TRUE;
                 break;
             }
             // If we are positioned just before a new-line that is located at the
             //   end of input, succeed.
-            if (fp->fInputIdx == inputLen-1) {
+            if (fp->fInputIdx == fAnchorLimit-1) {
                 UChar32 c = fInput->char32At(fp->fInputIdx);
-                if ((c<=0x0d && c>=0x0a) || c==0x85 ||c==0x2028 || c==0x2029) {
+                if ((c>=0x0a && c<=0x0d) || c==0x85 || c==0x2028 || c==0x2029) {
                     // If not in the middle of a CR/LF sequence
-                    if ( !(c==0x0a && fp->fInputIdx>0 && inputBuf[fp->fInputIdx-1]==0x0d)) {
-                        break;
+                    if ( !(c==0x0a && fp->fInputIdx>fAnchorStart && inputBuf[fp->fInputIdx-1]==0x0d)) {
                         // At new-line at end of input. Success
+                        fHitEnd = TRUE;
+                        fRequireEnd = TRUE;
+                        break;
                     }
                 }
             }
 
-            if (fp->fInputIdx == inputLen-2) {
-                if (fInput->char32At(fp->fInputIdx) == 0x0d && fInput->char32At(fp->fInputIdx+1) == 0x0a) {
+            if (fp->fInputIdx == fAnchorLimit-2 &&
+                 fInput->char32At(fp->fInputIdx) == 0x0d && fInput->char32At(fp->fInputIdx+1) == 0x0a) {
+                    fHitEnd = TRUE;
+                    fRequireEnd = TRUE;
                     break;                         // At CR/LF at end of input.  Success
-                }
             }
 
-            fp = (REStackFrame *)fStack->popFrame(frameSize);
+            fp = (REStackFrame *)fStack->popFrame(fFrameSize);
+
+            break;
+
+
+         case URX_DOLLAR_D:                   //  $, test for End of Line, in UNIX_LINES mode.
+            if (fp->fInputIdx >= fAnchorLimit-1) {
+                // Either at the last character of input, or off the end.
+                if (fp->fInputIdx == fAnchorLimit-1) {
+                    // At last char of input.  Success if it's a new line.
+                    if (fInput->char32At(fp->fInputIdx) == 0x0a) {
+                        fHitEnd = TRUE;
+                        fRequireEnd = TRUE;
+                        break;
+                    }
+                } else {
+                    // Off the end of input.  Success.
+                    fHitEnd = TRUE;
+                    fRequireEnd = TRUE;
+                    break;
+                }
+            }
 
+            // Not at end of input.  Back-track out.
+            fp = (REStackFrame *)fStack->popFrame(fFrameSize);
             break;
 
 
          case URX_DOLLAR_M:                //  $, test for End of line in multi-line mode
              {
-                 if (fp->fInputIdx >= inputLen) {
+                 if (fp->fInputIdx >= fAnchorLimit) {
                      // We really are at the end of input.  Success.
+                     fHitEnd = TRUE;
+                     fRequireEnd = TRUE;
                      break;
                  }
                  // If we are positioned just before a new-line, succeed.
                  // It makes no difference where the new-line is within the input.
                  UChar32 c = inputBuf[fp->fInputIdx];
-                 if ((c<=0x0d && c>=0x0a) || c==0x85 ||c==0x2028 || c==0x2029) {
+                 if ((c>=0x0a && c<=0x0d) || c==0x85 ||c==0x2028 || c==0x2029) {
                      // At a line end, except for the odd chance of  being in the middle of a CR/LF sequence
-                     if ( !(c==0x0a && fp->fInputIdx>0 && inputBuf[fp->fInputIdx-1]==0x0d)) {
-                        break;                         // At new-line at end of input. Success
+                     //  In multi-line mode, hitting a new-line just before the end of input does not
+                     //   set the hitEnd or requireEnd flags
+                     if ( !(c==0x0a && fp->fInputIdx>fAnchorStart && inputBuf[fp->fInputIdx-1]==0x0d)) {
+                        break;
                      }
                  }
-                 
                  // not at a new line.  Fail.
-                 fp = (REStackFrame *)fStack->popFrame(frameSize);
+                 fp = (REStackFrame *)fStack->popFrame(fFrameSize);
+             }
+             break;
+
+
+         case URX_DOLLAR_MD:                //  $, test for End of line in multi-line and UNIX_LINES mode
+             {
+                 if (fp->fInputIdx >= fAnchorLimit) {
+                     // We really are at the end of input.  Success.
+                     fHitEnd = TRUE;
+                     fRequireEnd = TRUE;  // Java set requireEnd in this case, even though
+                     break;               //   adding a new-line would not lose the match.
+                 }
+                 // If we are not positioned just before a new-line, the test fails; backtrack out.
+                 // It makes no difference where the new-line is within the input.
+                 if (inputBuf[fp->fInputIdx] != 0x0a) {
+                     fp = (REStackFrame *)fStack->popFrame(fFrameSize);
+                 }
              }
              break;
 
 
        case URX_CARET:                    //  ^, test for start of line
-            if (fp->fInputIdx != 0) {
-                fp = (REStackFrame *)fStack->popFrame(frameSize);
-            }           
+            if (fp->fInputIdx != fAnchorStart) {
+                fp = (REStackFrame *)fStack->popFrame(fFrameSize);
+            }
             break;
 
 
        case URX_CARET_M:                   //  ^, test for start of line in mulit-line mode
            {
-               if (fp->fInputIdx == 0) {
+               if (fp->fInputIdx == fAnchorStart) {
                    // We are at the start input.  Success.
                    break;
                }
                // Check whether character just before the current pos is a new-line
                //   unless we are at the end of input
                UChar  c = inputBuf[fp->fInputIdx - 1]; 
-               if ((fp->fInputIdx < inputLen) && 
+               if ((fp->fInputIdx < fAnchorLimit) && 
                    ((c<=0x0d && c>=0x0a) || c==0x85 ||c==0x2028 || c==0x2029)) {
                    //  It's a new-line.  ^ is true.  Success.
-                   break;                        
+                   //  TODO:  what should be done with positions between a CR and LF?
+                   break;
                }
                // Not at the start of a line.  Fail.
-               fp = (REStackFrame *)fStack->popFrame(frameSize);
-           }             
+               fp = (REStackFrame *)fStack->popFrame(fFrameSize);
+           }
            break;
 
 
+       case URX_CARET_M_UNIX:       //  ^, test for start of line in mulit-line + Unix-line mode
+           {
+               U_ASSERT(fp->fInputIdx >= fAnchorStart);
+               if (fp->fInputIdx <= fAnchorStart) {
+                   // We are at the start input.  Success.
+                   break;
+               }
+               // Check whether character just before the current pos is a new-line
+               U_ASSERT(fp->fInputIdx <= fAnchorLimit);
+               UChar  c = inputBuf[fp->fInputIdx - 1]; 
+               if (c != 0x0a) {
+                   // Not at the start of a line.  Back-track out.
+                   fp = (REStackFrame *)fStack->popFrame(fFrameSize);
+               }
+           }
+           break;
+
         case URX_BACKSLASH_B:          // Test for word boundaries
             {
                 UBool success = isWordBoundary(fp->fInputIdx);
                 success ^= (opValue != 0);     // flip sense for \B
                 if (!success) {
-                    fp = (REStackFrame *)fStack->popFrame(frameSize);
+                    fp = (REStackFrame *)fStack->popFrame(fFrameSize);
                 }
             }
             break;
@@ -1317,7 +1796,7 @@ void RegexMatcher::MatchAt(int32_t startIdx, UErrorCode &status) {
                 UBool success = isUWordBoundary(fp->fInputIdx);
                 success ^= (opValue != 0);     // flip sense for \B
                 if (!success) {
-                    fp = (REStackFrame *)fStack->popFrame(frameSize);
+                    fp = (REStackFrame *)fStack->popFrame(fFrameSize);
                 }
             }
             break;
@@ -1325,29 +1804,28 @@ void RegexMatcher::MatchAt(int32_t startIdx, UErrorCode &status) {
 
         case URX_BACKSLASH_D:            // Test for decimal digit
             {
-                if (fp->fInputIdx >= inputLen) {
-                    fp = (REStackFrame *)fStack->popFrame(frameSize);
+                if (fp->fInputIdx >= fActiveLimit) {
+                    fHitEnd = TRUE;
+                    fp = (REStackFrame *)fStack->popFrame(fFrameSize);
                     break;
                 }
 
-                UChar32 c = fInput->char32At(fp->fInputIdx);   
-                int8_t ctype = u_charType(c);
+                UChar32 c = fInput->char32At(fp->fInputIdx);
+                int8_t ctype = u_charType(c);     // TODO:  make a unicode set for this.  Will be faster.
                 UBool success = (ctype == U_DECIMAL_DIGIT_NUMBER);
                 success ^= (opValue != 0);        // flip sense for \D
                 if (success) {
                     fp->fInputIdx = fInput->moveIndex32(fp->fInputIdx, 1);
                 } else {
-                    fp = (REStackFrame *)fStack->popFrame(frameSize);
+                    fp = (REStackFrame *)fStack->popFrame(fFrameSize);
                 }
             }
             break;
 
 
-
-
         case URX_BACKSLASH_G:          // Test for position at end of previous match
-            if (!((fMatch && fp->fInputIdx==fMatchEnd) || fMatch==FALSE && fp->fInputIdx==0)) {
-                fp = (REStackFrame *)fStack->popFrame(frameSize);
+            if (!((fMatch && fp->fInputIdx==fMatchEnd) || fMatch==FALSE && fp->fInputIdx==fActiveStart)) {
+                fp = (REStackFrame *)fStack->popFrame(fFrameSize);
             }
             break;
 
@@ -1356,18 +1834,19 @@ void RegexMatcher::MatchAt(int32_t startIdx, UErrorCode &status) {
             //  Match a Grapheme, as defined by Unicode TR 29.
             //  Differs slightly from Perl, which consumes combining marks independently
             //    of context.
-            {                  
+            {
 
                 // Fail if at end of input
-                if (fp->fInputIdx >= inputLen) {
-                    fp = (REStackFrame *)fStack->popFrame(frameSize);
+                if (fp->fInputIdx >= fActiveLimit) {
+                    fHitEnd = TRUE;
+                    fp = (REStackFrame *)fStack->popFrame(fFrameSize);
                     break;
                 }
 
                 // Examine (and consume) the current char.
                 //   Dispatch into a little state machine, based on the char.
                 UChar32  c;
-                U16_NEXT(inputBuf, fp->fInputIdx, inputLen, c);
+                U16_NEXT(inputBuf, fp->fInputIdx, fActiveLimit, c);
                 UnicodeSet **sets = fPattern->fStaticSets;
                 if (sets[URX_GC_NORMAL]->contains(c))  goto GC_Extend;
                 if (sets[URX_GC_CONTROL]->contains(c)) goto GC_Control;
@@ -1381,8 +1860,8 @@ void RegexMatcher::MatchAt(int32_t startIdx, UErrorCode &status) {
 
 
 GC_L:
-                if (fp->fInputIdx >= inputLen)         goto GC_Done;
-                U16_NEXT(inputBuf, fp->fInputIdx, inputLen, c);
+                if (fp->fInputIdx >= fActiveLimit)         goto GC_Done;
+                U16_NEXT(inputBuf, fp->fInputIdx, fActiveLimit, c);
                 if (sets[URX_GC_L]->contains(c))       goto GC_L;
                 if (sets[URX_GC_LV]->contains(c))      goto GC_V;
                 if (sets[URX_GC_LVT]->contains(c))     goto GC_T;
@@ -1391,16 +1870,16 @@ GC_L:
                 goto GC_Extend;
 
 GC_V:
-                if (fp->fInputIdx >= inputLen)         goto GC_Done;
-                U16_NEXT(inputBuf, fp->fInputIdx, inputLen, c);
+                if (fp->fInputIdx >= fActiveLimit)         goto GC_Done;
+                U16_NEXT(inputBuf, fp->fInputIdx, fActiveLimit, c);
                 if (sets[URX_GC_V]->contains(c))       goto GC_V;
                 if (sets[URX_GC_T]->contains(c))       goto GC_T;
                 U16_PREV(inputBuf, 0, fp->fInputIdx, c);
                 goto GC_Extend;
 
 GC_T:
-                if (fp->fInputIdx >= inputLen)         goto GC_Done;
-                U16_NEXT(inputBuf, fp->fInputIdx, inputLen, c);
+                if (fp->fInputIdx >= fActiveLimit)         goto GC_Done;
+                U16_NEXT(inputBuf, fp->fInputIdx, fActiveLimit, c);
                 if (sets[URX_GC_T]->contains(c))       goto GC_T;
                 U16_PREV(inputBuf, 0, fp->fInputIdx, c);
                 goto GC_Extend;
@@ -1408,34 +1887,40 @@ GC_T:
 GC_Extend:
                 // Combining characters are consumed here
                 for (;;) {
-                    if (fp->fInputIdx >= inputLen) {
+                    if (fp->fInputIdx >= fActiveLimit) {
                         break;
                     }
-                    U16_GET(inputBuf, 0, fp->fInputIdx, inputLen, c);
+                    U16_GET(inputBuf, 0, fp->fInputIdx, fActiveLimit, c);
                     if (sets[URX_GC_EXTEND]->contains(c) == FALSE) {
                         break;
                     }
-                    U16_FWD_1(inputBuf, fp->fInputIdx, inputLen);
+                    U16_FWD_1(inputBuf, fp->fInputIdx, fActiveLimit);
                 }
                 goto GC_Done;
 
 GC_Control:
                 // Most control chars stand alone (don't combine with combining chars),  
                 //   except for that CR/LF sequence is a single grapheme cluster.
-                if (c == 0x0d && fp->fInputIdx < inputLen && inputBuf[fp->fInputIdx] == 0x0a) {
+                if (c == 0x0d && fp->fInputIdx < fActiveLimit && inputBuf[fp->fInputIdx] == 0x0a) {
                     fp->fInputIdx++;
                 }
 
 GC_Done:
+                if (fp->fInputIdx >= fActiveLimit) {
+                    fHitEnd = TRUE;
+                }
                 break;
             }
             
 
 
 
-        case URX_BACKSLASH_Z:          // Test for end of line
-            if (fp->fInputIdx < inputLen) {
-                fp = (REStackFrame *)fStack->popFrame(frameSize);
+        case URX_BACKSLASH_Z:          // Test for end of Input
+            if (fp->fInputIdx < fAnchorLimit) {
+                fp = (REStackFrame *)fStack->popFrame(fFrameSize);
+            } else {
+                fHitEnd = TRUE;
+                fRequireEnd = TRUE;
             }
             break;
 
@@ -1448,8 +1933,9 @@ GC_Done:
                 // The high bit of the op value is a flag for the match polarity.
                 //    0:   success if input char is in set.
                 //    1:   success if input char is not in set.
-                if (fp->fInputIdx >= inputLen) {
-                    fp = (REStackFrame *)fStack->popFrame(frameSize);
+                if (fp->fInputIdx >= fActiveLimit) {
+                    fHitEnd = TRUE;
+                    fp = (REStackFrame *)fStack->popFrame(fFrameSize);
                     break;
                 }
 
@@ -1457,7 +1943,7 @@ GC_Done:
                 opValue &= ~URX_NEG_SET;
                 U_ASSERT(opValue > 0 && opValue < URX_LAST_SET);
                 UChar32  c;
-                U16_NEXT(inputBuf, fp->fInputIdx, inputLen, c);
+                U16_NEXT(inputBuf, fp->fInputIdx, fActiveLimit, c);
                 if (c < 256) {
                     Regex8BitSet *s8 = &fPattern->fStaticSets8[opValue];
                     if (s8->contains(c)) {
@@ -1470,7 +1956,7 @@ GC_Done:
                     }
                 }
                 if (!success) {
-                    fp = (REStackFrame *)fStack->popFrame(frameSize);
+                    fp = (REStackFrame *)fStack->popFrame(fFrameSize);
                 }
             }
             break;
@@ -1480,14 +1966,15 @@ GC_Done:
             {
                 // Test input character for NOT being a member of  one of 
                 //    the predefined sets (Word Characters, for example)
-                if (fp->fInputIdx >= inputLen) {
-                    fp = (REStackFrame *)fStack->popFrame(frameSize);
+                if (fp->fInputIdx >= fActiveLimit) {
+                    fHitEnd = TRUE;
+                    fp = (REStackFrame *)fStack->popFrame(fFrameSize);
                     break;
                 }
 
                 U_ASSERT(opValue > 0 && opValue < URX_LAST_SET);
                 UChar32  c;
-                U16_NEXT(inputBuf, fp->fInputIdx, inputLen, c);
+                U16_NEXT(inputBuf, fp->fInputIdx, fActiveLimit, c);
                 if (c < 256) {
                     Regex8BitSet *s8 = &fPattern->fStaticSets8[opValue];
                     if (s8->contains(c) == FALSE) {
@@ -1500,71 +1987,74 @@ GC_Done:
                     }
                 }
 
-                fp = (REStackFrame *)fStack->popFrame(frameSize);
+                fp = (REStackFrame *)fStack->popFrame(fFrameSize);
             }
             break;
             
 
         case URX_SETREF:
-            if (fp->fInputIdx < inputLen) {
-                // There is input left.  Pick up one char and test it for set membership.
-                UChar32   c;
-                U16_NEXT(inputBuf, fp->fInputIdx, inputLen, c);
-                U_ASSERT(opValue > 0 && opValue < sets->size());
-                if (c<256) {
-                    Regex8BitSet *s8 = &fPattern->fSets8[opValue];
-                    if (s8->contains(c)) {
-                        break;
-                    }
-                } else {
-                    
-                    UnicodeSet *s = (UnicodeSet *)sets->elementAt(opValue);
-                    if (s->contains(c)) {
-                        // The character is in the set.  A Match.
-                        break;
-                    }
+            if (fp->fInputIdx >= fActiveLimit) {
+                fHitEnd = TRUE;
+                fp = (REStackFrame *)fStack->popFrame(fFrameSize);
+                break;
+            }
+            // There is input left.  Pick up one char and test it for set membership.
+            UChar32   c;
+            U16_NEXT(inputBuf, fp->fInputIdx, fActiveLimit, c);
+            U_ASSERT(opValue > 0 && opValue < sets->size());
+            if (c<256) {
+                Regex8BitSet *s8 = &fPattern->fSets8[opValue];
+                if (s8->contains(c)) {
+                    break;
+                }
+            } else {
+                UnicodeSet *s = (UnicodeSet *)sets->elementAt(opValue);
+                if (s->contains(c)) {
+                    // The character is in the set.  A Match.
+                    break;
                 }
-            } 
-            // Either at end of input, or the character wasn't in the set.
-            // Either way, we need to back track out.
-            fp = (REStackFrame *)fStack->popFrame(frameSize);
+            }
+            // the character wasn't in the set. Back track out.
+            fp = (REStackFrame *)fStack->popFrame(fFrameSize);
             break;
-            
+
 
         case URX_DOTANY:
             {
                 // . matches anything, but stops at end-of-line.
-                if (fp->fInputIdx >= inputLen) {
+                if (fp->fInputIdx >= fActiveLimit) {
                     // At end of input.  Match failed.  Backtrack out.
-                    fp = (REStackFrame *)fStack->popFrame(frameSize);
+                    fHitEnd = TRUE;
+                    fp = (REStackFrame *)fStack->popFrame(fFrameSize);
                     break;
                 }
                 // There is input left.  Advance over one char, unless we've hit end-of-line
                 UChar32 c;
-                U16_NEXT(inputBuf, fp->fInputIdx, inputLen, c);
+                U16_NEXT(inputBuf, fp->fInputIdx, fActiveLimit, c);
                 if (((c & 0x7f) <= 0x29) &&     // First quickly bypass as many chars as possible
                     ((c<=0x0d && c>=0x0a) || c==0x85 ||c==0x2028 || c==0x2029)) {
                     // End of line in normal mode.   . does not match.
-                        fp = (REStackFrame *)fStack->popFrame(frameSize);
+                        fp = (REStackFrame *)fStack->popFrame(fFrameSize);
                     break;
                 }
             }
             break;
-            
-            
+
+
         case URX_DOTANY_ALL:
             {
                 // ., in dot-matches-all (including new lines) mode
-                if (fp->fInputIdx >= inputLen) {
+                if (fp->fInputIdx >= fActiveLimit) {
                     // At end of input.  Match failed.  Backtrack out.
-                    fp = (REStackFrame *)fStack->popFrame(frameSize);
+                    fHitEnd = TRUE;
+                    fp = (REStackFrame *)fStack->popFrame(fFrameSize);
                     break;
                 }
                 // There is input left.  Advance over one char, except if we are
                 //   at a cr/lf, advance over both of them.
                 UChar32 c; 
-                U16_NEXT(inputBuf, fp->fInputIdx, inputLen, c);
-                if (c==0x0d) {
+                U16_NEXT(inputBuf, fp->fInputIdx, fActiveLimit, c);
+                if (c==0x0d && fp->fInputIdx < fActiveLimit) {
                     // In the case of a CR/LF, we need to advance over both.
                     UChar nextc = inputBuf[fp->fInputIdx];
                     if (nextc == 0x0a) {
@@ -1574,46 +2064,23 @@ GC_Done:
             }
             break;
 
-        case URX_DOTANY_PL:
-            // Match all up to and end-of-line or end-of-input.
+
+        case URX_DOTANY_UNIX:
             {
-                //  Fail if input already exhausted.
-                if (fp->fInputIdx >= inputLen) {
-                    fp = (REStackFrame *)fStack->popFrame(frameSize);
+                // '.' operator, matches all, but stops at end-of-line.
+                //   UNIX_LINES mode, so 0x0a is the only recognized line ending.
+                if (fp->fInputIdx >= fActiveLimit) {
+                    // At end of input.  Match failed.  Backtrack out.
+                    fHitEnd = TRUE;
+                    fp = (REStackFrame *)fStack->popFrame(fFrameSize);
                     break;
                 }
-                
-                // There is input left. Fail if we are  at the end of a line.
+                // There is input left.  Advance over one char, unless we've hit end-of-line
                 UChar32 c;
-                U16_NEXT(inputBuf, fp->fInputIdx, inputLen, c);
-                if (((c & 0x7f) <= 0x29) &&     // First quickly bypass as many chars as possible
-                    ((c<=0x0d && c>=0x0a) || c==0x85 ||c==0x2028 || c==0x2029)) {
-                    // End of line in normal mode.   . does not match.
-                    fp = (REStackFrame *)fStack->popFrame(frameSize);
-                    break;
-                }
-                
-                // There was input left.  Consume it until we hit the end of a line,
-                //   or until it's exhausted.
-                while  (fp->fInputIdx < inputLen) {
-                    U16_NEXT(inputBuf, fp->fInputIdx, inputLen, c);
-                    if (((c & 0x7f) <= 0x29) &&     // First quickly bypass as many chars as possible
-                        ((c<=0x0d && c>=0x0a) || c==0x85 ||c==0x2028 || c==0x2029)) {
-                        U16_BACK_1(inputBuf, 0, fp->fInputIdx)
-                            // Scan has reached a line-end.  We are done.
-                            break;
-                    }
-                }
-            }
-            break;
-
-        case URX_DOTANY_ALL_PL:
-            {
-                // Match up to end of input.  Fail if already at end of input.
-                if (fp->fInputIdx >= inputLen) {
-                    fp = (REStackFrame *)fStack->popFrame(frameSize);
-                } else {
-                    fp->fInputIdx = inputLen;
+                U16_NEXT(inputBuf, fp->fInputIdx, fActiveLimit, c);
+                if (c == 0x0a) {
+                    // End of line in normal mode.   '.' does not match the \n
+                    fp = (REStackFrame *)fStack->popFrame(fFrameSize);
                 }
             }
             break;
@@ -1629,8 +2096,8 @@ GC_Done:
 
         case URX_JMP_SAV:
             U_ASSERT(opValue < fPattern->fCompiledPat->size());
-            fp = StateSave(fp, fp->fPatIdx, frameSize, status);  // State save to loc following current
-            fp->fPatIdx = opValue;                               // Then JMP.
+            fp = StateSave(fp, fp->fPatIdx, status);       // State save to loc following current
+            fp->fPatIdx = opValue;                         // Then JMP.
             break;
 
         case URX_JMP_SAV_X:
@@ -1643,12 +2110,12 @@ GC_Done:
                 int32_t  stoOp = pat[opValue-1];
                 U_ASSERT(URX_TYPE(stoOp) == URX_STO_INP_LOC);
                 int32_t  frameLoc = URX_VAL(stoOp);
-                U_ASSERT(frameLoc >= 0 && frameLoc < frameSize);
+                U_ASSERT(frameLoc >= 0 && frameLoc < fFrameSize);
                 int32_t prevInputIdx = fp->fExtra[frameLoc];
                 U_ASSERT(prevInputIdx <= fp->fInputIdx);
                 if (prevInputIdx < fp->fInputIdx) {
                     // The match did make progress.  Repeat the loop.
-                    fp = StateSave(fp, fp->fPatIdx, frameSize, status);  // State save to loc following current
+                    fp = StateSave(fp, fp->fPatIdx, status);  // State save to loc following current
                     fp->fPatIdx = opValue;
                     fp->fExtra[frameLoc] = fp->fInputIdx;
                 } 
@@ -1659,7 +2126,7 @@ GC_Done:
 
         case URX_CTR_INIT:
             {
-                U_ASSERT(opValue >= 0 && opValue < frameSize-2);
+                U_ASSERT(opValue >= 0 && opValue < fFrameSize-2);
                 fp->fExtra[opValue] = 0;       //  Set the loop counter variable to zero
 
                 // Pick up the three extra operands that CTR_INIT has, and
@@ -1674,10 +2141,10 @@ GC_Done:
                 U_ASSERT(loopLoc>fp->fPatIdx);
 
                 if (minCount == 0) {
-                    fp = StateSave(fp, loopLoc+1, frameSize, status);
+                    fp = StateSave(fp, loopLoc+1, status);
                 }
                 if (maxCount == 0) {
-                    fp = (REStackFrame *)fStack->popFrame(frameSize);
+                    fp = (REStackFrame *)fStack->popFrame(fFrameSize);
                 }
             }
             break;
@@ -1700,7 +2167,7 @@ GC_Done:
                     break;
                 }
                 if (*pCounter >= minCount) {
-                    fp = StateSave(fp, fp->fPatIdx, frameSize, status);
+                    fp = StateSave(fp, fp->fPatIdx, status);
                 }
                 fp->fPatIdx = opValue + 4;    // Loop back.
             }
@@ -1708,7 +2175,8 @@ GC_Done:
 
         case URX_CTR_INIT_NG:
             {
-                U_ASSERT(opValue >= 0 && opValue < frameSize-2);
+                // Initialize a non-greedy loop
+                U_ASSERT(opValue >= 0 && opValue < fFrameSize-2);
                 fp->fExtra[opValue] = 0;       //  Set the loop counter variable to zero
 
                 // Pick up the three extra operands that CTR_INIT has, and
@@ -1724,7 +2192,7 @@ GC_Done:
 
                 if (minCount == 0) {
                     if (maxCount != 0) {
-                        fp = StateSave(fp, fp->fPatIdx, frameSize, status);
+                        fp = StateSave(fp, fp->fPatIdx, status);
                     }
                     fp->fPatIdx = loopLoc+1;   // Continue with stuff after repeated block
                 } 
@@ -1733,6 +2201,7 @@ GC_Done:
 
         case URX_CTR_LOOP_NG:
             {
+                // Non-greedy {min, max} loops
                 U_ASSERT(opValue>0 && opValue < fp->fPatIdx-2);
                 int32_t initOp = pat[opValue];
                 U_ASSERT(URX_TYPE(initOp) == URX_CTR_INIT_NG);
@@ -1762,13 +2231,11 @@ GC_Done:
                     //   Fall into the following pattern, but first do
                     //   a state save to the top of the loop, so that a failure
                     //   in the following pattern will try another iteration of the loop.
-                    fp = StateSave(fp, opValue + 4, frameSize, status);
+                    fp = StateSave(fp, opValue + 4, status);
                 }
             }
             break;
 
-            // TODO:  Possessive flavor of loop ops, or take them out if no longer needed.
-
         case URX_STO_SP:
             U_ASSERT(opValue >= 0 && opValue < fPattern->fDataSize);
             fData[opValue] = fStack->size();
@@ -1779,12 +2246,12 @@ GC_Done:
                 U_ASSERT(opValue >= 0 && opValue < fPattern->fDataSize);
                 int32_t newStackSize = fData[opValue];
                 U_ASSERT(newStackSize <= fStack->size());
-                int32_t *newFP = fStack->getBuffer() + newStackSize - frameSize;
+                int32_t *newFP = fStack->getBuffer() + newStackSize - fFrameSize;
                 if (newFP == (int32_t *)fp) {
                     break;
                 }
                 int32_t i;
-                for (i=0; i<frameSize; i++) {
+                for (i=0; i<fFrameSize; i++) {
                     newFP[i] = ((int32_t *)fp)[i];
                 }
                 fp = (REStackFrame *)newFP;
@@ -1795,14 +2262,14 @@ GC_Done:
         case URX_BACKREF:
         case URX_BACKREF_I:
             {
-                U_ASSERT(opValue < frameSize);
+                U_ASSERT(opValue < fFrameSize);
                 int32_t groupStartIdx = fp->fExtra[opValue];
                 int32_t groupEndIdx   = fp->fExtra[opValue+1];
                 U_ASSERT(groupStartIdx <= groupEndIdx);
                 int32_t len = groupEndIdx-groupStartIdx;
                 if (groupStartIdx < 0) {
                     // This capture group has not participated in the match thus far,
-                    fp = (REStackFrame *)fStack->popFrame(frameSize);   // FAIL, no match.
+                    fp = (REStackFrame *)fStack->popFrame(fFrameSize);   // FAIL, no match.
                 }
 
                 if (len == 0) {
@@ -1813,7 +2280,7 @@ GC_Done:
                     }
 
                 UBool  haveMatch = FALSE;
-                if (fp->fInputIdx + len <= inputLen) {
+                if (fp->fInputIdx + len <= fActiveLimit) {
                     if (opType == URX_BACKREF) {
                         if (u_strncmp(inputBuf+groupStartIdx, inputBuf+fp->fInputIdx, len) == 0) {
                             haveMatch = TRUE;
@@ -1824,18 +2291,22 @@ GC_Done:
                             haveMatch = TRUE;
                         }
                     }
+                } else {
+                    // TODO: probably need to do a partial string comparison, and only
+                    //       set HitEnd if the available input matched.  Ticket #6074
+                    fHitEnd = TRUE;
                 }
                 if (haveMatch) {
                     fp->fInputIdx += len;     // Match.  Advance current input position.
                 } else {
-                    fp = (REStackFrame *)fStack->popFrame(frameSize);   // FAIL, no match.
+                    fp = (REStackFrame *)fStack->popFrame(fFrameSize);   // FAIL, no match.
                 }
             }
             break;
 
         case URX_STO_INP_LOC:
             {
-                U_ASSERT(opValue >= 0 && opValue < frameSize);
+                U_ASSERT(opValue >= 0 && opValue < fFrameSize);
                 fp->fExtra[opValue] = fp->fInputIdx;
             }
             break;
@@ -1845,13 +2316,13 @@ GC_Done:
                 int32_t instrOperandLoc = fp->fPatIdx;
                 fp->fPatIdx += 1;
                 int32_t dataLoc  = URX_VAL(pat[instrOperandLoc]);
-                U_ASSERT(dataLoc >= 0 && dataLoc < frameSize);
+                U_ASSERT(dataLoc >= 0 && dataLoc < fFrameSize);
                 int32_t savedInputIdx = fp->fExtra[dataLoc];
                 U_ASSERT(savedInputIdx <= fp->fInputIdx);
                 if (savedInputIdx < fp->fInputIdx) {
                     fp->fPatIdx = opValue;                               // JMP
                 } else {
-                     fp = (REStackFrame *)fStack->popFrame(frameSize);   // FAIL, no progress in loop.
+                     fp = (REStackFrame *)fStack->popFrame(fFrameSize);   // FAIL, no progress in loop.
                 }
             }
             break;
@@ -1863,6 +2334,8 @@ GC_Done:
                 U_ASSERT(opValue>=0 && opValue+1<fPattern->fDataSize);
                 fData[opValue]   = fStack->size();
                 fData[opValue+1] = fp->fInputIdx;
+                fActiveStart     = fLookStart;          // Set the match region change for
+                fActiveLimit     = fLookLimit;          //   transparent bounds.
             }
             break;
 
@@ -1875,27 +2348,37 @@ GC_Done:
                 int32_t newStackSize = fData[opValue];
                 U_ASSERT(stackSize >= newStackSize);
                 if (stackSize > newStackSize) {
-                    int32_t *newFP = fStack->getBuffer() + newStackSize - frameSize;
+                    // Copy the current top frame back to the new (cut back) top frame.
+                    //   This makes the capture groups from within the look-ahead
+                    //   expression available.
+                    int32_t *newFP = fStack->getBuffer() + newStackSize - fFrameSize;
                     int32_t i;
-                    for (i=0; i<frameSize; i++) {
+                    for (i=0; i<fFrameSize; i++) {
                         newFP[i] = ((int32_t *)fp)[i];
                     }
                     fp = (REStackFrame *)newFP;
                     fStack->setSize(newStackSize);
                 }
                 fp->fInputIdx = fData[opValue+1];
+
+                // Restore the active region bounds in the input string; they may have
+                //    been changed because of transparent bounds on a Region.
+                fActiveStart = fRegionStart;
+                fActiveLimit = fRegionLimit;
             }
             break;
 
         case URX_ONECHAR_I:
-            if (fp->fInputIdx < inputLen) {
+            if (fp->fInputIdx < fActiveLimit) {
                 UChar32   c;
-                U16_NEXT(inputBuf, fp->fInputIdx, inputLen, c);
-                if (u_foldCase(c, U_FOLD_CASE_DEFAULT) == opValue) {           
+                U16_NEXT(inputBuf, fp->fInputIdx, fActiveLimit, c);
+                if (u_foldCase(c, U_FOLD_CASE_DEFAULT) == opValue) {
                     break;
                 }
-            } 
-            fp = (REStackFrame *)fStack->popFrame(frameSize);
+            } else {
+                fHitEnd = TRUE;
+            }
+            fp = (REStackFrame *)fStack->popFrame(fFrameSize);
             break;
 
         case URX_STRING_I:
@@ -1914,16 +2397,19 @@ GC_Done:
                 stringLen = opValue;
                 
                 int32_t stringEndIndex = fp->fInputIdx + stringLen;
-                if (stringEndIndex <= inputLen) {
+                if (stringEndIndex <= fActiveLimit) {
                     if (u_strncasecmp(inputBuf+fp->fInputIdx, litText+stringStartIdx,
                         stringLen, U_FOLD_CASE_DEFAULT) == 0) {
                         // Success.  Advance the current input position.
                         fp->fInputIdx = stringEndIndex;
                         break;
                     }
-                }                 
+                } else {
+                    // Insufficent input left for a match.
+                    fHitEnd = TRUE;    // See ticket 6074
+                }
                 // No match.  Back up matching to a saved state
-                fp = (REStackFrame *)fStack->popFrame(frameSize);
+                fp = (REStackFrame *)fStack->popFrame(fFrameSize);
             }
             break;
 
@@ -1931,6 +2417,7 @@ GC_Done:
             {
                 // Entering a look-behind block.
                 // Save Stack Ptr, Input Pos.
+                //   TODO:  implement transparent bounds.  Ticket #6067
                 U_ASSERT(opValue>=0 && opValue+1<fPattern->fDataSize);
                 fData[opValue]   = fStack->size();
                 fData[opValue+1] = fp->fInputIdx;
@@ -1938,8 +2425,8 @@ GC_Done:
                 fData[opValue+2] = -1;
                 // Save input string length, then reset to pin any matches to end at
                 //   the current position.
-                fData[opValue+3] = inputLen;
-                inputLen         = fp->fInputIdx;
+                fData[opValue+3] = fActiveLimit;
+                fActiveLimit     = fp->fInputIdx;
             }
             break;
 
@@ -1976,17 +2463,17 @@ GC_Done:
                     // We have tried all potential match starting points without
                     //  getting a match.  Backtrack out, and out of the
                     //   Look Behind altogether.
-                    fp = (REStackFrame *)fStack->popFrame(frameSize);
+                    fp = (REStackFrame *)fStack->popFrame(fFrameSize);
                     int32_t restoreInputLen = fData[opValue+3];
-                    U_ASSERT(restoreInputLen >= inputLen);
+                    U_ASSERT(restoreInputLen >= fActiveLimit);
                     U_ASSERT(restoreInputLen <= fInput->length());
-                    inputLen = restoreInputLen;
+                    fActiveLimit = restoreInputLen;
                     break;
                 }
 
                 //    Save state to this URX_LB_CONT op, so failure to match will repeat the loop.
                 //      (successful match will fall off the end of the loop.)
-                fp = StateSave(fp, fp->fPatIdx-3, frameSize, status);
+                fp = StateSave(fp, fp->fPatIdx-3, status);
                 fp->fInputIdx =  *lbStartIdx;
             }
             break;
@@ -1995,13 +2482,13 @@ GC_Done:
             // End of a look-behind block, after a successful match.
             {
                 U_ASSERT(opValue>=0 && opValue+1<fPattern->fDataSize);
-                if (fp->fInputIdx != inputLen) {
+                if (fp->fInputIdx != fActiveLimit) {
                     //  The look-behind expression matched, but the match did not
                     //    extend all the way to the point that we are looking behind from.
                     //  FAIL out of here, which will take us back to the LB_CONT, which
                     //     will retry the match starting at another position or fail
                     //     the look-behind altogether, whichever is appropriate.
-                    fp = (REStackFrame *)fStack->popFrame(frameSize);
+                    fp = (REStackFrame *)fStack->popFrame(fFrameSize);
                     break;
                 }
 
@@ -2009,9 +2496,9 @@ GC_Done:
                 //   which had been truncated to pin the end of the lookbehind match to the 
                 //   position being looked-behind.
                 int32_t originalInputLen = fData[opValue+3];
-                U_ASSERT(originalInputLen >= inputLen);
+                U_ASSERT(originalInputLen >= fActiveLimit);
                 U_ASSERT(originalInputLen <= fInput->length());
-                inputLen = originalInputLen;
+                fActiveLimit = originalInputLen;
             }
             break;
 
@@ -2051,16 +2538,16 @@ GC_Done:
                     //  getting a match, which means that the negative lookbehind as
                     //  a whole has succeeded.  Jump forward to the continue location
                     int32_t restoreInputLen = fData[opValue+3];
-                    U_ASSERT(restoreInputLen >= inputLen);
+                    U_ASSERT(restoreInputLen >= fActiveLimit);
                     U_ASSERT(restoreInputLen <= fInput->length());
-                    inputLen = restoreInputLen;
+                    fActiveLimit = restoreInputLen;
                     fp->fPatIdx = continueLoc;
                     break;
                 }
 
                 //    Save state to this URX_LB_CONT op, so failure to match will repeat the loop.
                 //      (successful match will cause a FAIL out of the loop altogether.)
-                fp = StateSave(fp, fp->fPatIdx-4, frameSize, status);
+                fp = StateSave(fp, fp->fPatIdx-4, status);
                 fp->fInputIdx =  *lbStartIdx;
             }
             break;
@@ -2069,13 +2556,13 @@ GC_Done:
             // End of a negative look-behind block, after a successful match.
             {
                 U_ASSERT(opValue>=0 && opValue+1<fPattern->fDataSize);
-                if (fp->fInputIdx != inputLen) {
+                if (fp->fInputIdx != fActiveLimit) {
                     //  The look-behind expression matched, but the match did not
                     //    extend all the way to the point that we are looking behind from.
                     //  FAIL out of here, which will take us back to the LB_CONT, which
                     //     will retry the match starting at another position or succeed
                     //     the look-behind altogether, whichever is appropriate.
-                    fp = (REStackFrame *)fStack->popFrame(frameSize);
+                    fp = (REStackFrame *)fStack->popFrame(fFrameSize);
                     break;
                 }
 
@@ -2086,9 +2573,9 @@ GC_Done:
                 //   inorder to pin the end of the lookbehind match  
                 //   to the position being looked-behind.
                 int32_t originalInputLen = fData[opValue+3];
-                U_ASSERT(originalInputLen >= inputLen);
+                U_ASSERT(originalInputLen >= fActiveLimit);
                 U_ASSERT(originalInputLen <= fInput->length());
-                inputLen = originalInputLen;
+                fActiveLimit = originalInputLen;
 
                 // Restore original stack position, discarding any state saved
                 //   by the successful pattern match.
@@ -2099,7 +2586,7 @@ GC_Done:
                 
                 //  FAIL, which will take control back to someplace 
                 //  prior to entering the look-behind test.
-                fp = (REStackFrame *)fStack->popFrame(frameSize);
+                fp = (REStackFrame *)fStack->popFrame(fFrameSize);
             }
             break;
 
@@ -2118,11 +2605,12 @@ GC_Done:
                 //   we reach a character that is not a member of the set.
                 int32_t ix = fp->fInputIdx;
                 for (;;) {
-                    if (ix >= inputLen) {
+                    if (ix >= fActiveLimit) {
+                        fHitEnd = TRUE;
                         break;
                     }
                     UChar32   c;
-                    U16_NEXT(inputBuf, ix, inputLen, c);
+                    U16_NEXT(inputBuf, ix, fActiveLimit, c);
                     if (c<256) {
                         if (s8->contains(c) == FALSE) {
                             U16_BACK_1(inputBuf, 0, ix);
@@ -2149,14 +2637,14 @@ GC_Done:
                 int32_t loopcOp = pat[fp->fPatIdx];
                 U_ASSERT(URX_TYPE(loopcOp) == URX_LOOP_C);
                 int32_t stackLoc = URX_VAL(loopcOp);
-                U_ASSERT(stackLoc >= 0 && stackLoc < frameSize);
+                U_ASSERT(stackLoc >= 0 && stackLoc < fFrameSize);
                 fp->fExtra[stackLoc] = fp->fInputIdx;
                 fp->fInputIdx = ix;
 
                 // Save State to the URX_LOOP_C op that follows this one,
                 //   so that match failures in the following code will return to there.
                 //   Then bump the pattern idx so the LOOP_C is skipped on the way out of here.
-                fp = StateSave(fp, fp->fPatIdx, frameSize, status);
+                fp = StateSave(fp, fp->fPatIdx, status);
                 fp->fPatIdx++;
             }
             break;
@@ -2168,32 +2656,37 @@ GC_Done:
             //   The following LOOP_C op emulates stack unwinding if the following pattern fails.
             {
                 // Loop through input until the input is exhausted (we reach an end-of-line)
-                // In multi-line mode, we can just go straight to the end of the input.
+                // In DOTALL mode, we can just go straight to the end of the input.
                 int32_t ix;
-                if (opValue == 1) {
-                    // Multi-line mode.
-                    ix = inputLen;
+                if ((opValue & 1) == 1) {
+                    // Dot-matches-All mode.  Jump straight to the end of the string.
+                    ix = fActiveLimit;
+                    fHitEnd = TRUE;
                 } else {
-                    // NOT multi-line mode.  Line endings do not match '.'
+                    // NOT DOT ALL mode.  Line endings do not match '.'
                     // Scan forward until a line ending or end of input.
                     ix = fp->fInputIdx;
                     for (;;) {
-                        if (ix >= inputLen) {
-                            ix = inputLen;
+                        if (ix >= fActiveLimit) {
+                            fHitEnd = TRUE;
+                            ix = fActiveLimit;
                             break;
                         }
                         UChar32   c;
-                        U16_NEXT(inputBuf, ix, inputLen, c);   // c = inputBuf[ix++]
-                        if (((c & 0x7f) <= 0x29) &&     
-                            ((c<=0x0d && c>=0x0a) || c==0x85 ||c==0x2028 || c==0x2029)) {
-                            //  char is a line ending.  Put the input pos back to the  
-                            //    line ending char, and exit the scanning loop.
-                            U16_BACK_1(inputBuf, 0, ix);
-                            break;
+                        U16_NEXT(inputBuf, ix, fActiveLimit, c);   // c = inputBuf[ix++]
+                        if ((c & 0x7f) <= 0x29) {        // Fast filter of non-new-line-s
+                            if ((c == 0x0a) ||            //  0x0a is newline in both modes.
+                               ((opValue & 2) == 0) &&    // IF not UNIX_LINES mode
+                                    (c<=0x0d && c>=0x0a) || c==0x85 ||c==0x2028 || c==0x2029) {
+                                //  char is a line ending.  Put the input pos back to the
+                                //    line ending char, and exit the scanning loop.
+                                U16_BACK_1(inputBuf, 0, ix);
+                                break;
+                            }
                         }
                     }
                 }
-                
+
                 // If there were no matching characters, skip over the loop altogether.
                 //   The loop doesn't run at all, a * op always succeeds.
                 if (ix == fp->fInputIdx) {
@@ -2203,18 +2696,18 @@ GC_Done:
 
                 // Peek ahead in the compiled pattern, to the URX_LOOP_C that
                 //   must follow.  It's operand is the stack location
-                //   that holds the starting input index for the match of this [set]*
+                //   that holds the starting input index for the match of this .*
                 int32_t loopcOp = pat[fp->fPatIdx];
                 U_ASSERT(URX_TYPE(loopcOp) == URX_LOOP_C);
                 int32_t stackLoc = URX_VAL(loopcOp);
-                U_ASSERT(stackLoc >= 0 && stackLoc < frameSize);
+                U_ASSERT(stackLoc >= 0 && stackLoc < fFrameSize);
                 fp->fExtra[stackLoc] = fp->fInputIdx;
                 fp->fInputIdx = ix;
 
                 // Save State to the URX_LOOP_C op that follows this one,
                 //   so that match failures in the following code will return to there.
                 //   Then bump the pattern idx so the LOOP_C is skipped on the way out of here.
-                fp = StateSave(fp, fp->fPatIdx, frameSize, status);
+                fp = StateSave(fp, fp->fPatIdx, status);
                 fp->fPatIdx++;
             }
             break;
@@ -2222,7 +2715,7 @@ GC_Done:
 
         case URX_LOOP_C:
             {
-                U_ASSERT(opValue>=0 && opValue<frameSize);
+                U_ASSERT(opValue>=0 && opValue<fFrameSize);
                 int32_t   terminalIdx =  fp->fExtra[opValue];
                 U_ASSERT(terminalIdx <= fp->fInputIdx);
                 if (terminalIdx == fp->fInputIdx) {
@@ -2249,7 +2742,7 @@ GC_Done:
                 }
 
 
-                fp = StateSave(fp, fp->fPatIdx-1, frameSize, status);
+                fp = StateSave(fp, fp->fPatIdx-1, status);
             }
             break;
 
@@ -2262,6 +2755,7 @@ GC_Done:
         }
 
         if (U_FAILURE(status)) {
+            isMatch = FALSE;
             break;
         }
     }