| /* |
| ******************************************************************************* |
| * |
| * Copyright (C) 2002, International Business Machines |
| * Corporation and others. All Rights Reserved. |
| * |
| ******************************************************************************* |
| * file name: uiter.cpp |
| * encoding: US-ASCII |
| * tab size: 8 (not used) |
| * indentation:4 |
| * |
| * created on: 2002jan18 |
| * created by: Markus W. Scherer |
| */ |
| |
| #include "unicode/utypes.h" |
| #include "unicode/ustring.h" |
| #include "unicode/chariter.h" |
| #include "unicode/rep.h" |
| #include "unicode/uiter.h" |
| |
| U_CDECL_BEGIN |
| |
| /* No-Op UCharIterator implementation for illegal input --------------------- */ |
| |
| static int32_t U_CALLCONV |
| noopGetIndex(UCharIterator * /*iter*/, UCharIteratorOrigin /*origin*/) { |
| return 0; |
| } |
| |
| static int32_t U_CALLCONV |
| noopMove(UCharIterator * /*iter*/, int32_t /*delta*/, UCharIteratorOrigin /*origin*/) { |
| return 0; |
| } |
| |
| static UBool U_CALLCONV |
| noopHasNext(UCharIterator * /*iter*/) { |
| return FALSE; |
| } |
| |
| static int32_t U_CALLCONV |
| noopCurrent(UCharIterator * /*iter*/) { |
| return -1; |
| } |
| |
| static const UCharIterator noopIterator={ |
| 0, 0, 0, 0, 0, 0, |
| noopGetIndex, |
| noopMove, |
| noopHasNext, |
| noopHasNext, |
| noopCurrent, |
| noopCurrent, |
| noopCurrent, |
| 0 |
| }; |
| |
| /* UCharIterator implementation for simple strings -------------------------- */ |
| |
| /* |
| * This is an implementation of a code unit (UChar) iterator |
| * for UChar * strings. |
| * |
| * The UCharIterator.context field holds a pointer to the string. |
| */ |
| |
| static int32_t U_CALLCONV |
| stringIteratorGetIndex(UCharIterator *iter, UCharIteratorOrigin origin) { |
| switch(origin) { |
| case UITER_ZERO: |
| return 0; |
| case UITER_START: |
| return iter->start; |
| case UITER_CURRENT: |
| return iter->index; |
| case UITER_LIMIT: |
| return iter->limit; |
| case UITER_LENGTH: |
| return iter->length; |
| default: |
| /* not a valid origin */ |
| /* Should never get here! */ |
| return 0; |
| } |
| } |
| |
| static int32_t U_CALLCONV |
| stringIteratorMove(UCharIterator *iter, int32_t delta, UCharIteratorOrigin origin) { |
| int32_t pos; |
| |
| switch(origin) { |
| case UITER_ZERO: |
| pos=delta; |
| break; |
| case UITER_START: |
| pos=iter->start+delta; |
| break; |
| case UITER_CURRENT: |
| pos=iter->index+delta; |
| break; |
| case UITER_LIMIT: |
| pos=iter->limit+delta; |
| break; |
| case UITER_LENGTH: |
| pos=iter->length+delta; |
| break; |
| default: |
| /* not a valid origin, no move */ |
| /* Should never get here! */ |
| pos = iter->start; |
| break; |
| } |
| |
| if(pos<iter->start) { |
| pos=iter->start; |
| } else if(pos>iter->limit) { |
| pos=iter->limit; |
| } |
| |
| return iter->index=pos; |
| } |
| |
| static UBool U_CALLCONV |
| stringIteratorHasNext(UCharIterator *iter) { |
| return iter->index<iter->limit; |
| } |
| |
| static UBool U_CALLCONV |
| stringIteratorHasPrevious(UCharIterator *iter) { |
| return iter->index>iter->start; |
| } |
| |
| static int32_t U_CALLCONV |
| stringIteratorCurrent(UCharIterator *iter) { |
| if(iter->index<iter->limit) { |
| return ((const UChar *)(iter->context))[iter->index]; |
| } else { |
| return -1; |
| } |
| } |
| |
| static int32_t U_CALLCONV |
| stringIteratorNext(UCharIterator *iter) { |
| if(iter->index<iter->limit) { |
| return ((const UChar *)(iter->context))[iter->index++]; |
| } else { |
| return -1; |
| } |
| } |
| |
| static int32_t U_CALLCONV |
| stringIteratorPrevious(UCharIterator *iter) { |
| if(iter->index>iter->start) { |
| return ((const UChar *)(iter->context))[--iter->index]; |
| } else { |
| return -1; |
| } |
| } |
| |
| static const UCharIterator stringIterator={ |
| 0, 0, 0, 0, 0, 0, |
| stringIteratorGetIndex, |
| stringIteratorMove, |
| stringIteratorHasNext, |
| stringIteratorHasPrevious, |
| stringIteratorCurrent, |
| stringIteratorNext, |
| stringIteratorPrevious, |
| 0 |
| }; |
| |
| U_CAPI void U_EXPORT2 |
| uiter_setString(UCharIterator *iter, const UChar *s, int32_t length) { |
| if(iter!=0) { |
| if(s!=0 && length>=-1) { |
| *iter=stringIterator; |
| iter->context=s; |
| if(length>=0) { |
| iter->length=length; |
| } else { |
| iter->length=u_strlen(s); |
| } |
| iter->limit=iter->length; |
| } else { |
| *iter=noopIterator; |
| } |
| } |
| } |
| |
| /* UCharIterator wrapper around CharacterIterator --------------------------- */ |
| |
| /* |
| * This is wrapper code around a C++ CharacterIterator to |
| * look like a C UCharIterator. |
| * |
| * The UCharIterator.context field holds a pointer to the CharacterIterator. |
| */ |
| |
| static int32_t U_CALLCONV |
| characterIteratorGetIndex(UCharIterator *iter, UCharIteratorOrigin origin) { |
| switch(origin) { |
| case UITER_ZERO: |
| return 0; |
| case UITER_START: |
| return ((CharacterIterator *)(iter->context))->startIndex(); |
| case UITER_CURRENT: |
| return ((CharacterIterator *)(iter->context))->getIndex(); |
| case UITER_LIMIT: |
| return ((CharacterIterator *)(iter->context))->endIndex(); |
| case UITER_LENGTH: |
| return ((CharacterIterator *)(iter->context))->getLength(); |
| default: |
| /* not a valid origin */ |
| /* Should never get here! */ |
| return 0; |
| } |
| } |
| |
| static int32_t U_CALLCONV |
| characterIteratorMove(UCharIterator *iter, int32_t delta, UCharIteratorOrigin origin) { |
| switch(origin) { |
| case UITER_ZERO: |
| ((CharacterIterator *)(iter->context))->setIndex(delta); |
| return ((CharacterIterator *)(iter->context))->getIndex(); |
| case UITER_START: |
| case UITER_CURRENT: |
| case UITER_LIMIT: |
| return ((CharacterIterator *)(iter->context))->move(delta, (CharacterIterator::EOrigin)origin); |
| case UITER_LENGTH: |
| ((CharacterIterator *)(iter->context))->setIndex(((CharacterIterator *)(iter->context))->getLength()+delta); |
| return ((CharacterIterator *)(iter->context))->getIndex(); |
| default: |
| /* not a valid origin */ |
| /* Should never get here! */ |
| return 0; |
| } |
| } |
| |
| static UBool U_CALLCONV |
| characterIteratorHasNext(UCharIterator *iter) { |
| return ((CharacterIterator *)(iter->context))->hasNext(); |
| } |
| |
| static UBool U_CALLCONV |
| characterIteratorHasPrevious(UCharIterator *iter) { |
| return ((CharacterIterator *)(iter->context))->hasPrevious(); |
| } |
| |
| static int32_t U_CALLCONV |
| characterIteratorCurrent(UCharIterator *iter) { |
| int32_t c; |
| |
| c=((CharacterIterator *)(iter->context))->current(); |
| if(c!=0xffff || ((CharacterIterator *)(iter->context))->hasNext()) { |
| return c; |
| } else { |
| return -1; |
| } |
| } |
| |
| static int32_t U_CALLCONV |
| characterIteratorNext(UCharIterator *iter) { |
| if(((CharacterIterator *)(iter->context))->hasNext()) { |
| return ((CharacterIterator *)(iter->context))->nextPostInc(); |
| } else { |
| return -1; |
| } |
| } |
| |
| static int32_t U_CALLCONV |
| characterIteratorPrevious(UCharIterator *iter) { |
| if(((CharacterIterator *)(iter->context))->hasPrevious()) { |
| return ((CharacterIterator *)(iter->context))->previous(); |
| } else { |
| return -1; |
| } |
| } |
| |
| static const UCharIterator characterIteratorWrapper={ |
| 0, 0, 0, 0, 0, 0, |
| characterIteratorGetIndex, |
| characterIteratorMove, |
| characterIteratorHasNext, |
| characterIteratorHasPrevious, |
| characterIteratorCurrent, |
| characterIteratorNext, |
| characterIteratorPrevious, |
| 0 |
| }; |
| |
| U_CAPI void U_EXPORT2 |
| uiter_setCharacterIterator(UCharIterator *iter, CharacterIterator *charIter) { |
| if(iter!=0) { |
| if(charIter!=0) { |
| *iter=characterIteratorWrapper; |
| iter->context=charIter; |
| } else { |
| *iter=noopIterator; |
| } |
| } |
| } |
| |
| /* UCharIterator wrapper around Replaceable --------------------------------- */ |
| |
| /* |
| * This is an implementation of a code unit (UChar) iterator |
| * based on a Replaceable object. |
| * |
| * The UCharIterator.context field holds a pointer to the Replaceable. |
| * UCharIterator.length and UCharIterator.index hold Replaceable.length() |
| * and the iteration index. |
| */ |
| |
| static int32_t U_CALLCONV |
| replaceableIteratorCurrent(UCharIterator *iter) { |
| if(iter->index<iter->limit) { |
| return ((Replaceable *)(iter->context))->charAt(iter->index); |
| } else { |
| return -1; |
| } |
| } |
| |
| static int32_t U_CALLCONV |
| replaceableIteratorNext(UCharIterator *iter) { |
| if(iter->index<iter->limit) { |
| return ((Replaceable *)(iter->context))->charAt(iter->index++); |
| } else { |
| return -1; |
| } |
| } |
| |
| static int32_t U_CALLCONV |
| replaceableIteratorPrevious(UCharIterator *iter) { |
| if(iter->index>iter->start) { |
| return ((Replaceable *)(iter->context))->charAt(--iter->index); |
| } else { |
| return -1; |
| } |
| } |
| |
| static const UCharIterator replaceableIterator={ |
| 0, 0, 0, 0, 0, 0, |
| stringIteratorGetIndex, |
| stringIteratorMove, |
| stringIteratorHasNext, |
| stringIteratorHasPrevious, |
| replaceableIteratorCurrent, |
| replaceableIteratorNext, |
| replaceableIteratorPrevious, |
| 0 |
| }; |
| |
| U_CAPI void U_EXPORT2 |
| uiter_setReplaceable(UCharIterator *iter, const Replaceable *rep) { |
| if(iter!=0) { |
| if(rep!=0) { |
| *iter=replaceableIterator; |
| iter->context=rep; |
| iter->limit=iter->length=rep->length(); |
| } else { |
| *iter=noopIterator; |
| } |
| } |
| } |
| |
| /* Helper functions --------------------------------------------------------- */ |
| |
| U_CAPI int32_t U_EXPORT2 |
| uiter_current32(UCharIterator *iter) { |
| int32_t c, c2; |
| |
| c=iter->current(iter); |
| if(UTF_IS_SURROGATE(c)) { |
| if(UTF_IS_SURROGATE_FIRST(c)) { |
| /* |
| * go to the next code unit |
| * we know that we are not at the limit because c!=-1 |
| */ |
| iter->move(iter, 1, UITER_CURRENT); |
| if(UTF_IS_SECOND_SURROGATE(c2=iter->current(iter))) { |
| c=UTF16_GET_PAIR_VALUE(c, c2); |
| } |
| |
| /* undo index movement */ |
| iter->move(iter, -1, UITER_CURRENT); |
| } else { |
| if(UTF_IS_FIRST_SURROGATE(c2=iter->previous(iter))) { |
| c=UTF16_GET_PAIR_VALUE(c2, c); |
| } |
| if(c2>=0) { |
| /* undo index movement */ |
| iter->move(iter, 1, UITER_CURRENT); |
| } |
| } |
| } |
| return c; |
| } |
| |
| U_CAPI int32_t U_EXPORT2 |
| uiter_next32(UCharIterator *iter) { |
| int32_t c, c2; |
| |
| c=iter->next(iter); |
| if(UTF_IS_FIRST_SURROGATE(c)) { |
| if(UTF_IS_SECOND_SURROGATE(c2=iter->next(iter))) { |
| c=UTF16_GET_PAIR_VALUE(c, c2); |
| } else if(c2>=0) { |
| /* unmatched first surrogate, undo index movement */ |
| iter->move(iter, -1, UITER_CURRENT); |
| } |
| } |
| return c; |
| } |
| |
| U_CAPI int32_t U_EXPORT2 |
| uiter_previous32(UCharIterator *iter) { |
| int32_t c, c2; |
| |
| c=iter->previous(iter); |
| if(UTF_IS_SECOND_SURROGATE(c)) { |
| if(UTF_IS_FIRST_SURROGATE(c2=iter->previous(iter))) { |
| c=UTF16_GET_PAIR_VALUE(c2, c); |
| } else if(c2>=0) { |
| /* unmatched second surrogate, undo index movement */ |
| iter->move(iter, 1, UITER_CURRENT); |
| } |
| } |
| return c; |
| } |
| |
| U_CDECL_END |