+//-----------------------------------------------------------------------------------
+//
+// handlePrevious()
+//
+// This method backs the iterator back up to a "safe position" in the text.
+// This is a position that we know, without any context, may be any position
+// not more than 2 breaks away. Occasionally, the position may be less than
+// one break away.
+// The various calling methods then iterate forward from this safe position to
+// the appropriate position to return.
+//
+// The logic of this function is very similar to handleNext(), above.
+//
+//-----------------------------------------------------------------------------------
+int32_t RuleBasedBreakIterator::handlePrevious(const RBBIStateTable *statetable) {
+ if (fText == NULL || statetable == NULL) {
+ return 0;
+ }
+ // break tag is no longer valid after icu switched to exact backwards
+ // positioning.
+ fLastStatusIndexValid = FALSE;
+ if (statetable == NULL) {
+ return fText->setToStart();
+ }
+
+ int32_t state = START_STATE;
+ int32_t category;
+ int32_t lastCategory = 0;
+ UBool hasPassedStartText = !fText->hasPrevious();
+ UChar32 c = fText->previous32();
+ // previous character
+ int32_t result = fText->getIndex();
+ int32_t lookaheadStatus = 0;
+ int32_t lookaheadResult = 0;
+ int32_t lookaheadTagIdx = 0;
+ UBool lookAheadHardBreak = (statetable->fFlags & RBBI_LOOKAHEAD_HARD_BREAK) != 0;
+
+ RBBIStateTableRow *row;
+
+ row = (RBBIStateTableRow *)
+ (statetable->fTableData + (state * statetable->fRowLen));
+ UTRIE_GET16(&fData->fTrie, c, category);
+ if ((category & 0x4000) != 0) {
+ fDictionaryCharCount++;
+ category &= ~0x4000;
+ }
+
+ if (fTrace) {
+ RBBIDebugPuts("Handle Prev pos char state category");
+ }
+
+ // loop until we reach the beginning of the text or transition to state 0
+ for (;;) {
+ // if (c == CharacterIterator::DONE && fText->hasPrevious()==FALSE) {
+ if (hasPassedStartText) {
+ // if we have already considered the start of the text
+ if (row->fLookAhead != 0 && lookaheadResult == 0) {
+ result = 0;
+ }
+ break;
+ }
+
+ // save the last character's category and look up the current
+ // character's category
+ lastCategory = category;
+ UTRIE_GET16(&fData->fTrie, c, category);
+
+ // Check the dictionary bit in the character's category.
+ // Counter is only used by dictionary based iterators.
+ //
+ if ((category & 0x4000) != 0) {
+ fDictionaryCharCount++;
+ category &= ~0x4000;
+ }
+
+ #ifdef RBBI_DEBUG
+ if (fTrace) {
+ RBBIDebugPrintf(" %4d ", fText->getIndex());
+ if (0x20<=c && c<0x7f) {
+ RBBIDebugPrintf("\"%c\" ", c);
+ } else {
+ RBBIDebugPrintf("%5x ", c);
+ }
+ RBBIDebugPrintf("%3d %3d\n", state, category);
+ }
+ #endif
+
+ // look up a state transition in the backwards state table
+ state = row->fNextState[category];
+ row = (RBBIStateTableRow *)
+ (statetable->fTableData + (state * statetable->fRowLen));
+
+ if (row->fAccepting == -1) {
+ // Match found, common case, could have lookahead so we move on to check it
+ result = fText->getIndex();
+ /// added
+ fLastRuleStatusIndex = row->fTagIdx; // Remember the break status (tag) value.
+ }
+
+ if (row->fLookAhead != 0) {
+ if (lookaheadStatus != 0
+ && row->fAccepting == lookaheadStatus) {
+ // Lookahead match is completed. Set the result accordingly, but only
+ // if no other rule has matched further in the mean time.
+ result = lookaheadResult;
+ fLastRuleStatusIndex = lookaheadTagIdx;
+ lookaheadStatus = 0;
+ /// i think we have to back up to read the lookahead character again
+ /// fText->setIndex(lookaheadResult);
+ /// TODO: this is a simple hack since reverse rules only have simple
+ /// lookahead rules that we can definitely break out from.
+ /// we need to make the lookahead rules not chain eventually.
+ /// return result;
+ /// this is going to be the longest match again
+
+ /// syn wee todo hard coded for line breaks stuff
+ /// needs to provide a tag in rules to ensure a stop.
+
+ if (lookAheadHardBreak) {
+ fText->setIndex(result);
+ return result;
+ }
+ category = lastCategory;
+ fText->setIndex(result);
+
+ goto continueOn;
+ }
+
+ int32_t r = fText->getIndex();
+ lookaheadResult = r;
+ lookaheadStatus = row->fLookAhead;
+ fLastRuleStatusIndex = row->fTagIdx;
+ goto continueOn;
+ }
+
+ // not lookahead
+ if (row->fAccepting == 0) {
+ // No match, nothing of interest happening, common case.
+ goto continueOn;
+ }
+
+ lookaheadStatus = 0; // clear out any pending look-ahead matches.
+
+continueOn:
+ if (state == STOP_STATE) {
+ break;
+ }
+
+ // then advance one character backwards
+ hasPassedStartText = !fText->hasPrevious();
+ c = fText->previous32();
+ }
+
+ // Note: the result postion isn't what is returned to the user by previous(),
+ // but where the implementation of previous() turns around and
+ // starts iterating forward again.
+ fText->setIndex(result);
+
+ return result;
+}
+
+