diff --git a/ext/intl/breakiterator/breakiterator_class.cpp b/ext/intl/breakiterator/breakiterator_class.cpp index 8c25314a4a8..633550203b8 100644 --- a/ext/intl/breakiterator/breakiterator_class.cpp +++ b/ext/intl/breakiterator/breakiterator_class.cpp @@ -20,6 +20,7 @@ #include #include +#include "codepointiterator_internal.h" #include "breakiterator_iterators.h" @@ -30,14 +31,18 @@ extern "C" { #include "breakiterator_class.h" #include "breakiterator_methods.h" #include "rulebasedbreakiterator_methods.h" +#include "codepointiterator_methods.h" #include #include #include } +using PHP::CodePointBreakIterator; + /* {{{ Global variables */ zend_class_entry *BreakIterator_ce_ptr; zend_class_entry *RuleBasedBreakIterator_ce_ptr; +zend_class_entry *CodePointBreakIterator_ce_ptr; zend_object_handlers BreakIterator_handlers; /* }}} */ @@ -49,6 +54,8 @@ U_CFUNC void breakiterator_object_create(zval *object, if (classId == RuleBasedBreakIterator::getStaticClassID()) { ce = RuleBasedBreakIterator_ce_ptr; + } else if (classId == CodePointBreakIterator::getStaticClassID()) { + ce = CodePointBreakIterator_ce_ptr; } else { ce = BreakIterator_ce_ptr; } @@ -274,6 +281,7 @@ static const zend_function_entry BreakIterator_class_functions[] = { PHP_ME_MAPPING(createCharacterInstance, breakiter_create_character_instance, ainfo_biter_locale, ZEND_ACC_STATIC | ZEND_ACC_PUBLIC) PHP_ME_MAPPING(createSentenceInstance, breakiter_create_sentence_instance, ainfo_biter_locale, ZEND_ACC_STATIC | ZEND_ACC_PUBLIC) PHP_ME_MAPPING(createTitleInstance, breakiter_create_title_instance, ainfo_biter_locale, ZEND_ACC_STATIC | ZEND_ACC_PUBLIC) + PHP_ME_MAPPING(createCodePointInstance, breakiter_create_code_point_instance, ainfo_biter_void, ZEND_ACC_STATIC | ZEND_ACC_PUBLIC) PHP_ME_MAPPING(getText, breakiter_get_text, ainfo_biter_void, ZEND_ACC_PUBLIC) PHP_ME_MAPPING(setText, breakiter_set_text, ainfo_biter_setText, ZEND_ACC_PUBLIC) PHP_ME_MAPPING(first, breakiter_first, ainfo_biter_void, ZEND_ACC_PUBLIC) @@ -305,6 +313,14 @@ static const zend_function_entry RuleBasedBreakIterator_class_functions[] = { }; /* }}} */ +/* {{{ CodePointBreakIterator_class_functions + */ +static const zend_function_entry CodePointBreakIterator_class_functions[] = { + PHP_ME_MAPPING(getLastCodePoint, cpbi_get_last_code_point, ainfo_biter_void, ZEND_ACC_PUBLIC) + PHP_FE_END +}; +/* }}} */ + /* {{{ breakiterator_register_BreakIterator_class * Initialize 'BreakIterator' class @@ -364,6 +380,12 @@ void breakiterator_register_BreakIterator_class(TSRMLS_D) INIT_CLASS_ENTRY(ce, "IntlRuleBasedBreakIterator", RuleBasedBreakIterator_class_functions); RuleBasedBreakIterator_ce_ptr = zend_register_internal_class_ex(&ce, - BreakIterator_ce_ptr, NULL TSRMLS_CC); + BreakIterator_ce_ptr, NULL TSRMLS_CC); + + /* Create and register 'CodePointBreakIterator' class. */ + INIT_CLASS_ENTRY(ce, "IntlCodePointBreakIterator", + CodePointBreakIterator_class_functions); + CodePointBreakIterator_ce_ptr = zend_register_internal_class_ex(&ce, + BreakIterator_ce_ptr, NULL TSRMLS_CC); } /* }}} */ diff --git a/ext/intl/breakiterator/breakiterator_methods.cpp b/ext/intl/breakiterator/breakiterator_methods.cpp index 5b8f859d527..e9e6b19ba3b 100644 --- a/ext/intl/breakiterator/breakiterator_methods.cpp +++ b/ext/intl/breakiterator/breakiterator_methods.cpp @@ -19,6 +19,7 @@ #endif #include +#include "codepointiterator_internal.h" #include "breakiterator_iterators.h" @@ -29,6 +30,8 @@ extern "C" { #include } +using PHP::CodePointBreakIterator; + U_CFUNC PHP_METHOD(BreakIterator, __construct) { zend_throw_exception( NULL, @@ -107,6 +110,21 @@ U_CFUNC PHP_FUNCTION(breakiter_create_title_instance) INTERNAL_FUNCTION_PARAM_PASSTHRU); } +U_CFUNC PHP_FUNCTION(breakiter_create_code_point_instance) +{ + UErrorCode status = UErrorCode(); + intl_error_reset(NULL TSRMLS_CC); + + if (zend_parse_parameters_none() == FAILURE) { + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, + "breakiter_create_code_point_instance: bad arguments", 0 TSRMLS_CC); + RETURN_NULL(); + } + + CodePointBreakIterator *cpbi = new CodePointBreakIterator(); + breakiterator_object_create(return_value, cpbi TSRMLS_CC); +} + U_CFUNC PHP_FUNCTION(breakiter_get_text) { BREAKITER_METHOD_INIT_VARS; diff --git a/ext/intl/breakiterator/breakiterator_methods.h b/ext/intl/breakiterator/breakiterator_methods.h index e0d13b0f45e..a479ac92e85 100644 --- a/ext/intl/breakiterator/breakiterator_methods.h +++ b/ext/intl/breakiterator/breakiterator_methods.h @@ -31,6 +31,8 @@ PHP_FUNCTION(breakiter_create_sentence_instance); PHP_FUNCTION(breakiter_create_title_instance); +PHP_FUNCTION(breakiter_create_code_point_instance); + PHP_FUNCTION(breakiter_get_text); PHP_FUNCTION(breakiter_set_text); diff --git a/ext/intl/breakiterator/codepointiterator_internal.cpp b/ext/intl/breakiterator/codepointiterator_internal.cpp new file mode 100644 index 00000000000..2dfae1aa4ff --- /dev/null +++ b/ext/intl/breakiterator/codepointiterator_internal.cpp @@ -0,0 +1,286 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Gustavo Lopes | + +----------------------------------------------------------------------+ + */ + +#include "codepointiterator_internal.h" +#include + +//copied from cmemory.h, which is not public +typedef union { + long t1; + double t2; + void *t3; +} UAlignedMemory; + +#define U_POINTER_MASK_LSB(ptr, mask) (((ptrdiff_t)(char *)(ptr)) & (mask)) +#define U_ALIGNMENT_OFFSET(ptr) U_POINTER_MASK_LSB(ptr, sizeof(UAlignedMemory) - 1) +#define U_ALIGNMENT_OFFSET_UP(ptr) (sizeof(UAlignedMemory) - U_ALIGNMENT_OFFSET(ptr)) + +using namespace PHP; + +UOBJECT_DEFINE_RTTI_IMPLEMENTATION(CodePointBreakIterator); + +CodePointBreakIterator::CodePointBreakIterator() +: BreakIterator(), fCharIter(NULL), lastCodePoint(U_SENTINEL) +{ + UErrorCode uec = UErrorCode(); + this->fText = utext_openUChars(NULL, NULL, 0, &uec); +} + +CodePointBreakIterator::CodePointBreakIterator(const PHP::CodePointBreakIterator &other) +: BreakIterator(other), fText(NULL), fCharIter(NULL), lastCodePoint(U_SENTINEL) +{ + *this = other; +} + +CodePointBreakIterator& CodePointBreakIterator::operator=(const CodePointBreakIterator& that) +{ + UErrorCode uec = UErrorCode(); + UText *ut_clone = NULL; + + if (this == &that) { + return *this; + } + + this->fText = utext_clone(this->fText, that.fText, FALSE, TRUE, &uec); + + //don't bother copying the character iterator, getText() is deprecated + clearCurrentCharIter(); + + this->lastCodePoint = that.lastCodePoint; + return *this; +} + +CodePointBreakIterator::~CodePointBreakIterator() +{ + if (this->fText) { + utext_close(this->fText); + } + clearCurrentCharIter(); +} + +UBool CodePointBreakIterator::operator==(const BreakIterator& that) const +{ + if (typeid(*this) != typeid(that)) { + return FALSE; + } + + const CodePointBreakIterator& that2 = + static_cast(that); + + if (!utext_equals(this->fText, that2.fText)) { + return FALSE; + } + + return TRUE; +} + +CodePointBreakIterator* CodePointBreakIterator::clone(void) const +{ + return new CodePointBreakIterator(*this); +} + +CharacterIterator& CodePointBreakIterator::getText(void) const +{ + if (this->fCharIter == NULL) { + //this method is deprecated anyway; setup bogus iterator + static const UChar c = 0; + this->fCharIter = new UCharCharacterIterator(&c, 0); + } + + return *this->fCharIter; +} + +UText *CodePointBreakIterator::getUText(UText *fillIn, UErrorCode &status) const +{ + return utext_clone(fillIn, this->fText, FALSE, TRUE, &status); +} + +void CodePointBreakIterator::setText(const UnicodeString &text) +{ + UErrorCode uec = UErrorCode(); + + //this closes the previous utext, if any + this->fText = utext_openConstUnicodeString(this->fText, &text, &uec); + + clearCurrentCharIter(); +} + +void CodePointBreakIterator::setText(UText *text, UErrorCode &status) +{ + if (U_FAILURE(status)) { + return; + } + + this->fText = utext_clone(this->fText, text, FALSE, TRUE, &status); + + clearCurrentCharIter(); +} + +void CodePointBreakIterator::adoptText(CharacterIterator* it) +{ + UErrorCode uec = UErrorCode(); + clearCurrentCharIter(); + + this->fCharIter = it; + this->fText = utext_openCharacterIterator(this->fText, it, &uec); +} + +int32_t CodePointBreakIterator::first(void) +{ + UTEXT_SETNATIVEINDEX(this->fText, 0); + this->lastCodePoint = U_SENTINEL; + + return 0; +} + +int32_t CodePointBreakIterator::last(void) +{ + int32_t pos = (int32_t)utext_nativeLength(this->fText); + UTEXT_SETNATIVEINDEX(this->fText, pos); + this->lastCodePoint = U_SENTINEL; + + return pos; +} + +int32_t CodePointBreakIterator::previous(void) +{ + this->lastCodePoint = UTEXT_PREVIOUS32(this->fText); + if (this->lastCodePoint == U_SENTINEL) { + return BreakIterator::DONE; + } + + return (int32_t)UTEXT_GETNATIVEINDEX(this->fText); +} + +int32_t CodePointBreakIterator::next(void) +{ + this->lastCodePoint = UTEXT_NEXT32(this->fText); + if (this->lastCodePoint == U_SENTINEL) { + return BreakIterator::DONE; + } + + return (int32_t)UTEXT_GETNATIVEINDEX(this->fText); +} + +int32_t CodePointBreakIterator::current(void) const +{ + return (int32_t)UTEXT_GETNATIVEINDEX(this->fText); +} + +int32_t CodePointBreakIterator::following(int32_t offset) +{ + this->lastCodePoint = utext_next32From(this->fText, offset); + if (this->lastCodePoint == U_SENTINEL) { + return BreakIterator::DONE; + } + + return (int32_t)UTEXT_GETNATIVEINDEX(this->fText); +} + +int32_t CodePointBreakIterator::preceding(int32_t offset) +{ + this->lastCodePoint = utext_previous32From(this->fText, offset); + if (this->lastCodePoint == U_SENTINEL) { + return BreakIterator::DONE; + } + + return (int32_t)UTEXT_GETNATIVEINDEX(this->fText); +} + +UBool CodePointBreakIterator::isBoundary(int32_t offset) +{ + //this function has side effects, and it's supposed to + utext_setNativeIndex(this->fText, offset); + return (offset == utext_getNativeIndex(this->fText)); +} + +int32_t CodePointBreakIterator::next(int32_t n) +{ + UBool res = utext_moveIndex32(this->fText, n); + + if (res) { + this->lastCodePoint = UTEXT_CURRENT32(this->fText); + return (int32_t)UTEXT_GETNATIVEINDEX(this->fText); + } else { + this->lastCodePoint = U_SENTINEL; + return BreakIterator::DONE; + } +} + +CodePointBreakIterator *CodePointBreakIterator::createBufferClone( + void *stackBuffer, int32_t &bufferSize, UErrorCode &status) +{ + //see implementation of RuleBasedBreakIterator::createBufferClone() + if (U_FAILURE(status)) { + return NULL; + } + + if (bufferSize <= 0) { + bufferSize = sizeof(CodePointBreakIterator) + U_ALIGNMENT_OFFSET_UP(0); + return NULL; + } + + char *buf = (char*)stackBuffer; + uint32_t s = bufferSize; + + if (stackBuffer == NULL) { + s = 0; + } + + if (U_ALIGNMENT_OFFSET(stackBuffer) != 0) { + uint32_t offsetUp = (uint32_t)U_ALIGNMENT_OFFSET_UP(buf); + s -= offsetUp; + buf += offsetUp; + } + + if (s < sizeof(CodePointBreakIterator)) { + CodePointBreakIterator *clonedBI = new CodePointBreakIterator(*this); + if (clonedBI == NULL) { + status = U_MEMORY_ALLOCATION_ERROR; + } else { + status = U_SAFECLONE_ALLOCATED_WARNING; + } + + return clonedBI; + } + + return new(buf) CodePointBreakIterator(*this); +} + +CodePointBreakIterator &CodePointBreakIterator::refreshInputText(UText *input, UErrorCode &status) +{ + //see implementation of RuleBasedBreakIterator::createBufferClone() + if (U_FAILURE(status)) { + return *this; + } + if (input == NULL) { + status = U_ILLEGAL_ARGUMENT_ERROR; + return *this; + } + + int64_t pos = utext_getNativeIndex(this->fText); + this->fText = utext_clone(this->fText, input, FALSE, TRUE, &status); + if (U_FAILURE(status)) { + return *this; + } + + utext_setNativeIndex(this->fText, pos); + if (utext_getNativeIndex(fText) != pos) { + status = U_ILLEGAL_ARGUMENT_ERROR; + } + + return *this; +} \ No newline at end of file diff --git a/ext/intl/breakiterator/codepointiterator_internal.h b/ext/intl/breakiterator/codepointiterator_internal.h new file mode 100644 index 00000000000..988b91c2009 --- /dev/null +++ b/ext/intl/breakiterator/codepointiterator_internal.h @@ -0,0 +1,98 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Gustavo Lopes | + +----------------------------------------------------------------------+ + */ + +#ifndef CODEPOINTITERATOR_INTERNAL_H +#define CODEPOINTITERATOR_INTERNAL_H + +#include + +using U_ICU_NAMESPACE::BreakIterator; + +namespace PHP { + + class CodePointBreakIterator : public BreakIterator { + + public: + static UClassID getStaticClassID(); + + CodePointBreakIterator(); + + CodePointBreakIterator(const CodePointBreakIterator &other); + + CodePointBreakIterator& operator=(const CodePointBreakIterator& that); + + virtual ~CodePointBreakIterator(); + + virtual UBool operator==(const BreakIterator& that) const; + + virtual CodePointBreakIterator* clone(void) const; + + virtual UClassID getDynamicClassID(void) const; + + virtual CharacterIterator& getText(void) const; + + virtual UText *getUText(UText *fillIn, UErrorCode &status) const; + + virtual void setText(const UnicodeString &text); + + virtual void setText(UText *text, UErrorCode &status); + + virtual void adoptText(CharacterIterator* it); + + virtual int32_t first(void); + + virtual int32_t last(void); + + virtual int32_t previous(void); + + virtual int32_t next(void); + + virtual int32_t current(void) const; + + virtual int32_t following(int32_t offset); + + virtual int32_t preceding(int32_t offset); + + virtual UBool isBoundary(int32_t offset); + + virtual int32_t next(int32_t n); + + virtual CodePointBreakIterator *createBufferClone(void *stackBuffer, + int32_t &BufferSize, + UErrorCode &status); + + virtual CodePointBreakIterator &refreshInputText(UText *input, UErrorCode &status); + + inline UChar32 getLastCodePoint() + { + return this->lastCodePoint; + } + + private: + UText *fText; + UChar32 lastCodePoint; + mutable CharacterIterator *fCharIter; + + inline void clearCurrentCharIter() + { + delete this->fCharIter; + this->fCharIter = NULL; + this->lastCodePoint = U_SENTINEL; + } + }; +} + +#endif \ No newline at end of file diff --git a/ext/intl/breakiterator/codepointiterator_methods.cpp b/ext/intl/breakiterator/codepointiterator_methods.cpp new file mode 100644 index 00000000000..ae7e526eada --- /dev/null +++ b/ext/intl/breakiterator/codepointiterator_methods.cpp @@ -0,0 +1,44 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Gustavo Lopes | + +----------------------------------------------------------------------+ + */ + +#include "codepointiterator_internal.h" + +extern "C" { +#define USE_BREAKITERATOR_POINTER 1 +#include "breakiterator_class.h" +} + +using PHP::CodePointBreakIterator; + +static inline CodePointBreakIterator *fetch_cpbi(BreakIterator_object *bio) { + return (CodePointBreakIterator*)bio->biter; +} + +U_CFUNC PHP_FUNCTION(cpbi_get_last_code_point) +{ + BREAKITER_METHOD_INIT_VARS; + object = getThis(); + + if (zend_parse_parameters_none() == FAILURE) { + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, + "cpbi_get_last_code_point: bad arguments", 0 TSRMLS_CC); + RETURN_FALSE; + } + + BREAKITER_METHOD_FETCH_OBJECT; + + RETURN_LONG(fetch_cpbi(bio)->getLastCodePoint()); +} \ No newline at end of file diff --git a/ext/intl/breakiterator/codepointiterator_methods.h b/ext/intl/breakiterator/codepointiterator_methods.h new file mode 100644 index 00000000000..d34e5b61e22 --- /dev/null +++ b/ext/intl/breakiterator/codepointiterator_methods.h @@ -0,0 +1,24 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Gustavo Lopes | + +----------------------------------------------------------------------+ + */ + +#ifndef CODEPOINTITERATOR_METHODS_H +#define CODEPOINTITERATOR_METHODS_H + +#include + +PHP_FUNCTION(cpbi_get_last_code_point); + +#endif \ No newline at end of file diff --git a/ext/intl/config.m4 b/ext/intl/config.m4 index 227368334df..d7eacbc0b41 100755 --- a/ext/intl/config.m4 +++ b/ext/intl/config.m4 @@ -79,6 +79,8 @@ if test "$PHP_INTL" != "no"; then breakiterator/breakiterator_iterators.cpp \ breakiterator/breakiterator_methods.cpp \ breakiterator/rulebasedbreakiterator_methods.cpp \ + breakiterator/codepointiterator_internal.cpp \ + breakiterator/codepointiterator_methods.cpp \ idn/idn.c \ $icu_spoof_src, $ext_shared,,$ICU_INCS -Wno-write-strings) PHP_ADD_BUILD_DIR($ext_builddir/collator) @@ -95,4 +97,5 @@ if test "$PHP_INTL" != "no"; then PHP_ADD_BUILD_DIR($ext_builddir/calendar) PHP_ADD_BUILD_DIR($ext_builddir/idn) PHP_ADD_BUILD_DIR($ext_builddir/spoofchecker) + PHP_ADD_BUILD_DIR($ext_builddir/breakiterator) fi diff --git a/ext/intl/config.w32 b/ext/intl/config.w32 index 6b7d15d56d8..a223505f8c9 100755 --- a/ext/intl/config.w32 +++ b/ext/intl/config.w32 @@ -107,7 +107,9 @@ if (PHP_INTL != "no") { breakiterator_class.cpp \ breakiterator_methods.cpp \ breakiterator_iterators.cpp \ - rulebasedbreakiterator_methods.cpp", + rulebasedbreakiterator_methods.cpp \ + codepointiterator_internal.cpp \ + codepointiterator_methods.cpp ", "intl"); ADD_FLAG("LIBS_INTL", "icudt.lib icuin.lib icuio.lib icule.lib iculx.lib"); diff --git a/ext/intl/tests/breakiter_createCodePointInstance_basic.phpt b/ext/intl/tests/breakiter_createCodePointInstance_basic.phpt new file mode 100644 index 00000000000..a43e82760cc --- /dev/null +++ b/ext/intl/tests/breakiter_createCodePointInstance_basic.phpt @@ -0,0 +1,43 @@ +--TEST-- +IntlBreakIterator::createCodePointInstance(): basic test +--SKIPIF-- +setText($text); + +print_r(iterator_to_array($codepoint_it)); + +?> +==DONE== +--EXPECT-- +string(26) "IntlCodePointBreakIterator" +Array +( + [0] => 0 + [1] => 3 + [2] => 6 + [3] => 9 + [4] => 12 + [5] => 15 + [6] => 18 + [7] => 21 + [8] => 24 + [9] => 27 + [10] => 30 + [11] => 33 + [12] => 36 + [13] => 39 + [14] => 42 + [15] => 45 +) +==DONE== diff --git a/ext/intl/tests/breakiter_createCodePointInstance_error.phpt b/ext/intl/tests/breakiter_createCodePointInstance_error.phpt new file mode 100644 index 00000000000..90228e128f6 --- /dev/null +++ b/ext/intl/tests/breakiter_createCodePointInstance_error.phpt @@ -0,0 +1,18 @@ +--TEST-- +IntlBreakIterator::createCodePointInstance(): bad arguments +--SKIPIF-- +setText($text); + +$it_clone = clone $it; +var_dump($it == $it_clone); + +$it->setText($text2 ); +var_dump($it == $it_clone); + +$it_clone->setText($text2); +var_dump($it == $it_clone); + +?> +==DONE== +--EXPECT-- +bool(true) +bool(false) +bool(true) +==DONE== diff --git a/ext/intl/tests/cpbi_getLastCodePoint_basic.phpt b/ext/intl/tests/cpbi_getLastCodePoint_basic.phpt new file mode 100644 index 00000000000..74a07a62922 --- /dev/null +++ b/ext/intl/tests/cpbi_getLastCodePoint_basic.phpt @@ -0,0 +1,82 @@ +--TEST-- +IntlCodepointBreakIterator::getLastCodePoint(): basic test +--SKIPIF-- +setText($text); + +var_dump($codepoint_it->getLastCodePoint()); +//first() and last() don't read codepoint and set the last code point var to -1 +//The pointer is after the last read codepoint if moving forward and +//before the last read codepoint is moving backwards +$p = $codepoint_it->first(); +while ($p != IntlBreakIterator::DONE) { + $c = $codepoint_it->getLastCodePoint(); + if ($c > 0) + var_dump(sprintf('U+%04X', $codepoint_it->getLastCodePoint())); + else + var_dump($c); + //it's a post-increment operation as to the codepoint, i.e., it gives the codepoint + //starting at the initial position and only then moves the pointer forward + $p = $codepoint_it->next(); +} + +echo "Now backwards\n"; +$p = $codepoint_it->last(); +while ($p != IntlBreakIterator::DONE) { + $c = $codepoint_it->getLastCodePoint(); + if ($c > 0) + var_dump(sprintf('U+%04X', $codepoint_it->getLastCodePoint())); + else + var_dump($c); + $p = $codepoint_it->previous(); +} + + +?> +==DONE== +--EXPECT-- +int(-1) +int(-1) +string(6) "U+0E15" +string(6) "U+0E31" +string(6) "U+0E27" +string(6) "U+0E2D" +string(6) "U+0E22" +string(6) "U+0E48" +string(6) "U+0E32" +string(6) "U+0E07" +string(6) "U+0E02" +string(6) "U+0E49" +string(6) "U+0E2D" +string(6) "U+0E04" +string(6) "U+0E27" +string(6) "U+0E32" +string(6) "U+0E21" +Now backwards +int(-1) +string(6) "U+0E21" +string(6) "U+0E32" +string(6) "U+0E27" +string(6) "U+0E04" +string(6) "U+0E2D" +string(6) "U+0E49" +string(6) "U+0E02" +string(6) "U+0E07" +string(6) "U+0E32" +string(6) "U+0E48" +string(6) "U+0E22" +string(6) "U+0E2D" +string(6) "U+0E27" +string(6) "U+0E31" +string(6) "U+0E15" +==DONE== diff --git a/ext/intl/tests/cpbi_getLastCodePoint_error.phpt b/ext/intl/tests/cpbi_getLastCodePoint_error.phpt new file mode 100644 index 00000000000..78bd216629b --- /dev/null +++ b/ext/intl/tests/cpbi_getLastCodePoint_error.phpt @@ -0,0 +1,19 @@ +--TEST-- +IntlBreakIterator::getLastCodePoint(): bad args +--SKIPIF-- +getLastCodePoint(array())); +--EXPECTF-- + +Warning: IntlCodePointBreakIterator::getLastCodePoint() expects exactly 0 parameters, 1 given in %s on line %d + +Warning: IntlCodePointBreakIterator::getLastCodePoint(): cpbi_get_last_code_point: bad arguments in %s on line %d +bool(false) + diff --git a/ext/intl/tests/cpbi_parts_iterator.phpt b/ext/intl/tests/cpbi_parts_iterator.phpt new file mode 100644 index 00000000000..4754c123710 --- /dev/null +++ b/ext/intl/tests/cpbi_parts_iterator.phpt @@ -0,0 +1,40 @@ +--TEST-- +IntlCodepointBreakIterator's part iterator +--SKIPIF-- +getPartsIterator(); +$it->getBreakIterator()->setText($text); + +foreach ($it as $k => $v) { + echo "$k. $v (" . sprintf("U+%04X", $it->getBreakIterator()->getLastCodePoint()) . + ") at {$it->getBreakIterator()->current()}\r\n"; +} + +?> +==DONE== +--EXPECT-- +0. ต (U+0E15) at 3 +1. ั (U+0E31) at 6 +2. ว (U+0E27) at 9 +3. อ (U+0E2D) at 12 +4. ย (U+0E22) at 15 +5. ่ (U+0E48) at 18 +6. า (U+0E32) at 21 +7. ง (U+0E07) at 24 +8. ข (U+0E02) at 27 +9. ้ (U+0E49) at 30 +10. อ (U+0E2D) at 33 +11. ค (U+0E04) at 36 +12. ว (U+0E27) at 39 +13. า (U+0E32) at 42 +14. ม (U+0E21) at 45 +==DONE==