diff options
Diffstat (limited to 'ext/intl')
272 files changed, 15622 insertions, 648 deletions
diff --git a/ext/intl/breakiterator/breakiterator_class.cpp b/ext/intl/breakiterator/breakiterator_class.cpp new file mode 100644 index 0000000000..de4bfbb7b0 --- /dev/null +++ b/ext/intl/breakiterator/breakiterator_class.cpp @@ -0,0 +1,397 @@ +/* + +----------------------------------------------------------------------+ + | 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 <cataphract@php.net> | + +----------------------------------------------------------------------+ +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <unicode/brkiter.h> +#include <unicode/rbbi.h> +#include "codepointiterator_internal.h" + +#include "breakiterator_iterators.h" + +#include <typeinfo> + +extern "C" { +#define USE_BREAKITERATOR_POINTER 1 +#include "breakiterator_class.h" +#include "breakiterator_methods.h" +#include "rulebasedbreakiterator_methods.h" +#include "codepointiterator_methods.h" +#include <zend_exceptions.h> +#include <zend_interfaces.h> +#include <assert.h> +} + +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; +/* }}} */ + +U_CFUNC void breakiterator_object_create(zval *object, + BreakIterator *biter TSRMLS_DC) +{ + UClassID classId = biter->getDynamicClassID(); + zend_class_entry *ce; + + if (classId == RuleBasedBreakIterator::getStaticClassID()) { + ce = RuleBasedBreakIterator_ce_ptr; + } else if (classId == CodePointBreakIterator::getStaticClassID()) { + ce = CodePointBreakIterator_ce_ptr; + } else { + ce = BreakIterator_ce_ptr; + } + + object_init_ex(object, ce); + breakiterator_object_construct(object, biter TSRMLS_CC); +} + +U_CFUNC void breakiterator_object_construct(zval *object, + BreakIterator *biter TSRMLS_DC) +{ + BreakIterator_object *bio; + + BREAKITER_METHOD_FETCH_OBJECT_NO_CHECK; //populate to from object + assert(bio->biter == NULL); + bio->biter = biter; +} + +/* {{{ compare handler for BreakIterator */ +static int BreakIterator_compare_objects(zval *object1, + zval *object2 TSRMLS_DC) +{ + BreakIterator_object *bio1, + *bio2; + + bio1 = (BreakIterator_object*)zend_object_store_get_object(object1 TSRMLS_CC); + bio2 = (BreakIterator_object*)zend_object_store_get_object(object2 TSRMLS_CC); + + if (bio1->biter == NULL || bio2->biter == NULL) { + return bio1->biter == bio2->biter ? 0 : 1; + } + + return *bio1->biter == *bio2->biter ? 0 : 1; +} +/* }}} */ + +/* {{{ clone handler for BreakIterator */ +static zend_object_value BreakIterator_clone_obj(zval *object TSRMLS_DC) +{ + BreakIterator_object *bio_orig, + *bio_new; + zend_object_value ret_val; + + bio_orig = (BreakIterator_object*)zend_object_store_get_object(object TSRMLS_CC); + intl_errors_reset(INTL_DATA_ERROR_P(bio_orig) TSRMLS_CC); + + ret_val = BreakIterator_ce_ptr->create_object(Z_OBJCE_P(object) TSRMLS_CC); + bio_new = (BreakIterator_object*)zend_object_store_get_object_by_handle( + ret_val.handle TSRMLS_CC); + + zend_objects_clone_members(&bio_new->zo, ret_val, + &bio_orig->zo, Z_OBJ_HANDLE_P(object) TSRMLS_CC); + + if (bio_orig->biter != NULL) { + BreakIterator *new_biter; + + new_biter = bio_orig->biter->clone(); + if (!new_biter) { + char *err_msg; + intl_errors_set_code(BREAKITER_ERROR_P(bio_orig), + U_MEMORY_ALLOCATION_ERROR TSRMLS_CC); + intl_errors_set_custom_msg(BREAKITER_ERROR_P(bio_orig), + "Could not clone BreakIterator", 0 TSRMLS_CC); + err_msg = intl_error_get_message(BREAKITER_ERROR_P(bio_orig) TSRMLS_CC); + zend_throw_exception(NULL, err_msg, 0 TSRMLS_CC); + efree(err_msg); + } else { + bio_new->biter = new_biter; + bio_new->text = bio_orig->text; + if (bio_new->text) { + zval_add_ref(&bio_new->text); + } + } + } else { + zend_throw_exception(NULL, "Cannot clone unconstructed BreakIterator", 0 TSRMLS_CC); + } + + return ret_val; +} +/* }}} */ + +/* {{{ get_debug_info handler for BreakIterator */ +static HashTable *BreakIterator_get_debug_info(zval *object, int *is_temp TSRMLS_DC) +{ + zval zv = zval_used_for_init; + BreakIterator_object *bio; + const BreakIterator *biter; + + *is_temp = 1; + + array_init_size(&zv, 8); + + bio = (BreakIterator_object*)zend_object_store_get_object(object TSRMLS_CC); + biter = bio->biter; + + if (biter == NULL) { + add_assoc_bool_ex(&zv, "valid", sizeof("valid"), 0); + return Z_ARRVAL(zv); + } + add_assoc_bool_ex(&zv, "valid", sizeof("valid"), 1); + + if (bio->text == NULL) { + add_assoc_null_ex(&zv, "text", sizeof("text")); + } else { + zval_add_ref(&bio->text); + add_assoc_zval_ex(&zv, "text", sizeof("text"), bio->text); + } + + add_assoc_string_ex(&zv, "type", sizeof("type"), + const_cast<char*>(typeid(*biter).name()), 1); + + return Z_ARRVAL(zv); +} +/* }}} */ + +/* {{{ void breakiterator_object_init(BreakIterator_object* to) + * Initialize internals of BreakIterator_object not specific to zend standard objects. + */ +static void breakiterator_object_init(BreakIterator_object *bio TSRMLS_DC) +{ + intl_error_init(BREAKITER_ERROR_P(bio) TSRMLS_CC); + bio->biter = NULL; + bio->text = NULL; +} +/* }}} */ + +/* {{{ BreakIterator_objects_dtor */ +static void BreakIterator_objects_dtor(void *object, + zend_object_handle handle TSRMLS_DC) +{ + zend_objects_destroy_object((zend_object*)object, handle TSRMLS_CC); +} +/* }}} */ + +/* {{{ BreakIterator_objects_free */ +static void BreakIterator_objects_free(zend_object *object TSRMLS_DC) +{ + BreakIterator_object* bio = (BreakIterator_object*) object; + + if (bio->text) { + zval_ptr_dtor(&bio->text); + } + if (bio->biter) { + delete bio->biter; + bio->biter = NULL; + } + intl_error_reset(BREAKITER_ERROR_P(bio) TSRMLS_CC); + + zend_object_std_dtor(&bio->zo TSRMLS_CC); + + efree(bio); +} +/* }}} */ + +/* {{{ BreakIterator_object_create */ +static zend_object_value BreakIterator_object_create(zend_class_entry *ce TSRMLS_DC) +{ + zend_object_value retval; + BreakIterator_object* intern; + + intern = (BreakIterator_object*)ecalloc(1, sizeof(BreakIterator_object)); + + zend_object_std_init(&intern->zo, ce TSRMLS_CC); +#if PHP_VERSION_ID < 50399 + zend_hash_copy(intern->zo.properties, &(ce->default_properties), + (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval*)); +#else + object_properties_init((zend_object*) intern, ce); +#endif + breakiterator_object_init(intern TSRMLS_CC); + + retval.handle = zend_objects_store_put( + intern, + BreakIterator_objects_dtor, + (zend_objects_free_object_storage_t) BreakIterator_objects_free, + NULL TSRMLS_CC); + + retval.handlers = &BreakIterator_handlers; + + return retval; +} +/* }}} */ + +/* {{{ BreakIterator/RuleBasedBreakIterator methods arguments info */ + +ZEND_BEGIN_ARG_INFO_EX(ainfo_biter_void, 0, 0, 0) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(ainfo_biter_locale, 0, 0, 0) + ZEND_ARG_INFO(0, "locale") +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(ainfo_biter_setText, 0, 0, 1) + ZEND_ARG_INFO(0, "text") +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(ainfo_biter_next, 0, 0, 0) + ZEND_ARG_INFO(0, "offset") +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(ainfo_biter_offset, 0, 0, 1) + ZEND_ARG_INFO(0, "offset") +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(ainfo_biter_get_locale, 0, 0, 1) + ZEND_ARG_INFO(0, "locale_type") +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(ainfo_biter_getPartsIterator, 0, 0, 0) + ZEND_ARG_INFO(0, "key_type") +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(ainfo_rbbi___construct, 0, 0, 1) + ZEND_ARG_INFO(0, "rules") + ZEND_ARG_INFO(0, "areCompiled") +ZEND_END_ARG_INFO() + +/* }}} */ + +/* {{{ BreakIterator_class_functions + * Every 'BreakIterator' class method has an entry in this table + */ +static const zend_function_entry BreakIterator_class_functions[] = { + PHP_ME(BreakIterator, __construct, ainfo_biter_void, ZEND_ACC_PRIVATE) + PHP_ME_MAPPING(createWordInstance, breakiter_create_word_instance, ainfo_biter_locale, ZEND_ACC_STATIC | ZEND_ACC_PUBLIC) + PHP_ME_MAPPING(createLineInstance, breakiter_create_line_instance, ainfo_biter_locale, ZEND_ACC_STATIC | ZEND_ACC_PUBLIC) + 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) + PHP_ME_MAPPING(last, breakiter_last, ainfo_biter_void, ZEND_ACC_PUBLIC) + PHP_ME_MAPPING(previous, breakiter_previous, ainfo_biter_void, ZEND_ACC_PUBLIC) + PHP_ME_MAPPING(next, breakiter_next, ainfo_biter_next, ZEND_ACC_PUBLIC) + PHP_ME_MAPPING(current, breakiter_current, ainfo_biter_void, ZEND_ACC_PUBLIC) + PHP_ME_MAPPING(following, breakiter_following, ainfo_biter_offset, ZEND_ACC_PUBLIC) + PHP_ME_MAPPING(preceding, breakiter_preceding, ainfo_biter_offset, ZEND_ACC_PUBLIC) + PHP_ME_MAPPING(isBoundary, breakiter_is_boundary, ainfo_biter_offset, ZEND_ACC_PUBLIC) + PHP_ME_MAPPING(getLocale, breakiter_get_locale, ainfo_biter_void, ZEND_ACC_PUBLIC) + PHP_ME_MAPPING(getPartsIterator, breakiter_get_parts_iterator, ainfo_biter_getPartsIterator, ZEND_ACC_PUBLIC) + + PHP_ME_MAPPING(getErrorCode, breakiter_get_error_code, ainfo_biter_void, ZEND_ACC_PUBLIC) + PHP_ME_MAPPING(getErrorMessage, breakiter_get_error_message, ainfo_biter_void, ZEND_ACC_PUBLIC) + PHP_FE_END +}; +/* }}} */ + +/* {{{ RuleBasedBreakIterator_class_functions + */ +static const zend_function_entry RuleBasedBreakIterator_class_functions[] = { + PHP_ME(IntlRuleBasedBreakIterator, __construct, ainfo_rbbi___construct, ZEND_ACC_PUBLIC) + PHP_ME_MAPPING(getRules, rbbi_get_rules, ainfo_biter_void, ZEND_ACC_PUBLIC) + PHP_ME_MAPPING(getRuleStatus, rbbi_get_rule_status, ainfo_biter_void, ZEND_ACC_PUBLIC) + PHP_ME_MAPPING(getRuleStatusVec, rbbi_get_rule_status_vec, ainfo_biter_void, ZEND_ACC_PUBLIC) +#if U_ICU_VERSION_MAJOR_NUM * 10 + U_ICU_VERSION_MINOR_NUM >= 48 + PHP_ME_MAPPING(getBinaryRules, rbbi_get_binary_rules, ainfo_biter_void, ZEND_ACC_PUBLIC) +#endif + PHP_FE_END +}; +/* }}} */ + +/* {{{ 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 + */ +U_CFUNC void breakiterator_register_BreakIterator_class(TSRMLS_D) +{ + zend_class_entry ce; + + /* Create and register 'BreakIterator' class. */ + INIT_CLASS_ENTRY(ce, "IntlBreakIterator", BreakIterator_class_functions); + ce.create_object = BreakIterator_object_create; + ce.get_iterator = _breakiterator_get_iterator; + BreakIterator_ce_ptr = zend_register_internal_class(&ce TSRMLS_CC); + + memcpy(&BreakIterator_handlers, zend_get_std_object_handlers(), + sizeof BreakIterator_handlers); + BreakIterator_handlers.compare_objects = BreakIterator_compare_objects; + BreakIterator_handlers.clone_obj = BreakIterator_clone_obj; + BreakIterator_handlers.get_debug_info = BreakIterator_get_debug_info; + + zend_class_implements(BreakIterator_ce_ptr TSRMLS_CC, 1, + zend_ce_traversable); + + zend_declare_class_constant_long(BreakIterator_ce_ptr, + "DONE", sizeof("DONE") - 1, BreakIterator::DONE TSRMLS_CC ); + + /* Declare constants that are defined in the C header */ +#define BREAKITER_DECL_LONG_CONST(name) \ + zend_declare_class_constant_long(BreakIterator_ce_ptr, #name, \ + sizeof(#name) - 1, UBRK_ ## name TSRMLS_CC) + + BREAKITER_DECL_LONG_CONST(WORD_NONE); + BREAKITER_DECL_LONG_CONST(WORD_NONE_LIMIT); + BREAKITER_DECL_LONG_CONST(WORD_NUMBER); + BREAKITER_DECL_LONG_CONST(WORD_NUMBER_LIMIT); + BREAKITER_DECL_LONG_CONST(WORD_LETTER); + BREAKITER_DECL_LONG_CONST(WORD_LETTER_LIMIT); + BREAKITER_DECL_LONG_CONST(WORD_KANA); + BREAKITER_DECL_LONG_CONST(WORD_KANA_LIMIT); + BREAKITER_DECL_LONG_CONST(WORD_IDEO); + BREAKITER_DECL_LONG_CONST(WORD_IDEO_LIMIT); + + BREAKITER_DECL_LONG_CONST(LINE_SOFT); + BREAKITER_DECL_LONG_CONST(LINE_SOFT_LIMIT); + BREAKITER_DECL_LONG_CONST(LINE_HARD); + BREAKITER_DECL_LONG_CONST(LINE_HARD_LIMIT); + + BREAKITER_DECL_LONG_CONST(SENTENCE_TERM); + BREAKITER_DECL_LONG_CONST(SENTENCE_TERM_LIMIT); + BREAKITER_DECL_LONG_CONST(SENTENCE_SEP); + BREAKITER_DECL_LONG_CONST(SENTENCE_SEP_LIMIT); + +#undef BREAKITER_DECL_LONG_CONST + + + /* Create and register 'RuleBasedBreakIterator' class. */ + INIT_CLASS_ENTRY(ce, "IntlRuleBasedBreakIterator", + RuleBasedBreakIterator_class_functions); + RuleBasedBreakIterator_ce_ptr = zend_register_internal_class_ex(&ce, + 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_class.h b/ext/intl/breakiterator/breakiterator_class.h new file mode 100644 index 0000000000..cc5d51256f --- /dev/null +++ b/ext/intl/breakiterator/breakiterator_class.h @@ -0,0 +1,71 @@ +/* + +----------------------------------------------------------------------+ + | 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 <cataphract@php.net> | + +----------------------------------------------------------------------+ + */ + +#ifndef BREAKITERATOR_CLASS_H +#define BREAKITERATOR_CLASS_H + +//redefinition of inline in PHP headers causes problems, so include this before +#include <math.h> + +#include <php.h> +#include "../intl_error.h" +#include "../intl_data.h" + +#ifndef USE_BREAKITERATOR_POINTER +typedef void BreakIterator; +#endif + +typedef struct { + zend_object zo; + + // error handling + intl_error err; + + // ICU break iterator + BreakIterator* biter; + + // current text + zval *text; +} BreakIterator_object; + +#define BREAKITER_ERROR(bio) (bio)->err +#define BREAKITER_ERROR_P(bio) &(BREAKITER_ERROR(bio)) + +#define BREAKITER_ERROR_CODE(bio) INTL_ERROR_CODE(BREAKITER_ERROR(bio)) +#define BREAKITER_ERROR_CODE_P(bio) &(INTL_ERROR_CODE(BREAKITER_ERROR(bio))) + +#define BREAKITER_METHOD_INIT_VARS INTL_METHOD_INIT_VARS(BreakIterator, bio) +#define BREAKITER_METHOD_FETCH_OBJECT_NO_CHECK INTL_METHOD_FETCH_OBJECT(BreakIterator, bio) +#define BREAKITER_METHOD_FETCH_OBJECT \ + BREAKITER_METHOD_FETCH_OBJECT_NO_CHECK; \ + if (bio->biter == NULL) \ + { \ + intl_errors_set(&bio->err, U_ILLEGAL_ARGUMENT_ERROR, "Found unconstructed BreakIterator", 0 TSRMLS_CC); \ + RETURN_FALSE; \ + } + +void breakiterator_object_create(zval *object, BreakIterator *break_iter TSRMLS_DC); + +void breakiterator_object_construct(zval *object, BreakIterator *break_iter TSRMLS_DC); + +void breakiterator_register_BreakIterator_class(TSRMLS_D); + +extern zend_class_entry *BreakIterator_ce_ptr, + *RuleBasedBreakIterator_ce_ptr; + +extern zend_object_handlers BreakIterator_handlers; + +#endif /* #ifndef BREAKITERATOR_CLASS_H */ diff --git a/ext/intl/breakiterator/breakiterator_iterators.cpp b/ext/intl/breakiterator/breakiterator_iterators.cpp new file mode 100644 index 0000000000..d88ad8a712 --- /dev/null +++ b/ext/intl/breakiterator/breakiterator_iterators.cpp @@ -0,0 +1,346 @@ +/* + +----------------------------------------------------------------------+ + | 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 <cataphract@php.net> | + +----------------------------------------------------------------------+ +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <unicode/brkiter.h> + +#include "breakiterator_iterators.h" +#include "../common/common_enum.h" + +extern "C" { +#define USE_BREAKITERATOR_POINTER +#include "breakiterator_class.h" +#include "../intl_convert.h" +#include "../locale/locale.h" +#include <zend_exceptions.h> +} + +static zend_class_entry *IntlPartsIterator_ce_ptr; +static zend_object_handlers IntlPartsIterator_handlers; + +/* BreakIterator's iterator */ + +inline BreakIterator *_breakiter_prolog(zend_object_iterator *iter TSRMLS_DC) +{ + BreakIterator_object *bio; + bio = (BreakIterator_object*)zend_object_store_get_object( + (const zval*)iter->data TSRMLS_CC); + intl_errors_reset(BREAKITER_ERROR_P(bio) TSRMLS_CC); + if (bio->biter == NULL) { + intl_errors_set(BREAKITER_ERROR_P(bio), U_INVALID_STATE_ERROR, + "The BreakIterator object backing the PHP iterator is not " + "properly constructed", 0 TSRMLS_CC); + } + return bio->biter; +} + +static void _breakiterator_destroy_it(zend_object_iterator *iter TSRMLS_DC) +{ + zval_ptr_dtor((zval**)&iter->data); +} + +static void _breakiterator_move_forward(zend_object_iterator *iter TSRMLS_DC) +{ + BreakIterator *biter = _breakiter_prolog(iter TSRMLS_CC); + zoi_with_current *zoi_iter = (zoi_with_current*)iter; + + iter->funcs->invalidate_current(iter TSRMLS_CC); + + if (biter == NULL) { + return; + } + + int32_t pos = biter->next(); + if (pos != BreakIterator::DONE) { + MAKE_STD_ZVAL(zoi_iter->current); + ZVAL_LONG(zoi_iter->current, (long)pos); + } //else we've reached the end of the enum, nothing more is required +} + +static void _breakiterator_rewind(zend_object_iterator *iter TSRMLS_DC) +{ + BreakIterator *biter = _breakiter_prolog(iter TSRMLS_CC); + zoi_with_current *zoi_iter = (zoi_with_current*)iter; + + int32_t pos = biter->first(); + MAKE_STD_ZVAL(zoi_iter->current); + ZVAL_LONG(zoi_iter->current, (long)pos); +} + +static zend_object_iterator_funcs breakiterator_iterator_funcs = { + zoi_with_current_dtor, + zoi_with_current_valid, + zoi_with_current_get_current_data, + NULL, + _breakiterator_move_forward, + _breakiterator_rewind, + zoi_with_current_invalidate_current +}; + +U_CFUNC zend_object_iterator *_breakiterator_get_iterator( + zend_class_entry *ce, zval *object, int by_ref TSRMLS_DC) +{ + BreakIterator_object *bio; + if (by_ref) { + zend_throw_exception(NULL, + "Iteration by reference is not supported", 0 TSRMLS_CC); + return NULL; + } + + bio = (BreakIterator_object*)zend_object_store_get_object(object TSRMLS_CC); + BreakIterator *biter = bio->biter; + + if (biter == NULL) { + zend_throw_exception(NULL, + "The BreakIterator is not properly constructed", 0 TSRMLS_CC); + return NULL; + } + + zoi_with_current *zoi_iter = + static_cast<zoi_with_current*>(emalloc(sizeof *zoi_iter)); + zoi_iter->zoi.data = static_cast<void*>(object); + zoi_iter->zoi.funcs = &breakiterator_iterator_funcs; + zoi_iter->zoi.index = 0; + zoi_iter->destroy_it = _breakiterator_destroy_it; + zoi_iter->wrapping_obj = NULL; /* not used; object is in zoi.data */ + zoi_iter->current = NULL; + + zval_add_ref(&object); + + return reinterpret_cast<zend_object_iterator *>(zoi_iter); +} + +/* BreakIterator parts iterator */ + +typedef struct zoi_break_iter_parts { + zoi_with_current zoi_cur; + parts_iter_key_type key_type; + BreakIterator_object *bio; /* so we don't have to fetch it all the time */ +} zoi_break_iter_parts; + +static void _breakiterator_parts_destroy_it(zend_object_iterator *iter TSRMLS_DC) +{ + zval_ptr_dtor(reinterpret_cast<zval**>(&iter->data)); +} + +static int _breakiterator_parts_get_current_key(zend_object_iterator *iter, + char **str_key, + uint *str_key_len, + ulong *int_key TSRMLS_DC) +{ + /* the actual work is done in move_forward and rewind */ + *int_key = iter->index; + return HASH_KEY_IS_LONG; +} + +static void _breakiterator_parts_move_forward(zend_object_iterator *iter TSRMLS_DC) +{ + zoi_break_iter_parts *zoi_bit = (zoi_break_iter_parts*)iter; + BreakIterator_object *bio = zoi_bit->bio; + + iter->funcs->invalidate_current(iter TSRMLS_CC); + + int32_t cur, + next; + + cur = bio->biter->current(); + if (cur == BreakIterator::DONE) { + return; + } + next = bio->biter->next(); + if (next == BreakIterator::DONE) { + return; + } + + if (zoi_bit->key_type == PARTS_ITERATOR_KEY_LEFT) { + iter->index = cur; + } else if (zoi_bit->key_type == PARTS_ITERATOR_KEY_RIGHT) { + iter->index = next; + } + /* else zoi_bit->key_type == PARTS_ITERATOR_KEY_SEQUENTIAL + * No need to do anything, the engine increments ->index */ + + const char *s = Z_STRVAL_P(bio->text); + int32_t slen = Z_STRLEN_P(bio->text), + len; + char *res; + + if (next == BreakIterator::DONE) { + next = slen; + } + assert(next <= slen && next >= cur); + len = next - cur; + res = static_cast<char*>(emalloc(len + 1)); + + memcpy(res, &s[cur], len); + res[len] = '\0'; + + MAKE_STD_ZVAL(zoi_bit->zoi_cur.current); + ZVAL_STRINGL(zoi_bit->zoi_cur.current, res, len, 0); +} + +static void _breakiterator_parts_rewind(zend_object_iterator *iter TSRMLS_DC) +{ + zoi_break_iter_parts *zoi_bit = (zoi_break_iter_parts*)iter; + BreakIterator_object *bio = zoi_bit->bio; + + if (zoi_bit->zoi_cur.current) { + iter->funcs->invalidate_current(iter TSRMLS_CC); + } + + bio->biter->first(); + + iter->funcs->move_forward(iter TSRMLS_CC); +} + +static zend_object_iterator_funcs breakiterator_parts_it_funcs = { + zoi_with_current_dtor, + zoi_with_current_valid, + zoi_with_current_get_current_data, + _breakiterator_parts_get_current_key, + _breakiterator_parts_move_forward, + _breakiterator_parts_rewind, + zoi_with_current_invalidate_current +}; + +void IntlIterator_from_BreakIterator_parts(zval *break_iter_zv, + zval *object, + parts_iter_key_type key_type TSRMLS_DC) +{ + IntlIterator_object *ii; + + zval_add_ref(&break_iter_zv); + + object_init_ex(object, IntlPartsIterator_ce_ptr); + ii = (IntlIterator_object*)zend_object_store_get_object(object TSRMLS_CC); + + ii->iterator = (zend_object_iterator*)emalloc(sizeof(zoi_break_iter_parts)); + ii->iterator->data = break_iter_zv; + ii->iterator->funcs = &breakiterator_parts_it_funcs; + ii->iterator->index = 0; + ((zoi_with_current*)ii->iterator)->destroy_it = _breakiterator_parts_destroy_it; + ((zoi_with_current*)ii->iterator)->wrapping_obj = object; + ((zoi_with_current*)ii->iterator)->current = NULL; + + ((zoi_break_iter_parts*)ii->iterator)->bio = (BreakIterator_object*) + zend_object_store_get_object(break_iter_zv TSRMLS_CC); + assert(((zoi_break_iter_parts*)ii->iterator)->bio->biter != NULL); + ((zoi_break_iter_parts*)ii->iterator)->key_type = key_type; +} + +U_CFUNC zend_object_value IntlPartsIterator_object_create(zend_class_entry *ce TSRMLS_DC) +{ + zend_object_value retval; + + retval = IntlIterator_ce_ptr->create_object(ce TSRMLS_CC); + retval.handlers = &IntlPartsIterator_handlers; + + return retval; +} + +U_CFUNC zend_function *IntlPartsIterator_get_method(zval **object_ptr, + char *method, int method_len, const zend_literal *key TSRMLS_DC) +{ + zend_literal local_literal = {0}; + zend_function *ret; + ALLOCA_FLAG(use_heap) + + if (key == NULL) { + Z_STRVAL(local_literal.constant) = static_cast<char*>( + do_alloca(method_len + 1, use_heap)); + zend_str_tolower_copy(Z_STRVAL(local_literal.constant), + method, method_len); + local_literal.hash_value = zend_hash_func( + Z_STRVAL(local_literal.constant), method_len + 1); + key = &local_literal; + } + + if ((key->hash_value & 0xFFFFFFFF) == 0xA2B486A1 /* hash of getrulestatus\0 */ + && method_len == sizeof("getrulestatus") - 1 + && memcmp("getrulestatus", Z_STRVAL(key->constant), method_len) == 0) { + IntlIterator_object *obj = (IntlIterator_object*) + zend_object_store_get_object(*object_ptr TSRMLS_CC); + if (obj->iterator && obj->iterator->data) { + zval *break_iter_zv = static_cast<zval*>(obj->iterator->data); + *object_ptr = break_iter_zv; + ret = Z_OBJ_HANDLER_P(break_iter_zv, get_method)(object_ptr, + method, method_len, key TSRMLS_CC); + goto end; + } + } + + ret = std_object_handlers.get_method(object_ptr, + method, method_len, key TSRMLS_CC); + +end: + if (key == &local_literal) { + free_alloca(Z_STRVAL(local_literal.constant), use_heap); + } + + return ret; +} + +U_CFUNC PHP_METHOD(IntlPartsIterator, getBreakIterator) +{ + INTLITERATOR_METHOD_INIT_VARS; + + if (zend_parse_parameters_none() == FAILURE) { + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, + "IntlPartsIterator::getBreakIterator: bad arguments", 0 TSRMLS_CC); + return; + } + + INTLITERATOR_METHOD_FETCH_OBJECT; + + zval *biter_zval = static_cast<zval*>(ii->iterator->data); + RETURN_ZVAL(biter_zval, 1, 0); +} + +ZEND_BEGIN_ARG_INFO_EX(ainfo_parts_it_void, 0, 0, 0) +ZEND_END_ARG_INFO() + +static const zend_function_entry IntlPartsIterator_class_functions[] = { + PHP_ME(IntlPartsIterator, getBreakIterator, ainfo_parts_it_void, ZEND_ACC_PUBLIC) + PHP_FE_END +}; + +U_CFUNC void breakiterator_register_IntlPartsIterator_class(TSRMLS_D) +{ + zend_class_entry ce; + + /* Create and register 'BreakIterator' class. */ + INIT_CLASS_ENTRY(ce, "IntlPartsIterator", IntlPartsIterator_class_functions); + IntlPartsIterator_ce_ptr = zend_register_internal_class_ex(&ce, + IntlIterator_ce_ptr, NULL TSRMLS_CC); + IntlPartsIterator_ce_ptr->create_object = IntlPartsIterator_object_create; + + memcpy(&IntlPartsIterator_handlers, &IntlIterator_handlers, + sizeof IntlPartsIterator_handlers); + IntlPartsIterator_handlers.get_method = IntlPartsIterator_get_method; + +#define PARTSITER_DECL_LONG_CONST(name) \ + zend_declare_class_constant_long(IntlPartsIterator_ce_ptr, #name, \ + sizeof(#name) - 1, PARTS_ITERATOR_ ## name TSRMLS_CC) + + PARTSITER_DECL_LONG_CONST(KEY_SEQUENTIAL); + PARTSITER_DECL_LONG_CONST(KEY_LEFT); + PARTSITER_DECL_LONG_CONST(KEY_RIGHT); + +#undef PARTSITER_DECL_LONG_CONST +}
\ No newline at end of file diff --git a/ext/intl/breakiterator/breakiterator_iterators.h b/ext/intl/breakiterator/breakiterator_iterators.h new file mode 100644 index 0000000000..7162072414 --- /dev/null +++ b/ext/intl/breakiterator/breakiterator_iterators.h @@ -0,0 +1,42 @@ +/* + +----------------------------------------------------------------------+ + | 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 <cataphract@php.net> | + +----------------------------------------------------------------------+ +*/ +#ifndef INTL_BREAKITERATOR_ITERATORS_H +#define INTL_BREAKITERATOR_ITERATORS_H + +#include <unicode/umachine.h> + +U_CDECL_BEGIN +#include <math.h> +#include <php.h> +U_CDECL_END + +typedef enum { + PARTS_ITERATOR_KEY_SEQUENTIAL, + PARTS_ITERATOR_KEY_LEFT, + PARTS_ITERATOR_KEY_RIGHT, +} parts_iter_key_type; + +#ifdef __cplusplus +void IntlIterator_from_BreakIterator_parts(zval *break_iter_zv, + zval *object, + parts_iter_key_type key_type TSRMLS_DC); +#endif + +U_CFUNC zend_object_iterator *_breakiterator_get_iterator( + zend_class_entry *ce, zval *object, int by_ref TSRMLS_DC); +U_CFUNC void breakiterator_register_IntlPartsIterator_class(TSRMLS_D); + +#endif
\ No newline at end of file diff --git a/ext/intl/breakiterator/breakiterator_methods.cpp b/ext/intl/breakiterator/breakiterator_methods.cpp new file mode 100644 index 0000000000..6a61f8cb93 --- /dev/null +++ b/ext/intl/breakiterator/breakiterator_methods.cpp @@ -0,0 +1,452 @@ +/* + +----------------------------------------------------------------------+ + | 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 <cataphract@php.net> | + +----------------------------------------------------------------------+ +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <unicode/brkiter.h> +#include "codepointiterator_internal.h" + +#include "breakiterator_iterators.h" + +extern "C" { +#include "../php_intl.h" +#define USE_BREAKITERATOR_POINTER 1 +#include "breakiterator_class.h" +#include "../locale/locale.h" +#include <zend_exceptions.h> +} + +using PHP::CodePointBreakIterator; + +U_CFUNC PHP_METHOD(BreakIterator, __construct) +{ + zend_throw_exception( NULL, + "An object of this type cannot be created with the new operator", + 0 TSRMLS_CC ); +} + +static void _breakiter_factory(const char *func_name, + BreakIterator *(*func)(const Locale&, UErrorCode&), + INTERNAL_FUNCTION_PARAMETERS) +{ + BreakIterator *biter; + const char *locale_str = NULL; + int dummy; + char *msg; + UErrorCode status = UErrorCode(); + intl_error_reset(NULL TSRMLS_CC); + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s!", + &locale_str, &dummy) == FAILURE) { + spprintf(&msg, NULL, "%s: bad arguments", func_name); + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, msg, 1 TSRMLS_CC); + efree(msg); + RETURN_NULL(); + } + + if (locale_str == NULL) { + locale_str = intl_locale_get_default(TSRMLS_C); + } + + biter = func(Locale::createFromName(locale_str), status); + intl_error_set_code(NULL, status TSRMLS_CC); + if (U_FAILURE(status)) { + spprintf(&msg, NULL, "%s: error creating BreakIterator", + func_name); + intl_error_set_custom_msg(NULL, msg, 1 TSRMLS_CC); + efree(msg); + RETURN_NULL(); + } + + breakiterator_object_create(return_value, biter TSRMLS_CC); +} + +U_CFUNC PHP_FUNCTION(breakiter_create_word_instance) +{ + _breakiter_factory("breakiter_create_word_instance", + &BreakIterator::createWordInstance, + INTERNAL_FUNCTION_PARAM_PASSTHRU); +} + +U_CFUNC PHP_FUNCTION(breakiter_create_line_instance) +{ + _breakiter_factory("breakiter_create_line_instance", + &BreakIterator::createLineInstance, + INTERNAL_FUNCTION_PARAM_PASSTHRU); +} + +U_CFUNC PHP_FUNCTION(breakiter_create_character_instance) +{ + _breakiter_factory("breakiter_create_character_instance", + &BreakIterator::createCharacterInstance, + INTERNAL_FUNCTION_PARAM_PASSTHRU); +} + +U_CFUNC PHP_FUNCTION(breakiter_create_sentence_instance) +{ + _breakiter_factory("breakiter_create_sentence_instance", + &BreakIterator::createSentenceInstance, + INTERNAL_FUNCTION_PARAM_PASSTHRU); +} + +U_CFUNC PHP_FUNCTION(breakiter_create_title_instance) +{ + _breakiter_factory("breakiter_create_title_instance", + &BreakIterator::createTitleInstance, + 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; + object = getThis(); + + if (zend_parse_parameters_none() == FAILURE) { + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, + "breakiter_get_text: bad arguments", 0 TSRMLS_CC); + RETURN_FALSE; + } + + BREAKITER_METHOD_FETCH_OBJECT; + + if (bio->text == NULL) { + RETURN_NULL(); + } else { + RETURN_ZVAL(bio->text, 1, 0); + } +} + +U_CFUNC PHP_FUNCTION(breakiter_set_text) +{ + char *text; + int text_len; + UText *ut = NULL; + zval **textzv; + BREAKITER_METHOD_INIT_VARS; + object = getThis(); + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", + &text, &text_len) == FAILURE) { + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, + "breakiter_set_text: bad arguments", 0 TSRMLS_CC); + RETURN_FALSE; + } + + int res = zend_get_parameters_ex(1, &textzv); + assert(res == SUCCESS); + + BREAKITER_METHOD_FETCH_OBJECT; + + /* assert it's safe to use text and text_len because zpp changes the + * arguments in the stack */ + assert(text == Z_STRVAL_PP(textzv)); + + ut = utext_openUTF8(ut, text, text_len, BREAKITER_ERROR_CODE_P(bio)); + INTL_CTOR_CHECK_STATUS(bio, "breakiter_set_text: error opening UText"); + + bio->biter->setText(ut, BREAKITER_ERROR_CODE(bio)); + utext_close(ut); /* ICU shallow clones the UText */ + INTL_CTOR_CHECK_STATUS(bio, "breakiter_set_text: error calling " + "BreakIterator::setText()"); + + /* When ICU clones the UText, it does not copy the buffer, so we have to + * keep the string buffer around by holding a reference to its zval. This + * also allows a faste implementation of getText() */ + if (bio->text != NULL) { + zval_ptr_dtor(&bio->text); + } + bio->text = *textzv; + zval_add_ref(&bio->text); + + RETURN_TRUE; +} + +static void _breakiter_no_args_ret_int32( + const char *func_name, + int32_t (BreakIterator::*func)(), + INTERNAL_FUNCTION_PARAMETERS) +{ + char *msg; + BREAKITER_METHOD_INIT_VARS; + object = getThis(); + + if (zend_parse_parameters_none() == FAILURE) { + spprintf(&msg, NULL, "%s: bad arguments", func_name); + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, msg, 1 TSRMLS_CC); + efree(msg); + RETURN_FALSE; + } + + BREAKITER_METHOD_FETCH_OBJECT; + + int32_t res = (bio->biter->*func)(); + + RETURN_LONG((long)res); +} + +static void _breakiter_int32_ret_int32( + const char *func_name, + int32_t (BreakIterator::*func)(int32_t), + INTERNAL_FUNCTION_PARAMETERS) +{ + char *msg; + long arg; + BREAKITER_METHOD_INIT_VARS; + object = getThis(); + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &arg) == FAILURE) { + spprintf(&msg, NULL, "%s: bad arguments", func_name); + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, msg, 1 TSRMLS_CC); + efree(msg); + RETURN_FALSE; + } + + BREAKITER_METHOD_FETCH_OBJECT; + + if (arg < INT32_MIN || arg > INT32_MAX) { + spprintf(&msg, NULL, "%s: offset argument is outside bounds of " + "a 32-bit wide integer", func_name); + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, msg, 1 TSRMLS_CC); + efree(msg); + RETURN_FALSE; + } + + int32_t res = (bio->biter->*func)((int32_t)arg); + + RETURN_LONG((long)res); +} + +U_CFUNC PHP_FUNCTION(breakiter_first) +{ + _breakiter_no_args_ret_int32("breakiter_first", + &BreakIterator::first, + INTERNAL_FUNCTION_PARAM_PASSTHRU); +} + +U_CFUNC PHP_FUNCTION(breakiter_last) +{ + _breakiter_no_args_ret_int32("breakiter_last", + &BreakIterator::last, + INTERNAL_FUNCTION_PARAM_PASSTHRU); +} + +U_CFUNC PHP_FUNCTION(breakiter_previous) +{ + _breakiter_no_args_ret_int32("breakiter_previous", + &BreakIterator::previous, + INTERNAL_FUNCTION_PARAM_PASSTHRU); +} + +U_CFUNC PHP_FUNCTION(breakiter_next) +{ + bool no_arg_version = false; + + if (ZEND_NUM_ARGS() == 0) { + no_arg_version = true; + } else if (ZEND_NUM_ARGS() == 1) { + zval **arg; + int res = zend_get_parameters_ex(1, &arg); + assert(res == SUCCESS); + if (Z_TYPE_PP(arg) == IS_NULL) { + no_arg_version = true; + ht = 0; /* pretend we don't have any argument */ + } else { + no_arg_version = false; + } + } + + if (no_arg_version) { + _breakiter_no_args_ret_int32("breakiter_next", + &BreakIterator::next, + INTERNAL_FUNCTION_PARAM_PASSTHRU); + } else { + _breakiter_int32_ret_int32("breakiter_next", + &BreakIterator::next, + INTERNAL_FUNCTION_PARAM_PASSTHRU); + } +} + +U_CFUNC PHP_FUNCTION(breakiter_current) +{ + BREAKITER_METHOD_INIT_VARS; + object = getThis(); + + if (zend_parse_parameters_none() == FAILURE) { + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, + "breakiter_current: bad arguments", 0 TSRMLS_CC); + RETURN_FALSE; + } + + BREAKITER_METHOD_FETCH_OBJECT; + + int32_t res = bio->biter->current(); + + RETURN_LONG((long)res); +} + +U_CFUNC PHP_FUNCTION(breakiter_following) +{ + _breakiter_int32_ret_int32("breakiter_following", + &BreakIterator::following, + INTERNAL_FUNCTION_PARAM_PASSTHRU); +} + +U_CFUNC PHP_FUNCTION(breakiter_preceding) +{ + _breakiter_int32_ret_int32("breakiter_preceding", + &BreakIterator::preceding, + INTERNAL_FUNCTION_PARAM_PASSTHRU); +} + +U_CFUNC PHP_FUNCTION(breakiter_is_boundary) +{ + long offset; + BREAKITER_METHOD_INIT_VARS; + object = getThis(); + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", + &offset) == FAILURE) { + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, + "breakiter_is_boundary: bad arguments", 0 TSRMLS_CC); + RETURN_FALSE; + } + + if (offset < INT32_MIN || offset > INT32_MAX) { + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, + "breakiter_is_boundary: offset argument is outside bounds of " + "a 32-bit wide integer", 0 TSRMLS_CC); + RETURN_FALSE; + } + + BREAKITER_METHOD_FETCH_OBJECT; + + UBool res = bio->biter->isBoundary((int32_t)offset); + + RETURN_BOOL((long)res); +} + +U_CFUNC PHP_FUNCTION(breakiter_get_locale) +{ + long locale_type; + BREAKITER_METHOD_INIT_VARS; + object = getThis(); + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &locale_type) == FAILURE) { + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, + "breakiter_get_locale: bad arguments", 0 TSRMLS_CC); + RETURN_FALSE; + } + + if (locale_type != ULOC_ACTUAL_LOCALE && locale_type != ULOC_VALID_LOCALE) { + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, + "breakiter_get_locale: invalid locale type", 0 TSRMLS_CC); + RETURN_FALSE; + } + + BREAKITER_METHOD_FETCH_OBJECT; + + Locale locale = bio->biter->getLocale((ULocDataLocaleType)locale_type, + BREAKITER_ERROR_CODE(bio)); + INTL_METHOD_CHECK_STATUS(bio, + "breakiter_get_locale: Call to ICU method has failed"); + + RETURN_STRING(locale.getName(), 1); +} + +U_CFUNC PHP_FUNCTION(breakiter_get_parts_iterator) +{ + long key_type = 0; + BREAKITER_METHOD_INIT_VARS; + object = getThis(); + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &key_type) == FAILURE) { + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, + "breakiter_get_parts_iterator: bad arguments", 0 TSRMLS_CC); + RETURN_FALSE; + } + + if (key_type != PARTS_ITERATOR_KEY_SEQUENTIAL + && key_type != PARTS_ITERATOR_KEY_LEFT + && key_type != PARTS_ITERATOR_KEY_RIGHT) { + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, + "breakiter_get_parts_iterator: bad key type", 0 TSRMLS_CC); + RETURN_FALSE; + } + + BREAKITER_METHOD_FETCH_OBJECT; + + IntlIterator_from_BreakIterator_parts( + object, return_value, (parts_iter_key_type)key_type TSRMLS_CC); +} + +U_CFUNC PHP_FUNCTION(breakiter_get_error_code) +{ + BREAKITER_METHOD_INIT_VARS; + object = getThis(); + + if (zend_parse_parameters_none() == FAILURE) { + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, + "breakiter_get_error_code: bad arguments", 0 TSRMLS_CC); + RETURN_FALSE; + } + + /* Fetch the object (without resetting its last error code ). */ + bio = (BreakIterator_object*)zend_object_store_get_object(object TSRMLS_CC); + if (bio == NULL) + RETURN_FALSE; + + RETURN_LONG((long)BREAKITER_ERROR_CODE(bio)); +} + +U_CFUNC PHP_FUNCTION(breakiter_get_error_message) +{ + const char* message = NULL; + BREAKITER_METHOD_INIT_VARS; + object = getThis(); + + if (zend_parse_parameters_none() == FAILURE) { + intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR, + "breakiter_get_error_message: bad arguments", 0 TSRMLS_CC ); + RETURN_FALSE; + } + + + /* Fetch the object (without resetting its last error code ). */ + bio = (BreakIterator_object*)zend_object_store_get_object(object TSRMLS_CC); + if (bio == NULL) + RETURN_FALSE; + + /* Return last error message. */ + message = intl_error_get_message(BREAKITER_ERROR_P(bio) TSRMLS_CC); + RETURN_STRING(message, 0); +} diff --git a/ext/intl/breakiterator/breakiterator_methods.h b/ext/intl/breakiterator/breakiterator_methods.h new file mode 100644 index 0000000000..a479ac92e8 --- /dev/null +++ b/ext/intl/breakiterator/breakiterator_methods.h @@ -0,0 +1,64 @@ +/* + +----------------------------------------------------------------------+ + | 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 <cataphract@php.net> | + +----------------------------------------------------------------------+ + */ + +#ifndef BREAKITERATOR_METHODS_H +#define BREAKITERATOR_METHODS_H + +#include <php.h> + +PHP_METHOD(BreakIterator, __construct); + +PHP_FUNCTION(breakiter_create_word_instance); + +PHP_FUNCTION(breakiter_create_line_instance); + +PHP_FUNCTION(breakiter_create_character_instance); + +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); + +PHP_FUNCTION(breakiter_first); + +PHP_FUNCTION(breakiter_last); + +PHP_FUNCTION(breakiter_previous); + +PHP_FUNCTION(breakiter_next); + +PHP_FUNCTION(breakiter_current); + +PHP_FUNCTION(breakiter_following); + +PHP_FUNCTION(breakiter_preceding); + +PHP_FUNCTION(breakiter_is_boundary); + +PHP_FUNCTION(breakiter_get_locale); + +PHP_FUNCTION(breakiter_get_parts_iterator); + +PHP_FUNCTION(breakiter_get_error_code); + +PHP_FUNCTION(breakiter_get_error_message); + +#endif
\ No newline at end of file diff --git a/ext/intl/breakiterator/codepointiterator_internal.cpp b/ext/intl/breakiterator/codepointiterator_internal.cpp new file mode 100644 index 0000000000..bf9239d531 --- /dev/null +++ b/ext/intl/breakiterator/codepointiterator_internal.cpp @@ -0,0 +1,291 @@ +/* + +----------------------------------------------------------------------+ + | 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 <cataphract@php.net> | + +----------------------------------------------------------------------+ + */ + +#include "codepointiterator_internal.h" +#include <unicode/uchriter.h> +#include <typeinfo> + +//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<const CodePointBreakIterator&>(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); + +#ifndef UTEXT_CURRENT32 +#define UTEXT_CURRENT32 utext_current32 +#endif + + 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; +} diff --git a/ext/intl/breakiterator/codepointiterator_internal.h b/ext/intl/breakiterator/codepointiterator_internal.h new file mode 100644 index 0000000000..988b91c200 --- /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 <cataphract@php.net> | + +----------------------------------------------------------------------+ + */ + +#ifndef CODEPOINTITERATOR_INTERNAL_H +#define CODEPOINTITERATOR_INTERNAL_H + +#include <unicode/brkiter.h> + +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 0000000000..ae7e526ead --- /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 <cataphract@php.net> | + +----------------------------------------------------------------------+ + */ + +#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 0000000000..d34e5b61e2 --- /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 <cataphract@php.net> | + +----------------------------------------------------------------------+ + */ + +#ifndef CODEPOINTITERATOR_METHODS_H +#define CODEPOINTITERATOR_METHODS_H + +#include <php.h> + +PHP_FUNCTION(cpbi_get_last_code_point); + +#endif
\ No newline at end of file diff --git a/ext/intl/breakiterator/rulebasedbreakiterator_methods.cpp b/ext/intl/breakiterator/rulebasedbreakiterator_methods.cpp new file mode 100644 index 0000000000..f2a39ba022 --- /dev/null +++ b/ext/intl/breakiterator/rulebasedbreakiterator_methods.cpp @@ -0,0 +1,219 @@ +/* + +----------------------------------------------------------------------+ + | 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 <cataphract@php.net> | + +----------------------------------------------------------------------+ + */ + +#include <unicode/rbbi.h> + +extern "C" { +#define USE_BREAKITERATOR_POINTER 1 +#include "breakiterator_class.h" +#include <zend_exceptions.h> +#include <limits.h> +} + +#include "../intl_convertcpp.h" + +static inline RuleBasedBreakIterator *fetch_rbbi(BreakIterator_object *bio) { + return (RuleBasedBreakIterator*)bio->biter; +} + +static void _php_intlgregcal_constructor_body(INTERNAL_FUNCTION_PARAMETERS) +{ + zval *object = getThis(); + char *rules; + int rules_len; + zend_bool compiled = 0; + UErrorCode status = U_ZERO_ERROR; + intl_error_reset(NULL TSRMLS_CC); + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|b", + &rules, &rules_len, &compiled) == FAILURE) { + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, + "rbbi_create_instance: bad arguments", 0 TSRMLS_CC); + RETURN_NULL(); + } + + // instantiation of ICU object + RuleBasedBreakIterator *rbbi; + + if (!compiled) { + UnicodeString rulesStr; + UParseError parseError = UParseError(); + if (intl_stringFromChar(rulesStr, rules, rules_len, &status) + == FAILURE) { + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, + "rbbi_create_instance: rules were not a valid UTF-8 string", + 0 TSRMLS_CC); + RETURN_NULL(); + } + + rbbi = new RuleBasedBreakIterator(rulesStr, parseError, status); + intl_error_set_code(NULL, status TSRMLS_CC); + if (U_FAILURE(status)) { + char *msg; + smart_str parse_error_str; + parse_error_str = intl_parse_error_to_string(&parseError); + spprintf(&msg, 0, "rbbi_create_instance: unable to create " + "RuleBasedBreakIterator from rules (%s)", parse_error_str.c); + smart_str_free(&parse_error_str); + intl_error_set_custom_msg(NULL, msg, 1 TSRMLS_CC); + efree(msg); + RETURN_NULL(); + } + } else { // compiled +#if U_ICU_VERSION_MAJOR_NUM * 10 + U_ICU_VERSION_MINOR_NUM >= 48 + rbbi = new RuleBasedBreakIterator((uint8_t*)rules, rules_len, status); + if (U_FAILURE(status)) { + intl_error_set(NULL, status, "rbbi_create_instance: unable to " + "create instance from compiled rules", 0 TSRMLS_CC); + RETURN_NULL(); + } +#else + intl_error_set(NULL, U_UNSUPPORTED_ERROR, "rbbi_create_instance: " + "compiled rules require ICU >= 4.8", 0 TSRMLS_CC); + RETURN_NULL(); +#endif + } + + breakiterator_object_create(return_value, rbbi TSRMLS_CC); +} + +U_CFUNC PHP_METHOD(IntlRuleBasedBreakIterator, __construct) +{ + zval orig_this = *getThis(); + + return_value = getThis(); + //changes this to IS_NULL (without first destroying) if there's an error + _php_intlgregcal_constructor_body(INTERNAL_FUNCTION_PARAM_PASSTHRU); + + if (Z_TYPE_P(return_value) == IS_NULL) { + zend_object_store_ctor_failed(&orig_this TSRMLS_CC); + zval_dtor(&orig_this); + } +} + +U_CFUNC PHP_FUNCTION(rbbi_get_rules) +{ + BREAKITER_METHOD_INIT_VARS; + object = getThis(); + + if (zend_parse_parameters_none() == FAILURE) { + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, + "rbbi_get_rules: bad arguments", 0 TSRMLS_CC); + RETURN_FALSE; + } + + BREAKITER_METHOD_FETCH_OBJECT; + + const UnicodeString rules = fetch_rbbi(bio)->getRules(); + + Z_TYPE_P(return_value) = IS_STRING; + if (intl_charFromString(rules, &Z_STRVAL_P(return_value), + &Z_STRLEN_P(return_value), BREAKITER_ERROR_CODE_P(bio)) == FAILURE) + { + intl_errors_set(BREAKITER_ERROR_P(bio), BREAKITER_ERROR_CODE(bio), + "rbbi_hash_code: Error converting result to UTF-8 string", + 0 TSRMLS_CC); + RETURN_FALSE; + } +} + +U_CFUNC PHP_FUNCTION(rbbi_get_rule_status) +{ + BREAKITER_METHOD_INIT_VARS; + object = getThis(); + + if (zend_parse_parameters_none() == FAILURE) { + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, + "rbbi_get_rule_status: bad arguments", 0 TSRMLS_CC); + RETURN_FALSE; + } + + BREAKITER_METHOD_FETCH_OBJECT; + + RETURN_LONG(fetch_rbbi(bio)->getRuleStatus()); +} + +U_CFUNC PHP_FUNCTION(rbbi_get_rule_status_vec) +{ + BREAKITER_METHOD_INIT_VARS; + object = getThis(); + + if (zend_parse_parameters_none() == FAILURE) { + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, + "rbbi_get_rule_status_vec: bad arguments", 0 TSRMLS_CC); + RETURN_FALSE; + } + + BREAKITER_METHOD_FETCH_OBJECT; + + int32_t num_rules = fetch_rbbi(bio)->getRuleStatusVec(NULL, 0, + BREAKITER_ERROR_CODE(bio)); + if (BREAKITER_ERROR_CODE(bio) == U_BUFFER_OVERFLOW_ERROR) { + BREAKITER_ERROR_CODE(bio) = U_ZERO_ERROR; + } else { + // should not happen + INTL_METHOD_CHECK_STATUS(bio, "rbbi_get_rule_status_vec: failed " + " determining the number of status values"); + } + int32_t *rules = new int32_t[num_rules]; + num_rules = fetch_rbbi(bio)->getRuleStatusVec(rules, num_rules, + BREAKITER_ERROR_CODE(bio)); + if (U_FAILURE(BREAKITER_ERROR_CODE(bio))) { + delete[] rules; + intl_errors_set(BREAKITER_ERROR_P(bio), BREAKITER_ERROR_CODE(bio), + "rbbi_get_rule_status_vec: failed obtaining the status values", + 0 TSRMLS_CC); + RETURN_FALSE; + } + + array_init_size(return_value, num_rules); + for (int32_t i = 0; i < num_rules; i++) { + add_next_index_long(return_value, rules[i]); + } + delete[] rules; +} + +#if U_ICU_VERSION_MAJOR_NUM * 10 + U_ICU_VERSION_MINOR_NUM >= 48 +U_CFUNC PHP_FUNCTION(rbbi_get_binary_rules) +{ + BREAKITER_METHOD_INIT_VARS; + object = getThis(); + + if (zend_parse_parameters_none() == FAILURE) { + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, + "rbbi_get_binary_rules: bad arguments", 0 TSRMLS_CC); + RETURN_FALSE; + } + + BREAKITER_METHOD_FETCH_OBJECT; + + uint32_t rules_len; + const uint8_t *rules = fetch_rbbi(bio)->getBinaryRules(rules_len); + + if (rules_len > INT_MAX - 1) { + intl_errors_set(BREAKITER_ERROR_P(bio), BREAKITER_ERROR_CODE(bio), + "rbbi_get_binary_rules: the rules are too large", + 0 TSRMLS_CC); + RETURN_FALSE; + } + + char *ret_rules = static_cast<char*>(emalloc(rules_len + 1)); + memcpy(ret_rules, rules, rules_len); + ret_rules[rules_len] = '\0'; + + RETURN_STRINGL(ret_rules, rules_len, 0); +} +#endif diff --git a/ext/intl/breakiterator/rulebasedbreakiterator_methods.h b/ext/intl/breakiterator/rulebasedbreakiterator_methods.h new file mode 100644 index 0000000000..edea4ea2a6 --- /dev/null +++ b/ext/intl/breakiterator/rulebasedbreakiterator_methods.h @@ -0,0 +1,32 @@ +/* + +----------------------------------------------------------------------+ + | 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 <cataphract@php.net> | + +----------------------------------------------------------------------+ + */ + +#ifndef RULEBASEDBREAKITERATOR_METHODS_H +#define RULEBASEDBREAKITERATOR_METHODS_H + +#include <php.h> + +PHP_METHOD(IntlRuleBasedBreakIterator, __construct); + +PHP_FUNCTION(rbbi_get_rules); + +PHP_FUNCTION(rbbi_get_rule_status); + +PHP_FUNCTION(rbbi_get_rule_status_vec); + +PHP_FUNCTION(rbbi_get_binary_rules); + +#endif
\ No newline at end of file diff --git a/ext/intl/calendar/calendar_class.cpp b/ext/intl/calendar/calendar_class.cpp new file mode 100644 index 0000000000..beb65f718f --- /dev/null +++ b/ext/intl/calendar/calendar_class.cpp @@ -0,0 +1,550 @@ +/* + +----------------------------------------------------------------------+ + | 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 <cataphract@php.net> | + +----------------------------------------------------------------------+ +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "../intl_cppshims.h" + +#include <unicode/calendar.h> +#include <unicode/gregocal.h> + +extern "C" { +#define USE_TIMEZONE_POINTER 1 +#include "../timezone/timezone_class.h" +#define USE_CALENDAR_POINTER 1 +#include "calendar_class.h" +#include "calendar_methods.h" +#include "gregoriancalendar_methods.h" +#include <zend_exceptions.h> +#include <assert.h> +} + +/* {{{ Global variables */ +zend_class_entry *Calendar_ce_ptr; +zend_class_entry *GregorianCalendar_ce_ptr; +zend_object_handlers Calendar_handlers; +/* }}} */ + +U_CFUNC void calendar_object_create(zval *object, + Calendar *calendar TSRMLS_DC) +{ + UClassID classId = calendar->getDynamicClassID(); + zend_class_entry *ce; + + //if (dynamic_cast<GregorianCalendar*>(calendar) != NULL) { + if (classId == GregorianCalendar::getStaticClassID()) { + ce = GregorianCalendar_ce_ptr; + } else { + ce = Calendar_ce_ptr; + } + + object_init_ex(object, ce); + calendar_object_construct(object, calendar TSRMLS_CC); +} + +U_CFUNC Calendar *calendar_fetch_native_calendar(zval *object TSRMLS_DC) +{ + Calendar_object *co = (Calendar_object*) + zend_object_store_get_object(object TSRMLS_CC); + + return co->ucal; +} + +U_CFUNC void calendar_object_construct(zval *object, + Calendar *calendar TSRMLS_DC) +{ + Calendar_object *co; + + CALENDAR_METHOD_FETCH_OBJECT_NO_CHECK; //populate to from object + assert(co->ucal == NULL); + co->ucal = (Calendar*)calendar; +} + +/* {{{ clone handler for Calendar */ +static zend_object_value Calendar_clone_obj(zval *object TSRMLS_DC) +{ + Calendar_object *co_orig, + *co_new; + zend_object_value ret_val; + intl_error_reset(NULL TSRMLS_CC); + + co_orig = (Calendar_object*)zend_object_store_get_object(object TSRMLS_CC); + intl_error_reset(INTL_DATA_ERROR_P(co_orig) TSRMLS_CC); + + ret_val = Calendar_ce_ptr->create_object(Z_OBJCE_P(object) TSRMLS_CC); + co_new = (Calendar_object*)zend_object_store_get_object_by_handle(ret_val.handle TSRMLS_CC); + + zend_objects_clone_members(&co_new->zo, ret_val, + &co_orig->zo, Z_OBJ_HANDLE_P(object) TSRMLS_CC); + + if (co_orig->ucal != NULL) { + Calendar *newCalendar; + + newCalendar = co_orig->ucal->clone(); + if (!newCalendar) { + char *err_msg; + intl_errors_set_code(CALENDAR_ERROR_P(co_orig), + U_MEMORY_ALLOCATION_ERROR TSRMLS_CC); + intl_errors_set_custom_msg(CALENDAR_ERROR_P(co_orig), + "Could not clone IntlCalendar", 0 TSRMLS_CC); + err_msg = intl_error_get_message(CALENDAR_ERROR_P(co_orig) TSRMLS_CC); + zend_throw_exception(NULL, err_msg, 0 TSRMLS_CC); + efree(err_msg); + } else { + co_new->ucal = newCalendar; + } + } else { + zend_throw_exception(NULL, "Cannot clone unconstructed IntlCalendar", 0 TSRMLS_CC); + } + + return ret_val; +} +/* }}} */ + +static const struct { + UCalendarDateFields field; + const char *name; +} debug_info_fields[] = { + {UCAL_ERA, "era"}, + {UCAL_YEAR, "year"}, + {UCAL_MONTH, "month"}, + {UCAL_WEEK_OF_YEAR, "week of year"}, + {UCAL_WEEK_OF_MONTH, "week of month"}, + {UCAL_DAY_OF_YEAR, "day of year"}, + {UCAL_DAY_OF_MONTH, "day of month"}, + {UCAL_DAY_OF_WEEK, "day of week"}, + {UCAL_DAY_OF_WEEK_IN_MONTH, "day of week in month"}, + {UCAL_AM_PM, "AM/PM"}, + {UCAL_HOUR, "hour"}, + {UCAL_HOUR_OF_DAY, "hour of day"}, + {UCAL_MINUTE, "minute"}, + {UCAL_SECOND, "second"}, + {UCAL_MILLISECOND, "millisecond"}, + {UCAL_ZONE_OFFSET, "zone offset"}, + {UCAL_DST_OFFSET, "DST offset"}, + {UCAL_YEAR_WOY, "year for week of year"}, + {UCAL_DOW_LOCAL, "localized day of week"}, + {UCAL_EXTENDED_YEAR, "extended year"}, + {UCAL_JULIAN_DAY, "julian day"}, + {UCAL_MILLISECONDS_IN_DAY, "milliseconds in day"}, + {UCAL_IS_LEAP_MONTH, "is leap month"}, +}; + +/* {{{ get_debug_info handler for Calendar */ +static HashTable *Calendar_get_debug_info(zval *object, int *is_temp TSRMLS_DC) +{ + zval zv = zval_used_for_init, + *zfields; + Calendar_object *co; + const Calendar *cal; + + *is_temp = 1; + + array_init_size(&zv, 8); + + co = (Calendar_object*)zend_object_store_get_object(object TSRMLS_CC); + cal = co->ucal; + + if (cal == NULL) { + add_assoc_bool_ex(&zv, "valid", sizeof("valid"), 0); + return Z_ARRVAL(zv); + } + + add_assoc_bool_ex(&zv, "valid", sizeof("valid"), 1); + + add_assoc_string_ex(&zv, "type", sizeof("type"), + const_cast<char*>(cal->getType()), 1); + + { + zval ztz = zval_used_for_init, + *ztz_debug; + int is_tmp; + HashTable *debug_info; + + timezone_object_construct(&cal->getTimeZone(), &ztz , 0 TSRMLS_CC); + debug_info = Z_OBJ_HANDLER(ztz, get_debug_info)(&ztz, &is_tmp TSRMLS_CC); + assert(is_tmp == 1); + + ALLOC_INIT_ZVAL(ztz_debug); + Z_TYPE_P(ztz_debug) = IS_ARRAY; + Z_ARRVAL_P(ztz_debug) = debug_info; + add_assoc_zval_ex(&zv, "timeZone", sizeof("timeZone"), ztz_debug); + } + + { + UErrorCode uec = U_ZERO_ERROR; + Locale locale = cal->getLocale(ULOC_VALID_LOCALE, uec); + if (U_SUCCESS(uec)) { + add_assoc_string_ex(&zv, "locale", sizeof("locale"), + const_cast<char*>(locale.getName()), 1); + } else { + add_assoc_string_ex(&zv, "locale", sizeof("locale"), + const_cast<char*>(u_errorName(uec)), 1); + } + } + + ALLOC_INIT_ZVAL(zfields); + array_init_size(zfields, UCAL_FIELD_COUNT); + + for (int i = 0; + i < sizeof(debug_info_fields) / sizeof(*debug_info_fields); + i++) { + UErrorCode uec = U_ZERO_ERROR; + const char *name = debug_info_fields[i].name; + int32_t res = cal->get(debug_info_fields[i].field, uec); + if (U_SUCCESS(uec)) { + add_assoc_long(zfields, name, (long)res); + } else { + add_assoc_string(zfields, name, const_cast<char*>(u_errorName(uec)), 1); + } + } + + add_assoc_zval_ex(&zv, "fields", sizeof("fields"), zfields); + + return Z_ARRVAL(zv); +} +/* }}} */ + +/* {{{ void calendar_object_init(Calendar_object* to) + * Initialize internals of Calendar_object not specific to zend standard objects. + */ +static void calendar_object_init(Calendar_object *co TSRMLS_DC) +{ + intl_error_init(CALENDAR_ERROR_P(co) TSRMLS_CC); + co->ucal = NULL; +} +/* }}} */ + +/* {{{ Calendar_objects_dtor */ +static void Calendar_objects_dtor(void *object, + zend_object_handle handle TSRMLS_DC) +{ + zend_objects_destroy_object((zend_object*)object, handle TSRMLS_CC); +} +/* }}} */ + +/* {{{ Calendar_objects_free */ +static void Calendar_objects_free(zend_object *object TSRMLS_DC) +{ + Calendar_object* co = (Calendar_object*) object; + + if (co->ucal) { + delete co->ucal; + co->ucal = NULL; + } + intl_error_reset(CALENDAR_ERROR_P(co) TSRMLS_CC); + + zend_object_std_dtor(&co->zo TSRMLS_CC); + + efree(co); +} +/* }}} */ + +/* {{{ Calendar_object_create */ +static zend_object_value Calendar_object_create(zend_class_entry *ce TSRMLS_DC) +{ + zend_object_value retval; + Calendar_object* intern; + + intern = (Calendar_object*)ecalloc(1, sizeof(Calendar_object)); + + zend_object_std_init(&intern->zo, ce TSRMLS_CC); +#if PHP_VERSION_ID < 50399 + zend_hash_copy(intern->zo.properties, &(ce->default_properties), + (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval*)); +#else + object_properties_init((zend_object*) intern, ce); +#endif + calendar_object_init(intern TSRMLS_CC); + + retval.handle = zend_objects_store_put( + intern, + Calendar_objects_dtor, + (zend_objects_free_object_storage_t) Calendar_objects_free, + NULL TSRMLS_CC); + + retval.handlers = &Calendar_handlers; + + return retval; +} +/* }}} */ + +/* {{{ Calendar methods arguments info */ + +ZEND_BEGIN_ARG_INFO_EX(ainfo_cal_void, 0, 0, 0) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(ainfo_cal_field, 0, 0, 1) + ZEND_ARG_INFO(0, field) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(ainfo_cal_dow, 0, 0, 1) + ZEND_ARG_INFO(0, dayOfWeek) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(ainfo_cal_other_cal, 0, 0, 1) + ZEND_ARG_OBJ_INFO(0, calendar, IntlCalendar, 0) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(ainfo_cal_date, 0, 0, 1) + ZEND_ARG_INFO(0, date) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(ainfo_cal_date_optional, 0, 0, 0) + ZEND_ARG_INFO(0, date) +ZEND_END_ARG_INFO() + + +ZEND_BEGIN_ARG_INFO_EX(ainfo_cal_createInstance, 0, 0, 0) + ZEND_ARG_INFO(0, timeZone) + ZEND_ARG_INFO(0, locale) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(ainfo_cal_get_keyword_values_for_locale, 0, 0, 3) + ZEND_ARG_INFO(0, key) + ZEND_ARG_INFO(0, locale) + ZEND_ARG_INFO(0, commonlyUsed) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(ainfo_cal_add, 0, 0, 2) + ZEND_ARG_INFO(0, field) + ZEND_ARG_INFO(0, amount) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(ainfo_cal_setTimeZone, 0, 0, 1) + ZEND_ARG_INFO(0, timeZone) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(ainfo_cal_set, 0, 0, 2) + ZEND_ARG_INFO(0, fieldOrYear) + ZEND_ARG_INFO(0, valueOrMonth) + ZEND_ARG_INFO(0, dayOfMonth) + ZEND_ARG_INFO(0, hour) + ZEND_ARG_INFO(0, minute) + ZEND_ARG_INFO(0, second) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(ainfo_cal_roll, 0, 0, 2) + ZEND_ARG_INFO(0, field) + ZEND_ARG_INFO(0, amountOrUpOrDown) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(ainfo_cal_clear, 0, 0, 0) + ZEND_ARG_INFO(0, field) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(ainfo_cal_field_difference, 0, 0, 2) + ZEND_ARG_INFO(0, when) + ZEND_ARG_INFO(0, field) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(ainfo_cal_get_locale, 0, 0, 1) + ZEND_ARG_INFO(0, localeType) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(ainfo_cal_setLenient, 0, 0, 1) + ZEND_ARG_INFO(0, isLenient) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(ainfo_cal_from_date_time, 0, 0, 1) + ZEND_ARG_INFO(0, dateTime) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(ainfo_cal_wall_time_option, 0, 0, 1) + ZEND_ARG_INFO(0, wallTimeOption) +ZEND_END_ARG_INFO() + +/* Gregorian Calendar */ +ZEND_BEGIN_ARG_INFO_EX(ainfo_gregcal___construct, 0, 0, 0) + ZEND_ARG_INFO(0, timeZoneOrYear) + ZEND_ARG_INFO(0, localeOrMonth) + ZEND_ARG_INFO(0, dayOfMonth) + ZEND_ARG_INFO(0, hour) + ZEND_ARG_INFO(0, minute) + ZEND_ARG_INFO(0, second) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(ainfo_gregcal_isLeapYear, 0, 0, 1) + ZEND_ARG_INFO(0, year) +ZEND_END_ARG_INFO() + +/* }}} */ + +/* {{{ Calendar_class_functions + * Every 'IntlCalendar' class method has an entry in this table + */ +static const zend_function_entry Calendar_class_functions[] = { + PHP_ME(IntlCalendar, __construct, ainfo_cal_void, ZEND_ACC_PRIVATE) + PHP_ME_MAPPING(createInstance, intlcal_create_instance, ainfo_cal_createInstance, ZEND_ACC_STATIC | ZEND_ACC_PUBLIC) +#if U_ICU_VERSION_MAJOR_NUM * 10 + U_ICU_VERSION_MINOR_NUM >= 42 + PHP_ME_MAPPING(getKeywordValuesForLocale, intlcal_get_keyword_values_for_locale, ainfo_cal_get_keyword_values_for_locale, ZEND_ACC_STATIC | ZEND_ACC_PUBLIC) +#endif + PHP_ME_MAPPING(getNow, intlcal_get_now, ainfo_cal_void, ZEND_ACC_STATIC | ZEND_ACC_PUBLIC) + PHP_ME_MAPPING(getAvailableLocales, intlcal_get_available_locales, ainfo_cal_void, ZEND_ACC_STATIC | ZEND_ACC_PUBLIC) + PHP_ME_MAPPING(get, intlcal_get, ainfo_cal_field, ZEND_ACC_PUBLIC) + PHP_ME_MAPPING(getTime, intlcal_get_time, ainfo_cal_void, ZEND_ACC_PUBLIC) + PHP_ME_MAPPING(setTime, intlcal_set_time, ainfo_cal_date, ZEND_ACC_PUBLIC) + PHP_ME_MAPPING(add, intlcal_add, ainfo_cal_add, ZEND_ACC_PUBLIC) + PHP_ME_MAPPING(setTimeZone, intlcal_set_time_zone, ainfo_cal_setTimeZone, ZEND_ACC_PUBLIC) + PHP_ME_MAPPING(after, intlcal_after, ainfo_cal_other_cal, ZEND_ACC_PUBLIC) + PHP_ME_MAPPING(before, intlcal_before, ainfo_cal_other_cal, ZEND_ACC_PUBLIC) + PHP_ME_MAPPING(set, intlcal_set, ainfo_cal_set, ZEND_ACC_PUBLIC) + PHP_ME_MAPPING(roll, intlcal_roll, ainfo_cal_roll, ZEND_ACC_PUBLIC) + PHP_ME_MAPPING(clear, intlcal_clear, ainfo_cal_clear, ZEND_ACC_PUBLIC) + PHP_ME_MAPPING(fieldDifference, intlcal_field_difference, ainfo_cal_field_difference, ZEND_ACC_PUBLIC) + PHP_ME_MAPPING(getActualMaximum, intlcal_get_actual_maximum, ainfo_cal_field, ZEND_ACC_PUBLIC) + PHP_ME_MAPPING(getActualMinimum, intlcal_get_actual_minimum, ainfo_cal_field, ZEND_ACC_PUBLIC) +#if U_ICU_VERSION_MAJOR_NUM * 10 + U_ICU_VERSION_MINOR_NUM >= 44 + PHP_ME_MAPPING(getDayOfWeekType, intlcal_get_day_of_week_type, ainfo_cal_dow, ZEND_ACC_PUBLIC) +#endif + PHP_ME_MAPPING(getFirstDayOfWeek, intlcal_get_first_day_of_week, ainfo_cal_void, ZEND_ACC_PUBLIC) + PHP_ME_MAPPING(getGreatestMinimum, intlcal_get_greatest_minimum, ainfo_cal_field, ZEND_ACC_PUBLIC) + PHP_ME_MAPPING(getLeastMaximum, intlcal_get_least_maximum, ainfo_cal_field, ZEND_ACC_PUBLIC) + PHP_ME_MAPPING(getLocale, intlcal_get_locale, ainfo_cal_get_locale, ZEND_ACC_PUBLIC) + PHP_ME_MAPPING(getMaximum, intlcal_get_maximum, ainfo_cal_field, ZEND_ACC_PUBLIC) + PHP_ME_MAPPING(getMinimalDaysInFirstWeek, intlcal_get_minimal_days_in_first_week, ainfo_cal_void, ZEND_ACC_PUBLIC) + PHP_ME_MAPPING(getMinimum, intlcal_get_minimum, ainfo_cal_field, ZEND_ACC_PUBLIC) + PHP_ME_MAPPING(getTimeZone, intlcal_get_time_zone, ainfo_cal_void, ZEND_ACC_PUBLIC) + PHP_ME_MAPPING(getType, intlcal_get_type, ainfo_cal_void, ZEND_ACC_PUBLIC) +#if U_ICU_VERSION_MAJOR_NUM * 10 + U_ICU_VERSION_MINOR_NUM >= 44 + PHP_ME_MAPPING(getWeekendTransition,intlcal_get_weekend_transition, ainfo_cal_dow, ZEND_ACC_PUBLIC) +#endif + PHP_ME_MAPPING(inDaylightTime, intlcal_in_daylight_time, ainfo_cal_void, ZEND_ACC_PUBLIC) + PHP_ME_MAPPING(isEquivalentTo, intlcal_is_equivalent_to, ainfo_cal_other_cal, ZEND_ACC_PUBLIC) + PHP_ME_MAPPING(isLenient, intlcal_is_lenient, ainfo_cal_void, ZEND_ACC_PUBLIC) + PHP_ME_MAPPING(isSet, intlcal_is_set, ainfo_cal_field, ZEND_ACC_PUBLIC) +#if U_ICU_VERSION_MAJOR_NUM * 10 + U_ICU_VERSION_MINOR_NUM >= 44 + PHP_ME_MAPPING(isWeekend, intlcal_is_weekend, ainfo_cal_date_optional, ZEND_ACC_PUBLIC) +#endif + PHP_ME_MAPPING(setFirstDayOfWeek, intlcal_set_first_day_of_week, ainfo_cal_dow, ZEND_ACC_PUBLIC) + PHP_ME_MAPPING(setLenient, intlcal_set_lenient, ainfo_cal_setLenient, ZEND_ACC_PUBLIC) + PHP_ME_MAPPING(equals, intlcal_equals, ainfo_cal_other_cal, ZEND_ACC_PUBLIC) +#if U_ICU_VERSION_MAJOR_NUM >= 49 + PHP_ME_MAPPING(getRepeatedWallTimeOption,intlcal_get_repeated_wall_time_option,ainfo_cal_void, ZEND_ACC_PUBLIC) + PHP_ME_MAPPING(getSkippedWallTimeOption,intlcal_get_skipped_wall_time_option,ainfo_cal_void, ZEND_ACC_PUBLIC) + PHP_ME_MAPPING(setRepeatedWallTimeOption,intlcal_set_repeated_wall_time_option,ainfo_cal_wall_time_option,ZEND_ACC_PUBLIC) + PHP_ME_MAPPING(setSkippedWallTimeOption,intlcal_set_skipped_wall_time_option,ainfo_cal_wall_time_option,ZEND_ACC_PUBLIC) +#endif + PHP_ME_MAPPING(fromDateTime, intlcal_from_date_time, ainfo_cal_from_date_time, ZEND_ACC_STATIC | ZEND_ACC_PUBLIC) + PHP_ME_MAPPING(toDateTime, intlcal_to_date_time, ainfo_cal_void, ZEND_ACC_PUBLIC) + PHP_ME_MAPPING(getErrorCode, intlcal_get_error_code, ainfo_cal_void, ZEND_ACC_PUBLIC) + PHP_ME_MAPPING(getErrorMessage, intlcal_get_error_message, ainfo_cal_void, ZEND_ACC_PUBLIC) + PHP_FE_END +}; +/* }}} */ + +/* {{{ GregorianCalendar_class_functions + */ +static const zend_function_entry GregorianCalendar_class_functions[] = { + PHP_ME(IntlGregorianCalendar, __construct, ainfo_gregcal___construct, ZEND_ACC_PUBLIC) + PHP_ME_MAPPING(setGregorianChange, intlgregcal_set_gregorian_change, ainfo_cal_date, ZEND_ACC_PUBLIC) + PHP_ME_MAPPING(getGregorianChange, intlgregcal_get_gregorian_change, ainfo_cal_void, ZEND_ACC_PUBLIC) + PHP_ME_MAPPING(isLeapYear, intlgregcal_is_leap_year, ainfo_gregcal_isLeapYear, ZEND_ACC_PUBLIC) + PHP_FE_END +}; +/* }}} */ + + +/* {{{ calendar_register_IntlCalendar_class + * Initialize 'IntlCalendar' class + */ +void calendar_register_IntlCalendar_class(TSRMLS_D) +{ + zend_class_entry ce; + + /* Create and register 'IntlCalendar' class. */ + INIT_CLASS_ENTRY(ce, "IntlCalendar", Calendar_class_functions); + ce.create_object = Calendar_object_create; + Calendar_ce_ptr = zend_register_internal_class(&ce TSRMLS_CC); + if (!Calendar_ce_ptr) { + //can't happen now without bigger problems before + php_error_docref0(NULL TSRMLS_CC, E_ERROR, + "IntlCalendar: class registration has failed."); + return; + } + memcpy( &Calendar_handlers, zend_get_std_object_handlers(), + sizeof Calendar_handlers); + Calendar_handlers.clone_obj = Calendar_clone_obj; + Calendar_handlers.get_debug_info = Calendar_get_debug_info; + + /* Create and register 'IntlGregorianCalendar' class. */ + INIT_CLASS_ENTRY(ce, "IntlGregorianCalendar", GregorianCalendar_class_functions); + GregorianCalendar_ce_ptr = zend_register_internal_class_ex(&ce, + Calendar_ce_ptr, NULL TSRMLS_CC); + if (!GregorianCalendar_ce_ptr) { + //can't happen know without bigger problems before + php_error_docref0(NULL TSRMLS_CC, E_ERROR, + "IntlGregorianCalendar: class registration has failed."); + return; + } + + /* Declare 'IntlCalendar' class constants */ +#define CALENDAR_DECL_LONG_CONST(name, val) \ + zend_declare_class_constant_long(Calendar_ce_ptr, name, sizeof(name) - 1, \ + val TSRMLS_CC) + + CALENDAR_DECL_LONG_CONST("FIELD_ERA", UCAL_ERA); + CALENDAR_DECL_LONG_CONST("FIELD_YEAR", UCAL_YEAR); + CALENDAR_DECL_LONG_CONST("FIELD_MONTH", UCAL_MONTH); + CALENDAR_DECL_LONG_CONST("FIELD_WEEK_OF_YEAR", UCAL_WEEK_OF_YEAR); + CALENDAR_DECL_LONG_CONST("FIELD_WEEK_OF_MONTH", UCAL_WEEK_OF_MONTH); + CALENDAR_DECL_LONG_CONST("FIELD_DATE", UCAL_DATE); + CALENDAR_DECL_LONG_CONST("FIELD_DAY_OF_YEAR", UCAL_DAY_OF_YEAR); + CALENDAR_DECL_LONG_CONST("FIELD_DAY_OF_WEEK", UCAL_DAY_OF_WEEK); + CALENDAR_DECL_LONG_CONST("FIELD_DAY_OF_WEEK_IN_MONTH", UCAL_DAY_OF_WEEK_IN_MONTH); + CALENDAR_DECL_LONG_CONST("FIELD_AM_PM", UCAL_AM_PM); + CALENDAR_DECL_LONG_CONST("FIELD_HOUR", UCAL_HOUR); + CALENDAR_DECL_LONG_CONST("FIELD_HOUR_OF_DAY", UCAL_HOUR_OF_DAY); + CALENDAR_DECL_LONG_CONST("FIELD_HOUR", UCAL_HOUR); + CALENDAR_DECL_LONG_CONST("FIELD_HOUR_OF_DAY", UCAL_HOUR_OF_DAY); + CALENDAR_DECL_LONG_CONST("FIELD_MINUTE", UCAL_MINUTE); + CALENDAR_DECL_LONG_CONST("FIELD_SECOND", UCAL_SECOND); + CALENDAR_DECL_LONG_CONST("FIELD_MILLISECOND", UCAL_MILLISECOND); + CALENDAR_DECL_LONG_CONST("FIELD_ZONE_OFFSET", UCAL_ZONE_OFFSET); + CALENDAR_DECL_LONG_CONST("FIELD_DST_OFFSET", UCAL_DST_OFFSET); + CALENDAR_DECL_LONG_CONST("FIELD_YEAR_WOY", UCAL_YEAR_WOY); + CALENDAR_DECL_LONG_CONST("FIELD_DOW_LOCAL", UCAL_DOW_LOCAL); + CALENDAR_DECL_LONG_CONST("FIELD_EXTENDED_YEAR", UCAL_EXTENDED_YEAR); + CALENDAR_DECL_LONG_CONST("FIELD_JULIAN_DAY", UCAL_JULIAN_DAY); + CALENDAR_DECL_LONG_CONST("FIELD_MILLISECONDS_IN_DAY", UCAL_MILLISECONDS_IN_DAY); + CALENDAR_DECL_LONG_CONST("FIELD_IS_LEAP_MONTH", UCAL_IS_LEAP_MONTH); + CALENDAR_DECL_LONG_CONST("FIELD_FIELD_COUNT ", UCAL_FIELD_COUNT); + CALENDAR_DECL_LONG_CONST("FIELD_DAY_OF_MONTH", UCAL_DAY_OF_MONTH); + + CALENDAR_DECL_LONG_CONST("DOW_SUNDAY", UCAL_SUNDAY); + CALENDAR_DECL_LONG_CONST("DOW_MONDAY", UCAL_MONDAY); + CALENDAR_DECL_LONG_CONST("DOW_TUESDAY", UCAL_TUESDAY); + CALENDAR_DECL_LONG_CONST("DOW_WEDNESDAY", UCAL_WEDNESDAY); + CALENDAR_DECL_LONG_CONST("DOW_THURSDAY", UCAL_THURSDAY); + CALENDAR_DECL_LONG_CONST("DOW_FRIDAY", UCAL_FRIDAY); + CALENDAR_DECL_LONG_CONST("DOW_SATURDAY", UCAL_SATURDAY); + +#if U_ICU_VERSION_MAJOR_NUM * 10 + U_ICU_VERSION_MINOR_NUM >= 44 + CALENDAR_DECL_LONG_CONST("DOW_TYPE_WEEKDAY", UCAL_WEEKDAY); + CALENDAR_DECL_LONG_CONST("DOW_TYPE_WEEKEND", UCAL_WEEKEND); + CALENDAR_DECL_LONG_CONST("DOW_TYPE_WEEKEND_OFFSET", UCAL_WEEKEND_ONSET); + CALENDAR_DECL_LONG_CONST("DOW_TYPE_WEEKEND_CEASE", UCAL_WEEKEND_CEASE); +#endif + +#if U_ICU_VERSION_MAJOR_NUM >= 49 + CALENDAR_DECL_LONG_CONST("WALLTIME_FIRST", UCAL_WALLTIME_FIRST); + CALENDAR_DECL_LONG_CONST("WALLTIME_LAST", UCAL_WALLTIME_LAST); + CALENDAR_DECL_LONG_CONST("WALLTIME_NEXT_VALID", UCAL_WALLTIME_NEXT_VALID); +#endif +} +/* }}} */ diff --git a/ext/intl/calendar/calendar_class.h b/ext/intl/calendar/calendar_class.h new file mode 100644 index 0000000000..140389b639 --- /dev/null +++ b/ext/intl/calendar/calendar_class.h @@ -0,0 +1,70 @@ +/* + +----------------------------------------------------------------------+ + | 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 <cataphract@php.net> | + +----------------------------------------------------------------------+ + */ + +#ifndef CALENDAR_CLASS_H +#define CALENDAR_CLASS_H + +//redefinition of inline in PHP headers causes problems, so include this before +#include <math.h> + +#include <php.h> +#include "intl_error.h" +#include "intl_data.h" + +#ifndef USE_CALENDAR_POINTER +typedef void Calendar; +#endif + +typedef struct { + zend_object zo; + + // error handling + intl_error err; + + // ICU calendar + Calendar* ucal; +} Calendar_object; + +#define CALENDAR_ERROR(co) (co)->err +#define CALENDAR_ERROR_P(co) &(CALENDAR_ERROR(co)) + +#define CALENDAR_ERROR_CODE(co) INTL_ERROR_CODE(CALENDAR_ERROR(co)) +#define CALENDAR_ERROR_CODE_P(co) &(INTL_ERROR_CODE(CALENDAR_ERROR(co))) + +#define CALENDAR_METHOD_INIT_VARS INTL_METHOD_INIT_VARS(Calendar, co) +#define CALENDAR_METHOD_FETCH_OBJECT_NO_CHECK INTL_METHOD_FETCH_OBJECT(Calendar, co) +#define CALENDAR_METHOD_FETCH_OBJECT \ + CALENDAR_METHOD_FETCH_OBJECT_NO_CHECK; \ + if (co->ucal == NULL) \ + { \ + intl_errors_set(&co->err, U_ILLEGAL_ARGUMENT_ERROR, "Found unconstructed IntlCalendar", 0 TSRMLS_CC); \ + RETURN_FALSE; \ + } + +void calendar_object_create(zval *object, Calendar *calendar TSRMLS_DC); + +Calendar *calendar_fetch_native_calendar(zval *object TSRMLS_DC); + +void calendar_object_construct(zval *object, Calendar *calendar TSRMLS_DC); + +void calendar_register_IntlCalendar_class(TSRMLS_D); + +extern zend_class_entry *Calendar_ce_ptr, + *GregorianCalendar_ce_ptr; + +extern zend_object_handlers Calendar_handlers; + +#endif /* #ifndef CALENDAR_CLASS_H */ diff --git a/ext/intl/calendar/calendar_methods.cpp b/ext/intl/calendar/calendar_methods.cpp new file mode 100644 index 0000000000..539b11a1f7 --- /dev/null +++ b/ext/intl/calendar/calendar_methods.cpp @@ -0,0 +1,1325 @@ +/* + +----------------------------------------------------------------------+ + | 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 <cataphract@php.net> | + +----------------------------------------------------------------------+ +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "../intl_cppshims.h" + +#include <unicode/locid.h> +#include <unicode/calendar.h> +#include <unicode/ustring.h> +#include "../intl_convertcpp.h" +extern "C" { +#include "../php_intl.h" +#define USE_TIMEZONE_POINTER 1 +#include "../timezone/timezone_class.h" +#define USE_CALENDAR_POINTER 1 +#include "calendar_class.h" +#include "../intl_convert.h" +#include <zend_exceptions.h> +#include <zend_interfaces.h> +#include <ext/date/php_date.h> +} +#include "../common/common_enum.h" + +U_CFUNC PHP_METHOD(IntlCalendar, __construct) +{ + zend_throw_exception( NULL, + "An object of this type cannot be created with the new operator", + 0 TSRMLS_CC ); +} + +U_CFUNC PHP_FUNCTION(intlcal_create_instance) +{ + zval **zv_timezone = NULL; + const char *locale_str = NULL; + int dummy; + TimeZone *timeZone; + UErrorCode status = U_ZERO_ERROR; + intl_error_reset(NULL TSRMLS_CC); + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|Zs!", + &zv_timezone, &locale_str, &dummy) == FAILURE) { + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, + "intlcal_create_calendar: bad arguments", 0 TSRMLS_CC); + RETURN_NULL(); + } + + timeZone = timezone_process_timezone_argument(zv_timezone, NULL, + "intlcal_create_instance" TSRMLS_CC); + if (timeZone == NULL) { + RETURN_NULL(); + } + + if (!locale_str) { + locale_str = intl_locale_get_default(TSRMLS_C); + } + + Calendar *cal = Calendar::createInstance(timeZone, + Locale::createFromName(locale_str), status); + if (cal == NULL) { + delete timeZone; + intl_error_set(NULL, status, "Error creating ICU Calendar object", 0 TSRMLS_CC); + RETURN_NULL(); + } + + calendar_object_create(return_value, cal TSRMLS_CC); +} + +#if U_ICU_VERSION_MAJOR_NUM * 10 + U_ICU_VERSION_MINOR_NUM >= 42 +class BugStringCharEnumeration : public StringEnumeration +{ +public: + BugStringCharEnumeration(UEnumeration* _uenum) : uenum(_uenum) {} + + ~BugStringCharEnumeration() + { + uenum_close(uenum); + } + + int32_t count(UErrorCode& status) const { + return uenum_count(uenum, &status); + } + + virtual const UnicodeString* snext(UErrorCode& status) + { + int32_t length; + const UChar* str = uenum_unext(uenum, &length, &status); + if (str == 0 || U_FAILURE(status)) { + return 0; + } + return &unistr.setTo(str, length); + } + + virtual const char* next(int32_t *resultLength, UErrorCode &status) + { + int32_t length = -1; + const char* str = uenum_next(uenum, &length, &status); + if (str == 0 || U_FAILURE(status)) { + return 0; + } + if (resultLength) { + //the bug is that uenum_next doesn't set the length + *resultLength = (length == -1) ? strlen(str) : length; + } + + return str; + } + + void reset(UErrorCode& status) + { + uenum_reset(uenum, &status); + } + + virtual UClassID getDynamicClassID() const; + + static UClassID U_EXPORT2 getStaticClassID(); + +private: + UEnumeration *uenum; +}; +UOBJECT_DEFINE_RTTI_IMPLEMENTATION(BugStringCharEnumeration) + +U_CFUNC PHP_FUNCTION(intlcal_get_keyword_values_for_locale) +{ + UErrorCode status = U_ZERO_ERROR; + char *key, + *locale; + int key_len, + locale_len; + zend_bool commonly_used; + intl_error_reset(NULL TSRMLS_CC); + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ssb", + &key, &key_len, &locale, &locale_len, &commonly_used) == FAILURE) { + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, + "intlcal_get_keyword_values_for_locale: bad arguments", 0 TSRMLS_CC); + RETURN_FALSE; + } + + //does not work; see ICU bug 9194 +#if 0 + StringEnumeration *se = Calendar::getKeywordValuesForLocale(key, + Locale::createFromName(locale), (UBool)commonly_used, + status); + if (se == NULL) { + intl_error_set(NULL, status, "intlcal_get_keyword_values_for_locale: " + "error calling underlying method", 0 TSRMLS_CC); + RETURN_FALSE; + } +#else + UEnumeration *uenum = ucal_getKeywordValuesForLocale( + key, locale, !!commonly_used, &status); + if (U_FAILURE(status)) { + uenum_close(uenum); + intl_error_set(NULL, status, "intlcal_get_keyword_values_for_locale: " + "error calling underlying method", 0 TSRMLS_CC); + RETURN_FALSE; + } + + StringEnumeration *se = new BugStringCharEnumeration(uenum); +#endif + + IntlIterator_from_StringEnumeration(se, return_value TSRMLS_CC); +} +#endif //ICU 4.2 only + +U_CFUNC PHP_FUNCTION(intlcal_get_now) +{ + UErrorCode status = U_ZERO_ERROR; + intl_error_reset(NULL TSRMLS_CC); + + if (zend_parse_parameters_none() == FAILURE) { + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, + "intlcal_get_now: bad arguments", 0 TSRMLS_CC); + RETURN_FALSE; + } + + RETURN_DOUBLE((double)Calendar::getNow()); +} + +U_CFUNC PHP_FUNCTION(intlcal_get_available_locales) +{ + intl_error_reset(NULL TSRMLS_CC); + + if (zend_parse_parameters_none() == FAILURE) { + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, + "intlcal_get_available_locales: bad arguments", 0 TSRMLS_CC); + RETURN_FALSE; + } + + int32_t count; + const Locale *availLocales = Calendar::getAvailableLocales(count); + array_init(return_value); + for (int i = 0; i < count; i++) { + Locale locale = availLocales[i]; + add_next_index_string(return_value, locale.getName(), 1); + } +} + +static void _php_intlcal_field_uec_ret_in32t_method( + int32_t (Calendar::*func)(UCalendarDateFields, UErrorCode&) const, + const char *method_name, + INTERNAL_FUNCTION_PARAMETERS) +{ + long field; + char *message; + CALENDAR_METHOD_INIT_VARS; + + if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), + "Ol", &object, Calendar_ce_ptr, &field) == FAILURE) { + spprintf(&message, 0, "%s: bad arguments", method_name); + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, message, 1 TSRMLS_CC); + efree(message); + RETURN_FALSE; + } + + if (field < 0 || field >= UCAL_FIELD_COUNT) { + spprintf(&message, 0, "%s: invalid field", method_name); + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, message, 1 TSRMLS_CC); + efree(message); + RETURN_FALSE; + } + + CALENDAR_METHOD_FETCH_OBJECT; + + int32_t result = (co->ucal->*func)( + (UCalendarDateFields)field, CALENDAR_ERROR_CODE(co)); + INTL_METHOD_CHECK_STATUS(co, "Call to ICU method has failed"); + + RETURN_LONG((long)result); +} + +U_CFUNC PHP_FUNCTION(intlcal_get) +{ + _php_intlcal_field_uec_ret_in32t_method(&Calendar::get, + "intlcal_get", INTERNAL_FUNCTION_PARAM_PASSTHRU); +} + +U_CFUNC PHP_FUNCTION(intlcal_get_time) +{ + CALENDAR_METHOD_INIT_VARS; + + if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O", + &object, Calendar_ce_ptr) == FAILURE) { + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, + "intlcal_get_time: bad arguments", 0 TSRMLS_CC); + RETURN_FALSE; + } + + CALENDAR_METHOD_FETCH_OBJECT; + + UDate result = co->ucal->getTime(CALENDAR_ERROR_CODE(co)); + INTL_METHOD_CHECK_STATUS(co, + "intlcal_get_time: error calling ICU Calendar::getTime"); + + RETURN_DOUBLE((double)result); +} + +U_CFUNC PHP_FUNCTION(intlcal_set_time) +{ + double time_arg; + CALENDAR_METHOD_INIT_VARS; + + if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Od", + &object, Calendar_ce_ptr, &time_arg) == FAILURE) { + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, + "intlcal_set_time: bad arguments", 0 TSRMLS_CC); + RETURN_FALSE; + } + + CALENDAR_METHOD_FETCH_OBJECT; + + co->ucal->setTime((UDate)time_arg, CALENDAR_ERROR_CODE(co)); + INTL_METHOD_CHECK_STATUS(co, "Call to underlying method failed"); + + RETURN_TRUE; +} + +U_CFUNC PHP_FUNCTION(intlcal_add) +{ + long field, + amount; + CALENDAR_METHOD_INIT_VARS; + + if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), + "Oll", &object, Calendar_ce_ptr, &field, &amount) == FAILURE) { + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, + "intlcal_add: bad arguments", 0 TSRMLS_CC); + RETURN_FALSE; + } + + if (field < 0 || field >= UCAL_FIELD_COUNT) { + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, + "intlcal_add: invalid field", 0 TSRMLS_CC); + RETURN_FALSE; + } + if (amount < INT32_MIN || amount > INT32_MAX) { + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, + "intlcal_add: amount out of bounds", 0 TSRMLS_CC); + RETURN_FALSE; + } + + CALENDAR_METHOD_FETCH_OBJECT; + + co->ucal->add((UCalendarDateFields)field, (int32_t)amount, CALENDAR_ERROR_CODE(co)); + INTL_METHOD_CHECK_STATUS(co, "intlcal_add: Call to underlying method failed"); + + RETURN_TRUE; +} + +U_CFUNC PHP_FUNCTION(intlcal_set_time_zone) +{ + zval *zv_timezone; + TimeZone *timeZone; + CALENDAR_METHOD_INIT_VARS; + + if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), + "Oz!", &object, Calendar_ce_ptr, &zv_timezone) == FAILURE) { + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, + "intlcal_set_time_zone: bad arguments", 0 TSRMLS_CC); + RETURN_FALSE; + } + + CALENDAR_METHOD_FETCH_OBJECT; + + if (zv_timezone == NULL) { + RETURN_TRUE; /* the method does nothing if passed null */ + } + + timeZone = timezone_process_timezone_argument(&zv_timezone, + CALENDAR_ERROR_P(co), "intlcal_set_time_zone" TSRMLS_CC); + if (timeZone == NULL) { + RETURN_FALSE; + } + + co->ucal->adoptTimeZone(timeZone); + + RETURN_TRUE; +} + + +static void _php_intlcal_before_after( + UBool (Calendar::*func)(const Calendar&, UErrorCode&) const, + INTERNAL_FUNCTION_PARAMETERS) +{ + zval *when_object; + Calendar_object *when_co; + CALENDAR_METHOD_INIT_VARS; + + if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), + "OO", &object, Calendar_ce_ptr, &when_object, Calendar_ce_ptr) + == FAILURE) { + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, + "intlcal_before/after: bad arguments", 0 TSRMLS_CC); + RETURN_FALSE; + } + + CALENDAR_METHOD_FETCH_OBJECT; + + when_co = static_cast<Calendar_object*>( + zend_object_store_get_object(when_object TSRMLS_CC)); + if (when_co->ucal == NULL) { + intl_errors_set(&co->err, U_ILLEGAL_ARGUMENT_ERROR, + "intlcal_before/after: Other IntlCalendar was unconstructed", 0 TSRMLS_CC); + RETURN_FALSE; + } + + UBool res = (co->ucal->*func)(*when_co->ucal, CALENDAR_ERROR_CODE(co)); + INTL_METHOD_CHECK_STATUS(co, "intlcal_before/after: Error calling ICU method"); + + RETURN_BOOL((int)res); +} + +U_CFUNC PHP_FUNCTION(intlcal_after) +{ + _php_intlcal_before_after(&Calendar::after, INTERNAL_FUNCTION_PARAM_PASSTHRU); +} + +U_CFUNC PHP_FUNCTION(intlcal_before) +{ + _php_intlcal_before_after(&Calendar::before, INTERNAL_FUNCTION_PARAM_PASSTHRU); +} + +U_CFUNC PHP_FUNCTION(intlcal_set) +{ + long arg1, arg2, arg3, arg4, arg5, arg6; + zval **args_a[7] = {0}, + ***args = &args_a[0]; + int i; + int variant; /* number of args of the set() overload */ + CALENDAR_METHOD_INIT_VARS; + + /* must come before zpp because zpp would convert the args in the stack to 0 */ + if (ZEND_NUM_ARGS() > (getThis() ? 6 : 7) || + zend_get_parameters_array_ex(ZEND_NUM_ARGS(), args) == FAILURE) { + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, + "intlcal_set: too many arguments", 0 TSRMLS_CC); + RETURN_FALSE; + } + if (!getThis()) { + args++; + } + variant = ZEND_NUM_ARGS() - (getThis() ? 0 : 1); + while (variant > 2 && Z_TYPE_PP(args[variant - 1]) == IS_NULL) { + variant--; + } + + if (variant == 4 || + zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), + "Oll|llll", &object, Calendar_ce_ptr, &arg1, &arg2, &arg3, &arg4, + &arg5, &arg6) == FAILURE) { + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, + "intlcal_set: bad arguments", 0 TSRMLS_CC); + RETURN_FALSE; + } + + for (i = 0; i < variant; i++) { + if (Z_LVAL_PP(args[i]) < INT32_MIN || Z_LVAL_PP(args[i]) > INT32_MAX) { + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, + "intlcal_set: at least one of the arguments has an absolute " + "value that is too large", 0 TSRMLS_CC); + RETURN_FALSE; + } + } + + if (variant == 2 && (arg1 < 0 || arg1 >= UCAL_FIELD_COUNT)) { + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, + "intlcal_set: invalid field", 0 TSRMLS_CC); + RETURN_FALSE; + } + + CALENDAR_METHOD_FETCH_OBJECT; + + if (variant == 2) { + co->ucal->set((UCalendarDateFields)arg1, (int32_t)arg2); + } else if (variant == 3) { + co->ucal->set((int32_t)arg1, (int32_t)arg2, (int32_t)arg3); + } else if (variant == 5) { + co->ucal->set((int32_t)arg1, (int32_t)arg2, (int32_t)arg3, (int32_t)arg4, (int32_t)arg5); + } else if (variant == 6) { + co->ucal->set((int32_t)arg1, (int32_t)arg2, (int32_t)arg3, (int32_t)arg4, (int32_t)arg5, (int32_t)arg6); + } + + RETURN_TRUE; +} + +U_CFUNC PHP_FUNCTION(intlcal_roll) +{ + long field, + value; + zval **args_a[3] = {0}, + ***args = &args_a[0]; + zend_bool bool_variant_val = (zend_bool)-1; + CALENDAR_METHOD_INIT_VARS; + + if (ZEND_NUM_ARGS() > (getThis() ? 2 :3) || + zend_get_parameters_array_ex(ZEND_NUM_ARGS(), args) == FAILURE) { + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, + "intlcal_set: too many arguments", 0 TSRMLS_CC); + RETURN_FALSE; + } + if (!getThis()) { + args++; + } + if (args[1] != NULL && Z_TYPE_PP(args[1]) == IS_BOOL) { + if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), + "Olb", &object, Calendar_ce_ptr, &field, &bool_variant_val) + == FAILURE) { + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, + "intlcal_roll: bad arguments", 0 TSRMLS_CC); + RETURN_FALSE; + } + bool_variant_val = Z_BVAL_PP(args[1]); + } else if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), + "Oll", &object, Calendar_ce_ptr, &field, &value) == FAILURE) { + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, + "intlcal_roll: bad arguments", 0 TSRMLS_CC); + RETURN_FALSE; + } + + if (field < 0 || field >= UCAL_FIELD_COUNT) { + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, + "intlcal_roll: invalid field", 0 TSRMLS_CC); + RETURN_FALSE; + } + if (bool_variant_val == (zend_bool)-1 && + (value < INT32_MIN || value > INT32_MAX)) { + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, + "intlcal_roll: value out of bounds", 0 TSRMLS_CC); + RETURN_FALSE; + } + + CALENDAR_METHOD_FETCH_OBJECT; + + if (bool_variant_val != (zend_bool)-1) { + co->ucal->roll((UCalendarDateFields)field, (UBool)bool_variant_val, + CALENDAR_ERROR_CODE(co)); + } else { + co->ucal->roll((UCalendarDateFields)field, (int32_t)value, + CALENDAR_ERROR_CODE(co)); + } + INTL_METHOD_CHECK_STATUS(co, "intlcal_roll: Error calling ICU Calendar::roll"); + + RETURN_TRUE; +} + +U_CFUNC PHP_FUNCTION(intlcal_clear) +{ + zval **args_a[2] = {0}, + ***args = &args_a[0]; + long field; + int variant; + CALENDAR_METHOD_INIT_VARS; + + if (ZEND_NUM_ARGS() > (getThis() ? 1 : 2) || + zend_get_parameters_array_ex(ZEND_NUM_ARGS(), args) == FAILURE) { + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, + "intlcal_clear: too many arguments", 0 TSRMLS_CC); + RETURN_FALSE; + } + if (!getThis()) { + args++; + } + if (args[0] == NULL || Z_TYPE_PP(args[0]) == IS_NULL) { + zval *dummy; /* we know it's null */ + if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, + getThis(), "O|z", &object, Calendar_ce_ptr, &dummy) == FAILURE) { + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, + "intlcal_clear: bad arguments", 0 TSRMLS_CC); + RETURN_FALSE; + } + variant = 0; + } else if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, + getThis(), "Ol", &object, Calendar_ce_ptr, &field) == FAILURE) { + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, + "intlcal_clear: bad arguments", 0 TSRMLS_CC); + RETURN_FALSE; + } else if (field < 0 || field >= UCAL_FIELD_COUNT) { + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, + "intlcal_clear: invalid field", 0 TSRMLS_CC); + RETURN_FALSE; + } else { + variant = 1; + } + + CALENDAR_METHOD_FETCH_OBJECT; + + if (variant == 0) { + co->ucal->clear(); + } else { + co->ucal->clear((UCalendarDateFields)field); + } + + RETURN_TRUE; +} + +U_CFUNC PHP_FUNCTION(intlcal_field_difference) +{ + long field; + double when; + CALENDAR_METHOD_INIT_VARS; + + if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), + "Odl", &object, Calendar_ce_ptr, &when, &field) == FAILURE) { + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, + "intlcal_field_difference: bad arguments", 0 TSRMLS_CC); + RETURN_FALSE; + } + + if (field < 0 || field >= UCAL_FIELD_COUNT) { + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, + "intlcal_field_difference: invalid field", 0 TSRMLS_CC); + RETURN_FALSE; + } + + CALENDAR_METHOD_FETCH_OBJECT; + + int32_t result = co->ucal->fieldDifference((UDate)when, + (UCalendarDateFields)field, CALENDAR_ERROR_CODE(co)); + INTL_METHOD_CHECK_STATUS(co, + "intlcal_field_difference: Call to ICU method has failed"); + + RETURN_LONG((long)result); +} + +U_CFUNC PHP_FUNCTION(intlcal_get_actual_maximum) +{ + _php_intlcal_field_uec_ret_in32t_method(&Calendar::getActualMaximum, + "intlcal_get_actual_maximum", INTERNAL_FUNCTION_PARAM_PASSTHRU); +} + +U_CFUNC PHP_FUNCTION(intlcal_get_actual_minimum) +{ + _php_intlcal_field_uec_ret_in32t_method(&Calendar::getActualMinimum, + "intlcal_get_actual_minimum", INTERNAL_FUNCTION_PARAM_PASSTHRU); +} + +#if U_ICU_VERSION_MAJOR_NUM * 10 + U_ICU_VERSION_MINOR_NUM >= 44 +U_CFUNC PHP_FUNCTION(intlcal_get_day_of_week_type) +{ + long dow; + CALENDAR_METHOD_INIT_VARS; + + if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), + "Ol", &object, Calendar_ce_ptr, &dow) == FAILURE) { + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, + "intlcal_get_day_of_week_type: bad arguments", 0 TSRMLS_CC); + RETURN_FALSE; + } + + if (dow < UCAL_SUNDAY || dow > UCAL_SATURDAY) { + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, + "intlcal_get_day_of_week_type: invalid day of week", 0 TSRMLS_CC); + RETURN_FALSE; + } + + CALENDAR_METHOD_FETCH_OBJECT; + + int32_t result = co->ucal->getDayOfWeekType( + (UCalendarDaysOfWeek)dow, CALENDAR_ERROR_CODE(co)); + INTL_METHOD_CHECK_STATUS(co, + "intlcal_get_day_of_week_type: Call to ICU method has failed"); + + RETURN_LONG((long)result); +} +#endif + +U_CFUNC PHP_FUNCTION(intlcal_get_first_day_of_week) +{ + CALENDAR_METHOD_INIT_VARS; + + if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), + "O", &object, Calendar_ce_ptr) == FAILURE) { + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, + "intlcal_get_first_day_of_week: bad arguments", 0 TSRMLS_CC); + RETURN_FALSE; + } + + CALENDAR_METHOD_FETCH_OBJECT; + + int32_t result = co->ucal->getFirstDayOfWeek(CALENDAR_ERROR_CODE(co)); + INTL_METHOD_CHECK_STATUS(co, + "intlcal_get_first_day_of_week: Call to ICU method has failed"); + + RETURN_LONG((long)result); +} + +static void _php_intlcal_field_ret_in32t_method( + int32_t (Calendar::*func)(UCalendarDateFields) const, + const char *method_name, + INTERNAL_FUNCTION_PARAMETERS) +{ + long field; + char *message; + CALENDAR_METHOD_INIT_VARS; + + if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), + "Ol", &object, Calendar_ce_ptr, &field) == FAILURE) { + spprintf(&message, 0, "%s: bad arguments", method_name); + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, message, 1 TSRMLS_CC); + efree(message); + RETURN_FALSE; + } + + if (field < 0 || field >= UCAL_FIELD_COUNT) { + spprintf(&message, 0, "%s: invalid field", method_name); + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, message, 1 TSRMLS_CC); + efree(message); + RETURN_FALSE; + } + + CALENDAR_METHOD_FETCH_OBJECT; + + int32_t result = (co->ucal->*func)((UCalendarDateFields)field); + INTL_METHOD_CHECK_STATUS(co, "Call to ICU method has failed"); + + RETURN_LONG((long)result); +} + +U_CFUNC PHP_FUNCTION(intlcal_get_greatest_minimum) +{ + _php_intlcal_field_ret_in32t_method(&Calendar::getGreatestMinimum, + "intlcal_get_greatest_minimum", INTERNAL_FUNCTION_PARAM_PASSTHRU); +} + +U_CFUNC PHP_FUNCTION(intlcal_get_least_maximum) +{ + _php_intlcal_field_ret_in32t_method(&Calendar::getLeastMaximum, + "intlcal_get_least_maximum", INTERNAL_FUNCTION_PARAM_PASSTHRU); +} + +U_CFUNC PHP_FUNCTION(intlcal_get_locale) +{ + long locale_type; + CALENDAR_METHOD_INIT_VARS; + + if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), + "Ol", &object, Calendar_ce_ptr, &locale_type) == FAILURE) { + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, + "intlcal_get_locale: bad arguments", 0 TSRMLS_CC); + RETURN_FALSE; + } + + if (locale_type != ULOC_ACTUAL_LOCALE && locale_type != ULOC_VALID_LOCALE) { + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, + "intlcal_get_locale: invalid locale type", 0 TSRMLS_CC); + RETURN_FALSE; + } + + CALENDAR_METHOD_FETCH_OBJECT; + + Locale locale = co->ucal->getLocale((ULocDataLocaleType)locale_type, + CALENDAR_ERROR_CODE(co)); + INTL_METHOD_CHECK_STATUS(co, + "intlcal_get_locale: Call to ICU method has failed"); + + RETURN_STRING(locale.getName(), 1); +} + +U_CFUNC PHP_FUNCTION(intlcal_get_maximum) +{ + _php_intlcal_field_ret_in32t_method(&Calendar::getMaximum, + "intlcal_get_maximum", INTERNAL_FUNCTION_PARAM_PASSTHRU); +} + +U_CFUNC PHP_FUNCTION(intlcal_get_minimal_days_in_first_week) +{ + CALENDAR_METHOD_INIT_VARS; + + if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), + "O", &object, Calendar_ce_ptr) == FAILURE) { + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, + "intlcal_get_minimal_days_in_first_week: bad arguments", 0 TSRMLS_CC); + RETURN_FALSE; + } + + CALENDAR_METHOD_FETCH_OBJECT; + + uint8_t result = co->ucal->getMinimalDaysInFirstWeek(); + INTL_METHOD_CHECK_STATUS(co, + "intlcal_get_first_day_of_week: Call to ICU method has failed"); + + RETURN_LONG((long)result); +} + +U_CFUNC PHP_FUNCTION(intlcal_get_minimum) +{ + _php_intlcal_field_ret_in32t_method(&Calendar::getMinimum, + "intlcal_get_minimum", INTERNAL_FUNCTION_PARAM_PASSTHRU); +} + +U_CFUNC PHP_FUNCTION(intlcal_get_time_zone) +{ + CALENDAR_METHOD_INIT_VARS; + + if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), + "O", &object, Calendar_ce_ptr) == FAILURE) { + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, + "intlcal_get_time_zone: bad arguments", 0 TSRMLS_CC); + RETURN_FALSE; + } + + CALENDAR_METHOD_FETCH_OBJECT; + + TimeZone *tz = co->ucal->getTimeZone().clone(); + if (tz == NULL) { + intl_error_set(NULL, U_MEMORY_ALLOCATION_ERROR, + "intlcal_get_time_zone: could not clone TimeZone", 0 TSRMLS_CC); + RETURN_FALSE; + } + + timezone_object_construct(tz, return_value, 1 TSRMLS_CC); +} + +U_CFUNC PHP_FUNCTION(intlcal_get_type) +{ + CALENDAR_METHOD_INIT_VARS; + + if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), + "O", &object, Calendar_ce_ptr) == FAILURE) { + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, + "intlcal_get_type: bad arguments", 0 TSRMLS_CC); + RETURN_FALSE; + } + + CALENDAR_METHOD_FETCH_OBJECT; + + RETURN_STRING(co->ucal->getType(), 1); +} + +#if U_ICU_VERSION_MAJOR_NUM * 10 + U_ICU_VERSION_MINOR_NUM >= 44 +U_CFUNC PHP_FUNCTION(intlcal_get_weekend_transition) +{ + long dow; + CALENDAR_METHOD_INIT_VARS; + + if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), + "Ol", &object, Calendar_ce_ptr, &dow) == FAILURE) { + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, + "intlcal_get_weekend_transition: bad arguments", 0 TSRMLS_CC); + RETURN_FALSE; + } + + if (dow < UCAL_SUNDAY || dow > UCAL_SATURDAY) { + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, + "intlcal_get_weekend_transition: invalid day of week", 0 TSRMLS_CC); + RETURN_FALSE; + } + + CALENDAR_METHOD_FETCH_OBJECT; + + int32_t res = co->ucal->getWeekendTransition((UCalendarDaysOfWeek)dow, + CALENDAR_ERROR_CODE(co)); + INTL_METHOD_CHECK_STATUS(co, "intlcal_get_weekend_transition: " + "Error calling ICU method"); + + RETURN_LONG((long)res); +} +#endif + +U_CFUNC PHP_FUNCTION(intlcal_in_daylight_time) +{ + CALENDAR_METHOD_INIT_VARS; + + if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), + "O", &object, Calendar_ce_ptr) == FAILURE) { + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, + "intlcal_in_daylight_time: bad arguments", 0 TSRMLS_CC); + RETURN_FALSE; + } + + CALENDAR_METHOD_FETCH_OBJECT; + + UBool ret = co->ucal->inDaylightTime(CALENDAR_ERROR_CODE(co)); + INTL_METHOD_CHECK_STATUS(co, "intlcal_in_daylight_time: " + "Error calling ICU method"); + + RETURN_BOOL((int)ret); +} + +U_CFUNC PHP_FUNCTION(intlcal_is_equivalent_to) +{ + zval *other_object; + Calendar_object *other_co; + CALENDAR_METHOD_INIT_VARS; + + if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), + "OO", &object, Calendar_ce_ptr, &other_object, Calendar_ce_ptr) + == FAILURE) { + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, + "intlcal_is_equivalent_to: bad arguments", 0 TSRMLS_CC); + RETURN_FALSE; + } + + other_co = (Calendar_object*)zend_object_store_get_object(other_object TSRMLS_CC); + if (other_co->ucal == NULL) { + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, "intlcal_is_equivalent_to:" + " Other IntlCalendar is unconstructed", 0 TSRMLS_CC); + RETURN_FALSE; + } + + CALENDAR_METHOD_FETCH_OBJECT; + + RETURN_BOOL((int)co->ucal->isEquivalentTo(*other_co->ucal)); +} + +U_CFUNC PHP_FUNCTION(intlcal_is_lenient) +{ + CALENDAR_METHOD_INIT_VARS; + + if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), + "O", &object, Calendar_ce_ptr) == FAILURE) { + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, + "intlcal_is_lenient: bad arguments", 0 TSRMLS_CC); + RETURN_FALSE; + } + + CALENDAR_METHOD_FETCH_OBJECT; + + RETURN_BOOL((int)co->ucal->isLenient()); +} + +U_CFUNC PHP_FUNCTION(intlcal_is_set) +{ + long field; + CALENDAR_METHOD_INIT_VARS; + + if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), + "Ol", &object, Calendar_ce_ptr, &field) == FAILURE) { + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, + "intlcal_is_set: bad arguments", 0 TSRMLS_CC); + RETURN_FALSE; + } + + if (field < 0 || field >= UCAL_FIELD_COUNT) { + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, + "intlcal_is_set: invalid field", 0 TSRMLS_CC); + RETURN_FALSE; + } + + CALENDAR_METHOD_FETCH_OBJECT; + + RETURN_BOOL((int)co->ucal->isSet((UCalendarDateFields)field)); +} + +#if U_ICU_VERSION_MAJOR_NUM * 10 + U_ICU_VERSION_MINOR_NUM >= 44 +U_CFUNC PHP_FUNCTION(intlcal_is_weekend) +{ + double date; + zval *rawDate = NULL; + CALENDAR_METHOD_INIT_VARS; + + if (zend_parse_method_parameters_ex(ZEND_PARSE_PARAMS_QUIET, + ZEND_NUM_ARGS() TSRMLS_CC, getThis(), + "O|z!", &object, Calendar_ce_ptr, &rawDate) == FAILURE + || (rawDate != NULL && + zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), + "O|d", &object, Calendar_ce_ptr, &date) == FAILURE)) { + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, + "intlcal_is_weekend: bad arguments", 0 TSRMLS_CC); + RETURN_FALSE; + } + + CALENDAR_METHOD_FETCH_OBJECT; + + if (rawDate == NULL) { + RETURN_BOOL((int)co->ucal->isWeekend()); + } else { + UBool ret = co->ucal->isWeekend((UDate)date, CALENDAR_ERROR_CODE(co)); + INTL_METHOD_CHECK_STATUS(co, "intlcal_is_weekend: " + "Error calling ICU method"); + RETURN_BOOL((int)ret); + } +} +#endif + + +U_CFUNC PHP_FUNCTION(intlcal_set_first_day_of_week) +{ + long dow; + CALENDAR_METHOD_INIT_VARS; + + if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), + "Ol", &object, Calendar_ce_ptr, &dow) == FAILURE) { + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, + "intlcal_set_first_day_of_week: bad arguments", 0 TSRMLS_CC); + RETURN_FALSE; + } + + if (dow < UCAL_SUNDAY || dow > UCAL_SATURDAY) { + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, + "intlcal_set_first_day_of_week: invalid day of week", 0 TSRMLS_CC); + RETURN_FALSE; + } + + CALENDAR_METHOD_FETCH_OBJECT; + + co->ucal->setFirstDayOfWeek((UCalendarDaysOfWeek)dow); + + RETURN_TRUE; +} + +U_CFUNC PHP_FUNCTION(intlcal_set_lenient) +{ + zend_bool is_lenient; + CALENDAR_METHOD_INIT_VARS; + + if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), + "Ob", &object, Calendar_ce_ptr, &is_lenient) == FAILURE) { + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, + "intlcal_set_lenient: bad arguments", 0 TSRMLS_CC); + RETURN_FALSE; + } + + CALENDAR_METHOD_FETCH_OBJECT; + + co->ucal->setLenient((UBool) is_lenient); + + RETURN_TRUE; +} + +U_CFUNC PHP_FUNCTION(intlcal_equals) +{ + zval *other_object; + Calendar_object *other_co; + CALENDAR_METHOD_INIT_VARS; + + if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), + "OO", &object, Calendar_ce_ptr, &other_object, Calendar_ce_ptr) + == FAILURE) { + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, + "intlcal_equals: bad arguments", 0 TSRMLS_CC); + RETURN_FALSE; + } + + CALENDAR_METHOD_FETCH_OBJECT; + other_co = (Calendar_object *) zend_object_store_get_object(other_object TSRMLS_CC); + if (other_co->ucal == NULL) { + intl_errors_set(&co->err, U_ILLEGAL_ARGUMENT_ERROR, + "intlcal_equals: The second IntlCalendar is unconstructed", 0 TSRMLS_CC); + RETURN_FALSE; + } + + UBool result = co->ucal->equals(*other_co->ucal, CALENDAR_ERROR_CODE(co)); + INTL_METHOD_CHECK_STATUS(co, "intlcal_equals: error calling ICU Calendar::equals"); + + RETURN_BOOL((int)result); +} + +#if U_ICU_VERSION_MAJOR_NUM >= 49 + +U_CFUNC PHP_FUNCTION(intlcal_get_repeated_wall_time_option) +{ + CALENDAR_METHOD_INIT_VARS; + + if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), + "O", &object, Calendar_ce_ptr) == FAILURE) { + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, + "intlcal_get_repeated_wall_time_option: bad arguments", 0 TSRMLS_CC); + RETURN_FALSE; + } + + CALENDAR_METHOD_FETCH_OBJECT; + + RETURN_LONG(co->ucal->getRepeatedWallTimeOption()); +} + +U_CFUNC PHP_FUNCTION(intlcal_get_skipped_wall_time_option) +{ + CALENDAR_METHOD_INIT_VARS; + + if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), + "O", &object, Calendar_ce_ptr) == FAILURE) { + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, + "intlcal_get_skipped_wall_time_option: bad arguments", 0 TSRMLS_CC); + RETURN_FALSE; + } + + CALENDAR_METHOD_FETCH_OBJECT; + + RETURN_LONG(co->ucal->getSkippedWallTimeOption()); +} + +U_CFUNC PHP_FUNCTION(intlcal_set_repeated_wall_time_option) +{ + long option; + CALENDAR_METHOD_INIT_VARS; + + if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), + "Ol", &object, Calendar_ce_ptr, &option) == FAILURE) { + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, + "intlcal_set_repeated_wall_time_option: bad arguments", 0 TSRMLS_CC); + RETURN_FALSE; + } + + if (option != UCAL_WALLTIME_FIRST && option != UCAL_WALLTIME_LAST) { + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, + "intlcal_set_repeated_wall_time_option: invalid option", 0 TSRMLS_CC); + RETURN_FALSE; + } + + CALENDAR_METHOD_FETCH_OBJECT; + + co->ucal->setRepeatedWallTimeOption((UCalendarWallTimeOption)option); + + RETURN_TRUE; +} + +U_CFUNC PHP_FUNCTION(intlcal_set_skipped_wall_time_option) +{ + long option; + CALENDAR_METHOD_INIT_VARS; + + if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), + "Ol", &object, Calendar_ce_ptr, &option) == FAILURE) { + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, + "intlcal_set_skipped_wall_time_option: bad arguments", 0 TSRMLS_CC); + RETURN_FALSE; + } + + if (option != UCAL_WALLTIME_FIRST && option != UCAL_WALLTIME_LAST + && option != UCAL_WALLTIME_NEXT_VALID) { + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, + "intlcal_set_skipped_wall_time_option: invalid option", 0 TSRMLS_CC); + RETURN_FALSE; + } + + CALENDAR_METHOD_FETCH_OBJECT; + + co->ucal->setSkippedWallTimeOption((UCalendarWallTimeOption)option); + + RETURN_TRUE; +} + +#endif + +U_CFUNC PHP_FUNCTION(intlcal_from_date_time) +{ + zval **zv_arg, + *zv_datetime = NULL, + *zv_timestamp = NULL; + php_date_obj *datetime; + char *locale_str = NULL; + int locale_str_len; + TimeZone *timeZone; + UErrorCode status = U_ZERO_ERROR; + Calendar *cal; + intl_error_reset(NULL TSRMLS_CC); + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z|s!", + &zv_arg, &locale_str, &locale_str_len) == FAILURE) { + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, + "intlcal_from_date_time: bad arguments", 0 TSRMLS_CC); + RETURN_NULL(); + } + + if (!(Z_TYPE_PP(zv_arg) == IS_OBJECT && instanceof_function( + Z_OBJCE_PP(zv_arg), php_date_get_date_ce() TSRMLS_CC))) { + ALLOC_INIT_ZVAL(zv_datetime); + object_init_ex(zv_datetime, php_date_get_date_ce()); + zend_call_method_with_1_params(&zv_datetime, NULL, NULL, "__construct", + NULL, *zv_arg); + if (EG(exception)) { + zend_object_store_ctor_failed(zv_datetime TSRMLS_CC); + goto error; + } + } else { + zv_datetime = *zv_arg; + } + + datetime = (php_date_obj*)zend_object_store_get_object(zv_datetime TSRMLS_CC); + if (!datetime->time) { + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, + "intlcal_from_date_time: DateTime object is unconstructed", + 0 TSRMLS_CC); + goto error; + } + + zend_call_method_with_0_params(&zv_datetime, php_date_get_date_ce(), + NULL, "gettimestamp", &zv_timestamp); + if (!zv_timestamp || Z_TYPE_P(zv_timestamp) != IS_LONG) { + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, + "intlcal_from_date_time: bad DateTime; call to " + "DateTime::getTimestamp() failed", 0 TSRMLS_CC); + goto error; + } + + if (!datetime->time->is_localtime) { + timeZone = TimeZone::getGMT()->clone(); + } else { + timeZone = timezone_convert_datetimezone(datetime->time->zone_type, + datetime, 1, NULL, "intlcal_from_date_time" TSRMLS_CC); + if (timeZone == NULL) { + goto error; + } + } + + if (!locale_str) { + locale_str = const_cast<char*>(intl_locale_get_default(TSRMLS_C)); + } + + cal = Calendar::createInstance(timeZone, + Locale::createFromName(locale_str), status); + if (cal == NULL) { + delete timeZone; + intl_error_set(NULL, status, "intlcal_from_date_time: " + "error creating ICU Calendar object", 0 TSRMLS_CC); + goto error; + } + cal->setTime(((UDate)Z_LVAL_P(zv_timestamp)) * 1000., status); + if (U_FAILURE(status)) { + /* time zone was adopted by cal; should not be deleted here */ + delete cal; + intl_error_set(NULL, status, "intlcal_from_date_time: " + "error creating ICU Calendar::setTime()", 0 TSRMLS_CC); + goto error; + } + + calendar_object_create(return_value, cal TSRMLS_CC); + +error: + if (zv_datetime != *zv_arg) { + zval_ptr_dtor(&zv_datetime); + } + if (zv_timestamp) { + zval_ptr_dtor(&zv_timestamp); + } +} + +U_CFUNC PHP_FUNCTION(intlcal_to_date_time) +{ + zval *retval = NULL; + CALENDAR_METHOD_INIT_VARS; + + if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O", + &object, Calendar_ce_ptr) == FAILURE) { + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, + "intlcal_to_date_time: bad arguments", 0 TSRMLS_CC); + RETURN_FALSE; + } + + CALENDAR_METHOD_FETCH_OBJECT; + + /* There are no exported functions in ext/date to this + * in a more native fashion */ + double date = co->ucal->getTime(CALENDAR_ERROR_CODE(co)) / 1000.; + int64_t ts; + char ts_str[sizeof("@-9223372036854775808")]; + int ts_str_len; + zval ts_zval = zval_used_for_init; + + INTL_METHOD_CHECK_STATUS(co, "Call to ICU method has failed"); + + if (date > (double)U_INT64_MAX || date < (double)U_INT64_MIN) { + intl_errors_set(CALENDAR_ERROR_P(co), U_ILLEGAL_ARGUMENT_ERROR, + "intlcal_to_date_time: The calendar date is out of the " + "range for a 64-bit integer", 0 TSRMLS_CC); + RETURN_FALSE; + } + + ts = (int64_t)date; + + ts_str_len = slprintf(ts_str, sizeof(ts_str), "@%I64d", ts); + ZVAL_STRINGL(&ts_zval, ts_str, ts_str_len, 0); + + /* Now get the time zone */ + const TimeZone& tz = co->ucal->getTimeZone(); + zval *timezone_zval = timezone_convert_to_datetimezone( + &tz, CALENDAR_ERROR_P(co), "intlcal_to_date_time" TSRMLS_CC); + if (timezone_zval == NULL) { + RETURN_FALSE; + } + + /* resources allocated from now on */ + + /* Finally, instantiate object and call constructor */ + object_init_ex(return_value, php_date_get_date_ce()); + zend_call_method_with_2_params(&return_value, NULL, NULL, "__construct", + NULL, &ts_zval, timezone_zval); + if (EG(exception)) { + intl_errors_set(CALENDAR_ERROR_P(co), U_ILLEGAL_ARGUMENT_ERROR, + "intlcal_to_date_time: DateTime constructor has thrown exception", + 1 TSRMLS_CC); + zend_object_store_ctor_failed(return_value TSRMLS_CC); + zval_ptr_dtor(&return_value); + + RETVAL_FALSE; + goto error; + } + + /* due to bug #40743, we have to set the time zone again */ + zend_call_method_with_1_params(&return_value, NULL, NULL, "settimezone", + &retval, timezone_zval); + if (retval == NULL || Z_TYPE_P(retval) == IS_BOOL) { + intl_errors_set(CALENDAR_ERROR_P(co), U_ILLEGAL_ARGUMENT_ERROR, + "intlcal_to_date_time: call to DateTime::setTimeZone has failed", + 1 TSRMLS_CC); + zval_ptr_dtor(&return_value); + RETVAL_FALSE; + goto error; + } + +error: + zval_ptr_dtor(&timezone_zval); + if (retval != NULL) { + zval_ptr_dtor(&retval); + } +} + +U_CFUNC PHP_FUNCTION(intlcal_get_error_code) +{ + CALENDAR_METHOD_INIT_VARS; + + if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O", + &object, Calendar_ce_ptr) == FAILURE) { + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, + "intlcal_get_error_code: bad arguments", 0 TSRMLS_CC); + RETURN_FALSE; + } + + /* Fetch the object (without resetting its last error code ). */ + co = (Calendar_object*)zend_object_store_get_object(object TSRMLS_CC); + if (co == NULL) + RETURN_FALSE; + + RETURN_LONG((long)CALENDAR_ERROR_CODE(co)); +} + +U_CFUNC PHP_FUNCTION(intlcal_get_error_message) +{ + const char* message = NULL; + CALENDAR_METHOD_INIT_VARS; + + if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O", + &object, Calendar_ce_ptr) == FAILURE) { + intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR, + "intlcal_get_error_message: bad arguments", 0 TSRMLS_CC ); + RETURN_FALSE; + } + + + /* Fetch the object (without resetting its last error code ). */ + co = (Calendar_object*)zend_object_store_get_object(object TSRMLS_CC); + if (co == NULL) + RETURN_FALSE; + + /* Return last error message. */ + message = intl_error_get_message(CALENDAR_ERROR_P(co) TSRMLS_CC); + RETURN_STRING(message, 0); +} diff --git a/ext/intl/calendar/calendar_methods.h b/ext/intl/calendar/calendar_methods.h new file mode 100644 index 0000000000..2be13e4920 --- /dev/null +++ b/ext/intl/calendar/calendar_methods.h @@ -0,0 +1,112 @@ +/* + +----------------------------------------------------------------------+ + | 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 <cataphract@netcabo.pt> | + +----------------------------------------------------------------------+ + */ + +#ifndef CALENDAR_METHODS_H +#define CALENDAR_METHODS_H + +#include <php.h> + +PHP_METHOD(IntlCalendar, __construct); + +PHP_FUNCTION(intlcal_create_instance); + +PHP_FUNCTION(intlcal_get_keyword_values_for_locale); + +PHP_FUNCTION(intlcal_get_now); + +PHP_FUNCTION(intlcal_get_available_locales); + +PHP_FUNCTION(intlcal_get); + +PHP_FUNCTION(intlcal_get_time); + +PHP_FUNCTION(intlcal_set_time); + +PHP_FUNCTION(intlcal_add); + +PHP_FUNCTION(intlcal_set_time_zone); + +PHP_FUNCTION(intlcal_after); + +PHP_FUNCTION(intlcal_before); + +PHP_FUNCTION(intlcal_set); + +PHP_FUNCTION(intlcal_roll); + +PHP_FUNCTION(intlcal_clear); + +PHP_FUNCTION(intlcal_field_difference); + +PHP_FUNCTION(intlcal_get_actual_maximum); + +PHP_FUNCTION(intlcal_get_actual_minimum); + +PHP_FUNCTION(intlcal_get_day_of_week_type); + +PHP_FUNCTION(intlcal_get_first_day_of_week); + +PHP_FUNCTION(intlcal_get_greatest_minimum); + +PHP_FUNCTION(intlcal_get_least_maximum); + +PHP_FUNCTION(intlcal_get_locale); + +PHP_FUNCTION(intlcal_get_maximum); + +PHP_FUNCTION(intlcal_get_minimal_days_in_first_week); + +PHP_FUNCTION(intlcal_get_minimum); + +PHP_FUNCTION(intlcal_get_time_zone); + +PHP_FUNCTION(intlcal_get_type); + +PHP_FUNCTION(intlcal_get_weekend_transition); + +PHP_FUNCTION(intlcal_in_daylight_time); + +PHP_FUNCTION(intlcal_is_equivalent_to); + +PHP_FUNCTION(intlcal_is_lenient); + +PHP_FUNCTION(intlcal_is_set); + +PHP_FUNCTION(intlcal_is_weekend); + +PHP_FUNCTION(intlcal_set_first_day_of_week); + +PHP_FUNCTION(intlcal_set_lenient); + +PHP_FUNCTION(intlcal_equals); + +PHP_FUNCTION(intlcal_get_repeated_wall_time_option); + +PHP_FUNCTION(intlcal_get_skipped_wall_time_option); + +PHP_FUNCTION(intlcal_set_repeated_wall_time_option); + +PHP_FUNCTION(intlcal_set_skipped_wall_time_option); + +PHP_FUNCTION(intlcal_from_date_time); + +PHP_FUNCTION(intlcal_to_date_time); + +PHP_FUNCTION(intlcal_get_error_code); + +PHP_FUNCTION(intlcal_get_error_message); + +#endif /* #ifndef CALENDAR_METHODS_H */ diff --git a/ext/intl/calendar/gregoriancalendar_methods.cpp b/ext/intl/calendar/gregoriancalendar_methods.cpp new file mode 100644 index 0000000000..3c05253de1 --- /dev/null +++ b/ext/intl/calendar/gregoriancalendar_methods.cpp @@ -0,0 +1,256 @@ +/* + +----------------------------------------------------------------------+ + | 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 <cataphract@php.net> | + +----------------------------------------------------------------------+ + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "../intl_cppshims.h" + +#include <unicode/locid.h> +#include <unicode/calendar.h> +#include <unicode/gregocal.h> +extern "C" { +#include "../php_intl.h" +#define USE_TIMEZONE_POINTER 1 +#include "../timezone/timezone_class.h" +#define USE_CALENDAR_POINTER 1 +#include "calendar_class.h" +#include <ext/date/php_date.h> +} + +static inline GregorianCalendar *fetch_greg(Calendar_object *co) { + return (GregorianCalendar*)co->ucal; +} + +static void _php_intlgregcal_constructor_body(INTERNAL_FUNCTION_PARAMETERS) +{ + zval *object = getThis(); + zval **tz_object = NULL; + zval **args_a[6] = {0}, + ***args = &args_a[0]; + char *locale = NULL; + int locale_len; + long largs[6]; + UErrorCode status = U_ZERO_ERROR; + int variant; + intl_error_reset(NULL TSRMLS_CC); + + // parameter number validation / variant determination + if (ZEND_NUM_ARGS() > 6 || + zend_get_parameters_array_ex(ZEND_NUM_ARGS(), args) == FAILURE) { + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, + "intlgregcal_create_instance: too many arguments", 0 TSRMLS_CC); + RETURN_NULL(); + } + for (variant = ZEND_NUM_ARGS(); + variant > 0 && Z_TYPE_PP(args[variant - 1]) == IS_NULL; + variant--) {} + if (variant == 4) { + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, + "intlgregcal_create_instance: no variant with 4 arguments " + "(excluding trailing NULLs)", 0 TSRMLS_CC); + RETURN_NULL(); + } + + // argument parsing + if (variant <= 2) { + if (zend_parse_parameters(MIN(ZEND_NUM_ARGS(), 2) TSRMLS_CC, + "|Z!s!", &tz_object, &locale, &locale_len) == FAILURE) { + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, + "intlgregcal_create_instance: bad arguments", 0 TSRMLS_CC); + RETURN_NULL(); + } + } + if (variant > 2 && zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, + "lll|lll", &largs[0], &largs[1], &largs[2], &largs[3], &largs[4], + &largs[5]) == FAILURE) { + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, + "intlgregcal_create_instance: bad arguments", 0 TSRMLS_CC); + RETURN_NULL(); + } + + // instantion of ICU object + GregorianCalendar *gcal; + + if (variant <= 2) { + // From timezone and locale (0 to 2 arguments) + TimeZone *tz = timezone_process_timezone_argument(tz_object, NULL, + "intlgregcal_create_instance" TSRMLS_CC); + if (tz == NULL) { + RETURN_NULL(); + } + if (!locale) { + locale = const_cast<char*>(intl_locale_get_default(TSRMLS_C)); + } + + gcal = new GregorianCalendar(tz, Locale::createFromName(locale), + status); + if (U_FAILURE(status)) { + intl_error_set(NULL, status, "intlgregcal_create_instance: error " + "creating ICU GregorianCalendar from time zone and locale", 0 TSRMLS_CC); + if (gcal) { + delete gcal; + } + delete tz; + RETURN_NULL(); + } + } else { + // From date/time (3, 5 or 6 arguments) + for (int i = 0; i < variant; i++) { + if (largs[i] < INT32_MIN || largs[i] > INT32_MAX) { + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, + "intlgregcal_create_instance: at least one of the arguments" + " has an absolute value that is too large", 0 TSRMLS_CC); + RETURN_NULL(); + } + } + + if (variant == 3) { + gcal = new GregorianCalendar((int32_t)largs[0], (int32_t)largs[1], + (int32_t)largs[2], status); + } else if (variant == 5) { + gcal = new GregorianCalendar((int32_t)largs[0], (int32_t)largs[1], + (int32_t)largs[2], (int32_t)largs[3], (int32_t)largs[4], status); + } else if (variant == 6) { + gcal = new GregorianCalendar((int32_t)largs[0], (int32_t)largs[1], + (int32_t)largs[2], (int32_t)largs[3], (int32_t)largs[4], (int32_t)largs[5], + status); + } + if (U_FAILURE(status)) { + intl_error_set(NULL, status, "intlgregcal_create_instance: error " + "creating ICU GregorianCalendar from date", 0 TSRMLS_CC); + if (gcal) { + delete gcal; + } + RETURN_NULL(); + } + + timelib_tzinfo *tzinfo = get_timezone_info(TSRMLS_C); +#if U_ICU_VERSION_MAJOR_NUM * 10 + U_ICU_VERSION_MINOR_NUM >= 42 + UnicodeString tzstr = UnicodeString::fromUTF8(StringPiece(tzinfo->name)); +#else + UnicodeString tzstr = UnicodeString(tzinfo->name, + strlen(tzinfo->name), US_INV); +#endif + if (tzstr.isBogus()) { + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, + "intlgregcal_create_instance: could not create UTF-8 string " + "from PHP's default timezone name (see date_default_timezone_get())", + 0 TSRMLS_CC); + delete gcal; + RETURN_NULL(); + } + + TimeZone *tz = TimeZone::createTimeZone(tzstr); + gcal->adoptTimeZone(tz); + } + + Calendar_object *co = (Calendar_object*)zend_object_store_get_object( + return_value TSRMLS_CC); + co->ucal = gcal; +} + +U_CFUNC PHP_FUNCTION(intlgregcal_create_instance) +{ + zval orig; + intl_error_reset(NULL TSRMLS_CC); + + object_init_ex(return_value, GregorianCalendar_ce_ptr); + orig = *return_value; + + _php_intlgregcal_constructor_body(INTERNAL_FUNCTION_PARAM_PASSTHRU); + + if (Z_TYPE_P(return_value) == IS_NULL) { + zend_object_store_ctor_failed(&orig TSRMLS_CC); + zval_dtor(&orig); + } +} + +U_CFUNC PHP_METHOD(IntlGregorianCalendar, __construct) +{ + zval orig_this = *getThis(); + intl_error_reset(NULL TSRMLS_CC); + + return_value = getThis(); + //changes this to IS_NULL (without first destroying) if there's an error + _php_intlgregcal_constructor_body(INTERNAL_FUNCTION_PARAM_PASSTHRU); + + if (Z_TYPE_P(return_value) == IS_NULL) { + zend_object_store_ctor_failed(&orig_this TSRMLS_CC); + zval_dtor(&orig_this); + } +} + +U_CFUNC PHP_FUNCTION(intlgregcal_set_gregorian_change) +{ + double date; + CALENDAR_METHOD_INIT_VARS; + + if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), + "Od", &object, GregorianCalendar_ce_ptr, &date) == FAILURE) { + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, + "intlgregcal_set_gregorian_change: bad arguments", 0 TSRMLS_CC); + RETURN_FALSE; + } + + CALENDAR_METHOD_FETCH_OBJECT; + + fetch_greg(co)->setGregorianChange(date, CALENDAR_ERROR_CODE(co)); + INTL_METHOD_CHECK_STATUS(co, "intlgregcal_set_gregorian_change: error " + "calling ICU method"); + + RETURN_TRUE; +} + +U_CFUNC PHP_FUNCTION(intlgregcal_get_gregorian_change) +{ + CALENDAR_METHOD_INIT_VARS; + + if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), + "O", &object, GregorianCalendar_ce_ptr) == FAILURE) { + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, + "intlgregcal_get_gregorian_change: bad arguments", 0 TSRMLS_CC); + RETURN_FALSE; + } + + CALENDAR_METHOD_FETCH_OBJECT; + + RETURN_DOUBLE((double)fetch_greg(co)->getGregorianChange()); +} + +U_CFUNC PHP_FUNCTION(intlgregcal_is_leap_year) +{ + long year; + CALENDAR_METHOD_INIT_VARS; + + if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), + "Ol", &object, GregorianCalendar_ce_ptr, &year) == FAILURE) { + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, + "intlgregcal_is_leap_year: bad arguments", 0 TSRMLS_CC); + RETURN_FALSE; + } + + if (year < INT32_MIN || year > INT32_MAX) { + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, + "intlgregcal_is_leap_year: year out of bounds", 0 TSRMLS_CC); + RETURN_FALSE; + } + + CALENDAR_METHOD_FETCH_OBJECT; + + RETURN_BOOL((int)fetch_greg(co)->isLeapYear((int32_t)year)); +} diff --git a/ext/intl/calendar/gregoriancalendar_methods.h b/ext/intl/calendar/gregoriancalendar_methods.h new file mode 100644 index 0000000000..f911752cc7 --- /dev/null +++ b/ext/intl/calendar/gregoriancalendar_methods.h @@ -0,0 +1,32 @@ +/* + +----------------------------------------------------------------------+ + | 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 <cataphract@php.net> | + +----------------------------------------------------------------------+ + */ + +#ifndef GREORIANCALENDAR_METHODS_H +#define GREORIANCALENDAR_METHODS_H + +#include <php.h> + +PHP_FUNCTION(intlgregcal_create_instance); + +PHP_METHOD(IntlGregorianCalendar, __construct); + +PHP_FUNCTION(intlgregcal_set_gregorian_change); + +PHP_FUNCTION(intlgregcal_get_gregorian_change); + +PHP_FUNCTION(intlgregcal_is_leap_year); + +#endif diff --git a/ext/intl/collator/collator_sort.c b/ext/intl/collator/collator_sort.c index 0785111c96..04a24f013e 100755 --- a/ext/intl/collator/collator_sort.c +++ b/ext/intl/collator/collator_sort.c @@ -78,6 +78,7 @@ static int collator_regular_compare_function(zval *result, zval *op1, zval *op2 intl_errors_set_custom_msg( COLLATOR_ERROR_P( co ), "Object not initialized", 0 TSRMLS_CC ); php_error_docref(NULL TSRMLS_CC, E_RECOVERABLE_ERROR, "Object not initialized"); + } /* Compare the strings using ICU. */ diff --git a/ext/intl/common/common_enum.cpp b/ext/intl/common/common_enum.cpp new file mode 100644 index 0000000000..da47a437a6 --- /dev/null +++ b/ext/intl/common/common_enum.cpp @@ -0,0 +1,354 @@ +/* + +----------------------------------------------------------------------+ + | 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 <cataphract@php.net> | + +----------------------------------------------------------------------+ +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "../intl_cppshims.h" + +// Fix build on Windows/old versions of ICU +#include <stdio.h> + +#include "common_enum.h" + +extern "C" { +#include <zend_interfaces.h> +#include <zend_exceptions.h> +} + +zend_class_entry *IntlIterator_ce_ptr; +zend_object_handlers IntlIterator_handlers; + +void zoi_with_current_dtor(zend_object_iterator *iter TSRMLS_DC) +{ + zoi_with_current *zoiwc = (zoi_with_current*)iter; + + if (zoiwc->wrapping_obj) { + /* we have to copy the pointer because zoiwc->wrapping_obj may be + * changed midway the execution of zval_ptr_dtor() */ + zval *zwo = zoiwc->wrapping_obj; + + /* object is still here, we can rely on it to call this again and + * destroy this object */ + zval_ptr_dtor(&zwo); + } else { + /* Object not here anymore (we've been called by the object free handler) + * Note that the iterator wrapper objects (that also depend on this + * structure) call this function earlier, in the destruction phase, which + * precedes the object free phase. Therefore there's no risk on this + * function being called by the iterator wrapper destructor function and + * not finding the memory of this iterator allocated anymore. */ + iter->funcs->invalidate_current(iter TSRMLS_CC); + zoiwc->destroy_it(iter TSRMLS_CC); + efree(iter); + } +} + +U_CFUNC int zoi_with_current_valid(zend_object_iterator *iter TSRMLS_DC) +{ + return ((zoi_with_current*)iter)->current != NULL ? SUCCESS : FAILURE; +} + +U_CFUNC void zoi_with_current_get_current_data(zend_object_iterator *iter, zval ***data TSRMLS_DC) +{ + *data = &((zoi_with_current*)iter)->current; +} + +U_CFUNC void zoi_with_current_invalidate_current(zend_object_iterator *iter TSRMLS_DC) +{ + zoi_with_current *zoi_iter = (zoi_with_current*)iter; + if (zoi_iter->current) { + zval_ptr_dtor(&zoi_iter->current); + zoi_iter->current = NULL; //valid would return FAILURE now + } +} + +static void string_enum_current_move_forward(zend_object_iterator *iter TSRMLS_DC) +{ + zoi_with_current *zoi_iter = (zoi_with_current*)iter; + INTLITERATOR_METHOD_INIT_VARS; + + iter->funcs->invalidate_current(iter TSRMLS_CC); + + object = zoi_iter->wrapping_obj; + INTLITERATOR_METHOD_FETCH_OBJECT_NO_CHECK; + + int32_t result_length; + const char *result = ((StringEnumeration*)iter->data)->next( + &result_length, INTLITERATOR_ERROR_CODE(ii)); + + intl_error_set_code(NULL, INTLITERATOR_ERROR_CODE(ii) TSRMLS_CC); + if (U_FAILURE(INTLITERATOR_ERROR_CODE(ii))) { + intl_errors_set_custom_msg(INTL_DATA_ERROR_P(ii), + "Error fetching next iteration element", 0 TSRMLS_CC); + } else if (result) { + MAKE_STD_ZVAL(zoi_iter->current); + ZVAL_STRINGL(zoi_iter->current, result, result_length, 1); + } //else we've reached the end of the enum, nothing more is required +} + +static void string_enum_rewind(zend_object_iterator *iter TSRMLS_DC) +{ + zoi_with_current *zoi_iter = (zoi_with_current*)iter; + INTLITERATOR_METHOD_INIT_VARS; + + if (zoi_iter->current) { + iter->funcs->invalidate_current(iter TSRMLS_CC); + } + + object = zoi_iter->wrapping_obj; + INTLITERATOR_METHOD_FETCH_OBJECT_NO_CHECK; + + ((StringEnumeration*)iter->data)->reset(INTLITERATOR_ERROR_CODE(ii)); + + intl_error_set_code(NULL, INTLITERATOR_ERROR_CODE(ii) TSRMLS_CC); + if (U_FAILURE(INTLITERATOR_ERROR_CODE(ii))) { + intl_errors_set_custom_msg(INTL_DATA_ERROR_P(ii), + "Error resetting enumeration", 0 TSRMLS_CC); + } else { + iter->funcs->move_forward(iter TSRMLS_CC); + } +} + +static void string_enum_destroy_it(zend_object_iterator *iter TSRMLS_DC) +{ + delete (StringEnumeration*)iter->data; +} + +static zend_object_iterator_funcs string_enum_object_iterator_funcs = { + zoi_with_current_dtor, + zoi_with_current_valid, + zoi_with_current_get_current_data, + NULL, + string_enum_current_move_forward, + string_enum_rewind, + zoi_with_current_invalidate_current +}; + +U_CFUNC void IntlIterator_from_StringEnumeration(StringEnumeration *se, zval *object TSRMLS_DC) +{ + IntlIterator_object *ii; + object_init_ex(object, IntlIterator_ce_ptr); + ii = (IntlIterator_object*)zend_object_store_get_object(object TSRMLS_CC); + ii->iterator = (zend_object_iterator*)emalloc(sizeof(zoi_with_current)); + ii->iterator->data = (void*)se; + ii->iterator->funcs = &string_enum_object_iterator_funcs; + ii->iterator->index = 0; + ((zoi_with_current*)ii->iterator)->destroy_it = string_enum_destroy_it; + ((zoi_with_current*)ii->iterator)->wrapping_obj = object; + ((zoi_with_current*)ii->iterator)->current = NULL; +} + +static void IntlIterator_objects_free(zend_object *object TSRMLS_DC) +{ + IntlIterator_object *ii = (IntlIterator_object*) object; + + if (ii->iterator) { + zval **wrapping_objp = &((zoi_with_current*)ii->iterator)->wrapping_obj; + *wrapping_objp = NULL; + ii->iterator->funcs->dtor(ii->iterator TSRMLS_CC); + } + intl_error_reset(INTLITERATOR_ERROR_P(ii) TSRMLS_CC); + + zend_object_std_dtor(&ii->zo TSRMLS_CC); + + efree(ii); +} + +static zend_object_iterator *IntlIterator_get_iterator( + zend_class_entry *ce, zval *object, int by_ref TSRMLS_DC) +{ + if (by_ref) { + zend_throw_exception(NULL, + "Iteration by reference is not supported", 0 TSRMLS_CC); + return NULL; + } + + IntlIterator_object *ii = (IntlIterator_object*) + zend_object_store_get_object(object TSRMLS_CC); + + if (ii->iterator == NULL) { + zend_throw_exception(NULL, + "The IntlIterator is not properly constructed", 0 TSRMLS_CC); + return NULL; + } + + zval_add_ref(&object); + + return ii->iterator; +} + +static zend_object_value IntlIterator_object_create(zend_class_entry *ce TSRMLS_DC) +{ + zend_object_value retval; + IntlIterator_object *intern; + + intern = (IntlIterator_object*)ecalloc(1, sizeof(IntlIterator_object)); + + zend_object_std_init(&intern->zo, ce TSRMLS_CC); +#if PHP_VERSION_ID < 50399 + zend_hash_copy(intern->zo.properties, &(ce->default_properties), + (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval*)); +#else + object_properties_init((zend_object*) intern, ce); +#endif + intl_error_init(INTLITERATOR_ERROR_P(intern) TSRMLS_CC); + intern->iterator = NULL; + + retval.handle = zend_objects_store_put( + intern, + (zend_objects_store_dtor_t)zend_objects_destroy_object, + (zend_objects_free_object_storage_t)IntlIterator_objects_free, + NULL TSRMLS_CC); + + retval.handlers = &IntlIterator_handlers; + + return retval; +} + +static PHP_METHOD(IntlIterator, current) +{ + zval **data; + INTLITERATOR_METHOD_INIT_VARS; + + if (zend_parse_parameters_none() == FAILURE) { + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, + "IntlIterator::current: bad arguments", 0 TSRMLS_CC); + return; + } + + INTLITERATOR_METHOD_FETCH_OBJECT; + ii->iterator->funcs->get_current_data(ii->iterator, &data TSRMLS_CC); + if (data && *data) { + RETURN_ZVAL(*data, 1, 0); + } +} + +static PHP_METHOD(IntlIterator, key) +{ + INTLITERATOR_METHOD_INIT_VARS; + + if (zend_parse_parameters_none() == FAILURE) { + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, + "IntlIterator::key: bad arguments", 0 TSRMLS_CC); + return; + } + + INTLITERATOR_METHOD_FETCH_OBJECT; + + if (ii->iterator->funcs->get_current_key) { + char *str_key; + uint str_key_len; + ulong int_key; + + switch (ii->iterator->funcs->get_current_key( + ii->iterator, &str_key, &str_key_len, &int_key TSRMLS_CC)) { + case HASH_KEY_IS_LONG: + RETURN_LONG(int_key); + break; + case HASH_KEY_IS_STRING: + RETURN_STRINGL(str_key, str_key_len-1, 0); + break; + } + } else { + RETURN_LONG(ii->iterator->index); + } +} + +static PHP_METHOD(IntlIterator, next) +{ + INTLITERATOR_METHOD_INIT_VARS; + + if (zend_parse_parameters_none() == FAILURE) { + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, + "IntlIterator::next: bad arguments", 0 TSRMLS_CC); + return; + } + + INTLITERATOR_METHOD_FETCH_OBJECT; + ii->iterator->funcs->move_forward(ii->iterator TSRMLS_CC); + /* foreach also advances the index after the last iteration, + * so I see no problem in incrementing the index here unconditionally */ + ii->iterator->index++; +} + +static PHP_METHOD(IntlIterator, rewind) +{ + INTLITERATOR_METHOD_INIT_VARS; + + if (zend_parse_parameters_none() == FAILURE) { + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, + "IntlIterator::rewind: bad arguments", 0 TSRMLS_CC); + return; + } + + INTLITERATOR_METHOD_FETCH_OBJECT; + if (ii->iterator->funcs->rewind) { + ii->iterator->funcs->rewind(ii->iterator TSRMLS_CC); + } else { + intl_errors_set(INTLITERATOR_ERROR_P(ii), U_UNSUPPORTED_ERROR, + "IntlIterator::rewind: rewind not supported", 0 TSRMLS_CC); + } +} + +static PHP_METHOD(IntlIterator, valid) +{ + INTLITERATOR_METHOD_INIT_VARS; + + if (zend_parse_parameters_none() == FAILURE) { + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, + "IntlIterator::valid: bad arguments", 0 TSRMLS_CC); + return; + } + + INTLITERATOR_METHOD_FETCH_OBJECT; + RETURN_BOOL(ii->iterator->funcs->valid(ii->iterator TSRMLS_CC) == SUCCESS); +} + +ZEND_BEGIN_ARG_INFO_EX(ainfo_se_void, 0, 0, 0) +ZEND_END_ARG_INFO() + +static zend_function_entry IntlIterator_class_functions[] = { + PHP_ME(IntlIterator, current, ainfo_se_void, ZEND_ACC_PUBLIC) + PHP_ME(IntlIterator, key, ainfo_se_void, ZEND_ACC_PUBLIC) + PHP_ME(IntlIterator, next, ainfo_se_void, ZEND_ACC_PUBLIC) + PHP_ME(IntlIterator, rewind, ainfo_se_void, ZEND_ACC_PUBLIC) + PHP_ME(IntlIterator, valid, ainfo_se_void, ZEND_ACC_PUBLIC) + PHP_FE_END +}; + + +/* {{{ intl_register_IntlIterator_class + * Initialize 'IntlIterator' class + */ +U_CFUNC void intl_register_IntlIterator_class(TSRMLS_D) +{ + zend_class_entry ce; + + /* Create and register 'IntlIterator' class. */ + INIT_CLASS_ENTRY(ce, "IntlIterator", IntlIterator_class_functions); + ce.create_object = IntlIterator_object_create; + IntlIterator_ce_ptr = zend_register_internal_class(&ce TSRMLS_CC); + IntlIterator_ce_ptr->get_iterator = IntlIterator_get_iterator; + zend_class_implements(IntlIterator_ce_ptr TSRMLS_CC, 1, + zend_ce_iterator); + + memcpy(&IntlIterator_handlers, zend_get_std_object_handlers(), + sizeof IntlIterator_handlers); + IntlIterator_handlers.clone_obj = NULL; + +} diff --git a/ext/intl/common/common_enum.h b/ext/intl/common/common_enum.h new file mode 100644 index 0000000000..4c6abdb8f5 --- /dev/null +++ b/ext/intl/common/common_enum.h @@ -0,0 +1,77 @@ +/* + +----------------------------------------------------------------------+ + | 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: Vadim Savchuk <vsavchuk@productengine.com> | + | Dmitry Lakhtyuk <dlakhtyuk@productengine.com> | + +----------------------------------------------------------------------+ + */ + +#ifndef INTL_COMMON_ENUM_H +#define INTL_COMMON_ENUM_H + +#include <unicode/umachine.h> +#ifdef __cplusplus +#include <unicode/strenum.h> +extern "C" { +#include <math.h> +#endif +#include <php.h> +#include "../intl_error.h" +#include "../intl_data.h" +#ifdef __cplusplus +} +#endif + +#define INTLITERATOR_ERROR(ii) (ii)->err +#define INTLITERATOR_ERROR_P(ii) &(INTLITERATOR_ERROR(ii)) + +#define INTLITERATOR_ERROR_CODE(ii) INTL_ERROR_CODE(INTLITERATOR_ERROR(ii)) +#define INTLITERATOR_ERROR_CODE_P(ii) &(INTL_ERROR_CODE(INTLITERATOR_ERROR(ii))) + +#define INTLITERATOR_METHOD_INIT_VARS INTL_METHOD_INIT_VARS(IntlIterator, ii) +#define INTLITERATOR_METHOD_FETCH_OBJECT_NO_CHECK INTL_METHOD_FETCH_OBJECT(IntlIterator, ii) +#define INTLITERATOR_METHOD_FETCH_OBJECT\ + object = getThis(); \ + INTLITERATOR_METHOD_FETCH_OBJECT_NO_CHECK; \ + if (ii->iterator == NULL) { \ + intl_errors_set(&ii->err, U_ILLEGAL_ARGUMENT_ERROR, "Found unconstructed IntlIterator", 0 TSRMLS_CC); \ + RETURN_FALSE; \ + } + +typedef struct { + zend_object zo; + intl_error err; + zend_object_iterator *iterator; +} IntlIterator_object; + +typedef struct { + zend_object_iterator zoi; + zval *current; + zval *wrapping_obj; + void (*destroy_it)(zend_object_iterator *iterator TSRMLS_DC); +} zoi_with_current; + +extern zend_class_entry *IntlIterator_ce_ptr; +extern zend_object_handlers IntlIterator_handlers; + +U_CFUNC void zoi_with_current_dtor(zend_object_iterator *iter TSRMLS_DC); +U_CFUNC int zoi_with_current_valid(zend_object_iterator *iter TSRMLS_DC); +U_CFUNC void zoi_with_current_get_current_data(zend_object_iterator *iter, zval ***data TSRMLS_DC); +U_CFUNC void zoi_with_current_invalidate_current(zend_object_iterator *iter TSRMLS_DC); + +#ifdef __cplusplus +U_CFUNC void IntlIterator_from_StringEnumeration(StringEnumeration *se, zval *object TSRMLS_DC); +#endif + +U_CFUNC void intl_register_IntlIterator_class(TSRMLS_D); + +#endif // INTL_COMMON_ENUM_H diff --git a/ext/intl/config.m4 b/ext/intl/config.m4 index 0477c7f59d..d7eacbc0b4 100755 --- a/ext/intl/config.m4 +++ b/ext/intl/config.m4 @@ -20,6 +20,7 @@ if test "$PHP_INTL" != "no"; then PHP_NEW_EXTENSION(intl, php_intl.c \ intl_error.c \ intl_convert.c \ + intl_convertcpp.cpp \ collator/collator.c \ collator/collator_class.c \ collator/collator_sort.c \ @@ -31,6 +32,7 @@ if test "$PHP_INTL" != "no"; then collator/collator_is_numeric.c \ collator/collator_error.c \ common/common_error.c \ + common/common_enum.cpp \ formatter/formatter.c \ formatter/formatter_main.c \ formatter/formatter_class.c \ @@ -50,6 +52,9 @@ if test "$PHP_INTL" != "no"; then dateformat/dateformat_data.c \ dateformat/dateformat_format.c \ dateformat/dateformat_parse.c \ + dateformat/dateformat_create.cpp \ + dateformat/dateformat_attrcpp.cpp \ + dateformat/dateformat_helpers.cpp \ msgformat/msgformat.c \ msgformat/msgformat_attr.c \ msgformat/msgformat_class.c \ @@ -65,8 +70,19 @@ if test "$PHP_INTL" != "no"; then transliterator/transliterator.c \ transliterator/transliterator_class.c \ transliterator/transliterator_methods.c \ + timezone/timezone_class.cpp \ + timezone/timezone_methods.cpp \ + calendar/calendar_class.cpp \ + calendar/calendar_methods.cpp \ + calendar/gregoriancalendar_methods.cpp \ + breakiterator/breakiterator_class.cpp \ + 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) + $icu_spoof_src, $ext_shared,,$ICU_INCS -Wno-write-strings) PHP_ADD_BUILD_DIR($ext_builddir/collator) PHP_ADD_BUILD_DIR($ext_builddir/common) PHP_ADD_BUILD_DIR($ext_builddir/formatter) @@ -77,6 +93,9 @@ if test "$PHP_INTL" != "no"; then PHP_ADD_BUILD_DIR($ext_builddir/grapheme) PHP_ADD_BUILD_DIR($ext_builddir/resourcebundle) PHP_ADD_BUILD_DIR($ext_builddir/transliterator) + PHP_ADD_BUILD_DIR($ext_builddir/timezone) + 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 437fedb7d3..a223505f8c 100755 --- a/ext/intl/config.w32 +++ b/ext/intl/config.w32 @@ -7,7 +7,7 @@ if (PHP_INTL != "no") { if (CHECK_LIB("icuuc.lib", "intl", PHP_INTL) && CHECK_HEADER_ADD_INCLUDE("unicode/utf.h", "CFLAGS_INTL")) { // always build as shared - zend_strtod.c/ICU type conflict - EXTENSION("intl", "php_intl.c intl_convert.c intl_error.c ", true, + EXTENSION("intl", "php_intl.c intl_convert.c intl_convertcpp.cpp intl_error.c ", true, "/I \"" + configure_module_dirname + "\""); ADD_SOURCES(configure_module_dirname + "/collator", "\ collator.c \ @@ -23,6 +23,7 @@ if (PHP_INTL != "no") { ", "intl"); ADD_SOURCES(configure_module_dirname + "/common", "\ common_error.c \ + common_enum.cpp \ ", "intl"); ADD_SOURCES(configure_module_dirname + "/formatter", "\ formatter.c \ @@ -62,6 +63,9 @@ if (PHP_INTL != "no") { dateformat_format.c \ dateformat_parse.c \ dateformat_data.c \ + dateformat_attrcpp.cpp \ + dateformat_helpers.cpp \ + dateformat_create.cpp \ ", "intl"); ADD_SOURCES(configure_module_dirname + "/idn", "\ idn.c", @@ -87,6 +91,27 @@ if (PHP_INTL != "no") { transliterator_class.c \ transliterator_methods.c", "intl"); + + ADD_SOURCES(configure_module_dirname + "/timezone", "\ + timezone_class.cpp \ + timezone_methods.cpp", + "intl"); + + ADD_SOURCES(configure_module_dirname + "/calendar", "\ + calendar_methods.cpp \ + gregoriancalendar_methods.cpp \ + calendar_class.cpp", + "intl"); + + ADD_SOURCES(configure_module_dirname + "/breakiterator", "\ + breakiterator_class.cpp \ + breakiterator_methods.cpp \ + breakiterator_iterators.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"); AC_DEFINE("HAVE_INTL", 1, "Internationalization support enabled"); } else { diff --git a/ext/intl/dateformat/dateformat.c b/ext/intl/dateformat/dateformat.c index b399a39fcb..fb83eeef05 100755 --- a/ext/intl/dateformat/dateformat.c +++ b/ext/intl/dateformat/dateformat.c @@ -17,12 +17,9 @@ #include "config.h" #endif -#include <unicode/ustring.h> #include <unicode/udat.h> -#include <unicode/ucal.h> #include "php_intl.h" -#include "intl_convert.h" #include "dateformat_class.h" #include "dateformat.h" @@ -67,157 +64,6 @@ void dateformat_register_constants( INIT_FUNC_ARGS ) } /* }}} */ -/* {{{ */ -static void datefmt_ctor(INTERNAL_FUNCTION_PARAMETERS) -{ - char* locale; - int locale_len = 0; - zval* object; - long date_type = 0; - long time_type = 0; - long calendar = UCAL_GREGORIAN; - char* timezone_str = NULL; - int timezone_str_len = 0; - char* pattern_str = NULL; - int pattern_str_len = 0; - UChar* svalue = NULL; /* UTF-16 pattern_str */ - int slength = 0; - UChar* timezone_utf16 = NULL; /* UTF-16 timezone_str */ - int timezone_utf16_len = 0; - UCalendar ucal_obj = NULL; - IntlDateFormatter_object* dfo; - - intl_error_reset( NULL TSRMLS_CC ); - object = return_value; - /* Parse parameters. */ - if( zend_parse_parameters( ZEND_NUM_ARGS() TSRMLS_CC, "sll|sls", - &locale, &locale_len, &date_type, &time_type, &timezone_str, &timezone_str_len, &calendar,&pattern_str, &pattern_str_len ) == FAILURE ) - { - intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR, "datefmt_create: unable to parse input parameters", 0 TSRMLS_CC ); - zval_dtor(return_value); - RETURN_NULL(); - } - - INTL_CHECK_LOCALE_LEN_OBJ(locale_len, return_value); - - if (calendar != UCAL_TRADITIONAL && calendar != UCAL_GREGORIAN) { - intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, "datefmt_create: " - "invalid value for calendar type; it must be one of " - "IntlDateFormatter::TRADITIONAL (locale's default calendar) " - "or IntlDateFormatter::GREGORIAN", 0 TSRMLS_CC); - goto error; - } - - DATE_FORMAT_METHOD_FETCH_OBJECT; - - if (DATE_FORMAT_OBJECT(dfo) != NULL) { - intl_errors_set(INTL_DATA_ERROR_P(dfo), U_ILLEGAL_ARGUMENT_ERROR, - "datefmt_create: cannot call constructor twice", 0 TSRMLS_CC); - return; - } - - /* Convert pattern (if specified) to UTF-16. */ - if( pattern_str && pattern_str_len>0 ){ - intl_convert_utf8_to_utf16(&svalue, &slength, - pattern_str, pattern_str_len, &INTL_DATA_ERROR_CODE(dfo)); - if (U_FAILURE(INTL_DATA_ERROR_CODE(dfo))) { - /* object construction -> only set global error */ - intl_error_set(NULL, INTL_DATA_ERROR_CODE(dfo), "datefmt_create: " - "error converting pattern to UTF-16", 0 TSRMLS_CC); - goto error; - } - } - - /* resources allocated from now on */ - - /* Convert pattern (if specified) to UTF-16. */ - if( timezone_str && timezone_str_len >0 ){ - intl_convert_utf8_to_utf16(&timezone_utf16, &timezone_utf16_len, - timezone_str, timezone_str_len, &INTL_DATA_ERROR_CODE(dfo)); - if (U_FAILURE(INTL_DATA_ERROR_CODE(dfo))) { - intl_error_set(NULL, INTL_DATA_ERROR_CODE(dfo), "datefmt_create: " - "error converting timezone_str to UTF-16", 0 TSRMLS_CC); - goto error; - } - } - - if(locale_len == 0) { - locale = INTL_G(default_locale); - } - - if( pattern_str && pattern_str_len>0 ){ - DATE_FORMAT_OBJECT(dfo) = udat_open(UDAT_IGNORE, UDAT_IGNORE, locale, timezone_utf16, timezone_utf16_len, svalue, slength, &INTL_DATA_ERROR_CODE(dfo)); - } else { - DATE_FORMAT_OBJECT(dfo) = udat_open(time_type, date_type, locale, timezone_utf16, timezone_utf16_len, svalue, slength, &INTL_DATA_ERROR_CODE(dfo)); - } - - if (!U_FAILURE(INTL_DATA_ERROR_CODE(dfo))) { - if (calendar != UCAL_TRADITIONAL) { - ucal_obj = ucal_open(timezone_utf16, timezone_utf16_len, locale, - calendar, &INTL_DATA_ERROR_CODE(dfo)); - if (!U_FAILURE(INTL_DATA_ERROR_CODE(dfo))) { - udat_setCalendar(DATE_FORMAT_OBJECT(dfo), ucal_obj); - ucal_close(ucal_obj); - } else { - intl_error_set(NULL, INTL_DATA_ERROR_CODE(dfo), "datefmt_create" - ": error opening calendar", 0 TSRMLS_CC); - goto error; - } - } - } else { - intl_error_set(NULL, INTL_DATA_ERROR_CODE(dfo), "datefmt_create: date " - "formatter creation failed", 0 TSRMLS_CC); - goto error; - } - - /* Set the class variables */ - dfo->date_type = date_type; - dfo->time_type = time_type; - dfo->calendar = calendar; - if( timezone_str && timezone_str_len > 0){ - dfo->timezone_id = estrndup( timezone_str, timezone_str_len); - } - -error: - if (svalue) { - efree(svalue); - } - if (timezone_utf16) { - efree(timezone_utf16); - } - if (U_FAILURE(intl_error_get_code(NULL TSRMLS_CC))) { - /* free_object handles partially constructed instances fine */ - zval_dtor(return_value); - RETVAL_NULL(); - } -} -/* }}} */ - -/* {{{ proto IntlDateFormatter IntlDateFormatter::create(string $locale, long date_type, long time_type[, string $timezone_str, long $calendar, string $pattern] ) - * Create formatter. }}} */ -/* {{{ proto IntlDateFormatter datefmt_create(string $locale, long date_type, long time_type[, string $timezone_str, long $calendar, string $pattern] ) - - * Create formatter. - */ -PHP_FUNCTION( datefmt_create ) -{ - object_init_ex( return_value, IntlDateFormatter_ce_ptr ); - datefmt_ctor(INTERNAL_FUNCTION_PARAM_PASSTHRU); -} -/* }}} */ - -/* {{{ proto void IntlDateFormatter::__construct(string $locale, long date_type, long time_type[, string $timezone_str, long $calendar, string $pattern]) - * IntlDateFormatter object constructor. - */ -PHP_METHOD( IntlDateFormatter, __construct ) -{ - /* return_value param is being changed, therefore we will always return - * NULL here */ - return_value = getThis(); - datefmt_ctor(INTERNAL_FUNCTION_PARAM_PASSTHRU); -} -/* }}} */ - /* {{{ proto int IntlDateFormatter::getErrorCode() * Get formatter's last error code. }}} */ /* {{{ proto int datefmt_get_error_code( IntlDateFormatter $nf ) diff --git a/ext/intl/dateformat/dateformat_attr.c b/ext/intl/dateformat/dateformat_attr.c index 6131cedc95..a32a4860c9 100755 --- a/ext/intl/dateformat/dateformat_attr.c +++ b/ext/intl/dateformat/dateformat_attr.c @@ -24,39 +24,6 @@ #include <unicode/ustring.h> #include <unicode/udat.h> -#include <unicode/ucal.h> - -static void internal_set_calendar(IntlDateFormatter_object *dfo, char* timezone_id, int timezone_id_len, int calendar, zval* return_value TSRMLS_DC){ - int timezone_utf16_len = 0; - UChar* timezone_utf16 = NULL; /* timezone_id in UTF-16 */ - char* locale = NULL; - - UCalendar* ucal_obj = NULL; - - /* check for the validity of value of calendar passed */ - intl_error_reset( NULL TSRMLS_CC ); - if( calendar > 1){ - intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, - "datefmt_set_calendar: calendar value specified is out of valid range", 0 TSRMLS_CC); - RETURN_FALSE; - } - - /* Convert timezone to UTF-16. */ - intl_convert_utf8_to_utf16(&timezone_utf16, &timezone_utf16_len, timezone_id, timezone_id_len, &INTL_DATA_ERROR_CODE(dfo)); - INTL_METHOD_CHECK_STATUS(dfo, "Error converting timezone to UTF-16" ); - - /* Get the locale for the dateformatter */ - locale = (char *)udat_getLocaleByType(DATE_FORMAT_OBJECT(dfo), ULOC_ACTUAL_LOCALE, &INTL_DATA_ERROR_CODE(dfo)); - - /* Set the calendar if passed */ - ucal_obj = ucal_open(timezone_utf16, timezone_utf16_len, locale, calendar, &INTL_DATA_ERROR_CODE(dfo) ); - udat_setCalendar( DATE_FORMAT_OBJECT(dfo), ucal_obj ); - INTL_METHOD_CHECK_STATUS(dfo, "Error setting the calendar."); - - if( timezone_utf16){ - efree(timezone_utf16); - } -} /* {{{ proto unicode IntlDateFormatter::getDateType( ) * Get formatter datetype. }}} */ @@ -110,97 +77,6 @@ PHP_FUNCTION( datefmt_get_timetype ) } /* }}} */ - -/* {{{ proto unicode IntlDateFormatter::getCalendar( ) - * Get formatter calendar. }}} */ -/* {{{ proto string datefmt_get_calendar( IntlDateFormatter $mf ) - * Get formatter calendar. - */ -PHP_FUNCTION( datefmt_get_calendar ) -{ - DATE_FORMAT_METHOD_INIT_VARS; - - /* Parse parameters. */ - if( zend_parse_method_parameters( ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O", &object, IntlDateFormatter_ce_ptr ) == FAILURE ) - { - intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR, - "datefmt_get_calendar: unable to parse input params", 0 TSRMLS_CC ); - RETURN_FALSE; - } - - /* Fetch the object. */ - DATE_FORMAT_METHOD_FETCH_OBJECT; - - INTL_METHOD_CHECK_STATUS(dfo, "Error getting formatter calendar." ); - - RETURN_LONG(dfo->calendar); -} -/* }}} */ - -/* {{{ proto unicode IntlDateFormatter::getTimeZoneId( ) - * Get formatter timezone_id. }}} */ -/* {{{ proto string datefmt_get_timezone_id( IntlDateFormatter $mf ) - * Get formatter timezone_id. - */ -PHP_FUNCTION( datefmt_get_timezone_id ) -{ - DATE_FORMAT_METHOD_INIT_VARS; - - /* Parse parameters. */ - if( zend_parse_method_parameters( ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O", &object, IntlDateFormatter_ce_ptr ) == FAILURE ) - { - intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR, - "datefmt_get_timezone_id: unable to parse input params", 0 TSRMLS_CC ); - RETURN_FALSE; - } - - /* Fetch the object. */ - DATE_FORMAT_METHOD_FETCH_OBJECT; - - INTL_METHOD_CHECK_STATUS(dfo, "Error getting formatter timezone_id." ); - - if( dfo->timezone_id ){ - RETURN_STRING((char*)dfo->timezone_id, TRUE ); - }else{ - RETURN_NULL(); - } -} - -/* {{{ proto boolean IntlDateFormatter::setTimeZoneId( $timezone_id) - * Set formatter timezone_id. }}} */ -/* {{{ proto boolean datefmt_set_timezone_id( IntlDateFormatter $mf,$timezone_id) - * Set formatter timezone_id. - */ -PHP_FUNCTION( datefmt_set_timezone_id ) -{ - char* timezone_id = NULL; - int timezone_id_len = 0; - - DATE_FORMAT_METHOD_INIT_VARS; - - /* Parse parameters. */ - if( zend_parse_method_parameters( ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Os", &object, IntlDateFormatter_ce_ptr,&timezone_id, &timezone_id_len) == FAILURE ) - { - intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR, - "datefmt_set_timezone_id: unable to parse input params", 0 TSRMLS_CC ); - RETURN_FALSE; - } - - /* Fetch the object. */ - DATE_FORMAT_METHOD_FETCH_OBJECT; - - /* set the timezone for the calendar */ - internal_set_calendar( dfo, timezone_id, timezone_id_len, dfo->calendar, return_value TSRMLS_CC ); - - /* Set the IntlDateFormatter variable */ - if( dfo->timezone_id ){ - efree(dfo->timezone_id); - } - dfo->timezone_id = estrndup(timezone_id, timezone_id_len); - - RETURN_TRUE; -} - /* {{{ proto string IntlDateFormatter::getPattern( ) * Get formatter pattern. }}} */ /* {{{ proto string datefmt_get_pattern( IntlDateFormatter $mf ) @@ -369,43 +245,3 @@ PHP_FUNCTION( datefmt_set_lenient ) udat_setLenient(DATE_FORMAT_OBJECT(dfo), (UBool)isLenient ); } /* }}} */ - -/* {{{ proto bool IntlDateFormatter::setPattern( int $calendar ) - * Set formatter calendar. }}} */ -/* {{{ proto bool datefmt_set_calendar( IntlDateFormatter $mf, int $calendar ) - * Set formatter calendar. - */ -PHP_FUNCTION( datefmt_set_calendar ) -{ - long calendar = 0; - - DATE_FORMAT_METHOD_INIT_VARS; - - /* Parse parameters. */ - if( zend_parse_method_parameters( ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Ol", - &object, IntlDateFormatter_ce_ptr, &calendar ) == FAILURE ) { - intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, - "datefmt_set_calendar: unable to parse input params", 0 TSRMLS_CC); - RETURN_FALSE; - } - - /* check for the validity of value of calendar passed */ - intl_error_reset( NULL TSRMLS_CC ); - if (calendar > 1) { - intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, - "datefmt_set_calendar: calendar value specified is out of valid range", 0 TSRMLS_CC); - RETURN_FALSE; - } - - DATE_FORMAT_METHOD_FETCH_OBJECT; - - internal_set_calendar( dfo, dfo->timezone_id, strlen(dfo->timezone_id), calendar, return_value TSRMLS_CC ); - - /* Set the calendar value in the IntlDateFormatter object */ - dfo->calendar = calendar; - - RETURN_TRUE; -} -/* }}} */ - - diff --git a/ext/intl/dateformat/dateformat_attr.h b/ext/intl/dateformat/dateformat_attr.h index bf28824d63..6fe82a6e00 100755 --- a/ext/intl/dateformat/dateformat_attr.h +++ b/ext/intl/dateformat/dateformat_attr.h @@ -21,11 +21,7 @@ //PHP_FUNCTION( datefmt_get_timezone ); PHP_FUNCTION( datefmt_get_datetype ); PHP_FUNCTION( datefmt_get_timetype ); -PHP_FUNCTION( datefmt_get_calendar ); -PHP_FUNCTION( datefmt_set_calendar ); PHP_FUNCTION( datefmt_get_locale ); -PHP_FUNCTION( datefmt_get_timezone_id ); -PHP_FUNCTION( datefmt_set_timezone_id ); PHP_FUNCTION( datefmt_get_pattern ); PHP_FUNCTION( datefmt_set_pattern ); PHP_FUNCTION( datefmt_is_lenient ); diff --git a/ext/intl/dateformat/dateformat_attrcpp.cpp b/ext/intl/dateformat/dateformat_attrcpp.cpp new file mode 100644 index 0000000000..b68abec659 --- /dev/null +++ b/ext/intl/dateformat/dateformat_attrcpp.cpp @@ -0,0 +1,261 @@ +/* + +----------------------------------------------------------------------+ + | 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 <cataphract@php.net> | + +----------------------------------------------------------------------+ +*/ + +#include "../intl_cppshims.h" + +#include <unicode/timezone.h> +#include <unicode/calendar.h> +#include <unicode/datefmt.h> + +extern "C" { +#include "../php_intl.h" +#include "dateformat_class.h" +#include "dateformat_attrcpp.h" +#define USE_TIMEZONE_POINTER 1 +#include "../timezone/timezone_class.h" +#define USE_CALENDAR_POINTER 1 +#include "../calendar/calendar_class.h" +} + +#include "../intl_convertcpp.h" +#include "dateformat_helpers.h" + +static inline DateFormat *fetch_datefmt(IntlDateFormatter_object *dfo) { + return (DateFormat *)dfo->datef_data.udatf; +} + +/* {{{ proto string IntlDateFormatter::getTimeZoneId() + * Get formatter timezone_id. }}} */ +/* {{{ proto string datefmt_get_timezone_id(IntlDateFormatter $mf) + * Get formatter timezone_id. + */ +U_CFUNC PHP_FUNCTION(datefmt_get_timezone_id) +{ + DATE_FORMAT_METHOD_INIT_VARS; + + if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O", + &object, IntlDateFormatter_ce_ptr ) == FAILURE) { + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, "datefmt_get_timezone_" + "id: unable to parse input params", 0 TSRMLS_CC); + RETURN_FALSE; + } + + DATE_FORMAT_METHOD_FETCH_OBJECT; + + UnicodeString res = UnicodeString(); + fetch_datefmt(dfo)->getTimeZone().getID(res); + intl_charFromString(res, &Z_STRVAL_P(return_value), + &Z_STRLEN_P(return_value), &INTL_DATA_ERROR_CODE(dfo)); + INTL_METHOD_CHECK_STATUS(dfo, "Could not convert time zone id to UTF-8"); + + Z_TYPE_P(return_value) = IS_STRING; +} + +/* {{{ proto IntlTimeZone IntlDateFormatter::getTimeZone() + * Get formatter timezone. }}} */ +/* {{{ proto IntlTimeZone datefmt_get_timezone(IntlDateFormatter $mf) + * Get formatter timezone. + */ +U_CFUNC PHP_FUNCTION(datefmt_get_timezone) +{ + DATE_FORMAT_METHOD_INIT_VARS; + + if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O", + &object, IntlDateFormatter_ce_ptr ) == FAILURE) { + intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR, + "datefmt_get_timezone: unable to parse input params", 0 TSRMLS_CC ); + RETURN_FALSE; + } + + DATE_FORMAT_METHOD_FETCH_OBJECT; + + const TimeZone& tz = fetch_datefmt(dfo)->getTimeZone(); + TimeZone *tz_clone = tz.clone(); + if (tz_clone == NULL) { + intl_errors_set(INTL_DATA_ERROR_P(dfo), U_MEMORY_ALLOCATION_ERROR, + "datefmt_get_timezone: Out of memory when cloning time zone", + 0 TSRMLS_CC); + RETURN_FALSE; + } + + object_init_ex(return_value, TimeZone_ce_ptr); + timezone_object_construct(tz_clone, return_value, 1 TSRMLS_CC); +} + +U_CFUNC PHP_FUNCTION(datefmt_set_timezone_id) +{ + php_error_docref0(NULL TSRMLS_CC, E_DEPRECATED, + "Use datefmt_set_timezone() instead, which also accepts a plain " + "time zone identifier and for which this function is now an " + "alias"); + PHP_FN(datefmt_set_timezone)(INTERNAL_FUNCTION_PARAM_PASSTHRU); +} + +/* {{{ proto boolean IntlDateFormatter::setTimeZone(mixed $timezone) + * Set formatter's timezone. }}} */ +/* {{{ proto boolean datefmt_set_timezone_id(IntlDateFormatter $mf, $timezone_id) + * Set formatter timezone_id. + */ +U_CFUNC PHP_FUNCTION(datefmt_set_timezone) +{ + zval **timezone_zv; + TimeZone *timezone; + + DATE_FORMAT_METHOD_INIT_VARS; + + if ( zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), + "OZ", &object, IntlDateFormatter_ce_ptr, &timezone_zv) == FAILURE) { + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, "datefmt_set_timezone: " + "unable to parse input params", 0 TSRMLS_CC); + RETURN_FALSE; + } + + DATE_FORMAT_METHOD_FETCH_OBJECT; + + timezone = timezone_process_timezone_argument(timezone_zv, + INTL_DATA_ERROR_P(dfo), "datefmt_set_timezone" TSRMLS_CC); + if (timezone == NULL) { + RETURN_FALSE; + } + + fetch_datefmt(dfo)->adoptTimeZone(timezone); +} + +/* {{{ proto int IntlDateFormatter::getCalendar( ) + * Get formatter calendar type. }}} */ +/* {{{ proto int datefmt_get_calendar(IntlDateFormatter $mf) + * Get formatter calendar type. + */ +U_CFUNC PHP_FUNCTION(datefmt_get_calendar) +{ + DATE_FORMAT_METHOD_INIT_VARS; + + if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O", + &object, IntlDateFormatter_ce_ptr ) == FAILURE) { + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, + "datefmt_get_calendar: unable to parse input params", 0 TSRMLS_CC); + RETURN_FALSE; + } + + DATE_FORMAT_METHOD_FETCH_OBJECT; + + if (dfo->calendar == -1) { + /* an IntlCalendar was provided to the constructor */ + RETURN_FALSE; + } + + RETURN_LONG(dfo->calendar); +} +/* }}} */ + +/* {{{ proto IntlCalendar IntlDateFormatter::getCalendarObject() + * Get formatter calendar. }}} */ +/* {{{ proto IntlCalendar datefmt_get_calendar_object(IntlDateFormatter $mf) + * Get formatter calendar. + */ +U_CFUNC PHP_FUNCTION(datefmt_get_calendar_object) +{ + DATE_FORMAT_METHOD_INIT_VARS; + + if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O", + &object, IntlDateFormatter_ce_ptr ) == FAILURE) { + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, + "datefmt_get_calendar_object: unable to parse input params", + 0 TSRMLS_CC); + RETURN_FALSE; + } + + DATE_FORMAT_METHOD_FETCH_OBJECT; + + const Calendar *cal = fetch_datefmt(dfo)->getCalendar(); + if (cal == NULL) { + RETURN_NULL(); + } + + Calendar *cal_clone = cal->clone(); + if (cal_clone == NULL) { + intl_errors_set(INTL_DATA_ERROR_P(dfo), U_MEMORY_ALLOCATION_ERROR, + "datefmt_get_calendar_object: Out of memory when cloning " + "calendar", 0 TSRMLS_CC); + RETURN_FALSE; + } + + calendar_object_create(return_value, cal_clone TSRMLS_CC); +} +/* }}} */ + +/* {{{ proto bool IntlDateFormatter::setCalendar(mixed $calendar) + * Set formatter's calendar. }}} */ +/* {{{ proto bool datefmt_set_calendar(IntlDateFormatter $mf, mixed $calendar) + * Set formatter's calendar. + */ +U_CFUNC PHP_FUNCTION(datefmt_set_calendar) +{ + zval *calendar_zv; + DATE_FORMAT_METHOD_INIT_VARS; + + if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Oz", + &object, IntlDateFormatter_ce_ptr, &calendar_zv) == FAILURE) { + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, + "datefmt_set_calendar: unable to parse input params", 0 TSRMLS_CC); + RETURN_FALSE; + } + + DATE_FORMAT_METHOD_FETCH_OBJECT; + + Calendar *cal; + long cal_type; + bool cal_owned; + Locale locale = Locale::createFromName(dfo->requested_locale); + // getting the actual locale from the DateFormat is not enough + // because we would have lost modifiers such as @calendar. We + // must store the requested locale on object creation + + if (datefmt_process_calendar_arg(calendar_zv, locale, + "datefmt_set_calendar", INTL_DATA_ERROR_P(dfo), cal, cal_type, + cal_owned TSRMLS_CC) == FAILURE) { + RETURN_FALSE; + } + + if (cal_owned) { + /* a non IntlCalendar was specified, we want to keep the timezone */ + TimeZone *old_timezone = fetch_datefmt(dfo)->getTimeZone().clone(); + if (old_timezone == NULL) { + intl_errors_set(INTL_DATA_ERROR_P(dfo), U_MEMORY_ALLOCATION_ERROR, + "datefmt_set_calendar: Out of memory when cloning calendar", + 0 TSRMLS_CC); + delete cal; + RETURN_FALSE; + } + cal->adoptTimeZone(old_timezone); + } else { + cal = cal->clone(); + if (cal == NULL) { + intl_errors_set(INTL_DATA_ERROR_P(dfo), U_MEMORY_ALLOCATION_ERROR, + "datefmt_set_calendar: Out of memory when cloning calendar", + 0 TSRMLS_CC); + RETURN_FALSE; + } + } + + fetch_datefmt(dfo)->adoptCalendar(cal); + + dfo->calendar = cal_type; + + RETURN_TRUE; +} +/* }}} */ + diff --git a/ext/intl/dateformat/dateformat_attrcpp.h b/ext/intl/dateformat/dateformat_attrcpp.h new file mode 100644 index 0000000000..408232f940 --- /dev/null +++ b/ext/intl/dateformat/dateformat_attrcpp.h @@ -0,0 +1,35 @@ +/* + +----------------------------------------------------------------------+ + | 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 <cataphract@php.net> | + +----------------------------------------------------------------------+ +*/ + +#ifndef DATEFORMAT_ATTRCPP_H +#define DATEFORMAT_ATTRCPP_H + +PHP_FUNCTION(datefmt_get_timezone_id); + +PHP_FUNCTION(datefmt_set_timezone_id); + +PHP_FUNCTION(datefmt_get_timezone); + +PHP_FUNCTION(datefmt_set_timezone); + +PHP_FUNCTION(datefmt_get_calendar); + +PHP_FUNCTION(datefmt_set_calendar); + +PHP_FUNCTION(datefmt_get_calendar_object); + +#endif /* DATEFORMAT_ATTRCPP_H */ + diff --git a/ext/intl/dateformat/dateformat_class.c b/ext/intl/dateformat/dateformat_class.c index c66610f23b..fda67f1b70 100755 --- a/ext/intl/dateformat/dateformat_class.c +++ b/ext/intl/dateformat/dateformat_class.c @@ -22,6 +22,7 @@ #include "dateformat_parse.h" #include "dateformat.h" #include "dateformat_attr.h" +#include "dateformat_attrcpp.h" zend_class_entry *IntlDateFormatter_ce_ptr = NULL; static zend_object_handlers IntlDateFormatter_handlers; @@ -44,12 +45,12 @@ void IntlDateFormatter_object_free( zend_object *object TSRMLS_DC ) zend_object_std_dtor( &dfo->zo TSRMLS_CC ); - dateformat_data_free( &dfo->datef_data TSRMLS_CC ); - - if( dfo->timezone_id ){ - efree(dfo->timezone_id); + if (dfo->requested_locale) { + efree( dfo->requested_locale ); } + dateformat_data_free( &dfo->datef_data TSRMLS_CC ); + efree( dfo ); } /* }}} */ @@ -63,10 +64,10 @@ zend_object_value IntlDateFormatter_object_create(zend_class_entry *ce TSRMLS_DC intern = ecalloc( 1, sizeof(IntlDateFormatter_object) ); dateformat_data_init( &intern->datef_data TSRMLS_CC ); zend_object_std_init( &intern->zo, ce TSRMLS_CC ); - intern->date_type = 0; - intern->time_type = 0; - intern->calendar = 1; /* Gregorian calendar */ - intern->timezone_id = NULL; + intern->date_type = 0; + intern->time_type = 0; + intern->calendar = -1; + intern->requested_locale = NULL; retval.handle = zend_objects_store_put( intern, @@ -157,9 +158,12 @@ static zend_function_entry IntlDateFormatter_class_functions[] = { PHP_NAMED_FE( getDateType, ZEND_FN( datefmt_get_datetype ), arginfo_intldateformatter_getdatetype ) PHP_NAMED_FE( getTimeType, ZEND_FN( datefmt_get_timetype ), arginfo_intldateformatter_getdatetype ) PHP_NAMED_FE( getCalendar, ZEND_FN( datefmt_get_calendar ), arginfo_intldateformatter_getdatetype ) + PHP_NAMED_FE( getCalendarObject, ZEND_FN( datefmt_get_calendar_object ), arginfo_intldateformatter_getdatetype ) PHP_NAMED_FE( setCalendar, ZEND_FN( datefmt_set_calendar ), arginfo_intldateformatter_setcalendar ) PHP_NAMED_FE( getTimeZoneId, ZEND_FN( datefmt_get_timezone_id ), arginfo_intldateformatter_getdatetype ) PHP_NAMED_FE( setTimeZoneId, ZEND_FN( datefmt_set_timezone_id ), arginfo_intldateformatter_settimezoneid ) + PHP_NAMED_FE( getTimeZone, ZEND_FN( datefmt_get_timezone ), arginfo_intldateformatter_getdatetype ) + PHP_NAMED_FE( setTimeZone, ZEND_FN( datefmt_set_timezone ), arginfo_intldateformatter_settimezoneid ) PHP_NAMED_FE( setPattern, ZEND_FN( datefmt_set_pattern ), arginfo_intldateformatter_setpattern ) PHP_NAMED_FE( getPattern, ZEND_FN( datefmt_get_pattern ), arginfo_intldateformatter_getdatetype ) PHP_NAMED_FE( getLocale, ZEND_FN( datefmt_get_locale ), arginfo_intldateformatter_getdatetype ) diff --git a/ext/intl/dateformat/dateformat_class.h b/ext/intl/dateformat/dateformat_class.h index 9ad83ee3d6..de5cf4a181 100755 --- a/ext/intl/dateformat/dateformat_class.h +++ b/ext/intl/dateformat/dateformat_class.h @@ -24,12 +24,12 @@ #include "dateformat_data.h" typedef struct { - zend_object zo; - dateformat_data datef_data; - int date_type ; - int time_type ; - int calendar ; - char* timezone_id; + zend_object zo; + dateformat_data datef_data; + int date_type; + int time_type; + int calendar; + char *requested_locale; } IntlDateFormatter_object; void dateformat_register_IntlDateFormatter_class( TSRMLS_D ); diff --git a/ext/intl/dateformat/dateformat_create.cpp b/ext/intl/dateformat/dateformat_create.cpp new file mode 100644 index 0000000000..fef93e93d9 --- /dev/null +++ b/ext/intl/dateformat/dateformat_create.cpp @@ -0,0 +1,193 @@ +/* + +----------------------------------------------------------------------+ + | 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: Kirti Velankar <kirtig@yahoo-inc.com> | + | Gustavo Lopes <cataphract@php.net> | + +----------------------------------------------------------------------+ +*/ + +#include "../intl_cppshims.h" + +#include <unicode/timezone.h> +#include <unicode/calendar.h> +#include <unicode/datefmt.h> + +extern "C" { +#include <unicode/ustring.h> +#include <unicode/udat.h> + +#include "php_intl.h" +#include "dateformat_create.h" +#include "dateformat_class.h" +#define USE_TIMEZONE_POINTER 1 +#include "../timezone/timezone_class.h" +#include "../intl_convert.h" +} + +#include "dateformat_helpers.h" + +/* {{{ */ +static void datefmt_ctor(INTERNAL_FUNCTION_PARAMETERS) +{ + zval *object; + + char *locale_str; + int locale_len = 0; + Locale locale; + long date_type = 0; + long time_type = 0; + zval *calendar_zv = NULL; + Calendar *calendar = NULL; + long calendar_type; + bool calendar_owned; + zval **timezone_zv = NULL; + TimeZone *timezone = NULL; + bool explicit_tz; + char* pattern_str = NULL; + int pattern_str_len = 0; + UChar* svalue = NULL; /* UTF-16 pattern_str */ + int slength = 0; + IntlDateFormatter_object* dfo; + + intl_error_reset(NULL TSRMLS_CC); + object = return_value; + /* Parse parameters. */ + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sll|Zzs", + &locale_str, &locale_len, &date_type, &time_type, &timezone_zv, + &calendar_zv, &pattern_str, &pattern_str_len) == FAILURE) { + intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR, "datefmt_create: " + "unable to parse input parameters", 0 TSRMLS_CC); + zval_dtor(return_value); + RETURN_NULL(); + } + + INTL_CHECK_LOCALE_LEN_OBJ(locale_len, return_value); + if (locale_len == 0) { + locale_str = INTL_G(default_locale); + } + locale = Locale::createFromName(locale_str); + + DATE_FORMAT_METHOD_FETCH_OBJECT; + + if (DATE_FORMAT_OBJECT(dfo) != NULL) { + intl_errors_set(INTL_DATA_ERROR_P(dfo), U_ILLEGAL_ARGUMENT_ERROR, + "datefmt_create: cannot call constructor twice", 0 TSRMLS_CC); + return; + } + + /* process calendar */ + if (datefmt_process_calendar_arg(calendar_zv, locale, "datefmt_create", + INTL_DATA_ERROR_P(dfo), calendar, calendar_type, + calendar_owned TSRMLS_CC) + == FAILURE) { + goto error; + } + + /* process timezone */ + explicit_tz = timezone_zv != NULL && Z_TYPE_PP(timezone_zv) != IS_NULL; + + if (explicit_tz || calendar_owned ) { + //we have an explicit time zone or a non-object calendar + timezone = timezone_process_timezone_argument(timezone_zv, + INTL_DATA_ERROR_P(dfo), "datefmt_create" TSRMLS_CC); + if (timezone == NULL) { + goto error; + } + } + + /* Convert pattern (if specified) to UTF-16. */ + if (pattern_str && pattern_str_len > 0) { + intl_convert_utf8_to_utf16(&svalue, &slength, + pattern_str, pattern_str_len, &INTL_DATA_ERROR_CODE(dfo)); + if (U_FAILURE(INTL_DATA_ERROR_CODE(dfo))) { + /* object construction -> only set global error */ + intl_error_set(NULL, INTL_DATA_ERROR_CODE(dfo), "datefmt_create: " + "error converting pattern to UTF-16", 0 TSRMLS_CC); + goto error; + } + } + + if (pattern_str && pattern_str_len > 0) { + DATE_FORMAT_OBJECT(dfo) = udat_open(UDAT_IGNORE, UDAT_IGNORE, + locale_str, NULL, 0, svalue, slength, + &INTL_DATA_ERROR_CODE(dfo)); + } else { + DATE_FORMAT_OBJECT(dfo) = udat_open((UDateFormatStyle)time_type, + (UDateFormatStyle)date_type, locale_str, NULL, 0, svalue, + slength, &INTL_DATA_ERROR_CODE(dfo)); + } + + if (!U_FAILURE(INTL_DATA_ERROR_CODE(dfo))) { + DateFormat *df = (DateFormat*)DATE_FORMAT_OBJECT(dfo); + if (calendar_owned) { + df->adoptCalendar(calendar); + calendar_owned = false; + } else { + df->setCalendar(*calendar); + } + + if (timezone != NULL) { + df->adoptTimeZone(timezone); + } + } else { + intl_error_set(NULL, INTL_DATA_ERROR_CODE(dfo), "datefmt_create: date " + "formatter creation failed", 0 TSRMLS_CC); + goto error; + } + + /* Set the class variables */ + dfo->date_type = date_type; + dfo->time_type = time_type; + dfo->calendar = calendar_type; + dfo->requested_locale = estrdup(locale_str); + +error: + if (svalue) { + efree(svalue); + } + if (timezone != NULL && DATE_FORMAT_OBJECT(dfo) == NULL) { + delete timezone; + } + if (calendar != NULL && calendar_owned) { + delete calendar; + } + if (U_FAILURE(intl_error_get_code(NULL TSRMLS_CC))) { + /* free_object handles partially constructed instances fine */ + zval_dtor(return_value); + RETVAL_NULL(); + } +} +/* }}} */ + +/* {{{ proto IntlDateFormatter IntlDateFormatter::create(string $locale, long date_type, long time_type[, string $timezone_str, long $calendar, string $pattern] ) + * Create formatter. }}} */ +/* {{{ proto IntlDateFormatter datefmt_create(string $locale, long date_type, long time_type[, string $timezone_str, long $calendar, string $pattern) + * Create formatter. + */ +U_CFUNC PHP_FUNCTION( datefmt_create ) +{ + object_init_ex( return_value, IntlDateFormatter_ce_ptr ); + datefmt_ctor(INTERNAL_FUNCTION_PARAM_PASSTHRU); +} +/* }}} */ + +/* {{{ proto void IntlDateFormatter::__construct(string $locale, long date_type, long time_type[, string $timezone_str, long $calendar, string $pattern]) + * IntlDateFormatter object constructor. + */ +U_CFUNC PHP_METHOD( IntlDateFormatter, __construct ) +{ + /* return_value param is being changed, therefore we will always return + * NULL here */ + return_value = getThis(); + datefmt_ctor(INTERNAL_FUNCTION_PARAM_PASSTHRU); +} +/* }}} */ diff --git a/ext/intl/dateformat/dateformat_create.h b/ext/intl/dateformat/dateformat_create.h new file mode 100644 index 0000000000..47e67c2f45 --- /dev/null +++ b/ext/intl/dateformat/dateformat_create.h @@ -0,0 +1,25 @@ +/* + +----------------------------------------------------------------------+ + | 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 <cataphract@php.net> | + +----------------------------------------------------------------------+ +*/ +#ifndef DATE_FORMATTER_H +#define DATE_FORMATTER_H + +#include <php.h> + +PHP_FUNCTION( datefmt_create ); +PHP_METHOD( IntlDateFormatter, __construct ); +void dateformat_register_constants( INIT_FUNC_ARGS ); + +#endif // DATE_FORMATTER_H diff --git a/ext/intl/dateformat/dateformat_format.c b/ext/intl/dateformat/dateformat_format.c index 4d03d924c8..82f825f140 100755 --- a/ext/intl/dateformat/dateformat_format.c +++ b/ext/intl/dateformat/dateformat_format.c @@ -27,6 +27,8 @@ #include "dateformat_class.h" #include "dateformat_format.h" #include "dateformat_data.h" +/* avoid redefinition of int8_t, already defined in unicode/pwin32.h */ +#define _MSC_STDINT_H_ 1 #include "ext/date/php_date.h" /* {{{ @@ -91,7 +93,7 @@ static UDate internal_get_timestamp(IntlDateFormatter_object *dfo, HashTable* ha long yday =0; long mday =0; UBool isInDST = FALSE; - UCalendar *pcal; + const UCalendar *pcal; /* Fetch values from the incoming array */ year = internal_get_arr_ele( dfo, hash_arr, CALENDAR_YEAR TSRMLS_CC) + 1900; /* tm_year is years since 1900 */ diff --git a/ext/intl/dateformat/dateformat_helpers.cpp b/ext/intl/dateformat/dateformat_helpers.cpp new file mode 100644 index 0000000000..74758bbec9 --- /dev/null +++ b/ext/intl/dateformat/dateformat_helpers.cpp @@ -0,0 +1,106 @@ +/* + +----------------------------------------------------------------------+ + | 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 <cataphract@php.net> | + +----------------------------------------------------------------------+ +*/ + +#include "../intl_cppshims.h" + +#include <unicode/calendar.h> +#include <unicode/gregocal.h> + +#include "dateformat_helpers.h" + +extern "C" { +#include "../php_intl.h" +#include <Zend/zend_operators.h> +#define USE_CALENDAR_POINTER 1 +#include "../calendar/calendar_class.h" +} + +int datefmt_process_calendar_arg(zval* calendar_zv, + Locale const& locale, + const char *func_name, + intl_error *err, + Calendar*& cal, + long& cal_int_type, + bool& calendar_owned TSRMLS_DC) +{ + char *msg; + UErrorCode status = UErrorCode(); + + if (calendar_zv == NULL || Z_TYPE_P(calendar_zv) == IS_NULL) { + + // default requested + cal = new GregorianCalendar(locale, status); + calendar_owned = true; + + cal_int_type = UCAL_GREGORIAN; + + } else if (Z_TYPE_P(calendar_zv) == IS_LONG) { + + long v = Z_LVAL_P(calendar_zv); + if (v != (long)UCAL_TRADITIONAL && v != (long)UCAL_GREGORIAN) { + spprintf(&msg, 0, "%s: invalid value for calendar type; it must be " + "one of IntlDateFormatter::TRADITIONAL (locale's default " + "calendar) or IntlDateFormatter::GREGORIAN. " + "Alternatively, it can be an IntlCalendar object", + func_name); + intl_errors_set(err, U_ILLEGAL_ARGUMENT_ERROR, msg, 1 TSRMLS_CC); + efree(msg); + return FAILURE; + } else if (v == (long)UCAL_TRADITIONAL) { + cal = Calendar::createInstance(locale, status); + } else { //UCAL_GREGORIAN + cal = new GregorianCalendar(locale, status); + } + calendar_owned = true; + + cal_int_type = Z_LVAL_P(calendar_zv); + + } else if (Z_TYPE_P(calendar_zv) == IS_OBJECT && + instanceof_function_ex(Z_OBJCE_P(calendar_zv), + Calendar_ce_ptr, 0 TSRMLS_CC)) { + + cal = calendar_fetch_native_calendar(calendar_zv TSRMLS_CC); + if (cal == NULL) { + spprintf(&msg, 0, "%s: Found unconstructed IntlCalendar object", + func_name); + intl_errors_set(err, U_ILLEGAL_ARGUMENT_ERROR, msg, 1 TSRMLS_CC); + efree(msg); + return FAILURE; + } + calendar_owned = false; + + cal_int_type = -1; + + } else { + spprintf(&msg, 0, "%s: Invalid calendar argument; should be an integer " + "or an IntlCalendar instance", func_name); + intl_errors_set(err, U_ILLEGAL_ARGUMENT_ERROR, msg, 1 TSRMLS_CC); + efree(msg); + return FAILURE; + } + + if (cal == NULL && !U_FAILURE(status)) { + status = U_MEMORY_ALLOCATION_ERROR; + } + if (U_FAILURE(status)) { + spprintf(&msg, 0, "%s: Failure instantiating calendar", func_name); + intl_errors_set(err, U_ILLEGAL_ARGUMENT_ERROR, msg, 1 TSRMLS_CC); + efree(msg); + return FAILURE; + } + + return SUCCESS; +} diff --git a/ext/intl/dateformat/dateformat_helpers.h b/ext/intl/dateformat/dateformat_helpers.h new file mode 100644 index 0000000000..bded0b7d78 --- /dev/null +++ b/ext/intl/dateformat/dateformat_helpers.h @@ -0,0 +1,39 @@ +/* + +----------------------------------------------------------------------+ + | 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 <cataphract@php.net> | + +----------------------------------------------------------------------+ +*/ + +#ifndef DATEFORMAT_HELPERS_H +#define DATEFORMAT_HELPERS_H + +#ifndef __cplusplus +#error For C++ only +#endif + +#include <unicode/calendar.h> + +extern "C" { +#include "../php_intl.h" +} + +int datefmt_process_calendar_arg(zval* calendar_zv, + Locale const& locale, + const char *func_name, + intl_error *err, + Calendar*& cal, + long& cal_int_type, + bool& calendar_owned TSRMLS_DC); + +#endif /* DATEFORMAT_HELPERS_H */ + diff --git a/ext/intl/grapheme/grapheme.h b/ext/intl/grapheme/grapheme.h index c0e697ac1e..756ce9173e 100755 --- a/ext/intl/grapheme/grapheme.h +++ b/ext/intl/grapheme/grapheme.h @@ -19,7 +19,6 @@ #include <php.h> #include <unicode/utypes.h> -#include <unicode/ubrk.h> PHP_FUNCTION(grapheme_strlen); PHP_FUNCTION(grapheme_strpos); diff --git a/ext/intl/intl_convertcpp.cpp b/ext/intl/intl_convertcpp.cpp new file mode 100644 index 0000000000..f699a3c61c --- /dev/null +++ b/ext/intl/intl_convertcpp.cpp @@ -0,0 +1,89 @@ +/* + +----------------------------------------------------------------------+ + | 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 <cataphract@php.net> | + +----------------------------------------------------------------------+ +*/ + +/* $Id$ */ + +#include "intl_cppshims.h" + +#include "intl_convertcpp.h" +#include <unicode/ustring.h> +extern "C" { +#include <php.h> +} + +/* {{{ intl_stringFromChar */ +int intl_stringFromChar(UnicodeString &ret, char *str, int32_t str_len, UErrorCode *status) +{ + //the number of UTF-16 code units is not larger than that of UTF-8 code + //units, + 1 for the terminator + int32_t capacity = str_len + 1; + + //no check necessary -- if NULL will fail ahead + UChar *utf16 = ret.getBuffer(capacity); + int32_t utf16_len = 0; + *status = U_ZERO_ERROR; + u_strFromUTF8WithSub(utf16, ret.getCapacity(), &utf16_len, + str, str_len, U_SENTINEL /* no substitution */, NULL, + status); + ret.releaseBuffer(utf16_len); + if (U_FAILURE(*status)) { + ret.setToBogus(); + return FAILURE; + } + return SUCCESS; +} +/* }}} */ + +/* {{{ intl_charFromString + * faster than doing intl_convert_utf16_to_utf8(&res, &res_len, + * from.getBuffer(), from.length(), &status), + * but consumes more memory */ +int intl_charFromString(const UnicodeString &from, char **res, int *res_len, UErrorCode *status) +{ + if (from.isBogus()) { + return FAILURE; + } + + //the number of UTF-8 code units is not larger than that of UTF-16 code + //units * 3 + 1 for the terminator + int32_t capacity = from.length() * 3 + 1; + + if (from.isEmpty()) { + *res = (char*)emalloc(1); + **res = '\0'; + *res_len = 0; + return SUCCESS; + } + + *res = (char*)emalloc(capacity); + *res_len = 0; //tbd + + const UChar *utf16buf = from.getBuffer(); + int32_t actual_len; + u_strToUTF8WithSub(*res, capacity - 1, &actual_len, utf16buf, from.length(), + U_SENTINEL, NULL, status); + + if (U_FAILURE(*status)) { + efree(*res); + *res = NULL; + return FAILURE; + } + (*res)[actual_len] = '\0'; + *res_len = (int)actual_len; + + return SUCCESS; +} +/* }}} */ diff --git a/ext/intl/intl_convertcpp.h b/ext/intl/intl_convertcpp.h new file mode 100644 index 0000000000..89d4209dd3 --- /dev/null +++ b/ext/intl/intl_convertcpp.h @@ -0,0 +1,32 @@ +/* + +----------------------------------------------------------------------+ + | 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 <cataphract@php.net> | + +----------------------------------------------------------------------+ +*/ + +/* $Id$ */ + +#ifndef INTL_CONVERTCPP_H +#define INTL_CONVERTCPP_H + +#ifndef __cplusplus +#error Should be included only in C++ Files +#endif + +#include <unicode/unistr.h> + +int intl_stringFromChar(UnicodeString &ret, char *str, int32_t str_len, UErrorCode *status); + +int intl_charFromString(const UnicodeString &from, char **res, int *res_len, UErrorCode *status); + +#endif /* INTL_CONVERTCPP_H */ diff --git a/ext/intl/intl_cppshims.h b/ext/intl/intl_cppshims.h new file mode 100644 index 0000000000..2fb70edfd0 --- /dev/null +++ b/ext/intl/intl_cppshims.h @@ -0,0 +1,34 @@ +/* + +----------------------------------------------------------------------+ + | 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 <cataphract@php.net> | + +----------------------------------------------------------------------+ +*/ + +#ifndef INTL_CPPSHIMS_H +#define INTL_CPPSHIMS_H + +#ifndef __cplusplus +#error For inclusion form C++ files only +#endif + +#ifdef _MSC_VER +//This is only required for old versions of ICU only +#include <stdio.h> + +#include <math.h> + +/* avoid redefinition of int8_t, also defined in unicode/pwin32.h */ +#define _MSC_STDINT_H_ 1 +#endif + +#endif
\ No newline at end of file diff --git a/ext/intl/intl_error.c b/ext/intl/intl_error.c index 9c2e13dfd5..99b1c6001c 100755 --- a/ext/intl/intl_error.c +++ b/ext/intl/intl_error.c @@ -21,12 +21,16 @@ #endif #include <php.h> +#include <zend_exceptions.h> #include "php_intl.h" #include "intl_error.h" +#include "intl_convert.h" ZEND_EXTERN_MODULE_GLOBALS( intl ) +static zend_class_entry *IntlException_ce_ptr; + /* {{{ intl_error* intl_g_error_get() * Return global error structure. */ @@ -102,8 +106,11 @@ void intl_error_set_custom_msg( intl_error* err, char* msg, int copyMsg TSRMLS_D if( !msg ) return; - if(!err && INTL_G(error_level)) { - php_error_docref(NULL TSRMLS_CC, INTL_G(error_level), "%s", msg); + if( !err ) { + if( INTL_G( error_level ) ) + php_error_docref( NULL TSRMLS_CC, INTL_G( error_level ), "%s", msg ); + if( INTL_G( use_exceptions ) ) + zend_throw_exception_ex( IntlException_ce_ptr, 0 TSRMLS_CC, "%s", msg ); } if( !err && !( err = intl_g_error_get( TSRMLS_C ) ) ) return; @@ -223,6 +230,96 @@ void intl_errors_set_code( intl_error* err, UErrorCode err_code TSRMLS_DC ) } /* }}} */ +void intl_register_IntlException_class( TSRMLS_D ) +{ + zend_class_entry ce, + *default_exception_ce; + + default_exception_ce = zend_exception_get_default( TSRMLS_C ); + + /* Create and register 'IntlException' class. */ + INIT_CLASS_ENTRY_EX( ce, "IntlException", sizeof( "IntlException" ) - 1, NULL ); + IntlException_ce_ptr = zend_register_internal_class_ex( &ce, + default_exception_ce, NULL TSRMLS_CC ); + IntlException_ce_ptr->create_object = default_exception_ce->create_object; +} + +smart_str intl_parse_error_to_string( UParseError* pe ) +{ + smart_str ret = {0}; + char *buf; + int u8len; + UErrorCode status; + int any = 0; + + assert( pe != NULL ); + + smart_str_appends( &ret, "parse error " ); + if( pe->line > 0 ) + { + smart_str_appends( &ret, "on line " ); + smart_str_append_long( &ret, (long ) pe->line ); + any = 1; + } + if( pe->offset >= 0 ) { + if( any ) + smart_str_appends( &ret, ", " ); + else + smart_str_appends( &ret, "at " ); + + smart_str_appends( &ret, "offset " ); + smart_str_append_long( &ret, (long ) pe->offset ); + any = 1; + } + + if (pe->preContext[0] != 0 ) { + if( any ) + smart_str_appends( &ret, ", " ); + + smart_str_appends( &ret, "after \"" ); + intl_convert_utf16_to_utf8( &buf, &u8len, pe->preContext, -1, &status ); + if( U_FAILURE( status ) ) + { + smart_str_appends( &ret, "(could not convert parser error pre-context to UTF-8)" ); + } + else { + smart_str_appendl( &ret, buf, u8len ); + efree( buf ); + } + smart_str_appends( &ret, "\"" ); + any = 1; + } + + if( pe->postContext[0] != 0 ) + { + if( any ) + smart_str_appends( &ret, ", " ); + + smart_str_appends( &ret, "before or at \"" ); + intl_convert_utf16_to_utf8( &buf, &u8len, pe->postContext, -1, &status ); + if( U_FAILURE( status ) ) + { + smart_str_appends( &ret, "(could not convert parser error post-context to UTF-8)" ); + } + else + { + smart_str_appendl( &ret, buf, u8len ); + efree( buf ); + } + smart_str_appends( &ret, "\"" ); + any = 1; + } + + if( !any ) + { + smart_str_free( &ret ); + smart_str_appends( &ret, "no parse error" ); + } + + smart_str_0( &ret ); + return ret; +} + /* * Local variables: * tab-width: 4 diff --git a/ext/intl/intl_error.h b/ext/intl/intl_error.h index 3adae85474..4d8eb79327 100755 --- a/ext/intl/intl_error.h +++ b/ext/intl/intl_error.h @@ -20,6 +20,8 @@ #define INTL_ERROR_H #include <unicode/utypes.h> +#include <unicode/parseerr.h> +#include <ext/standard/php_smart_str.h> #define INTL_ERROR_CODE(e) (e).code @@ -44,4 +46,10 @@ void intl_errors_set_custom_msg( intl_error* err, char* msg, int copyMsg void intl_errors_set_code( intl_error* err, UErrorCode err_code TSRMLS_DC ); void intl_errors_set( intl_error* err, UErrorCode code, char* msg, int copyMsg TSRMLS_DC ); +// Other error helpers +smart_str intl_parse_error_to_string( UParseError* pe ); + +// exported to be called on extension MINIT +void intl_register_IntlException_class( TSRMLS_D ); + #endif // INTL_ERROR_H diff --git a/ext/intl/locale/locale_methods.c b/ext/intl/locale/locale_methods.c index 1707c69f93..936e3142ad 100755 --- a/ext/intl/locale/locale_methods.c +++ b/ext/intl/locale/locale_methods.c @@ -208,10 +208,7 @@ static int getSingletonPos(char* str) Get default locale */ PHP_NAMED_FUNCTION(zif_locale_get_default) { - if( INTL_G(default_locale) == NULL ) { - INTL_G(default_locale) = pestrdup( uloc_getDefault(), 1); - } - RETURN_STRING( INTL_G(default_locale), TRUE ); + RETURN_STRING( intl_locale_get_default( TSRMLS_C ), TRUE ); } /* }}} */ diff --git a/ext/intl/msgformat/msgformat_attr.c b/ext/intl/msgformat/msgformat_attr.c index ed2dae27d1..c333a24ee1 100755 --- a/ext/intl/msgformat/msgformat_attr.c +++ b/ext/intl/msgformat/msgformat_attr.c @@ -102,6 +102,12 @@ PHP_FUNCTION( msgfmt_set_pattern ) } mfo->mf_data.orig_format = estrndup(value, value_len); mfo->mf_data.orig_format_len = value_len; + /* invalidate cached format types */ + if (mfo->mf_data.arg_types) { + zend_hash_destroy(mfo->mf_data.arg_types); + efree(mfo->mf_data.arg_types); + mfo->mf_data.arg_types = NULL; + } RETURN_TRUE; } diff --git a/ext/intl/msgformat/msgformat_data.c b/ext/intl/msgformat/msgformat_data.c index 527c1d4d17..5d49054473 100755 --- a/ext/intl/msgformat/msgformat_data.c +++ b/ext/intl/msgformat/msgformat_data.c @@ -31,8 +31,10 @@ void msgformat_data_init( msgformat_data* mf_data TSRMLS_DC ) if( !mf_data ) return; - mf_data->umsgf = NULL; - mf_data->orig_format = NULL; + mf_data->umsgf = NULL; + mf_data->orig_format = NULL; + mf_data->arg_types = NULL; + mf_data->tz_set = 0; intl_error_reset( &mf_data->error TSRMLS_CC ); } /* }}} */ @@ -40,21 +42,27 @@ void msgformat_data_init( msgformat_data* mf_data TSRMLS_DC ) /* {{{ void msgformat_data_free( msgformat_data* mf_data ) * Clean up memory allocated for msgformat_data */ -void msgformat_data_free( msgformat_data* mf_data TSRMLS_DC ) +void msgformat_data_free(msgformat_data* mf_data TSRMLS_DC) { - if( !mf_data ) + if (!mf_data) return; - if( mf_data->umsgf ) - umsg_close( mf_data->umsgf ); + if (mf_data->umsgf) + umsg_close(mf_data->umsgf); - if(mf_data->orig_format) { + if (mf_data->orig_format) { efree(mf_data->orig_format); mf_data->orig_format = NULL; } + if (mf_data->arg_types) { + zend_hash_destroy(mf_data->arg_types); + efree(mf_data->arg_types); + mf_data->arg_types = NULL; + } + mf_data->umsgf = NULL; - intl_error_reset( &mf_data->error TSRMLS_CC ); + intl_error_reset(&mf_data->error TSRMLS_CC); } /* }}} */ diff --git a/ext/intl/msgformat/msgformat_data.h b/ext/intl/msgformat/msgformat_data.h index 6479888f8f..51d7687a3a 100755 --- a/ext/intl/msgformat/msgformat_data.h +++ b/ext/intl/msgformat/msgformat_data.h @@ -31,6 +31,8 @@ typedef struct { UMessageFormat* umsgf; char* orig_format; ulong orig_format_len; + HashTable* arg_types; + int tz_set; /* if we've already the time zone in sub-formats */ } msgformat_data; msgformat_data* msgformat_data_create( TSRMLS_D ); diff --git a/ext/intl/msgformat/msgformat_format.c b/ext/intl/msgformat/msgformat_format.c index 9a18ac0a70..39652327b9 100755 --- a/ext/intl/msgformat/msgformat_format.c +++ b/ext/intl/msgformat/msgformat_format.c @@ -32,51 +32,34 @@ #endif /* {{{ */ -static void msgfmt_do_format(MessageFormatter_object *mfo, zval *args, zval *return_value TSRMLS_DC) +static void msgfmt_do_format(MessageFormatter_object *mfo, zval *args, zval *return_value TSRMLS_DC) { - zval **fargs; int count; UChar* formatted = NULL; int formatted_len = 0; - HashPosition pos; - int i; + HashTable *args_copy; count = zend_hash_num_elements(Z_ARRVAL_P(args)); - if(count < umsg_format_arg_count(MSG_FORMAT_OBJECT(mfo))) { - /* Not enough aguments for format! */ - intl_error_set( INTL_DATA_ERROR_P(mfo), U_ILLEGAL_ARGUMENT_ERROR, - "msgfmt_format: not enough parameters", 0 TSRMLS_CC ); - RETVAL_FALSE; - return; - } - - fargs = safe_emalloc(count, sizeof(zval *), 0); + ALLOC_HASHTABLE(args_copy); + zend_hash_init(args_copy, count, NULL, ZVAL_PTR_DTOR, 0); + zend_hash_copy(args_copy, Z_ARRVAL_P(args), (copy_ctor_func_t)zval_add_ref, + NULL, sizeof(zval*)); - zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(args), &pos); - for(i=0;i<count;i++) { - zval **val; - zend_hash_get_current_data_ex(Z_ARRVAL_P(args), (void **)&val, &pos); - fargs[i] = *val; - Z_ADDREF_P(fargs[i]); - /* TODO: needs refcount increase here? */ - zend_hash_move_forward_ex(Z_ARRVAL_P(args), &pos); - } + umsg_format_helper(mfo, args_copy, &formatted, &formatted_len TSRMLS_CC); - umsg_format_helper(MSG_FORMAT_OBJECT(mfo), count, fargs, &formatted, &formatted_len, &INTL_DATA_ERROR_CODE(mfo) TSRMLS_CC); - - for(i=0;i<count;i++) { - zval_ptr_dtor(&fargs[i]); - } + zend_hash_destroy(args_copy); + efree(args_copy); - efree(fargs); - - if (formatted && U_FAILURE( INTL_DATA_ERROR_CODE(mfo) ) ) { + if (formatted && U_FAILURE(INTL_DATA_ERROR_CODE(mfo))) { efree(formatted); } - INTL_METHOD_CHECK_STATUS( mfo, "Number formatting failed" ); - INTL_METHOD_RETVAL_UTF8( mfo, formatted, formatted_len, 1 ); + if (U_FAILURE(INTL_DATA_ERROR_CODE(mfo))) { + RETURN_FALSE; + } else { + INTL_METHOD_RETVAL_UTF8(mfo, formatted, formatted_len, 1); + } } /* }}} */ diff --git a/ext/intl/msgformat/msgformat_helpers.cpp b/ext/intl/msgformat/msgformat_helpers.cpp index 1895de2c86..fd8df1a39c 100755 --- a/ext/intl/msgformat/msgformat_helpers.cpp +++ b/ext/intl/msgformat/msgformat_helpers.cpp @@ -18,9 +18,19 @@ #include "config.h" #endif -#include <math.h> +#include "../intl_cppshims.h" + +#include <limits.h> #include <unicode/msgfmt.h> #include <unicode/chariter.h> +#include <unicode/ustdio.h> +#include <unicode/timezone.h> +#include <unicode/datefmt.h> +#include <unicode/calendar.h> + +#include <vector> + +#include "../intl_convertcpp.h" extern "C" { #include "php_intl.h" @@ -28,8 +38,27 @@ extern "C" { #include "msgformat_format.h" #include "msgformat_helpers.h" #include "intl_convert.h" +#define USE_CALENDAR_POINTER 1 +#include "../calendar/calendar_class.h" +/* avoid redefinition of int8_t, already defined in unicode/pwin32.h */ +#define _MSC_STDINT_H_ 1 +#include "ext/date/php_date.h" +#define USE_TIMEZONE_POINTER +#include "../timezone/timezone_class.h" } +#ifndef INFINITY +#define INFINITY (DBL_MAX+DBL_MAX) +#endif + +#ifndef NAN +#define NAN (INFINITY-INFINITY) +#endif + +#if U_ICU_VERSION_MAJOR_NUM * 10 + U_ICU_VERSION_MINOR_NUM >= 48 +#define HAS_MESSAGE_PATTERN 1 +#endif + U_NAMESPACE_BEGIN /** * This class isolates our access to private internal methods of @@ -40,96 +69,638 @@ class MessageFormatAdapter { public: static const Formattable::Type* getArgTypeList(const MessageFormat& m, int32_t& count); +#ifdef HAS_MESSAGE_PATTERN + static const MessagePattern getMessagePattern(MessageFormat* m); +#endif }; + const Formattable::Type* MessageFormatAdapter::getArgTypeList(const MessageFormat& m, int32_t& count) { return m.getArgTypeList(count); } + +#ifdef HAS_MESSAGE_PATTERN +const MessagePattern +MessageFormatAdapter::getMessagePattern(MessageFormat* m) { + return m->msgPattern; +} +#endif U_NAMESPACE_END -U_CFUNC int32_t umsg_format_arg_count(UMessageFormat *fmt) +U_CFUNC int32_t umsg_format_arg_count(UMessageFormat *fmt) { int32_t fmt_count = 0; MessageFormatAdapter::getArgTypeList(*(const MessageFormat*)fmt, fmt_count); return fmt_count; } -U_CFUNC void umsg_format_helper(UMessageFormat *fmt, int arg_count, zval **args, UChar **formatted, int *formatted_len, UErrorCode *status TSRMLS_DC) +static double umsg_helper_zval_to_millis(zval *z, UErrorCode *status TSRMLS_DC) { + double rv = NAN; + long lv; + int type; + + if (U_FAILURE(*status)) { + return NAN; + } + + switch (Z_TYPE_P(z)) { + case IS_STRING: + type = is_numeric_string(Z_STRVAL_P(z), Z_STRLEN_P(z), &lv, &rv, 0); + if (type == IS_DOUBLE) { + rv *= U_MILLIS_PER_SECOND; + } else if (type == IS_LONG) { + rv = U_MILLIS_PER_SECOND * (double)lv; + } else { + *status = U_ILLEGAL_ARGUMENT_ERROR; + } + break; + case IS_LONG: + rv = U_MILLIS_PER_SECOND * (double)Z_LVAL_P(z); + break; + case IS_DOUBLE: + rv = U_MILLIS_PER_SECOND * Z_DVAL_P(z); + break; + case IS_OBJECT: + if (instanceof_function(Z_OBJCE_P(z), php_date_get_date_ce() TSRMLS_CC)) { + zval retval; + zval *zfuncname; + INIT_ZVAL(retval); + MAKE_STD_ZVAL(zfuncname); + ZVAL_STRING(zfuncname, "getTimestamp", 1); + if (call_user_function(NULL, &(z), zfuncname, &retval, 0, NULL TSRMLS_CC) + != SUCCESS || Z_TYPE(retval) != IS_LONG) { + *status = U_INTERNAL_PROGRAM_ERROR; + } else { + rv = U_MILLIS_PER_SECOND * (double)Z_LVAL(retval); + } + zval_ptr_dtor(&zfuncname); + } else if (instanceof_function(Z_OBJCE_P(z), Calendar_ce_ptr TSRMLS_CC)) { + Calendar_object *co = (Calendar_object *) + zend_object_store_get_object(z TSRMLS_CC ); + if (co->ucal == NULL) { + *status = U_ILLEGAL_ARGUMENT_ERROR; + } else { + rv = (double)co->ucal->getTime(*status); + } + } else { + /* TODO: try with cast(), get() to obtain a number */ + *status = U_ILLEGAL_ARGUMENT_ERROR; + } + break; + default: + *status = U_ILLEGAL_ARGUMENT_ERROR; + } + + return rv; +} + +static HashTable *umsg_get_numeric_types(MessageFormatter_object *mfo, + intl_error& err TSRMLS_DC) { - int fmt_count = 0; - const Formattable::Type* argTypes = - MessageFormatAdapter::getArgTypeList(*(const MessageFormat*)fmt, fmt_count); - Formattable* fargs = new Formattable[fmt_count ? fmt_count : 1]; + HashTable *ret; + int32_t parts_count; - for(int32_t i = 0; i < fmt_count; ++i) { - UChar *stringVal = NULL; - int stringLen = 0; - int64_t tInt64 = 0; + if (U_FAILURE(err.code)) { + return NULL; + } - switch(argTypes[i]) { - case Formattable::kDate: - convert_to_long_ex(&args[i]); - fargs[i].setDate(U_MILLIS_PER_SECOND * (double)Z_LVAL_P(args[i])); - break; + if (mfo->mf_data.arg_types) { + /* already cached */ + return mfo->mf_data.arg_types; + } - case Formattable::kDouble: - convert_to_double_ex(&args[i]); - fargs[i].setDouble(Z_DVAL_P(args[i])); - break; - - case Formattable::kLong: - convert_to_long_ex(&args[i]); - fargs[i].setLong(Z_LVAL_P(args[i])); - break; + const Formattable::Type *types = MessageFormatAdapter::getArgTypeList( + *(MessageFormat*)mfo->mf_data.umsgf, parts_count); + + /* Hash table will store Formattable::Type objects directly, + * so no need for destructor */ + ALLOC_HASHTABLE(ret); + zend_hash_init(ret, parts_count, NULL, NULL, 0); + + for (int i = 0; i < parts_count; i++) { + const Formattable::Type t = types[i]; + if (zend_hash_index_update(ret, (ulong)i, (void*)&t, sizeof(t), NULL) + == FAILURE) { + intl_errors_set(&err, U_MEMORY_ALLOCATION_ERROR, + "Write to argument types hash table failed", 0 TSRMLS_CC); + break; + } + } - case Formattable::kInt64: - if(Z_TYPE_P(args[i]) == IS_DOUBLE) { - tInt64 = (int64_t)Z_DVAL_P(args[i]); - } else if(Z_TYPE_P(args[i]) == IS_LONG) { - tInt64 = (int64_t)Z_LVAL_P(args[i]); + if (U_FAILURE(err.code)) { + zend_hash_destroy(ret); + efree(ret); + + return NULL; + } + + mfo->mf_data.arg_types = ret; + + return ret; +} + +#ifdef HAS_MESSAGE_PATTERN +static HashTable *umsg_parse_format(MessageFormatter_object *mfo, + const MessagePattern& mp, + intl_error& err TSRMLS_DC) +{ + HashTable *ret; + int32_t parts_count; + + if (U_FAILURE(err.code)) { + return NULL; + } + + if (!((MessageFormat *)mfo->mf_data.umsgf)->usesNamedArguments()) { + return umsg_get_numeric_types(mfo, err TSRMLS_CC); + } + + if (mfo->mf_data.arg_types) { + /* already cached */ + return mfo->mf_data.arg_types; + } + + /* Hash table will store Formattable::Type objects directly, + * so no need for destructor */ + ALLOC_HASHTABLE(ret); + zend_hash_init(ret, 32, NULL, NULL, 0); + + parts_count = mp.countParts(); + + // See MessageFormat::cacheExplicitFormats() + /* + * Looking through the pattern, go to each arg_start part type. + * The arg-typeof that tells us the argument type (simple, complicated) + * then the next part is either the arg_name or arg number + * and then if it's simple after that there could be a part-type=arg-type + * while substring will tell us number, spellout, etc. + * If the next thing isn't an arg-type then assume string. + */ + /* The last two "parts" can at most be ARG_LIMIT and MSG_LIMIT + * which we need not examine. */ + for (int32_t i = 0; i < parts_count - 2 && U_SUCCESS(err.code); i++) { + MessagePattern::Part p = mp.getPart(i); + + if (p.getType() != UMSGPAT_PART_TYPE_ARG_START) { + continue; + } + + MessagePattern::Part name_part = mp.getPart(++i); /* Getting name, advancing i */ + Formattable::Type type, + *storedType; + + if (name_part.getType() == UMSGPAT_PART_TYPE_ARG_NAME) { + UnicodeString argName = mp.getSubstring(name_part); + if (zend_hash_find(ret, (char*)argName.getBuffer(), argName.length(), + (void**)&storedType) == FAILURE) { + /* not found already; create new entry in HT */ + Formattable::Type bogusType = Formattable::kObject; + if (zend_hash_update(ret, (char*)argName.getBuffer(), argName.length(), + (void*)&bogusType, sizeof(bogusType), (void**)&storedType) == FAILURE) { + intl_errors_set(&err, U_MEMORY_ALLOCATION_ERROR, + "Write to argument types hash table failed", 0 TSRMLS_CC); + continue; + } + } + } else if (name_part.getType() == UMSGPAT_PART_TYPE_ARG_NUMBER) { + int32_t argNumber = name_part.getValue(); + if (argNumber < 0) { + intl_errors_set(&err, U_INVALID_FORMAT_ERROR, + "Found part with negative number", 0 TSRMLS_CC); + continue; + } + if (zend_hash_index_find(ret, (ulong)argNumber, (void**)&storedType) + == FAILURE) { + /* not found already; create new entry in HT */ + Formattable::Type bogusType = Formattable::kObject; + if (zend_hash_index_update(ret, (ulong)argNumber, (void*)&bogusType, + sizeof(bogusType), (void**)&storedType) == FAILURE) { + intl_errors_set(&err, U_MEMORY_ALLOCATION_ERROR, + "Write to argument types hash table failed", 0 TSRMLS_CC); + continue; + } + } + } + + UMessagePatternArgType argType = p.getArgType(); + /* No type specified, treat it as a string */ + if (argType == UMSGPAT_ARG_TYPE_NONE) { + type = Formattable::kString; + } else { /* Some type was specified, might be simple or complicated */ + if (argType == UMSGPAT_ARG_TYPE_SIMPLE) { + /* For a SIMPLE arg, after the name part, there should be + * an ARG_TYPE part whose string value tells us what to do */ + MessagePattern::Part type_part = mp.getPart(++i); /* Getting type, advancing i */ + if (type_part.getType() == UMSGPAT_PART_TYPE_ARG_TYPE) { + UnicodeString typeString = mp.getSubstring(type_part); + /* This is all based on the rules in the docs for MessageFormat + * @see http://icu-project.org/apiref/icu4c/classMessageFormat.html */ + if (typeString == "number") { + MessagePattern::Part style_part = mp.getPart(i + 1); /* Not advancing i */ + if (style_part.getType() == UMSGPAT_PART_TYPE_ARG_STYLE) { + UnicodeString styleString = mp.getSubstring(style_part); + if (styleString == "integer") { + type = Formattable::kInt64; + } else if (styleString == "currency") { + type = Formattable::kDouble; + } else if (styleString == "percent") { + type = Formattable::kDouble; + } else { /* some style invalid/unknown to us */ + type = Formattable::kDouble; + } + } else { // if missing style, part, make it a double + type = Formattable::kDouble; + } + } else if ((typeString == "date") || (typeString == "time")) { + type = Formattable::kDate; + } else if ((typeString == "spellout") || (typeString == "ordinal") + || (typeString == "duration")) { + type = Formattable::kDouble; + } } else { - SEPARATE_ZVAL_IF_NOT_REF(&args[i]); - convert_scalar_to_number( args[i] TSRMLS_CC ); - tInt64 = (Z_TYPE_P(args[i]) == IS_DOUBLE)?(int64_t)Z_DVAL_P(args[i]):Z_LVAL_P(args[i]); + /* If there's no UMSGPAT_PART_TYPE_ARG_TYPE right after a + * UMSGPAT_ARG_TYPE_SIMPLE argument, then the pattern + * is broken. */ + intl_errors_set(&err, U_PARSE_ERROR, + "Expected UMSGPAT_PART_TYPE_ARG_TYPE part following " + "UMSGPAT_ARG_TYPE_SIMPLE part", 0 TSRMLS_CC); + continue; } - fargs[i].setInt64(tInt64); + } else if (argType == UMSGPAT_ARG_TYPE_PLURAL) { + type = Formattable::kDouble; + } else if (argType == UMSGPAT_ARG_TYPE_CHOICE) { + type = Formattable::kDouble; + } else if (argType == UMSGPAT_ARG_TYPE_SELECT) { + type = Formattable::kString; + } else { + type = Formattable::kString; + } + } /* was type specified? */ + + /* We found a different type for the same arg! */ + if (*storedType != Formattable::kObject && *storedType != type) { + intl_errors_set(&err, U_ARGUMENT_TYPE_MISMATCH, + "Inconsistent types declared for an argument", 0 TSRMLS_CC); + continue; + } + + *storedType = type; + } /* visiting each part */ + + if (U_FAILURE(err.code)) { + zend_hash_destroy(ret); + efree(ret); + + return NULL; + } + + mfo->mf_data.arg_types = ret; + + return ret; +} +#endif + +static HashTable *umsg_get_types(MessageFormatter_object *mfo, + intl_error& err TSRMLS_DC) +{ + MessageFormat *mf = (MessageFormat *)mfo->mf_data.umsgf; + +#ifdef HAS_MESSAGE_PATTERN + const MessagePattern mp = MessageFormatAdapter::getMessagePattern(mf); + + return umsg_parse_format(mfo, mp, err TSRMLS_CC); +#else + if (mf->usesNamedArguments()) { + intl_errors_set(&err, U_UNSUPPORTED_ERROR, + "This extension supports named arguments only on ICU 4.8+", + 0 TSRMLS_CC); + return NULL; + } + return umsg_get_numeric_types(mfo, err TSRMLS_CC); +#endif +} + +static void umsg_set_timezone(MessageFormatter_object *mfo, + intl_error& err TSRMLS_DC) +{ + MessageFormat *mf = (MessageFormat *)mfo->mf_data.umsgf; + TimeZone *used_tz = NULL; + const Format **formats; + int32_t count; + + /* Unfortanely, this cannot change the time zone for arguments that + * appear inside complex formats because ::getFormats() returns NULL + * for all uncached formats, which is the case for complex formats + * unless they were set via one of the ::setFormat() methods */ + + if (mfo->mf_data.tz_set) { + return; /* already done */ + } + + formats = mf->getFormats(count); + + if (formats == NULL) { + intl_errors_set(&err, U_MEMORY_ALLOCATION_ERROR, + "Out of memory retrieving subformats", 0 TSRMLS_CC); + } + + for (int i = 0; U_SUCCESS(err.code) && i < count; i++) { + DateFormat* df = dynamic_cast<DateFormat*>( + const_cast<Format *>(formats[i])); + if (df == NULL) { + continue; + } + + if (used_tz == NULL) { + zval nullzv = zval_used_for_init, + *zvptr = &nullzv; + used_tz = timezone_process_timezone_argument(&zvptr, &err, + "msgfmt_format" TSRMLS_CC); + if (used_tz == NULL) { + continue; + } + } + + df->setTimeZone(*used_tz); + } + + if (U_SUCCESS(err.code)) { + mfo->mf_data.tz_set = 1; + } +} + +U_CFUNC void umsg_format_helper(MessageFormatter_object *mfo, + HashTable *args, + UChar **formatted, + int *formatted_len TSRMLS_DC) +{ + int arg_count = zend_hash_num_elements(args); + std::vector<Formattable> fargs; + std::vector<UnicodeString> farg_names; + MessageFormat *mf = (MessageFormat *)mfo->mf_data.umsgf; + HashTable *types; + intl_error& err = INTL_DATA_ERROR(mfo); + + if (U_FAILURE(err.code)) { + return; + } + + types = umsg_get_types(mfo, err TSRMLS_CC); + + umsg_set_timezone(mfo, err TSRMLS_CC); + + fargs.resize(arg_count); + farg_names.resize(arg_count); + + int argNum = 0; + HashPosition pos; + zval **elem; + + // Key related variables + int key_type; + char *str_index; + uint str_len; + ulong num_index; + + for (zend_hash_internal_pointer_reset_ex(args, &pos); + U_SUCCESS(err.code) && + (key_type = zend_hash_get_current_key_ex( + args, &str_index, &str_len, &num_index, 0, &pos), + zend_hash_get_current_data_ex(args, (void **)&elem, &pos) + ) == SUCCESS; + zend_hash_move_forward_ex(args, &pos), argNum++) + { + Formattable& formattable = fargs[argNum]; + UnicodeString& key = farg_names[argNum]; + Formattable::Type argType = Formattable::kObject, //unknown + *storedArgType = NULL; + + /* Process key and retrieve type */ + if (key_type == HASH_KEY_IS_LONG) { + /* includes case where index < 0 because it's exposed as unsigned */ + if (num_index > (ulong)INT32_MAX) { + intl_errors_set(&err, U_ILLEGAL_ARGUMENT_ERROR, + "Found negative or too large array key", 0 TSRMLS_CC); + continue; + } + + UChar temp[16]; + int32_t len = u_sprintf(temp, "%u", (uint32_t)num_index); + key.append(temp, len); + + zend_hash_index_find(types, (ulong)num_index, (void**)&storedArgType); + } else { //string; assumed to be in UTF-8 + intl_stringFromChar(key, str_index, str_len-1, &err.code); + + if (U_FAILURE(err.code)) { + char *message; + spprintf(&message, 0, + "Invalid UTF-8 data in argument key: '%s'", str_index); + intl_errors_set(&err, err.code, message, 1 TSRMLS_CC); + efree(message); + continue; + } + + zend_hash_find(types, (char*)key.getBuffer(), key.length(), + (void**)&storedArgType); + } + + if (storedArgType != NULL) { + argType = *storedArgType; + } + + /* Convert zval to formattable according to message format type + * or (as a fallback) the zval type */ + if (argType != Formattable::kObject) { + switch (argType) { + case Formattable::kString: + { + string_arg: + /* This implicitly converts objects + * Note that our vectors will leak if object conversion fails + * and PHP ends up with a fatal error and calls longjmp + * as a result of that. + */ + convert_to_string_ex(elem); + + UnicodeString *text = new UnicodeString(); + intl_stringFromChar(*text, + Z_STRVAL_PP(elem), Z_STRLEN_PP(elem), &err.code); + + if (U_FAILURE(err.code)) { + char *message; + spprintf(&message, 0, "Invalid UTF-8 data in string argument: " + "'%s'", Z_STRVAL_PP(elem)); + intl_errors_set(&err, err.code, message, 1 TSRMLS_CC); + efree(message); + delete text; + continue; + } + formattable.adoptString(text); + break; + } + case Formattable::kDouble: + { + double d; + if (Z_TYPE_PP(elem) == IS_DOUBLE) { + d = Z_DVAL_PP(elem); + } else if (Z_TYPE_PP(elem) == IS_LONG) { + d = (double)Z_LVAL_PP(elem); + } else { + SEPARATE_ZVAL_IF_NOT_REF(elem); + convert_scalar_to_number(*elem TSRMLS_CC); + d = (Z_TYPE_PP(elem) == IS_DOUBLE) + ? Z_DVAL_PP(elem) + : (double)Z_LVAL_PP(elem); + } + formattable.setDouble(d); + break; + } + case Formattable::kLong: + { + int32_t tInt32; +retry_klong: + if (Z_TYPE_PP(elem) == IS_DOUBLE) { + if (Z_DVAL_PP(elem) > (double)INT32_MAX || + Z_DVAL_PP(elem) < (double)INT32_MIN) { + intl_errors_set(&err, U_ILLEGAL_ARGUMENT_ERROR, + "Found PHP float with absolute value too large for " + "32 bit integer argument", 0 TSRMLS_CC); + } else { + tInt32 = (int32_t)Z_DVAL_PP(elem); + } + } else if (Z_TYPE_PP(elem) == IS_LONG) { + if (Z_LVAL_PP(elem) > INT32_MAX || + Z_LVAL_PP(elem) < INT32_MIN) { + intl_errors_set(&err, U_ILLEGAL_ARGUMENT_ERROR, + "Found PHP integer with absolute value too large " + "for 32 bit integer argument", 0 TSRMLS_CC); + } else { + tInt32 = (int32_t)Z_LVAL_PP(elem); + } + } else { + SEPARATE_ZVAL_IF_NOT_REF(elem); + convert_scalar_to_number(*elem TSRMLS_CC); + goto retry_klong; + } + formattable.setLong(tInt32); + break; + } + case Formattable::kInt64: + { + int64_t tInt64; +retry_kint64: + if (Z_TYPE_PP(elem) == IS_DOUBLE) { + if (Z_DVAL_PP(elem) > (double)U_INT64_MAX || + Z_DVAL_PP(elem) < (double)U_INT64_MIN) { + intl_errors_set(&err, U_ILLEGAL_ARGUMENT_ERROR, + "Found PHP float with absolute value too large for " + "64 bit integer argument", 0 TSRMLS_CC); + } else { + tInt64 = (int64_t)Z_DVAL_PP(elem); + } + } else if (Z_TYPE_PP(elem) == IS_LONG) { + /* assume long is not wider than 64 bits */ + tInt64 = (int64_t)Z_LVAL_PP(elem); + } else { + SEPARATE_ZVAL_IF_NOT_REF(elem); + convert_scalar_to_number(*elem TSRMLS_CC); + goto retry_kint64; + } + formattable.setInt64(tInt64); + break; + } + case Formattable::kDate: + { + double dd = umsg_helper_zval_to_millis(*elem, &err.code TSRMLS_CC); + if (U_FAILURE(err.code)) { + char *message, *key_char; + int key_len; + UErrorCode status = UErrorCode(); + if (intl_charFromString(key, &key_char, &key_len, + &status) == SUCCESS) { + spprintf(&message, 0, "The argument for key '%s' " + "cannot be used as a date or time", key_char); + intl_errors_set(&err, err.code, message, 1 TSRMLS_CC); + efree(key_char); + efree(message); + } + continue; + } + formattable.setDate(dd); + break; + } + default: + intl_errors_set(&err, U_ILLEGAL_ARGUMENT_ERROR, + "Found unsupported argument type", 0 TSRMLS_CC); break; - - case Formattable::kString: - convert_to_string_ex(&args[i]); - intl_convert_utf8_to_utf16(&stringVal, &stringLen, Z_STRVAL_P(args[i]), Z_STRLEN_P(args[i]), status); - if(U_FAILURE(*status)){ - delete[] fargs; - return; + } + } else { + /* We couldn't find any information about the argument in the pattern, this + * means it's an extra argument. So convert it to a number if it's a number or + * bool or null and to a string if it's anything else except arrays . */ + switch (Z_TYPE_PP(elem)) { + case IS_DOUBLE: + formattable.setDouble(Z_DVAL_PP(elem)); + break; + case IS_BOOL: + convert_to_long_ex(elem); + /* Intentional fallthrough */ + case IS_LONG: + formattable.setInt64((int64_t)Z_LVAL_PP(elem)); + break; + case IS_NULL: + formattable.setInt64((int64_t)0); + break; + case IS_STRING: + case IS_OBJECT: + goto string_arg; + default: + { + char *message, *key_char; + int key_len; + UErrorCode status = UErrorCode(); + if (intl_charFromString(key, &key_char, &key_len, + &status) == SUCCESS) { + spprintf(&message, 0, "No strategy to convert the " + "value given for the argument with key '%s' " + "is available", key_char); + intl_errors_set(&err, + U_ILLEGAL_ARGUMENT_ERROR, message, 1 TSRMLS_CC); + efree(key_char); + efree(message); + } } - fargs[i].setString(stringVal); - efree(stringVal); - break; - - case Formattable::kArray: - case Formattable::kObject: - *status = U_UNSUPPORTED_ERROR; - delete[] fargs; - return; - } + } + } + } // visiting each argument + + if (U_FAILURE(err.code)) { + return; } - UnicodeString resultStr; - FieldPosition fieldPosition(0); - - /* format the message */ - ((const MessageFormat*)fmt)->format(fargs, fmt_count, resultStr, fieldPosition, *status); + UnicodeString resultStr; + FieldPosition fieldPosition(0); - delete[] fargs; + /* format the message */ + mf->format(farg_names.empty() ? NULL : &farg_names[0], + fargs.empty() ? NULL : &fargs[0], arg_count, resultStr, err.code); - if(U_FAILURE(*status)){ - return; - } + if (U_FAILURE(err.code)) { + intl_errors_set(&err, err.code, + "Call to ICU MessageFormat::format() has failed", 0 TSRMLS_CC); + return; + } *formatted_len = resultStr.length(); *formatted = eumalloc(*formatted_len+1); - resultStr.extract(*formatted, *formatted_len+1, *status); + resultStr.extract(*formatted, *formatted_len+1, err.code); + if (U_FAILURE(err.code)) { + intl_errors_set(&err, err.code, + "Error copying format() result", 0 TSRMLS_CC); + return; + } } #define cleanup_zvals() for(int j=i;j>=0;j--) { zval_ptr_dtor((*args)+i); } @@ -154,15 +725,11 @@ U_CFUNC void umsg_parse_helper(UMessageFormat *fmt, int *count, zval ***args, UC int stmp_len; ALLOC_INIT_ZVAL((*args)[i]); - + switch(fargs[i].getType()) { case Formattable::kDate: aDate = ((double)fargs[i].getDate())/U_MILLIS_PER_SECOND; - if(aDate > LONG_MAX || aDate < -LONG_MAX) { - ZVAL_DOUBLE((*args)[i], aDate<0?ceil(aDate):floor(aDate)); - } else { - ZVAL_LONG((*args)[i], (long)aDate); - } + ZVAL_DOUBLE((*args)[i], aDate); break; case Formattable::kDouble: diff --git a/ext/intl/msgformat/msgformat_helpers.h b/ext/intl/msgformat/msgformat_helpers.h index 30c7e3930f..e6eda087d2 100755 --- a/ext/intl/msgformat/msgformat_helpers.h +++ b/ext/intl/msgformat/msgformat_helpers.h @@ -17,9 +17,9 @@ #ifndef MSG_FORMAT_HELPERS_H #define MSG_FORMAT_HELPERS_H -int32_t umsg_format_arg_count(UMessageFormat *fmt); -void umsg_format_helper(UMessageFormat *fmt, int arg_count, zval **args, - UChar **formatted, int *formatted_len, UErrorCode *status TSRMLS_DC); +int32_t umsg_format_arg_count(UMessageFormat *fmt); +void umsg_format_helper(MessageFormatter_object *mfo, HashTable *args, + UChar **formatted, int *formatted_len TSRMLS_DC); void umsg_parse_helper(UMessageFormat *fmt, int *count, zval ***args, UChar *source, int source_len, UErrorCode *status); #endif // MSG_FORMAT_HELPERS_H diff --git a/ext/intl/php_intl.c b/ext/intl/php_intl.c index efe0ddd242..19896a7108 100755 --- a/ext/intl/php_intl.c +++ b/ext/intl/php_intl.c @@ -41,6 +41,8 @@ #include "formatter/formatter_main.h" #include "formatter/formatter_parse.h" +#include "grapheme/grapheme.h" + #include "msgformat/msgformat.h" #include "msgformat/msgformat_class.h" #include "msgformat/msgformat_attr.h" @@ -58,6 +60,7 @@ #include "dateformat/dateformat.h" #include "dateformat/dateformat_class.h" #include "dateformat/dateformat_attr.h" +#include "dateformat/dateformat_attrcpp.h" #include "dateformat/dateformat_format.h" #include "dateformat/dateformat_parse.h" #include "dateformat/dateformat_data.h" @@ -68,6 +71,16 @@ #include "transliterator/transliterator_class.h" #include "transliterator/transliterator_methods.h" +#include "timezone/timezone_class.h" +#include "timezone/timezone_methods.h" + +#include "calendar/calendar_class.h" +#include "calendar/calendar_methods.h" +#include "calendar/gregoriancalendar_methods.h" + +#include "breakiterator/breakiterator_class.h" +#include "breakiterator/breakiterator_iterators.h" + #include "idn/idn.h" #if U_ICU_VERSION_MAJOR_NUM > 3 && U_ICU_VERSION_MINOR_NUM >=2 @@ -79,6 +92,7 @@ #include "msgformat/msgformat.h" #include "common/common_error.h" +#include "common/common_enum.h" #include <unicode/uloc.h> #include <ext/standard/info.h> @@ -98,6 +112,14 @@ ZEND_DECLARE_MODULE_GLOBALS( intl ) +const char *intl_locale_get_default( TSRMLS_D ) +{ + if( INTL_G(default_locale) == NULL ) { + return uloc_getDefault(); + } + return INTL_G(default_locale); +} + /* {{{ Arguments info */ ZEND_BEGIN_ARG_INFO_EX(collator_static_0_args, 0, 0, 0) ZEND_END_ARG_INFO() @@ -313,6 +335,11 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_datefmt_set_pattern, 0, 0, 2) ZEND_ARG_INFO(0, pattern) ZEND_END_ARG_INFO() +ZEND_BEGIN_ARG_INFO_EX(arginfo_datefmt_set_timezone, 0, 0, 2) + ZEND_ARG_INFO(0, mf) + ZEND_ARG_INFO(0, timezone) +ZEND_END_ARG_INFO() + ZEND_BEGIN_ARG_INFO_EX(arginfo_datefmt_set_calendar, 0, 0, 2) ZEND_ARG_INFO(0, mf) ZEND_ARG_INFO(0, calendar) @@ -402,6 +429,189 @@ ZEND_BEGIN_ARG_INFO_EX( arginfo_transliterator_error, 0, 0, 1 ) ZEND_ARG_OBJ_INFO( 0, trans, Transliterator, 0 ) ZEND_END_ARG_INFO() +ZEND_BEGIN_ARG_INFO_EX( arginfo_tz_idarg_static, 0, 0, 1 ) + ZEND_ARG_INFO( 0, zoneId ) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX( arginfo_tz_from_date_time_zone, 0, 0, 1 ) + ZEND_ARG_OBJ_INFO( 0, dateTimeZone, IntlDateTimeZone, 0 ) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX( arginfo_tz_create_enumeration, 0, 0, 0 ) + ZEND_ARG_INFO( 0, countryOrRawOffset ) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX( arginfo_tz_count_equivalent_ids, 0, 0, 1 ) + ZEND_ARG_INFO( 0, zoneId ) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX( arginfo_tz_create_time_zone_id_enumeration, 0, 0, 1 ) + ZEND_ARG_INFO( 0, zoneType ) + ZEND_ARG_INFO( 0, region ) + ZEND_ARG_INFO( 0, rawOffset ) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX( arginfo_tz_get_canonical_id, 0, 0, 1 ) + ZEND_ARG_INFO( 0, zoneId ) + ZEND_ARG_INFO( 1, isSystemID ) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX( arginfo_tz_get_equivalent_id, 0, 0, 2 ) + ZEND_ARG_INFO( 0, zoneId ) + ZEND_ARG_INFO( 0, index ) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX( arginfo_tz_get_offset, 0, 0, 5 ) + ZEND_ARG_OBJ_INFO( 0, timeZone, IntlTimeZone, 0 ) + ZEND_ARG_INFO( 0, date ) + ZEND_ARG_INFO( 0, local ) + ZEND_ARG_INFO( 1, rawOffset ) + ZEND_ARG_INFO( 1, dstOffset ) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX( arginfo_tz_has_same_rules, 0, 0, 1 ) + ZEND_ARG_OBJ_INFO( 0, timeZone, IntlTimeZone, 0 ) + ZEND_ARG_OBJ_INFO( 0, otherTimeZone, IntlTimeZone, 0 ) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX( arginfo_tz_get_display_name, 0, 0, 1 ) + ZEND_ARG_OBJ_INFO( 0, timeZone, IntlTimeZone, 0 ) + ZEND_ARG_INFO( 0, isDaylight ) + ZEND_ARG_INFO( 0, style ) + ZEND_ARG_INFO( 0, locale ) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX( arginfo_tz_only_tz, 0, 0, 1 ) + ZEND_ARG_OBJ_INFO( 0, timeZone, IntlTimeZone, 0 ) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX( arginfo_tz_void, 0, 0, 0 ) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX( ainfo_cal_create_instance, 0, 0, 0 ) + ZEND_ARG_INFO( 0, timeZone ) + ZEND_ARG_INFO( 0, locale ) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX( ainfo_cal_only_cal, 0, 0, 1 ) + ZEND_ARG_OBJ_INFO( 0, calendar, IntlCalendar, 0 ) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX( ainfo_cal_void, 0, 0, 0 ) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX( ainfo_cal_field, 0, 0, 2 ) + ZEND_ARG_OBJ_INFO( 0, calendar, IntlCalendar, 0 ) + ZEND_ARG_INFO( 0, field ) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX( ainfo_cal_dow, 0, 0, 2 ) + ZEND_ARG_OBJ_INFO( 0, calendar, IntlCalendar, 0 ) + ZEND_ARG_INFO( 0, dayOfWeek ) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX( ainfo_cal_other_cal, 0, 0, 2 ) + ZEND_ARG_OBJ_INFO( 0, calendar, IntlCalendar, 0 ) + ZEND_ARG_OBJ_INFO( 0, otherCalendar, IntlCalendar, 0 ) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX( ainfo_cal_date, 0, 0, 2 ) + ZEND_ARG_OBJ_INFO( 0, calendar, IntlCalendar, 0 ) + ZEND_ARG_INFO( 0, date ) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX( ainfo_cal_date_optional, 0, 0, 1 ) + ZEND_ARG_OBJ_INFO( 0, calendar, IntlCalendar, 0 ) + ZEND_ARG_INFO( 0, date ) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX( ainfo_cal_get_keyword_values_for_locale, 0, 0, 3) + ZEND_ARG_INFO( 0, key ) + ZEND_ARG_INFO( 0, locale ) + ZEND_ARG_INFO( 0, commonlyUsed ) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX( ainfo_cal_add, 0, 0, 3 ) + ZEND_ARG_OBJ_INFO( 0, calendar, IntlCalendar, 0 ) + ZEND_ARG_INFO( 0, field ) + ZEND_ARG_INFO( 0, amount ) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX( ainfo_cal_set_time_zone, 0, 0, 2 ) + ZEND_ARG_OBJ_INFO( 0, calendar, IntlCalendar, 0 ) + ZEND_ARG_INFO( 0, timeZone ) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX( ainfo_cal_set, 0, 0, 3 ) + ZEND_ARG_OBJ_INFO( 0, calendar, IntlCalendar, 0 ) + ZEND_ARG_INFO( 0, fieldOrYear ) + ZEND_ARG_INFO( 0, valueOrMonth ) + ZEND_ARG_INFO( 0, dayOfMonth ) + ZEND_ARG_INFO( 0, hour ) + ZEND_ARG_INFO( 0, minute ) + ZEND_ARG_INFO( 0, second ) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX( ainfo_cal_roll, 0, 0, 2 ) + ZEND_ARG_OBJ_INFO( 0, calendar, IntlCalendar, 0 ) + ZEND_ARG_INFO( 0, field ) + ZEND_ARG_INFO( 0, amountOrUpOrDown ) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX( ainfo_cal_clear, 0, 0, 1 ) + ZEND_ARG_OBJ_INFO( 0, calendar, IntlCalendar, 0 ) + ZEND_ARG_INFO( 0, field ) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX( ainfo_cal_field_difference, 0, 0, 3 ) + ZEND_ARG_OBJ_INFO( 0, calendar, IntlCalendar, 0 ) + ZEND_ARG_INFO( 0, when ) + ZEND_ARG_INFO( 0, field ) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX( ainfo_cal_get_locale, 0, 0, 2 ) + ZEND_ARG_OBJ_INFO( 0, calendar, IntlCalendar, 0 ) + ZEND_ARG_INFO( 0, localeType ) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX( ainfo_cal_set_lenient, 0, 0, 2 ) + ZEND_ARG_OBJ_INFO( 0, calendar, IntlCalendar, 0 ) + ZEND_ARG_INFO( 0, isLenient ) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(ainfo_cal_from_date_time, 0, 0, 1) + ZEND_ARG_INFO(0, dateTime) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX( ainfo_cal_wall_time_option, 0, 0, 2 ) + ZEND_ARG_OBJ_INFO( 0, calendar, IntlCalendar, 0 ) + ZEND_ARG_INFO( 0, wallTimeOption ) +ZEND_END_ARG_INFO() + +/* Gregorian Calendar */ +ZEND_BEGIN_ARG_INFO_EX( ainfo_gregcal_create_instance, 0, 0, 0 ) + ZEND_ARG_INFO(0, timeZoneOrYear) + ZEND_ARG_INFO(0, localeOrMonth) + ZEND_ARG_INFO(0, dayOfMonth) + ZEND_ARG_INFO(0, hour) + ZEND_ARG_INFO(0, minute) + ZEND_ARG_INFO(0, second) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX( ainfo_gregcal_is_leap_year, 0, 0, 2 ) + ZEND_ARG_OBJ_INFO( 0, calendar, IntlGregorianCalendar, 0 ) + ZEND_ARG_INFO( 0, year ) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX( ainfo_gregcal_only_gregcal, 0, 0, 1 ) + ZEND_ARG_OBJ_INFO( 0, calendar, IntlGregorianCalendar, 0 ) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX( ainfo_gregcal_set_gregorian_change, 0, 0, 2 ) + ZEND_ARG_OBJ_INFO( 0, calendar, IntlGregorianCalendar, 0 ) + ZEND_ARG_INFO( 0, date ) +ZEND_END_ARG_INFO() + /* }}} */ /* {{{ intl_functions @@ -484,10 +694,13 @@ zend_function_entry intl_functions[] = { PHP_FE( datefmt_get_datetype, arginfo_msgfmt_get_locale ) PHP_FE( datefmt_get_timetype, arginfo_msgfmt_get_locale ) PHP_FE( datefmt_get_calendar, arginfo_msgfmt_get_locale ) + PHP_FE( datefmt_get_calendar_object, arginfo_msgfmt_get_locale ) PHP_FE( datefmt_set_calendar, arginfo_datefmt_set_calendar ) PHP_FE( datefmt_get_locale, arginfo_msgfmt_get_locale ) PHP_FE( datefmt_get_timezone_id, arginfo_msgfmt_get_locale ) - PHP_FE( datefmt_set_timezone_id, arginfo_msgfmt_get_locale ) + PHP_FE( datefmt_set_timezone_id, arginfo_datefmt_set_timezone ) + PHP_FE( datefmt_get_timezone, arginfo_msgfmt_get_locale ) + PHP_FE( datefmt_set_timezone, arginfo_datefmt_set_timezone ) PHP_FE( datefmt_get_pattern, arginfo_msgfmt_get_locale ) PHP_FE( datefmt_set_pattern, arginfo_datefmt_set_pattern ) PHP_FE( datefmt_is_lenient, arginfo_msgfmt_get_locale ) @@ -530,6 +743,96 @@ zend_function_entry intl_functions[] = { PHP_FE( transliterator_get_error_code, arginfo_transliterator_error ) PHP_FE( transliterator_get_error_message, arginfo_transliterator_error ) + /* TimeZone functions */ + PHP_FE( intltz_create_time_zone, arginfo_tz_idarg_static ) + PHP_FE( intltz_from_date_time_zone, arginfo_tz_from_date_time_zone ) + PHP_FE( intltz_create_default, arginfo_tz_void ) + PHP_FE( intltz_get_id, arginfo_tz_only_tz ) + PHP_FE( intltz_get_gmt, arginfo_tz_void ) +#if U_ICU_VERSION_MAJOR_NUM >= 49 + PHP_FE( intltz_get_unknown, arginfo_tz_void ) +#endif + PHP_FE( intltz_create_enumeration, arginfo_tz_create_enumeration ) + PHP_FE( intltz_count_equivalent_ids, arginfo_tz_idarg_static ) +#if U_ICU_VERSION_MAJOR_NUM * 10 + U_ICU_VERSION_MINOR_NUM >= 48 + PHP_FE( intltz_create_time_zone_id_enumeration, arginfo_tz_create_time_zone_id_enumeration ) +#endif + PHP_FE( intltz_get_canonical_id, arginfo_tz_get_canonical_id ) +#if U_ICU_VERSION_MAJOR_NUM * 10 + U_ICU_VERSION_MINOR_NUM >= 48 + PHP_FE( intltz_get_region, arginfo_tz_idarg_static ) +#endif + PHP_FE( intltz_get_tz_data_version, arginfo_tz_void ) + PHP_FE( intltz_get_equivalent_id, arginfo_tz_get_equivalent_id ) + PHP_FE( intltz_use_daylight_time, arginfo_tz_only_tz ) + PHP_FE( intltz_get_offset, arginfo_tz_get_offset ) + PHP_FE( intltz_get_raw_offset, arginfo_tz_only_tz ) + PHP_FE( intltz_has_same_rules, arginfo_tz_has_same_rules ) + PHP_FE( intltz_get_display_name, arginfo_tz_get_display_name ) + PHP_FE( intltz_get_dst_savings, arginfo_tz_only_tz ) + PHP_FE( intltz_to_date_time_zone, arginfo_tz_only_tz ) + PHP_FE( intltz_get_error_code, arginfo_tz_only_tz ) + PHP_FE( intltz_get_error_message, arginfo_tz_only_tz ) + + PHP_FE( intlcal_create_instance, ainfo_cal_create_instance ) +#if U_ICU_VERSION_MAJOR_NUM * 10 + U_ICU_VERSION_MINOR_NUM >= 42 + PHP_FE( intlcal_get_keyword_values_for_locale, ainfo_cal_get_keyword_values_for_locale ) +#endif + PHP_FE( intlcal_get_now, ainfo_cal_void ) + PHP_FE( intlcal_get_available_locales, ainfo_cal_void ) + PHP_FE( intlcal_get, ainfo_cal_field ) + PHP_FE( intlcal_get_time, ainfo_cal_only_cal ) + PHP_FE( intlcal_set_time, ainfo_cal_date ) + PHP_FE( intlcal_add, ainfo_cal_add ) + PHP_FE( intlcal_set_time_zone, ainfo_cal_set_time_zone ) + PHP_FE( intlcal_after, ainfo_cal_other_cal ) + PHP_FE( intlcal_before, ainfo_cal_other_cal ) + PHP_FE( intlcal_set, ainfo_cal_set ) + PHP_FE( intlcal_roll, ainfo_cal_roll ) + PHP_FE( intlcal_clear, ainfo_cal_clear ) + PHP_FE( intlcal_field_difference, ainfo_cal_field_difference ) + PHP_FE( intlcal_get_actual_maximum, ainfo_cal_field ) + PHP_FE( intlcal_get_actual_minimum, ainfo_cal_field ) +#if U_ICU_VERSION_MAJOR_NUM * 10 + U_ICU_VERSION_MINOR_NUM >= 44 + PHP_FE( intlcal_get_day_of_week_type, ainfo_cal_dow ) +#endif + PHP_FE( intlcal_get_first_day_of_week, ainfo_cal_only_cal ) + PHP_FE( intlcal_get_greatest_minimum, ainfo_cal_field ) + PHP_FE( intlcal_get_least_maximum, ainfo_cal_field ) + PHP_FE( intlcal_get_locale, ainfo_cal_get_locale ) + PHP_FE( intlcal_get_maximum, ainfo_cal_field ) + PHP_FE( intlcal_get_minimal_days_in_first_week, ainfo_cal_only_cal ) + PHP_FE( intlcal_get_minimum, ainfo_cal_field ) + PHP_FE( intlcal_get_time_zone, ainfo_cal_only_cal ) + PHP_FE( intlcal_get_type, ainfo_cal_only_cal ) +#if U_ICU_VERSION_MAJOR_NUM * 10 + U_ICU_VERSION_MINOR_NUM >= 44 + PHP_FE( intlcal_get_weekend_transition, ainfo_cal_dow ) +#endif + PHP_FE( intlcal_in_daylight_time, ainfo_cal_only_cal ) + PHP_FE( intlcal_is_equivalent_to, ainfo_cal_other_cal ) + PHP_FE( intlcal_is_lenient, ainfo_cal_only_cal ) + PHP_FE( intlcal_is_set, ainfo_cal_field ) +#if U_ICU_VERSION_MAJOR_NUM * 10 + U_ICU_VERSION_MINOR_NUM >= 44 + PHP_FE( intlcal_is_weekend, ainfo_cal_date_optional ) +#endif + PHP_FE( intlcal_set_first_day_of_week, ainfo_cal_dow ) + PHP_FE( intlcal_set_lenient, ainfo_cal_set_lenient ) + PHP_FE( intlcal_equals, ainfo_cal_other_cal ) + PHP_FE( intlcal_from_date_time, ainfo_cal_from_date_time ) + PHP_FE( intlcal_to_date_time, ainfo_cal_only_cal ) +#if U_ICU_VERSION_MAJOR_NUM >= 49 + PHP_FE( intlcal_get_repeated_wall_time_option, ainfo_cal_only_cal ) + PHP_FE( intlcal_get_skipped_wall_time_option, ainfo_cal_only_cal ) + PHP_FE( intlcal_set_repeated_wall_time_option, ainfo_cal_wall_time_option ) + PHP_FE( intlcal_set_skipped_wall_time_option, ainfo_cal_wall_time_option ) +#endif + PHP_FE( intlcal_get_error_code, ainfo_cal_only_cal ) + PHP_FE( intlcal_get_error_message, ainfo_cal_only_cal ) + + PHP_FE( intlgregcal_create_instance, ainfo_gregcal_create_instance ) + PHP_FE( intlgregcal_set_gregorian_change, ainfo_gregcal_set_gregorian_change ) + PHP_FE( intlgregcal_get_gregorian_change, ainfo_gregcal_only_gregcal ) + PHP_FE( intlgregcal_is_leap_year, ainfo_gregcal_is_leap_year ) + /* common functions */ PHP_FE( intl_get_error_code, intl_0_args ) PHP_FE( intl_get_error_message, intl_0_args ) @@ -545,7 +848,7 @@ zend_function_entry intl_functions[] = { PHP_INI_BEGIN() STD_PHP_INI_ENTRY(LOCALE_INI_NAME, NULL, PHP_INI_ALL, OnUpdateStringUnempty, default_locale, zend_intl_globals, intl_globals) STD_PHP_INI_ENTRY("intl.error_level", "0", PHP_INI_ALL, OnUpdateLong, error_level, zend_intl_globals, intl_globals) - + STD_PHP_INI_ENTRY("intl.use_exceptions", "0", PHP_INI_ALL, OnUpdateBool, use_exceptions, zend_intl_globals, intl_globals) PHP_INI_END() /* }}} */ @@ -640,6 +943,12 @@ PHP_MINIT_FUNCTION( intl ) /* Register Transliterator constants */ transliterator_register_constants( INIT_FUNC_ARGS_PASSTHRU ); + /* Register 'IntlTimeZone' PHP class */ + timezone_register_IntlTimeZone_class( TSRMLS_C ); + + /* Register 'IntlCalendar' PHP class */ + calendar_register_IntlCalendar_class( TSRMLS_C ); + /* Expose ICU error codes to PHP scripts. */ intl_expose_icu_error_codes( INIT_FUNC_ARGS_PASSTHRU ); @@ -653,6 +962,19 @@ PHP_MINIT_FUNCTION( intl ) /* Expose Spoofchecker constants to PHP scripts */ spoofchecker_register_constants( INIT_FUNC_ARGS_PASSTHRU ); #endif + + /* Register 'IntlException' PHP class */ + intl_register_IntlException_class( TSRMLS_C ); + + /* Register 'IntlIterator' PHP class */ + intl_register_IntlIterator_class( TSRMLS_C ); + + /* Register 'BreakIterator' class */ + breakiterator_register_BreakIterator_class( TSRMLS_C ); + + /* Register 'IntlPartsIterator' class */ + breakiterator_register_IntlPartsIterator_class( TSRMLS_C ); + /* Global error handling. */ intl_error_init( NULL TSRMLS_CC ); diff --git a/ext/intl/php_intl.h b/ext/intl/php_intl.h index 4ede069e2a..7a7112317d 100755 --- a/ext/intl/php_intl.h +++ b/ext/intl/php_intl.h @@ -22,8 +22,13 @@ #include <php.h> +/* Even if we're included from C++, don't introduce C++ definitions + * because we were included with extern "C". The effect would be that + * when the headers defined any method, they would do so with C linkage */ +#undef U_SHOW_CPLUSPLUS_API +#define U_SHOW_CPLUSPLUS_API 0 #include "collator/collator_sort.h" -#include "grapheme/grapheme.h" +#include <unicode/ubrk.h> #include "intl_error.h" extern zend_module_entry intl_module_entry; @@ -46,6 +51,7 @@ ZEND_BEGIN_MODULE_GLOBALS(intl) UBreakIterator* grapheme_iterator; intl_error g_error; long error_level; + zend_bool use_exceptions; ZEND_END_MODULE_GLOBALS(intl) /* Macro to access request-wide global variables. */ @@ -63,6 +69,8 @@ PHP_RINIT_FUNCTION(intl); PHP_RSHUTDOWN_FUNCTION(intl); PHP_MINFO_FUNCTION(intl); +const char *intl_locale_get_default( TSRMLS_D ); + #define PHP_INTL_VERSION "1.1.0" #endif /* PHP_INTL_H */ diff --git a/ext/intl/resourcebundle/resourcebundle_class.c b/ext/intl/resourcebundle/resourcebundle_class.c index 1205450c4c..7f1529e519 100644 --- a/ext/intl/resourcebundle/resourcebundle_class.c +++ b/ext/intl/resourcebundle/resourcebundle_class.c @@ -78,13 +78,11 @@ static zend_object_value ResourceBundle_object_create( zend_class_entry *ce TSRM /* {{{ ResourceBundle_ctor */ static void resourcebundle_ctor(INTERNAL_FUNCTION_PARAMETERS) { - char * bundlename; - int bundlename_len = 0; - char * locale; - int locale_len = 0; - zend_bool fallback = 1; - - char * pbuf; + const char *bundlename; + int bundlename_len = 0; + const char *locale; + int locale_len = 0; + zend_bool fallback = 1; zval *object = return_value; ResourceBundle_object *rb = (ResourceBundle_object *) zend_object_store_get_object( object TSRMLS_CC); @@ -103,7 +101,7 @@ static void resourcebundle_ctor(INTERNAL_FUNCTION_PARAMETERS) INTL_CHECK_LOCALE_LEN_OBJ(locale_len, return_value); if (locale == NULL) { - locale = INTL_G(default_locale); + locale = intl_locale_get_default(TSRMLS_C); } if (fallback) { @@ -116,6 +114,7 @@ static void resourcebundle_ctor(INTERNAL_FUNCTION_PARAMETERS) if (!fallback && (INTL_DATA_ERROR_CODE(rb) == U_USING_FALLBACK_WARNING || INTL_DATA_ERROR_CODE(rb) == U_USING_DEFAULT_WARNING)) { + char *pbuf; intl_errors_set_code(NULL, INTL_DATA_ERROR_CODE(rb) TSRMLS_CC); spprintf(&pbuf, 0, "resourcebundle_ctor: Cannot load libICU resource " "'%s' without fallback from %s to %s", diff --git a/ext/intl/tests/badargs.phpt b/ext/intl/tests/badargs.phpt index 9232bbf0c1..b8f48b371e 100755 --- a/ext/intl/tests/badargs.phpt +++ b/ext/intl/tests/badargs.phpt @@ -13,7 +13,10 @@ foreach($funcs as $func) { if($rfunc->getNumberOfRequiredParameters() == 0) { continue; } - $res = $func($arg); + + try { + $res = $func($arg); + } catch (Exception $e) { continue; } if($res != false) { echo "$func: "; var_dump($res); diff --git a/ext/intl/tests/breakiter___construct.phpt b/ext/intl/tests/breakiter___construct.phpt new file mode 100644 index 0000000000..9ea6a9cf11 --- /dev/null +++ b/ext/intl/tests/breakiter___construct.phpt @@ -0,0 +1,13 @@ +--TEST-- +IntlBreakIterator::__construct() should not be callable +--SKIPIF-- +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); + +new IntlBreakIterator(); +--EXPECTF-- + +Fatal error: Call to private IntlBreakIterator::__construct() from invalid context in %s on line %d diff --git a/ext/intl/tests/breakiter___construct_error.phpt b/ext/intl/tests/breakiter___construct_error.phpt new file mode 100644 index 0000000000..770f1403c7 --- /dev/null +++ b/ext/intl/tests/breakiter___construct_error.phpt @@ -0,0 +1,38 @@ +--TEST-- +IntlRuleBasedBreakIterator::__construct(): arg errors +--SKIPIF-- +<?php if( !extension_loaded( 'intl' ) ) print 'skip'; ?> +<?php if(version_compare(INTL_ICU_VERSION, '4.8') < 0) print 'skip ICU >= 4.8 only'; ?> +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); + +//missing ; at the end: +var_dump(new IntlRuleBasedBreakIterator('[\p{Letter}\uFFFD]+;[:number:]+')); +var_dump(new IntlRuleBasedBreakIterator()); +var_dump(new IntlRuleBasedBreakIterator(1,2,3)); +var_dump(new IntlRuleBasedBreakIterator('[\p{Letter}\uFFFD]+;[:number:]+;', array())); +var_dump(new IntlRuleBasedBreakIterator('[\p{Letter}\uFFFD]+;[:number:]+;', true)); + +--EXPECTF-- + +Warning: IntlRuleBasedBreakIterator::__construct(): rbbi_create_instance: unable to create RuleBasedBreakIterator from rules (parse error on line 1, offset 31) in %s on line %d +NULL + +Warning: IntlRuleBasedBreakIterator::__construct() expects at least 1 parameter, 0 given in %s on line %d + +Warning: IntlRuleBasedBreakIterator::__construct(): rbbi_create_instance: bad arguments in %s on line %d +NULL + +Warning: IntlRuleBasedBreakIterator::__construct() expects at most 2 parameters, 3 given in %s on line %d + +Warning: IntlRuleBasedBreakIterator::__construct(): rbbi_create_instance: bad arguments in %s on line %d +NULL + +Warning: IntlRuleBasedBreakIterator::__construct() expects parameter 2 to be boolean, array given in %s on line %d + +Warning: IntlRuleBasedBreakIterator::__construct(): rbbi_create_instance: bad arguments in %s on line %d +NULL + +Warning: IntlRuleBasedBreakIterator::__construct(): rbbi_create_instance: unable to create instance from compiled rules in %s on line %d +NULL diff --git a/ext/intl/tests/breakiter_clone_basic.phpt b/ext/intl/tests/breakiter_clone_basic.phpt new file mode 100644 index 0000000000..f5bcefc6f7 --- /dev/null +++ b/ext/intl/tests/breakiter_clone_basic.phpt @@ -0,0 +1,23 @@ +--TEST-- +IntlBreakIterator: clone handler +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); + +$bi = new IntlRuleBasedBreakIterator('[\p{Letter}\uFFFD]+;[:number:]+;'); +$bi_clone = clone $bi; +var_dump(get_class($bi), get_class($bi_clone)); +var_dump($bi == $bi_clone); + +$bi->setText('foobar'); +$bi_clone = clone $bi; +var_dump(get_class($bi), get_class($bi_clone)); +var_dump($bi == $bi_clone); + +--EXPECT-- +string(26) "IntlRuleBasedBreakIterator" +string(26) "IntlRuleBasedBreakIterator" +bool(true) +string(26) "IntlRuleBasedBreakIterator" +string(26) "IntlRuleBasedBreakIterator" +bool(true) diff --git a/ext/intl/tests/breakiter_createCodePointInstance_basic.phpt b/ext/intl/tests/breakiter_createCodePointInstance_basic.phpt new file mode 100644 index 0000000000..a43e82760c --- /dev/null +++ b/ext/intl/tests/breakiter_createCodePointInstance_basic.phpt @@ -0,0 +1,43 @@ +--TEST-- +IntlBreakIterator::createCodePointInstance(): basic test +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); +ini_set("intl.default_locale", "pt_PT"); + +$text = 'ตัวà¸à¸¢à¹ˆà¸²à¸‡à¸‚้à¸à¸„วาม'; + +$codepoint_it = IntlBreakIterator::createCodePointInstance(); +var_dump(get_class($codepoint_it)); +$codepoint_it->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 0000000000..90228e128f --- /dev/null +++ b/ext/intl/tests/breakiter_createCodePointInstance_error.phpt @@ -0,0 +1,18 @@ +--TEST-- +IntlBreakIterator::createCodePointInstance(): bad arguments +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); + +var_dump(IntlBreakIterator::createCodePointInstance(array())); +--EXPECTF-- + +Warning: IntlBreakIterator::createCodePointInstance() expects exactly 0 parameters, 1 given in %s on line %d + +Warning: IntlBreakIterator::createCodePointInstance(): breakiter_create_code_point_instance: bad arguments in %s on line %d +NULL + diff --git a/ext/intl/tests/breakiter_current_basic.phpt b/ext/intl/tests/breakiter_current_basic.phpt new file mode 100644 index 0000000000..515cb555bb --- /dev/null +++ b/ext/intl/tests/breakiter_current_basic.phpt @@ -0,0 +1,24 @@ +--TEST-- +IntlBreakIterator::current(): basic test +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); +ini_set("intl.default_locale", "pt_PT"); + +$bi = IntlBreakIterator::createWordInstance('pt'); +var_dump($bi->current()); +$bi->setText('foo bar trans zoo bee'); + +var_dump($bi->first()); +var_dump($bi->current()); +var_dump($bi->next()); +var_dump($bi->current()); +?> +==DONE== +--EXPECT-- +int(0) +int(0) +int(0) +int(3) +int(3) +==DONE==
\ No newline at end of file diff --git a/ext/intl/tests/breakiter_factories_basic.phpt b/ext/intl/tests/breakiter_factories_basic.phpt new file mode 100644 index 0000000000..333023a253 --- /dev/null +++ b/ext/intl/tests/breakiter_factories_basic.phpt @@ -0,0 +1,45 @@ +--TEST-- +IntlBreakIterator factories: basic tests +--SKIPIF-- +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); +ini_set("intl.default_locale", "ja"); + +$m = array('createWordInstance', 'createLineInstance', 'createCharacterInstance', + 'createSentenceInstance', 'createTitleInstance'); + +$t = 'Frase 1... Frase 2'. + +$o1 = $o2 = null; +foreach ($m as $method) { + echo "===== $method =====\n"; + $o1 = call_user_func(array('IntlBreakIterator', $method), 'ja'); + var_dump($o1 == $o2); + $o2 = call_user_func(array('IntlBreakIterator', $method), NULL); + var_dump($o1 == $o2); + echo "\n"; +} +--EXPECT-- +===== createWordInstance ===== +bool(false) +bool(true) + +===== createLineInstance ===== +bool(false) +bool(true) + +===== createCharacterInstance ===== +bool(false) +bool(true) + +===== createSentenceInstance ===== +bool(false) +bool(true) + +===== createTitleInstance ===== +bool(false) +bool(true) + diff --git a/ext/intl/tests/breakiter_factories_error.phpt b/ext/intl/tests/breakiter_factories_error.phpt new file mode 100644 index 0000000000..6001946ad2 --- /dev/null +++ b/ext/intl/tests/breakiter_factories_error.phpt @@ -0,0 +1,39 @@ +--TEST-- +IntlBreakIterator factory methods: argument errors +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); + +var_dump(IntlBreakIterator::createWordInstance(array())); +var_dump(IntlBreakIterator::createSentenceInstance(NULL, 2)); +var_dump(IntlBreakIterator::createCharacterInstance(NULL, 2)); +var_dump(IntlBreakIterator::createTitleInstance(NULL, 2)); +var_dump(IntlBreakIterator::createLineInstance(NULL, 2)); + + +--EXPECTF-- + +Warning: IntlBreakIterator::createWordInstance() expects parameter 1 to be string, array given in %s on line %d + +Warning: IntlBreakIterator::createWordInstance(): breakiter_create_word_instance: bad arguments in %s on line %d +NULL + +Warning: IntlBreakIterator::createSentenceInstance() expects exactly 1 parameter, 2 given in %s on line %d + +Warning: IntlBreakIterator::createSentenceInstance(): breakiter_create_sentence_instance: bad arguments in %s on line %d +NULL + +Warning: IntlBreakIterator::createCharacterInstance() expects exactly 1 parameter, 2 given in %s on line %d + +Warning: IntlBreakIterator::createCharacterInstance(): breakiter_create_character_instance: bad arguments in %s on line %d +NULL + +Warning: IntlBreakIterator::createTitleInstance() expects exactly 1 parameter, 2 given in %s on line %d + +Warning: IntlBreakIterator::createTitleInstance(): breakiter_create_title_instance: bad arguments in %s on line %d +NULL + +Warning: IntlBreakIterator::createLineInstance() expects exactly 1 parameter, 2 given in %s on line %d + +Warning: IntlBreakIterator::createLineInstance(): breakiter_create_line_instance: bad arguments in %s on line %d +NULL diff --git a/ext/intl/tests/breakiter_first_basic.phpt b/ext/intl/tests/breakiter_first_basic.phpt new file mode 100644 index 0000000000..c8427adc6c --- /dev/null +++ b/ext/intl/tests/breakiter_first_basic.phpt @@ -0,0 +1,21 @@ +--TEST-- +IntlBreakIterator::first(): basic test +--SKIPIF-- +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); + +$bi = IntlBreakIterator::createWordInstance('pt'); +$bi->setText('foo bar trans'); + +var_dump($bi->current()); +var_dump($bi->next()); +var_dump($bi->first()); +var_dump($bi->current()); +--EXPECT-- +int(0) +int(3) +int(0) +int(0) diff --git a/ext/intl/tests/breakiter_first_last_previous_current_error.phpt b/ext/intl/tests/breakiter_first_last_previous_current_error.phpt new file mode 100644 index 0000000000..9865cdec58 --- /dev/null +++ b/ext/intl/tests/breakiter_first_last_previous_current_error.phpt @@ -0,0 +1,35 @@ +--TEST-- +IntlBreakIterator::first()/last()/previous()/current(): arg errors +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); + +$bi = new IntlRuleBasedBreakIterator('[\p{Letter}\uFFFD]+;[:number:]+;'); +$bi->setText("\x80sdfé\x90d888 dfsa9"); + +var_dump($bi->first(1)); +var_dump($bi->last(1)); +var_dump($bi->previous(1)); +var_dump($bi->current(1)); + +--EXPECTF-- + +Warning: IntlBreakIterator::first() expects exactly 0 parameters, 1 given in %s on line %d + +Warning: IntlBreakIterator::first(): breakiter_first: bad arguments in %s on line %d +bool(false) + +Warning: IntlBreakIterator::last() expects exactly 0 parameters, 1 given in %s on line %d + +Warning: IntlBreakIterator::last(): breakiter_last: bad arguments in %s on line %d +bool(false) + +Warning: IntlBreakIterator::previous() expects exactly 0 parameters, 1 given in %s on line %d + +Warning: IntlBreakIterator::previous(): breakiter_previous: bad arguments in %s on line %d +bool(false) + +Warning: IntlBreakIterator::current() expects exactly 0 parameters, 1 given in %s on line %d + +Warning: IntlBreakIterator::current(): breakiter_current: bad arguments in %s on line %d +bool(false) diff --git a/ext/intl/tests/breakiter_following_basic.phpt b/ext/intl/tests/breakiter_following_basic.phpt new file mode 100644 index 0000000000..967ccafb62 --- /dev/null +++ b/ext/intl/tests/breakiter_following_basic.phpt @@ -0,0 +1,20 @@ +--TEST-- +IntlBreakIterator::following(): basic test +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); +ini_set("intl.default_locale", "pt_PT"); + +$bi = IntlBreakIterator::createWordInstance('pt'); +$bi->setText('foo bar trans zoo bee'); + +var_dump($bi->following(5)); +var_dump($bi->following(50)); +var_dump($bi->following(-1)); +?> +==DONE== +--EXPECT-- +int(7) +int(-1) +int(0) +==DONE==
\ No newline at end of file diff --git a/ext/intl/tests/breakiter_following_preceding_isBoundary_error.phpt b/ext/intl/tests/breakiter_following_preceding_isBoundary_error.phpt new file mode 100644 index 0000000000..a4b60857ab --- /dev/null +++ b/ext/intl/tests/breakiter_following_preceding_isBoundary_error.phpt @@ -0,0 +1,47 @@ +--TEST-- +IntlBreakIterator::following()/preceding()/isBoundary(): arg errors +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); + +$bi = new IntlRuleBasedBreakIterator('[\p{Letter}\uFFFD]+;[:number:]+;'); +$bi->setText("\x80sdfé\x90d888 dfsa9"); + +var_dump($bi->following(1, 2)); +var_dump($bi->following(array())); +var_dump($bi->preceding(1, 2)); +var_dump($bi->preceding(array())); +var_dump($bi->isBoundary(1, 2)); +var_dump($bi->isBoundary(array())); + +--EXPECTF-- + +Warning: IntlBreakIterator::following() expects exactly 1 parameter, 2 given in %s on line %d + +Warning: IntlBreakIterator::following(): breakiter_following: bad arguments in %s on line %d +bool(false) + +Warning: IntlBreakIterator::following() expects parameter 1 to be long, array given in %s on line %d + +Warning: IntlBreakIterator::following(): breakiter_following: bad arguments in %s on line %d +bool(false) + +Warning: IntlBreakIterator::preceding() expects exactly 1 parameter, 2 given in %s on line %d + +Warning: IntlBreakIterator::preceding(): breakiter_preceding: bad arguments in %s on line %d +bool(false) + +Warning: IntlBreakIterator::preceding() expects parameter 1 to be long, array given in %s on line %d + +Warning: IntlBreakIterator::preceding(): breakiter_preceding: bad arguments in %s on line %d +bool(false) + +Warning: IntlBreakIterator::isBoundary() expects exactly 1 parameter, 2 given in %s on line %d + +Warning: IntlBreakIterator::isBoundary(): breakiter_is_boundary: bad arguments in %s on line %d +bool(false) + +Warning: IntlBreakIterator::isBoundary() expects parameter 1 to be long, array given in %s on line %d + +Warning: IntlBreakIterator::isBoundary(): breakiter_is_boundary: bad arguments in %s on line %d +bool(false) diff --git a/ext/intl/tests/breakiter_getLocale_basic.phpt b/ext/intl/tests/breakiter_getLocale_basic.phpt new file mode 100644 index 0000000000..499316c169 --- /dev/null +++ b/ext/intl/tests/breakiter_getLocale_basic.phpt @@ -0,0 +1,17 @@ +--TEST-- +IntlBreakIterator::getLocale(): basic test +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); +ini_set("intl.default_locale", "pt_PT"); + +$bi = IntlBreakIterator::createSentenceInstance('pt'); + +var_dump($bi->getLocale(0)); +var_dump($bi->getLocale(1)); +?> +==DONE== +--EXPECT-- +string(4) "root" +string(4) "root" +==DONE==
\ No newline at end of file diff --git a/ext/intl/tests/breakiter_getLocale_error.phpt b/ext/intl/tests/breakiter_getLocale_error.phpt new file mode 100644 index 0000000000..1dec56db08 --- /dev/null +++ b/ext/intl/tests/breakiter_getLocale_error.phpt @@ -0,0 +1,29 @@ +--TEST-- +IntlBreakIterator::getLocale(): arg errors +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); + +$bi = new IntlRuleBasedBreakIterator('[\p{Letter}\uFFFD]+;[:number:]+;'); +$bi->setText("\x80sdfé\x90d888 dfsa9"); + +var_dump($bi->getLocale(1, 2)); +var_dump($bi->getLocale(array())); +var_dump($bi->getLocale()); + +--EXPECTF-- + +Warning: IntlBreakIterator::getLocale() expects exactly 1 parameter, 2 given in %s on line %d + +Warning: IntlBreakIterator::getLocale(): breakiter_get_locale: bad arguments in %s on line %d +bool(false) + +Warning: IntlBreakIterator::getLocale() expects parameter 1 to be long, array given in %s on line %d + +Warning: IntlBreakIterator::getLocale(): breakiter_get_locale: bad arguments in %s on line %d +bool(false) + +Warning: IntlBreakIterator::getLocale() expects exactly 1 parameter, 0 given in %s on line %d + +Warning: IntlBreakIterator::getLocale(): breakiter_get_locale: bad arguments in %s on line %d +bool(false) diff --git a/ext/intl/tests/breakiter_getPartsIterator_basic.phpt b/ext/intl/tests/breakiter_getPartsIterator_basic.phpt new file mode 100644 index 0000000000..794bab3014 --- /dev/null +++ b/ext/intl/tests/breakiter_getPartsIterator_basic.phpt @@ -0,0 +1,33 @@ +--TEST-- +IntlBreakIterator::getPartsIterator(): basic test +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); +ini_set("intl.default_locale", "pt_PT"); + +$bi = IntlBreakIterator::createWordInstance('pt'); +$pi = $bi->getPartsIterator(); +var_dump(get_class($pi)); +print_r(iterator_to_array($pi)); + +$bi->setText("foo bar"); +$pi = $bi->getPartsIterator(); +var_dump(get_class($pi->getBreakIterator())); +print_r(iterator_to_array($pi)); +var_dump($pi->getRuleStatus()); +?> +==DONE== +--EXPECT-- +string(17) "IntlPartsIterator" +Array +( +) +string(26) "IntlRuleBasedBreakIterator" +Array +( + [0] => foo + [1] => + [2] => bar +) +int(0) +==DONE==
\ No newline at end of file diff --git a/ext/intl/tests/breakiter_getPartsIterator_error.phpt b/ext/intl/tests/breakiter_getPartsIterator_error.phpt new file mode 100644 index 0000000000..9737618033 --- /dev/null +++ b/ext/intl/tests/breakiter_getPartsIterator_error.phpt @@ -0,0 +1,33 @@ +--TEST-- +IntlBreakIterator::getPartsIterator(): bad args +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); +ini_set("intl.default_locale", "pt_PT"); + +$it = IntlBreakIterator::createWordInstance(NULL); +var_dump($it->getPartsIterator(array())); +var_dump($it->getPartsIterator(1, 2)); +var_dump($it->getPartsIterator(-1)); + +?> +==DONE== +--EXPECTF-- + +Warning: IntlBreakIterator::getPartsIterator() expects parameter 1 to be long, array given in %s on line %d + +Warning: IntlBreakIterator::getPartsIterator(): breakiter_get_parts_iterator: bad arguments in %s on line %d +bool(false) + +Warning: IntlBreakIterator::getPartsIterator() expects at most 1 parameter, 2 given in %s on line %d + +Warning: IntlBreakIterator::getPartsIterator(): breakiter_get_parts_iterator: bad arguments in %s on line %d +bool(false) + +Warning: IntlBreakIterator::getPartsIterator(): breakiter_get_parts_iterator: bad key type in %s on line %d +bool(false) +==DONE== diff --git a/ext/intl/tests/breakiter_getPartsIterator_var1.phpt b/ext/intl/tests/breakiter_getPartsIterator_var1.phpt new file mode 100644 index 0000000000..7bbd27ea45 --- /dev/null +++ b/ext/intl/tests/breakiter_getPartsIterator_var1.phpt @@ -0,0 +1,60 @@ +--TEST-- +IntlBreakIterator::getPartsIterator(): argument variations +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); +ini_set("intl.default_locale", "pt_PT"); + +$text = 'foo bar tao'; + +$it = IntlBreakIterator::createWordInstance(NULL); +$it->setText($text); + +var_dump(iterator_to_array($it->getPartsIterator(IntlPartsIterator::KEY_SEQUENTIAL))); +var_dump(iterator_to_array($it->getPartsIterator(IntlPartsIterator::KEY_LEFT))); +var_dump(iterator_to_array($it->getPartsIterator(IntlPartsIterator::KEY_RIGHT))); + +?> +==DONE== +--EXPECT-- +array(5) { + [0]=> + string(3) "foo" + [1]=> + string(1) " " + [2]=> + string(3) "bar" + [3]=> + string(1) " " + [4]=> + string(3) "tao" +} +array(5) { + [0]=> + string(3) "foo" + [4]=> + string(1) " " + [5]=> + string(3) "bar" + [8]=> + string(1) " " + [9]=> + string(3) "tao" +} +array(5) { + [3]=> + string(3) "foo" + [5]=> + string(1) " " + [8]=> + string(3) "bar" + [9]=> + string(1) " " + [12]=> + string(3) "tao" +} +==DONE== diff --git a/ext/intl/tests/breakiter_getText_basic.phpt b/ext/intl/tests/breakiter_getText_basic.phpt new file mode 100644 index 0000000000..57f3e32aa3 --- /dev/null +++ b/ext/intl/tests/breakiter_getText_basic.phpt @@ -0,0 +1,16 @@ +--TEST-- +IntlBreakIterator::getText(): basic test +--SKIPIF-- +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); + +$bi = IntlBreakIterator::createWordInstance('pt'); +var_dump($bi->getText()); +$bi->setText('foo bar'); +var_dump($bi->getText()); +--EXPECTF-- +NULL +string(7) "foo bar" diff --git a/ext/intl/tests/breakiter_getText_error.phpt b/ext/intl/tests/breakiter_getText_error.phpt new file mode 100644 index 0000000000..f222002374 --- /dev/null +++ b/ext/intl/tests/breakiter_getText_error.phpt @@ -0,0 +1,15 @@ +--TEST-- +IntlBreakIterator::getText(): arg errors +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); + +$bi = new IntlRuleBasedBreakIterator('[\p{Letter}]+;'); +var_dump($bi->getText(array())); + +--EXPECTF-- + +Warning: IntlBreakIterator::getText() expects exactly 0 parameters, 1 given in %s on line %d + +Warning: IntlBreakIterator::getText(): breakiter_get_text: bad arguments in %s on line %d +bool(false) diff --git a/ext/intl/tests/breakiter_isBoundary_basic.phpt b/ext/intl/tests/breakiter_isBoundary_basic.phpt new file mode 100644 index 0000000000..87d8227352 --- /dev/null +++ b/ext/intl/tests/breakiter_isBoundary_basic.phpt @@ -0,0 +1,24 @@ +--TEST-- +IntlBreakIterator::isBoundary(): basic test +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); +ini_set("intl.default_locale", "pt_PT"); + +$bi = IntlBreakIterator::createWordInstance('pt'); +$bi->setText('foo bar trans zoo bee'); + +var_dump($bi->isBoundary(0)); +var_dump($bi->isBoundary(7)); +var_dump($bi->isBoundary(-1)); +var_dump($bi->isBoundary(1)); +var_dump($bi->isBoundary(50)); +?> +==DONE== +--EXPECT-- +bool(true) +bool(true) +bool(false) +bool(false) +bool(false) +==DONE==
\ No newline at end of file diff --git a/ext/intl/tests/breakiter_last_basic.phpt b/ext/intl/tests/breakiter_last_basic.phpt new file mode 100644 index 0000000000..0d3aead232 --- /dev/null +++ b/ext/intl/tests/breakiter_last_basic.phpt @@ -0,0 +1,19 @@ +--TEST-- +IntlBreakIterator::last(): basic test +--SKIPIF-- +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); + +$bi = IntlBreakIterator::createWordInstance('pt'); +$bi->setText('foo bar trans'); + +var_dump($bi->current()); +var_dump($bi->last()); +var_dump($bi->current()); +--EXPECTF-- +int(0) +int(13) +int(13) diff --git a/ext/intl/tests/breakiter_next_basic.phpt b/ext/intl/tests/breakiter_next_basic.phpt new file mode 100644 index 0000000000..3d535443b8 --- /dev/null +++ b/ext/intl/tests/breakiter_next_basic.phpt @@ -0,0 +1,26 @@ +--TEST-- +IntlBreakIterator::next(): basic test +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); +ini_set("intl.default_locale", "pt_PT"); + +$bi = IntlBreakIterator::createWordInstance('pt'); +$bi->setText('foo bar trans zoo bee'); + +var_dump($bi->first()); +var_dump($bi->next()); +var_dump($bi->next(2)); +var_dump($bi->next(-1)); +var_dump($bi->next(0)); +var_dump($bi->next(NULL)); +?> +==DONE== +--EXPECT-- +int(0) +int(3) +int(7) +int(4) +int(4) +int(7) +==DONE== diff --git a/ext/intl/tests/breakiter_next_error.phpt b/ext/intl/tests/breakiter_next_error.phpt new file mode 100644 index 0000000000..40d8f5813b --- /dev/null +++ b/ext/intl/tests/breakiter_next_error.phpt @@ -0,0 +1,23 @@ +--TEST-- +IntlBreakIterator::next(): arg errors +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); + +$bi = new IntlRuleBasedBreakIterator('[\p{Letter}\uFFFD]+;[:number:]+;'); +$bi->setText("\x80sdfé\x90d888 dfsa9"); + +var_dump($bi->next(1, 2)); +var_dump($bi->next(array())); + +--EXPECTF-- + +Warning: IntlBreakIterator::next() expects exactly 1 parameter, 2 given in %s on line %d + +Warning: IntlBreakIterator::next(): breakiter_next: bad arguments in %s on line %d +bool(false) + +Warning: IntlBreakIterator::next() expects parameter 1 to be long, array given in %s on line %d + +Warning: IntlBreakIterator::next(): breakiter_next: bad arguments in %s on line %d +bool(false) diff --git a/ext/intl/tests/breakiter_preceding_basic.phpt b/ext/intl/tests/breakiter_preceding_basic.phpt new file mode 100644 index 0000000000..60695209cc --- /dev/null +++ b/ext/intl/tests/breakiter_preceding_basic.phpt @@ -0,0 +1,20 @@ +--TEST-- +IntlBreakIterator::preceding(): basic test +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); +ini_set("intl.default_locale", "pt_PT"); + +$bi = IntlBreakIterator::createWordInstance('pt'); +$bi->setText('foo bar trans zoo bee'); + +var_dump($bi->preceding(5)); +var_dump($bi->preceding(50)); +var_dump($bi->preceding(-1)); +?> +==DONE== +--EXPECT-- +int(4) +int(21) +int(0) +==DONE==
\ No newline at end of file diff --git a/ext/intl/tests/breakiter_previous_basic.phpt b/ext/intl/tests/breakiter_previous_basic.phpt new file mode 100644 index 0000000000..6d4f3bce5f --- /dev/null +++ b/ext/intl/tests/breakiter_previous_basic.phpt @@ -0,0 +1,18 @@ +--TEST-- +IntlBreakIterator::previous(): basic test +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); +ini_set("intl.default_locale", "pt_PT"); + +$bi = IntlBreakIterator::createWordInstance('pt'); +$bi->setText('foo bar trans'); + +var_dump($bi->last()); +var_dump($bi->previous()); +?> +==DONE== +--EXPECT-- +int(13) +int(8) +==DONE==
\ No newline at end of file diff --git a/ext/intl/tests/breakiter_setText_basic.phpt b/ext/intl/tests/breakiter_setText_basic.phpt new file mode 100644 index 0000000000..7b3fa2a6e5 --- /dev/null +++ b/ext/intl/tests/breakiter_setText_basic.phpt @@ -0,0 +1,35 @@ +--TEST-- +IntlBreakIterator::setText(): basic test +--SKIPIF-- +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); + +class A { +function __tostring() { return 'aaa'; } +} + +$bi = IntlBreakIterator::createWordInstance('pt'); +var_dump($bi->setText('foo bar')); +var_dump($bi->getText()); +var_dump($bi->setText(1)); +var_dump($bi->getText()); +var_dump($bi->setText(new A)); +var_dump($bi->getText()); + +/* setText resets the pointer */ +var_dump($bi->next()); +var_dump($bi->setText('foo bar')); +var_dump($bi->current()); +--EXPECT-- +bool(true) +string(7) "foo bar" +bool(true) +string(1) "1" +bool(true) +string(3) "aaa" +int(3) +bool(true) +int(0) diff --git a/ext/intl/tests/breakiter_setText_error.phpt b/ext/intl/tests/breakiter_setText_error.phpt new file mode 100644 index 0000000000..bfcda8ddaa --- /dev/null +++ b/ext/intl/tests/breakiter_setText_error.phpt @@ -0,0 +1,40 @@ +--TEST-- +IntlBreakIterator::setText(): arg errors +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); + +$bi = new IntlRuleBasedBreakIterator('[\p{Letter}]+;'); +var_dump($bi->setText()); +var_dump($bi->setText(array())); +var_dump($bi->setText(1,2)); + +class A { +function __destruct() { var_dump('destructed'); throw new Exception('e'); } +function __tostring() { return 'foo'; } +} + +try { +var_dump($bi->setText(new A)); +} catch (Exception $e) { +var_dump($e->getMessage()); +} + +--EXPECTF-- + +Warning: IntlBreakIterator::setText() expects exactly 1 parameter, 0 given in %s on line %d + +Warning: IntlBreakIterator::setText(): breakiter_set_text: bad arguments in %s on line %d +bool(false) + +Warning: IntlBreakIterator::setText() expects parameter 1 to be string, array given in %s on line %d + +Warning: IntlBreakIterator::setText(): breakiter_set_text: bad arguments in %s on line %d +bool(false) + +Warning: IntlBreakIterator::setText() expects exactly 1 parameter, 2 given in %s on line %d + +Warning: IntlBreakIterator::setText(): breakiter_set_text: bad arguments in %s on line %d +bool(false) +string(10) "destructed" +string(1) "e" diff --git a/ext/intl/tests/bug50590.phpt b/ext/intl/tests/bug50590.phpt index c39c333b23..4784d37877 100644 --- a/ext/intl/tests/bug50590.phpt +++ b/ext/intl/tests/bug50590.phpt @@ -1,5 +1,7 @@ --TEST-- Bug #50590 (IntlDateFormatter::parse result is limited to the integer range) +--INI-- +date.timezone=Atlantic/Azores --SKIPIF-- <?php if( !extension_loaded( 'intl' ) ) print 'skip'; ?> --FILE-- diff --git a/ext/intl/tests/bug58756_MessageFormatter.phpt b/ext/intl/tests/bug58756_MessageFormatter.phpt new file mode 100644 index 0000000000..bbe96b7045 --- /dev/null +++ b/ext/intl/tests/bug58756_MessageFormatter.phpt @@ -0,0 +1,34 @@ +--TEST-- +Bug #58756: w.r.t MessageFormatter +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); +//ini_set("intl.default_locale", "nl"); + +$time = 1247013673; + +ini_set('date.timezone', 'America/New_York'); + +$msgf = new MessageFormatter('en_US', '{0,date,full} {0,time,h:m:s a V}'); + +echo "date: " . date('l, F j, Y g:i:s A T', $time) . "\n"; +echo "msgf: " . $msgf->format(array($time)) . "\n"; + +//NOT FIXED: +/*$msgf = new MessageFormatter('en_US', +'{1, select, date {{0,date,full}} other {{0,time,h:m:s a V}}}'); + +echo "msgf2: ", $msgf->format(array($time, 'date')), " ", + $msgf->format(array($time, 'time')), "\n"; +*/ + +?> +==DONE== +--EXPECT-- +date: Tuesday, July 7, 2009 8:41:13 PM EDT +msgf: Tuesday, July 7, 2009 8:41:13 PM EDT +==DONE==
\ No newline at end of file diff --git a/ext/intl/tests/bug62017.phpt b/ext/intl/tests/bug62017.phpt index 13c4fe5df0..50aeae4806 100644 --- a/ext/intl/tests/bug62017.phpt +++ b/ext/intl/tests/bug62017.phpt @@ -14,7 +14,7 @@ var_dump( new IntlDateFormatter('', IntlDateFormatter::NONE, IntlDateFormatter::NONE, "Europe/Lisbon", IntlDateFormatter::GREGORIAN, "\x80")); --EXPECTF-- -Warning: datefmt_create(): datefmt_create: error converting timezone_str to UTF-16 in %s on line %d +Warning: datefmt_create(): datefmt_create: Time zone identifier given is not a valid UTF-8 string in %s on line %d NULL Warning: IntlDateFormatter::__construct(): datefmt_create: error converting pattern to UTF-16 in %s on line %d diff --git a/ext/intl/tests/bug62081.phpt b/ext/intl/tests/bug62081.phpt index 7d9e2cec47..44ad4beec7 100644 --- a/ext/intl/tests/bug62081.phpt +++ b/ext/intl/tests/bug62081.phpt @@ -1,5 +1,7 @@ --TEST-- Bug #62081: IntlDateFormatter leaks memory if called twice +--INI-- +date.timezone=Atlantic/Azores --SKIPIF-- <?php if (!extension_loaded('intl')) @@ -7,8 +9,8 @@ if (!extension_loaded('intl')) --FILE-- <?php ini_set('intl.error_level', E_WARNING); -$x = new IntlDateFormatter(1,1,1,1,1); -var_dump($x->__construct(1,1,1,1,1)); +$x = new IntlDateFormatter('en', 1, 1); +var_dump($x->__construct('en', 1, 1)); --EXPECTF-- Warning: IntlDateFormatter::__construct(): datefmt_create: cannot call constructor twice in %s on line %d NULL diff --git a/ext/intl/tests/calendar_add_basic.phpt b/ext/intl/tests/calendar_add_basic.phpt new file mode 100644 index 0000000000..b0e44d5895 --- /dev/null +++ b/ext/intl/tests/calendar_add_basic.phpt @@ -0,0 +1,33 @@ +--TEST-- +IntlCalendar::add() basic test +--INI-- +date.timezone=Atlantic/Azores +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); +ini_set("intl.default_locale", "nl"); + +$time = strtotime('2012-02-29 00:00:00 +0000'); +$time2 = strtotime('2012-03-01 05:06:07 +0000'); + +$intlcal = IntlCalendar::createInstance('UTC'); +$intlcal->setTime($time * 1000); +$intlcal->add(IntlCalendar::FIELD_DAY_OF_MONTH, 1); +$intlcal->add(IntlCalendar::FIELD_HOUR, 5); +$intlcal->add(IntlCalendar::FIELD_MINUTE, 6); +intlcal_add($intlcal, IntlCalendar::FIELD_SECOND, 7); + +var_dump( + (float)$time2*1000, + $intlcal->getTime()); + +?> +==DONE== +--EXPECT-- +float(1330578367000) +float(1330578367000) +==DONE==
\ No newline at end of file diff --git a/ext/intl/tests/calendar_add_error.phpt b/ext/intl/tests/calendar_add_error.phpt new file mode 100644 index 0000000000..2e5fadb4ec --- /dev/null +++ b/ext/intl/tests/calendar_add_error.phpt @@ -0,0 +1,41 @@ +--TEST-- +IntlCalendar::add(): bad arguments +--INI-- +date.timezone=Atlantic/Azores +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); + +$c = new IntlGregorianCalendar(NULL, 'pt_PT'); + +var_dump($c->add(1, 2, 3)); +var_dump($c->add(-1, 2)); +var_dump($c->add(1)); + +var_dump(intlcal_add($c, 1, 2, 3)); +var_dump(intlcal_add(1, 2, 3)); +--EXPECTF-- + +Warning: IntlCalendar::add() expects exactly 2 parameters, 3 given in %s on line %d + +Warning: IntlCalendar::add(): intlcal_add: bad arguments in %s on line %d +bool(false) + +Warning: IntlCalendar::add(): intlcal_add: invalid field in %s on line %d +bool(false) + +Warning: IntlCalendar::add() expects exactly 2 parameters, 1 given in %s on line %d + +Warning: IntlCalendar::add(): intlcal_add: bad arguments in %s on line %d +bool(false) + +Warning: intlcal_add() expects exactly 3 parameters, 4 given in %s on line %d + +Warning: intlcal_add(): intlcal_add: bad arguments in %s on line %d +bool(false) + +Catchable fatal error: Argument 1 passed to intlcal_add() must be an instance of IntlCalendar, integer given in %s on line %d diff --git a/ext/intl/tests/calendar_before_after_error.phpt b/ext/intl/tests/calendar_before_after_error.phpt new file mode 100644 index 0000000000..10011ef852 --- /dev/null +++ b/ext/intl/tests/calendar_before_after_error.phpt @@ -0,0 +1,57 @@ +--TEST-- +IntlCalendar::before()/after(): bad arguments +--INI-- +date.timezone=Atlantic/Azores +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); + +$c = new IntlGregorianCalendar(NULL, 'pt_PT'); + +function eh($errno, $errstr) { +echo "error: $errno, $errstr\n"; +} +set_error_handler('eh'); + +var_dump($c->after()); +var_dump($c->before()); + +var_dump($c->after(1)); +var_dump($c->before(1)); + +var_dump($c->after($c, 1)); +var_dump($c->before($c, 1)); + +var_dump(intlcal_after($c)); +var_dump(intlcal_before($c)); +--EXPECT-- +error: 2, IntlCalendar::after() expects exactly 1 parameter, 0 given +error: 2, IntlCalendar::after(): intlcal_before/after: bad arguments +bool(false) +error: 2, IntlCalendar::before() expects exactly 1 parameter, 0 given +error: 2, IntlCalendar::before(): intlcal_before/after: bad arguments +bool(false) +error: 4096, Argument 1 passed to IntlCalendar::after() must be an instance of IntlCalendar, integer given +error: 2, IntlCalendar::after() expects parameter 1 to be IntlCalendar, integer given +error: 2, IntlCalendar::after(): intlcal_before/after: bad arguments +bool(false) +error: 4096, Argument 1 passed to IntlCalendar::before() must be an instance of IntlCalendar, integer given +error: 2, IntlCalendar::before() expects parameter 1 to be IntlCalendar, integer given +error: 2, IntlCalendar::before(): intlcal_before/after: bad arguments +bool(false) +error: 2, IntlCalendar::after() expects exactly 1 parameter, 2 given +error: 2, IntlCalendar::after(): intlcal_before/after: bad arguments +bool(false) +error: 2, IntlCalendar::before() expects exactly 1 parameter, 2 given +error: 2, IntlCalendar::before(): intlcal_before/after: bad arguments +bool(false) +error: 2, intlcal_after() expects exactly 2 parameters, 1 given +error: 2, intlcal_after(): intlcal_before/after: bad arguments +bool(false) +error: 2, intlcal_before() expects exactly 2 parameters, 1 given +error: 2, intlcal_before(): intlcal_before/after: bad arguments +bool(false) diff --git a/ext/intl/tests/calendar_clear_basic.phpt b/ext/intl/tests/calendar_clear_basic.phpt new file mode 100644 index 0000000000..f7e4371d92 --- /dev/null +++ b/ext/intl/tests/calendar_clear_basic.phpt @@ -0,0 +1,40 @@ +--TEST-- +IntlCalendar::clear() basic test +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); +ini_set("intl.default_locale", "nl"); + +$intlcal = IntlCalendar::createInstance('UTC'); +var_dump($intlcal->clear()); +var_dump( + $intlcal->get(IntlCalendar::FIELD_YEAR), + $intlcal->get(IntlCalendar::FIELD_MONTH), + $intlcal->get(IntlCalendar::FIELD_DAY_OF_MONTH), + $intlcal->get(IntlCalendar::FIELD_HOUR), + $intlcal->get(IntlCalendar::FIELD_MINUTE), + $intlcal->get(IntlCalendar::FIELD_SECOND), + $intlcal->get(IntlCalendar::FIELD_MILLISECOND) +); + +$intlcal2 = IntlCalendar::createInstance('Europe/Amsterdam'); +intlcal_clear($intlcal2, null); +var_dump($intlcal2->getTime()); + +?> +==DONE== +--EXPECT-- +bool(true) +int(1970) +int(0) +int(1) +int(0) +int(0) +int(0) +int(0) +float(-3600000) +==DONE==
\ No newline at end of file diff --git a/ext/intl/tests/calendar_clear_error.phpt b/ext/intl/tests/calendar_clear_error.phpt new file mode 100644 index 0000000000..9bde7e2c8d --- /dev/null +++ b/ext/intl/tests/calendar_clear_error.phpt @@ -0,0 +1,31 @@ +--TEST-- +IntlCalendar::clear(): bad arguments +--INI-- +date.timezone=Atlantic/Azores +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); + +$c = new IntlGregorianCalendar(NULL, 'pt_PT'); + +var_dump($c->clear(1, 2)); +var_dump($c->clear(-1)); + +var_dump(intlcal_clear($c, -1)); +var_dump(intlcal_clear(1, 2)); +--EXPECTF-- + +Warning: IntlCalendar::clear(): intlcal_clear: too many arguments in %s on line %d +bool(false) + +Warning: IntlCalendar::clear(): intlcal_clear: invalid field in %s on line %d +bool(false) + +Warning: intlcal_clear(): intlcal_clear: invalid field in %s on line %d +bool(false) + +Catchable fatal error: Argument 1 passed to intlcal_clear() must be an instance of IntlCalendar, integer given in %s on line %d diff --git a/ext/intl/tests/calendar_clear_variation1.phpt b/ext/intl/tests/calendar_clear_variation1.phpt new file mode 100644 index 0000000000..6adbcaa353 --- /dev/null +++ b/ext/intl/tests/calendar_clear_variation1.phpt @@ -0,0 +1,33 @@ +--TEST-- +IntlCalendar::clear() 1 arg variation +--INI-- +date.timezone=Atlantic/Azores +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); +ini_set("intl.default_locale", "nl"); + +$intlcal = IntlCalendar::createInstance('UTC'); +$intlcal->setTime(strtotime('2012-02-29 05:06:07 +0000') * 1000); +//print_R($intlcal); +var_dump($intlcal->isSet(IntlCalendar::FIELD_MONTH)); +var_dump($intlcal->clear(IntlCalendar::FIELD_MONTH)); +var_dump($intlcal->isSet(IntlCalendar::FIELD_MONTH)); +//print_R($intlcal); +var_dump( + $intlcal->getTime(), + strtotime('2012-01-29 05:06:07 +0000') * 1000. +); +?> +==DONE== +--EXPECT-- +bool(true) +bool(true) +bool(false) +float(1327813567000) +float(1327813567000) +==DONE==
\ No newline at end of file diff --git a/ext/intl/tests/calendar_createInstance_basic.phpt b/ext/intl/tests/calendar_createInstance_basic.phpt new file mode 100644 index 0000000000..e062030fec --- /dev/null +++ b/ext/intl/tests/calendar_createInstance_basic.phpt @@ -0,0 +1,42 @@ +--TEST-- +IntlCalendar::createInstance() basic test +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +if (version_compare(INTL_ICU_VERSION, '4.8') < 0) + die('skip for ICU 4.8+'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); +ini_set("intl.default_locale", "nl"); + +date_default_timezone_set('Europe/Amsterdam'); + +$cal = IntlCalendar::createInstance(); +print_R($cal->getTimeZone()); +print_R($cal->getLocale(Locale::ACTUAL_LOCALE)); +echo "\n"; +print_R($cal->getType()); +echo "\n"; + +$timeMillis = $cal->getTime(); +$time = time(); + +var_dump(abs($timeMillis - $time * 1000) < 1000); + +?> +==DONE== + +--EXPECTF-- +IntlTimeZone Object +( + [valid] => 1 + [id] => Europe/Amsterdam + [rawOffset] => 3600000 + [currentOffset] => %d +) +nl +gregorian +bool(true) +==DONE== diff --git a/ext/intl/tests/calendar_createInstance_error.phpt b/ext/intl/tests/calendar_createInstance_error.phpt new file mode 100644 index 0000000000..bf655bee79 --- /dev/null +++ b/ext/intl/tests/calendar_createInstance_error.phpt @@ -0,0 +1,38 @@ +--TEST-- +IntlCalendar::createInstance: bad arguments +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); + +class X extends IntlTimeZone { +function __construct() {} +} + +var_dump(IntlCalendar::createInstance(1, 2, 3)); +var_dump(intlcal_create_instance(1, 2, 3)); +var_dump(intlcal_create_instance(new X, NULL)); +var_dump(intlcal_create_instance(NULL, array())); + +--EXPECTF-- + +Warning: IntlCalendar::createInstance() expects at most 2 parameters, 3 given in %s on line %d + +Warning: IntlCalendar::createInstance(): intlcal_create_calendar: bad arguments in %s on line %d +NULL + +Warning: intlcal_create_instance() expects at most 2 parameters, 3 given in %s on line %d + +Warning: intlcal_create_instance(): intlcal_create_calendar: bad arguments in %s on line %d +NULL + +Warning: intlcal_create_instance(): intlcal_create_instance: passed IntlTimeZone is not properly constructed in %s on line %d +NULL + +Warning: intlcal_create_instance() expects parameter 2 to be string, array given in %s on line %d + +Warning: intlcal_create_instance(): intlcal_create_calendar: bad arguments in %s on line %d +NULL diff --git a/ext/intl/tests/calendar_createInstance_variation1.phpt b/ext/intl/tests/calendar_createInstance_variation1.phpt new file mode 100644 index 0000000000..138f2a2afd --- /dev/null +++ b/ext/intl/tests/calendar_createInstance_variation1.phpt @@ -0,0 +1,84 @@ +--TEST-- +IntlCalendar::createInstance() argument variations +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +if (version_compare(INTL_ICU_VERSION, '4.8') < 0) + die('skip for ICU 4.8+'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); +ini_set("intl.default_locale", "nl"); + +date_default_timezone_set('Europe/Amsterdam'); + +$cal = intlcal_create_instance('Europe/Amsterdam'); +print_R($cal->getTimeZone()); +print_R($cal->getLocale(Locale::ACTUAL_LOCALE)); +echo "\n"; + +$cal = intlcal_create_instance('Europe/Lisbon', null); +print_R($cal->getTimeZone()); +print_R($cal->getLocale(Locale::ACTUAL_LOCALE)); +echo "\n"; + +$cal = intlcal_create_instance(IntlTimeZone::createTimeZone('Europe/Lisbon')); +print_R($cal->getTimeZone()); +print_R($cal->getLocale(Locale::ACTUAL_LOCALE)); +echo "\n"; + +$cal = intlcal_create_instance(null, "pt"); +print_R($cal->getTimeZone()); +print_R($cal->getLocale(Locale::ACTUAL_LOCALE)); +echo "\n"; + +$cal = intlcal_create_instance("Europe/Lisbon", "pt"); +print_R($cal->getTimeZone()); +print_R($cal->getLocale(Locale::ACTUAL_LOCALE)); +echo "\n"; + +?> +==DONE== +--EXPECTF-- +IntlTimeZone Object +( + [valid] => 1 + [id] => Europe/Amsterdam + [rawOffset] => 3600000 + [currentOffset] => %d +) +nl +IntlTimeZone Object +( + [valid] => 1 + [id] => Europe/Lisbon + [rawOffset] => 0 + [currentOffset] => %d +) +nl +IntlTimeZone Object +( + [valid] => 1 + [id] => Europe/Lisbon + [rawOffset] => 0 + [currentOffset] => %d +) +nl +IntlTimeZone Object +( + [valid] => 1 + [id] => Europe/Amsterdam + [rawOffset] => 3600000 + [currentOffset] => %d +) +pt +IntlTimeZone Object +( + [valid] => 1 + [id] => Europe/Lisbon + [rawOffset] => 0 + [currentOffset] => %d +) +pt +==DONE==
\ No newline at end of file diff --git a/ext/intl/tests/calendar_equals_before_after_basic.phpt b/ext/intl/tests/calendar_equals_before_after_basic.phpt new file mode 100644 index 0000000000..50543ad0b4 --- /dev/null +++ b/ext/intl/tests/calendar_equals_before_after_basic.phpt @@ -0,0 +1,59 @@ +--TEST-- +IntlCalendar::equals(), ::before() and ::after() basic test +--INI-- +date.timezone=Atlantic/Azores +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); +ini_set("intl.default_locale", "nl"); + +$intlcal1 = new IntlGregorianCalendar(2012, 1, 29, 16, 59, 59); +$intlcal2 = IntlCalendar::createInstance(null, '@calendar=japanese'); +$intlcal3 = new IntlGregorianCalendar(2012, 1, 29, 17, 00, 00); +$intlcal2->setTime($intlcal1->getTime()); + +var_dump($intlcal2->getType()); + +var_dump("1 eq 1", $intlcal1->equals($intlcal1)); + +var_dump("1 eq 2", $intlcal1->equals($intlcal2)); +var_dump("1 before 2", $intlcal1->before($intlcal2)); +var_dump("1 after 2", $intlcal1->after($intlcal2)); + +var_dump("1 eq 3", $intlcal1->equals($intlcal3)); +var_dump("1 before 3", $intlcal1->before($intlcal3)); +var_dump("1 after 3", $intlcal1->after($intlcal3)); + +var_dump("3 eq 2", intlcal_equals($intlcal3, $intlcal2)); +var_dump("3 before 2", intlcal_before($intlcal3, $intlcal2)); +var_dump("3 after 2", intlcal_after($intlcal3, $intlcal2)); + +?> +==DONE== +--EXPECT-- +string(8) "japanese" +string(6) "1 eq 1" +bool(true) +string(6) "1 eq 2" +bool(true) +string(10) "1 before 2" +bool(false) +string(9) "1 after 2" +bool(false) +string(6) "1 eq 3" +bool(false) +string(10) "1 before 3" +bool(true) +string(9) "1 after 3" +bool(false) +string(6) "3 eq 2" +bool(false) +string(10) "3 before 2" +bool(false) +string(9) "3 after 2" +bool(true) +==DONE==
\ No newline at end of file diff --git a/ext/intl/tests/calendar_equals_error.phpt b/ext/intl/tests/calendar_equals_error.phpt new file mode 100644 index 0000000000..a947b42bfe --- /dev/null +++ b/ext/intl/tests/calendar_equals_error.phpt @@ -0,0 +1,46 @@ +--TEST-- +IntlCalendar::equals(): bad arguments +--INI-- +date.timezone=Atlantic/Azores +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); + +$c = new IntlGregorianCalendar(NULL, 'pt_PT'); + +function eh($errno, $errstr) { +echo "error: $errno, $errstr\n"; +} +set_error_handler('eh'); + +var_dump($c->equals()); +var_dump($c->equals(new stdclass)); +var_dump($c->equals(1, 2)); + +var_dump(intlcal_equals($c, array())); +var_dump(intlcal_equals(1, $c)); + +--EXPECT-- +error: 2, IntlCalendar::equals() expects exactly 1 parameter, 0 given +error: 2, IntlCalendar::equals(): intlcal_equals: bad arguments +bool(false) +error: 4096, Argument 1 passed to IntlCalendar::equals() must be an instance of IntlCalendar, instance of stdClass given +error: 2, IntlCalendar::equals() expects parameter 1 to be IntlCalendar, object given +error: 2, IntlCalendar::equals(): intlcal_equals: bad arguments +bool(false) +error: 4096, Argument 1 passed to IntlCalendar::equals() must be an instance of IntlCalendar, integer given +error: 2, IntlCalendar::equals() expects exactly 1 parameter, 2 given +error: 2, IntlCalendar::equals(): intlcal_equals: bad arguments +bool(false) +error: 4096, Argument 2 passed to intlcal_equals() must be an instance of IntlCalendar, array given +error: 2, intlcal_equals() expects parameter 2 to be IntlCalendar, array given +error: 2, intlcal_equals(): intlcal_equals: bad arguments +bool(false) +error: 4096, Argument 1 passed to intlcal_equals() must be an instance of IntlCalendar, integer given +error: 2, intlcal_equals() expects parameter 1 to be IntlCalendar, integer given +error: 2, intlcal_equals(): intlcal_equals: bad arguments +bool(false) diff --git a/ext/intl/tests/calendar_fieldDifference_basic.phpt b/ext/intl/tests/calendar_fieldDifference_basic.phpt new file mode 100644 index 0000000000..3432420df4 --- /dev/null +++ b/ext/intl/tests/calendar_fieldDifference_basic.phpt @@ -0,0 +1,35 @@ +--TEST-- +IntlCalendar::fieldDifference() basic test +--INI-- +date.timezone=Atlantic/Azores +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); +ini_set("intl.default_locale", "nl"); + +$intlcal = IntlCalendar::createInstance('UTC'); +$intlcal->setTime(strtotime('2012-02-29 05:06:07 +0000') * 1000); +var_dump( + $intlcal->fieldDifference( + strtotime('2012-02-29 06:06:08 +0000') * 1000, + IntlCalendar::FIELD_SECOND), + $intlcal->get(IntlCalendar::FIELD_HOUR_OF_DAY)); + + +$intlcal->setTime(strtotime('2012-02-29 05:06:07 +0000') * 1000); +var_dump( + intlcal_field_difference( + $intlcal, + strtotime('2012-02-29 06:07:08 +0000') * 1000, + IntlCalendar::FIELD_MINUTE)); +?> +==DONE== +--EXPECT-- +int(3601) +int(6) +int(61) +==DONE==
\ No newline at end of file diff --git a/ext/intl/tests/calendar_fieldDifference_error.phpt b/ext/intl/tests/calendar_fieldDifference_error.phpt new file mode 100644 index 0000000000..ef7e4fc8dc --- /dev/null +++ b/ext/intl/tests/calendar_fieldDifference_error.phpt @@ -0,0 +1,42 @@ +--TEST-- +IntlCalendar::fieldDifference(): bad arguments +--INI-- +date.timezone=Atlantic/Azores +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); + +$c = new IntlGregorianCalendar(NULL, 'pt_PT'); + +var_dump($c->fieldDifference($c, 2, 3)); +var_dump($c->fieldDifference(INF, 2)); +var_dump($c->fieldDifference(1)); + +var_dump(intlcal_field_difference($c, 0, 1, 2)); +var_dump(intlcal_field_difference(1, 0, 1)); + +--EXPECTF-- + +Warning: IntlCalendar::fieldDifference() expects exactly 2 parameters, 3 given in %s on line %d + +Warning: IntlCalendar::fieldDifference(): intlcal_field_difference: bad arguments in %s on line %d +bool(false) + +Warning: IntlCalendar::fieldDifference(): intlcal_field_difference: Call to ICU method has failed in %s on line %d +bool(false) + +Warning: IntlCalendar::fieldDifference() expects exactly 2 parameters, 1 given in %s on line %d + +Warning: IntlCalendar::fieldDifference(): intlcal_field_difference: bad arguments in %s on line %d +bool(false) + +Warning: intlcal_field_difference() expects exactly 3 parameters, 4 given in %s on line %d + +Warning: intlcal_field_difference(): intlcal_field_difference: bad arguments in %s on line %d +bool(false) + +Catchable fatal error: Argument 1 passed to intlcal_field_difference() must be an instance of IntlCalendar, integer given in %s on line %d diff --git a/ext/intl/tests/calendar_fromDateTime_basic.phpt b/ext/intl/tests/calendar_fromDateTime_basic.phpt new file mode 100644 index 0000000000..1863b7815c --- /dev/null +++ b/ext/intl/tests/calendar_fromDateTime_basic.phpt @@ -0,0 +1,52 @@ +--TEST-- +IntlCalendar::fromDateTime(): basic test +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); +ini_set("intl.default_locale", "nl_NL"); +date_default_timezone_set('Europe/Lisbon'); + +$cal = IntlCalendar::fromDateTime('2012-01-01 00:00:00 Europe/Rome'); +var_dump( + $cal->getTime(), + strtotime('2012-01-01 00:00:00 Europe/Rome') * 1000., + $cal->getTimeZone()->getID(), + $cal->getLocale(1) +); +echo "\n"; + +$cal = IntlCalendar::fromDateTime(new DateTime('2012-01-01 00:00:00 PST'), "pt_PT"); +var_dump( + $cal->getTime(), + strtotime('2012-01-01 00:00:00 PST') * 1000., + $cal->getTimeZone()->getID(), + $cal->getLocale(1) +); + +echo "\n"; + +$cal = intlcal_from_date_time(new DateTime('2012-01-01 00:00:00 +03:40')); +var_dump( + $cal->getTime(), + strtotime('2012-01-01 00:00:00 +03:40') * 1000., + $cal->getTimeZone()->getID() +); + +--EXPECTF-- +float(1325372400000) +float(1325372400000) +string(11) "Europe/Rome" +string(5) "nl_NL" + +float(1325404800000) +float(1325404800000) +string(3) "PST" +string(5) "pt_PT" + +float(1325362800000) +float(1325362800000) +string(%d) "GMT+03%S40" diff --git a/ext/intl/tests/calendar_fromDateTime_error.phpt b/ext/intl/tests/calendar_fromDateTime_error.phpt new file mode 100644 index 0000000000..2fbf7196f9 --- /dev/null +++ b/ext/intl/tests/calendar_fromDateTime_error.phpt @@ -0,0 +1,59 @@ +--TEST-- +IntlCalendar::fromDateTime(): errors +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); +ini_set("intl.default_locale", "nl"); +date_default_timezone_set('Europe/Lisbon'); + +var_dump(IntlCalendar::fromDateTime()); +var_dump(IntlCalendar::fromDateTime(0,1,2)); + +try { +IntlCalendar::fromDateTime("foobar"); +} catch (Exception $e) { + echo "threw exception, OK"; +} +class A extends DateTime { +function __construct() {} +} + +var_dump(IntlCalendar::fromDateTime(new A)); + +$date = new DateTime('2012-01-01 00:00:00 +24:00'); +var_dump(IntlCalendar::fromDateTime($date)); + +$date = new DateTime('2012-01-01 00:00:00 WEST'); +var_dump(IntlCalendar::fromDateTime($date)); + +var_dump(intlcal_from_date_time()); + +--EXPECTF-- + +Warning: IntlCalendar::fromDateTime() expects at least 1 parameter, 0 given in %s on line %d + +Warning: IntlCalendar::fromDateTime(): intlcal_from_date_time: bad arguments in %s on line %d +NULL + +Warning: IntlCalendar::fromDateTime() expects at most 2 parameters, 3 given in %s on line %d + +Warning: IntlCalendar::fromDateTime(): intlcal_from_date_time: bad arguments in %s on line %d +NULL +threw exception, OK +Warning: IntlCalendar::fromDateTime(): intlcal_from_date_time: DateTime object is unconstructed in %s on line %d +NULL + +Warning: IntlCalendar::fromDateTime(): intlcal_from_date_time: object has an time zone offset that's too large in %s on line %d +NULL + +Warning: IntlCalendar::fromDateTime(): intlcal_from_date_time: time zone id 'WEST' extracted from ext/date DateTimeZone not recognized in %s on line %d +NULL + +Warning: intlcal_from_date_time() expects at least 1 parameter, 0 given in %s on line %d + +Warning: intlcal_from_date_time(): intlcal_from_date_time: bad arguments in %s on line %d +NULL diff --git a/ext/intl/tests/calendar_getAvailableLocales_basic.phpt b/ext/intl/tests/calendar_getAvailableLocales_basic.phpt new file mode 100644 index 0000000000..5d5b79c020 --- /dev/null +++ b/ext/intl/tests/calendar_getAvailableLocales_basic.phpt @@ -0,0 +1,23 @@ +--TEST-- +IntlCalendar::getAvailableLocales() basic test +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); +ini_set("intl.default_locale", "nl"); + +$locales = IntlCalendar::getAvailableLocales(); +var_dump(count($locales) > 100); + +$locales = intlcal_get_available_locales(); +var_dump(in_array('pt', $locales)); + +?> +==DONE== +--EXPECT-- +bool(true) +bool(true) +==DONE==
\ No newline at end of file diff --git a/ext/intl/tests/calendar_getAvailableLocales_error.phpt b/ext/intl/tests/calendar_getAvailableLocales_error.phpt new file mode 100644 index 0000000000..e9edc468e5 --- /dev/null +++ b/ext/intl/tests/calendar_getAvailableLocales_error.phpt @@ -0,0 +1,24 @@ +--TEST-- +IntlCalendar::getAvailableLocales(): bad arguments +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); + +var_dump(intlcal_get_available_locales(1)); +var_dump(IntlCalendar::getAvailableLocales(2)); + +--EXPECTF-- + +Warning: intlcal_get_available_locales() expects exactly 0 parameters, 1 given in %s on line %d + +Warning: intlcal_get_available_locales(): intlcal_get_available_locales: bad arguments in %s on line %d +bool(false) + +Warning: IntlCalendar::getAvailableLocales() expects exactly 0 parameters, 1 given in %s on line %d + +Warning: IntlCalendar::getAvailableLocales(): intlcal_get_available_locales: bad arguments in %s on line %d +bool(false) diff --git a/ext/intl/tests/calendar_getDayOfWeekType_basic.phpt b/ext/intl/tests/calendar_getDayOfWeekType_basic.phpt new file mode 100644 index 0000000000..d5319f1471 --- /dev/null +++ b/ext/intl/tests/calendar_getDayOfWeekType_basic.phpt @@ -0,0 +1,34 @@ +--TEST-- +IntlCalendar::getDayOfWeekType() basic test +--INI-- +date.timezone=Atlantic/Azores +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +if (version_compare(INTL_ICU_VERSION, '4.4') < 0) + die('skip for ICU 4.4+'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); +ini_set("intl.default_locale", "nl"); + +$intlcal = IntlCalendar::createInstance('UTC'); +$intlcal->setTime(strtotime('2012-02-29 00:00:00 +0000') * 1000); +var_dump( + intlcal_get_day_of_week_type($intlcal, IntlCalendar::DOW_SUNDAY), + $intlcal->getDayOfWeekType(IntlCalendar::DOW_MONDAY), + $intlcal->getDayOfWeekType(IntlCalendar::DOW_TUESDAY), + $intlcal->getDayOfWeekType(IntlCalendar::DOW_FRIDAY), + $intlcal->getDayOfWeekType(IntlCalendar::DOW_SATURDAY) +); + +?> +==DONE== +--EXPECT-- +int(3) +int(0) +int(0) +int(0) +int(1) +==DONE==
\ No newline at end of file diff --git a/ext/intl/tests/calendar_getDayOfWeekType_error.phpt b/ext/intl/tests/calendar_getDayOfWeekType_error.phpt new file mode 100644 index 0000000000..3926655615 --- /dev/null +++ b/ext/intl/tests/calendar_getDayOfWeekType_error.phpt @@ -0,0 +1,44 @@ +--TEST-- +IntlCalendar::getDayOfWeekOfType(): bad arguments +--INI-- +date.timezone=Atlantic/Azores +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +if (version_compare(INTL_ICU_VERSION, '4.4') < 0) + die('skip for ICU 4.4+'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); + +$c = new IntlGregorianCalendar(NULL, 'pt_PT'); + +var_dump($c->getDayOfWeekType(1, 2)); +var_dump($c->getDayOfWeekType(0)); +var_dump($c->getDayOfWeekType()); + +var_dump(intlcal_get_day_of_week_type($c, "foo")); +var_dump(intlcal_get_day_of_week_type(1, 1)); + +--EXPECTF-- + +Warning: IntlCalendar::getDayOfWeekType() expects exactly 1 parameter, 2 given in %s on line %d + +Warning: IntlCalendar::getDayOfWeekType(): intlcal_get_day_of_week_type: bad arguments in %s on line %d +bool(false) + +Warning: IntlCalendar::getDayOfWeekType(): intlcal_get_day_of_week_type: invalid day of week in %s on line %d +bool(false) + +Warning: IntlCalendar::getDayOfWeekType() expects exactly 1 parameter, 0 given in %s on line %d + +Warning: IntlCalendar::getDayOfWeekType(): intlcal_get_day_of_week_type: bad arguments in %s on line %d +bool(false) + +Warning: intlcal_get_day_of_week_type() expects parameter 2 to be long, string given in %s on line %d + +Warning: intlcal_get_day_of_week_type(): intlcal_get_day_of_week_type: bad arguments in %s on line %d +bool(false) + +Catchable fatal error: Argument 1 passed to intlcal_get_day_of_week_type() must be an instance of IntlCalendar, integer given in %s on line %d diff --git a/ext/intl/tests/calendar_getErrorCode_error.phpt b/ext/intl/tests/calendar_getErrorCode_error.phpt new file mode 100644 index 0000000000..13aab81923 --- /dev/null +++ b/ext/intl/tests/calendar_getErrorCode_error.phpt @@ -0,0 +1,26 @@ +--TEST-- +IntlCalendar::getErrorCode(): bad arguments +--INI-- +date.timezone=Atlantic/Azores +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); + +$c = new IntlGregorianCalendar(NULL, 'pt_PT'); + +var_dump($c->getErrorCode(array())); + +var_dump(intlcal_get_error_code(null)); + +--EXPECTF-- + +Warning: IntlCalendar::getErrorCode() expects exactly 0 parameters, 1 given in %s on line %d + +Warning: IntlCalendar::getErrorCode(): intlcal_get_error_code: bad arguments in %s on line %d +bool(false) + +Catchable fatal error: Argument 1 passed to intlcal_get_error_code() must be an instance of IntlCalendar, null given in %s on line %d diff --git a/ext/intl/tests/calendar_getErrorCode_getErrorMessage_basic.phpt b/ext/intl/tests/calendar_getErrorCode_getErrorMessage_basic.phpt new file mode 100644 index 0000000000..71c053492f --- /dev/null +++ b/ext/intl/tests/calendar_getErrorCode_getErrorMessage_basic.phpt @@ -0,0 +1,43 @@ +--TEST-- +IntlCalendar::getErrorCode(), ::getErrorMessage() basic test +--INI-- +date.timezone=Atlantic/Azores +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); +ini_set("intl.default_locale", "nl"); + +$intlcal = new IntlGregorianCalendar(2012, 1, 29); +var_dump( + $intlcal->getErrorCode(), + intlcal_get_error_code($intlcal), + $intlcal->getErrorMessage(), + intlcal_get_error_message($intlcal) +); +$intlcal->add(IntlCalendar::FIELD_SECOND, 2147483647); +$intlcal->fieldDifference(-PHP_INT_MAX, IntlCalendar::FIELD_SECOND); + +var_dump( + $intlcal->getErrorCode(), + intlcal_get_error_code($intlcal), + $intlcal->getErrorMessage(), + intlcal_get_error_message($intlcal) +); +?> +==DONE== +--EXPECTF-- +int(0) +int(0) +string(12) "U_ZERO_ERROR" +string(12) "U_ZERO_ERROR" + +Warning: IntlCalendar::fieldDifference(): intlcal_field_difference: Call to ICU method has failed in %s on line %d +int(1) +int(1) +string(81) "intlcal_field_difference: Call to ICU method has failed: U_ILLEGAL_ARGUMENT_ERROR" +string(81) "intlcal_field_difference: Call to ICU method has failed: U_ILLEGAL_ARGUMENT_ERROR" +==DONE== diff --git a/ext/intl/tests/calendar_getErrorMessage_error.phpt b/ext/intl/tests/calendar_getErrorMessage_error.phpt new file mode 100644 index 0000000000..6081833904 --- /dev/null +++ b/ext/intl/tests/calendar_getErrorMessage_error.phpt @@ -0,0 +1,26 @@ +--TEST-- +IntlCalendar::getErrorMessage(): bad arguments +--INI-- +date.timezone=Atlantic/Azores +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); + +$c = new IntlGregorianCalendar(NULL, 'pt_PT'); + +var_dump($c->getErrorMessage(array())); + +var_dump(intlcal_get_error_message(null)); + +--EXPECTF-- + +Warning: IntlCalendar::getErrorMessage() expects exactly 0 parameters, 1 given in %s on line %d + +Warning: IntlCalendar::getErrorMessage(): intlcal_get_error_message: bad arguments in %s on line %d +bool(false) + +Catchable fatal error: Argument 1 passed to intlcal_get_error_message() must be an instance of IntlCalendar, null given in %s on line %d diff --git a/ext/intl/tests/calendar_getFirstDayOfWeek_basic.phpt b/ext/intl/tests/calendar_getFirstDayOfWeek_basic.phpt new file mode 100644 index 0000000000..82a0bc85cc --- /dev/null +++ b/ext/intl/tests/calendar_getFirstDayOfWeek_basic.phpt @@ -0,0 +1,20 @@ +--TEST-- +IntlCalendar::getFirstDayOfWeek() basic test +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); +ini_set("intl.default_locale", "nl"); + +$intlcal = IntlCalendar::createInstance('UTC'); +var_dump($intlcal->getFirstDayOfWeek()); +var_dump(intlcal_get_first_day_of_week($intlcal)); +?> +==DONE== +--EXPECT-- +int(2) +int(2) +==DONE==
\ No newline at end of file diff --git a/ext/intl/tests/calendar_getFirstDayOfWeek_error.phpt b/ext/intl/tests/calendar_getFirstDayOfWeek_error.phpt new file mode 100644 index 0000000000..e13b5138a7 --- /dev/null +++ b/ext/intl/tests/calendar_getFirstDayOfWeek_error.phpt @@ -0,0 +1,32 @@ +--TEST-- +IntlCalendar::getFirstDayOfWeek(): bad arguments +--INI-- +date.timezone=Atlantic/Azores +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); + +$c = new IntlGregorianCalendar(NULL, 'pt_PT'); + +var_dump($c->getFirstDayOfWeek(1)); + +var_dump(intlcal_get_first_day_of_week($c, 1)); +var_dump(intlcal_get_first_day_of_week(1)); + +--EXPECTF-- + +Warning: IntlCalendar::getFirstDayOfWeek() expects exactly 0 parameters, 1 given in %s on line %d + +Warning: IntlCalendar::getFirstDayOfWeek(): intlcal_get_first_day_of_week: bad arguments in %s on line %d +bool(false) + +Warning: intlcal_get_first_day_of_week() expects exactly 1 parameter, 2 given in %s on line %d + +Warning: intlcal_get_first_day_of_week(): intlcal_get_first_day_of_week: bad arguments in %s on line %d +bool(false) + +Catchable fatal error: Argument 1 passed to intlcal_get_first_day_of_week() must be an instance of IntlCalendar, integer given in %s on line %d diff --git a/ext/intl/tests/calendar_getKeywordValuesForLocale_basic.phpt b/ext/intl/tests/calendar_getKeywordValuesForLocale_basic.phpt new file mode 100644 index 0000000000..dedfcea8fe --- /dev/null +++ b/ext/intl/tests/calendar_getKeywordValuesForLocale_basic.phpt @@ -0,0 +1,36 @@ +--TEST-- +IntlCalendar::getKeywordValuesForLocale() basic test +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +if (version_compare(INTL_ICU_VERSION, '4.2') < 0) + die('skip for ICU 4.2+'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); +ini_set("intl.default_locale", "nl"); + +print_r( +iterator_to_array( +IntlCalendar::getKeywordValuesForLocale('calendar', 'pt', true) +)); +echo "\n"; + +$var = iterator_to_array( +intlcal_get_keyword_values_for_locale('calendar', 'pt', false) +); +var_dump(count($var) > 8); +var_dump(in_array('japanese', $var)); + +?> +==DONE== +--EXPECT-- +Array +( + [0] => gregorian +) + +bool(true) +bool(true) +==DONE==
\ No newline at end of file diff --git a/ext/intl/tests/calendar_getKeywordValuesForLocale_error.phpt b/ext/intl/tests/calendar_getKeywordValuesForLocale_error.phpt new file mode 100644 index 0000000000..2aa8002bd1 --- /dev/null +++ b/ext/intl/tests/calendar_getKeywordValuesForLocale_error.phpt @@ -0,0 +1,26 @@ +--TEST-- +IntlCalendar::getKeywordValuesForLocale(): bad arguments +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +if (version_compare(INTL_ICU_VERSION, '4.2') < 0) + die('skip for ICU 4.2+'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); + +var_dump(intlcal_get_keyword_values_for_locale(1, 2)); +var_dump(IntlCalendar::getKeywordValuesForLocale(1, 2, array())); + +--EXPECTF-- + +Warning: intlcal_get_keyword_values_for_locale() expects exactly 3 parameters, 2 given in %s on line %d + +Warning: intlcal_get_keyword_values_for_locale(): intlcal_get_keyword_values_for_locale: bad arguments in %s on line %d +bool(false) + +Warning: IntlCalendar::getKeywordValuesForLocale() expects parameter 3 to be boolean, array given in %s on line %d + +Warning: IntlCalendar::getKeywordValuesForLocale(): intlcal_get_keyword_values_for_locale: bad arguments in %s on line %d +bool(false) diff --git a/ext/intl/tests/calendar_getLocale_basic.phpt b/ext/intl/tests/calendar_getLocale_basic.phpt new file mode 100644 index 0000000000..63f846f9a8 --- /dev/null +++ b/ext/intl/tests/calendar_getLocale_basic.phpt @@ -0,0 +1,22 @@ +--TEST-- +IntlCalendar::getLocale() basic test +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +if (version_compare(INTL_ICU_VERSION, '4.8') < 0) + die('skip for ICU 4.8+'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); +ini_set("intl.default_locale", "nl"); + +$intlcal = IntlCalendar::createInstance('UTC'); +var_dump($intlcal->getLocale(Locale::ACTUAL_LOCALE)); +var_dump(intlcal_get_locale($intlcal, Locale::VALID_LOCALE)); +?> +==DONE== +--EXPECT-- +string(2) "nl" +string(5) "nl_NL" +==DONE==
\ No newline at end of file diff --git a/ext/intl/tests/calendar_getLocale_error.phpt b/ext/intl/tests/calendar_getLocale_error.phpt new file mode 100644 index 0000000000..42970a9e7f --- /dev/null +++ b/ext/intl/tests/calendar_getLocale_error.phpt @@ -0,0 +1,42 @@ +--TEST-- +IntlCalendar::getLocale(): bad arguments +--INI-- +date.timezone=Atlantic/Azores +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); + +$c = new IntlGregorianCalendar(NULL, 'pt_PT'); + +var_dump($c->getLocale()); +var_dump($c->getLocale(2)); +var_dump($c->getLocale(2, 3)); + +var_dump(intlcal_get_locale($c)); +var_dump(intlcal_get_locale(1)); + +--EXPECTF-- + +Warning: IntlCalendar::getLocale() expects exactly 1 parameter, 0 given in %s on line %d + +Warning: IntlCalendar::getLocale(): intlcal_get_locale: bad arguments in %s on line %d +bool(false) + +Warning: IntlCalendar::getLocale(): intlcal_get_locale: invalid locale type in %s on line %d +bool(false) + +Warning: IntlCalendar::getLocale() expects exactly 1 parameter, 2 given in %s on line %d + +Warning: IntlCalendar::getLocale(): intlcal_get_locale: bad arguments in %s on line %d +bool(false) + +Warning: intlcal_get_locale() expects exactly 2 parameters, 1 given in %s on line %d + +Warning: intlcal_get_locale(): intlcal_get_locale: bad arguments in %s on line %d +bool(false) + +Catchable fatal error: Argument 1 passed to intlcal_get_locale() must be an instance of IntlCalendar, integer given in %s on line %d diff --git a/ext/intl/tests/calendar_getMinimalDaysInFirstWeek_basic.phpt b/ext/intl/tests/calendar_getMinimalDaysInFirstWeek_basic.phpt new file mode 100644 index 0000000000..eeaa3104a8 --- /dev/null +++ b/ext/intl/tests/calendar_getMinimalDaysInFirstWeek_basic.phpt @@ -0,0 +1,22 @@ +--TEST-- +IntlCalendar::getMinimalDaysInFirstWeek() basic test +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +if (version_compare(INTL_ICU_VERSION, '4.8') < 0) + die('skip for ICU 4.8+'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); +ini_set("intl.default_locale", "nl"); + +$intlcal = IntlCalendar::createInstance('UTC'); +var_dump($intlcal->getMinimalDaysInFirstWeek()); +var_dump(intlcal_get_minimal_days_in_first_week($intlcal)); +?> +==DONE== +--EXPECT-- +int(4) +int(4) +==DONE==
\ No newline at end of file diff --git a/ext/intl/tests/calendar_getMinimalDaysInFirstWeek_error.phpt b/ext/intl/tests/calendar_getMinimalDaysInFirstWeek_error.phpt new file mode 100644 index 0000000000..8e1971dc2b --- /dev/null +++ b/ext/intl/tests/calendar_getMinimalDaysInFirstWeek_error.phpt @@ -0,0 +1,32 @@ +--TEST-- +IntlCalendar::getMinimalDaysInFirstWeek(): bad arguments +--INI-- +date.timezone=Atlantic/Azores +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); + +$c = new IntlGregorianCalendar(NULL, 'pt_PT'); + +var_dump($c->getMinimalDaysInFirstWeek(1)); + +var_dump(intlcal_get_minimal_days_in_first_week($c, 1)); +var_dump(intlcal_get_minimal_days_in_first_week(1)); + +--EXPECTF-- + +Warning: IntlCalendar::getMinimalDaysInFirstWeek() expects exactly 0 parameters, 1 given in %s on line %d + +Warning: IntlCalendar::getMinimalDaysInFirstWeek(): intlcal_get_minimal_days_in_first_week: bad arguments in %s on line %d +bool(false) + +Warning: intlcal_get_minimal_days_in_first_week() expects exactly 1 parameter, 2 given in %s on line %d + +Warning: intlcal_get_minimal_days_in_first_week(): intlcal_get_minimal_days_in_first_week: bad arguments in %s on line %d +bool(false) + +Catchable fatal error: Argument 1 passed to intlcal_get_minimal_days_in_first_week() must be an instance of IntlCalendar, integer given in %s on line %d diff --git a/ext/intl/tests/calendar_getNow_basic.phpt b/ext/intl/tests/calendar_getNow_basic.phpt new file mode 100644 index 0000000000..18325dfa60 --- /dev/null +++ b/ext/intl/tests/calendar_getNow_basic.phpt @@ -0,0 +1,23 @@ +--TEST-- +IntlCalendar::getNow() basic test +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); +ini_set("intl.default_locale", "nl"); + +$now = IntlCalendar::getNow(); +$proc_now = intlcal_get_now(); +$time = time(); +var_dump(abs($now - $proc_now) < 500); +var_dump(abs($time * 1000 - $proc_now) < 1000); + +?> +==DONE== +--EXPECT-- +bool(true) +bool(true) +==DONE==
\ No newline at end of file diff --git a/ext/intl/tests/calendar_getNow_error.phpt b/ext/intl/tests/calendar_getNow_error.phpt new file mode 100644 index 0000000000..31991bb591 --- /dev/null +++ b/ext/intl/tests/calendar_getNow_error.phpt @@ -0,0 +1,24 @@ +--TEST-- +IntlCalendar::getNow(): bad arguments +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); + +var_dump(intlcal_get_now(1)); +var_dump(IntlCalendar::getNow(2)); + +--EXPECTF-- + +Warning: intlcal_get_now() expects exactly 0 parameters, 1 given in %s on line %d + +Warning: intlcal_get_now(): intlcal_get_now: bad arguments in %s on line %d +bool(false) + +Warning: IntlCalendar::getNow() expects exactly 0 parameters, 1 given in %s on line %d + +Warning: IntlCalendar::getNow(): intlcal_get_now: bad arguments in %s on line %d +bool(false) diff --git a/ext/intl/tests/calendar_getSkipped_RepeatedWallTimeOption_error.phpt b/ext/intl/tests/calendar_getSkipped_RepeatedWallTimeOption_error.phpt new file mode 100644 index 0000000000..e07135586c --- /dev/null +++ b/ext/intl/tests/calendar_getSkipped_RepeatedWallTimeOption_error.phpt @@ -0,0 +1,47 @@ +--TEST-- +IntlCalendar::getSkipped/RepeatedWallTimeOption(): bad arguments +--INI-- +date.timezone=Atlantic/Azores +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +if (version_compare(INTL_ICU_VERSION, '49') < 0) + die('skip for ICU 49+'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); + +$c = new IntlGregorianCalendar(NULL, 'pt_PT'); + +var_dump($c->getSkippedWallTimeOption(1)); +var_dump($c->getRepeatedWallTimeOption(1)); + +var_dump(intlcal_get_skipped_wall_time_option($c, 1)); +var_dump(intlcal_get_repeated_wall_time_option($c, 1)); + +var_dump(intlcal_get_skipped_wall_time_option(1)); + +--EXPECTF-- + +Warning: IntlCalendar::getSkippedWallTimeOption() expects exactly 0 parameters, 1 given in %s on line %d + +Warning: IntlCalendar::getSkippedWallTimeOption(): intlcal_get_skipped_wall_time_option: bad arguments in %s on line %d +bool(false) + +Warning: IntlCalendar::getRepeatedWallTimeOption() expects exactly 0 parameters, 1 given in %s on line %d + +Warning: IntlCalendar::getRepeatedWallTimeOption(): intlcal_get_repeated_wall_time_option: bad arguments in %s on line %d +bool(false) + +Warning: intlcal_get_skipped_wall_time_option() expects exactly 1 parameter, 2 given in %s on line %d + +Warning: intlcal_get_skipped_wall_time_option(): intlcal_get_skipped_wall_time_option: bad arguments in %s on line %d +bool(false) + +Warning: intlcal_get_repeated_wall_time_option() expects exactly 1 parameter, 2 given in %s on line %d + +Warning: intlcal_get_repeated_wall_time_option(): intlcal_get_repeated_wall_time_option: bad arguments in %s on line %d +bool(false) + +Catchable fatal error: Argument 1 passed to intlcal_get_skipped_wall_time_option() must be an instance of IntlCalendar, integer given in %s on line %d diff --git a/ext/intl/tests/calendar_getTimeZone_basic.phpt b/ext/intl/tests/calendar_getTimeZone_basic.phpt new file mode 100644 index 0000000000..fd9aff1f99 --- /dev/null +++ b/ext/intl/tests/calendar_getTimeZone_basic.phpt @@ -0,0 +1,34 @@ +--TEST-- +IntlCalendar::getTimeZone() basic test +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +if (version_compare(INTL_ICU_VERSION, '4.8') < 0) + die('skip for ICU 4.8+'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); +ini_set("intl.default_locale", "nl"); + +$intlcal = IntlCalendar::createInstance('GMT+00:01'); +print_r($intlcal->getTimeZone()); +print_r(intlcal_get_time_zone($intlcal)); +?> +==DONE== +--EXPECT-- +IntlTimeZone Object +( + [valid] => 1 + [id] => GMT+00:01 + [rawOffset] => 60000 + [currentOffset] => 60000 +) +IntlTimeZone Object +( + [valid] => 1 + [id] => GMT+00:01 + [rawOffset] => 60000 + [currentOffset] => 60000 +) +==DONE==
\ No newline at end of file diff --git a/ext/intl/tests/calendar_getTimeZone_error.phpt b/ext/intl/tests/calendar_getTimeZone_error.phpt new file mode 100644 index 0000000000..470701cd91 --- /dev/null +++ b/ext/intl/tests/calendar_getTimeZone_error.phpt @@ -0,0 +1,32 @@ +--TEST-- +IntlCalendar::getTimeZone(): bad arguments +--INI-- +date.timezone=Atlantic/Azores +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); + +$c = new IntlGregorianCalendar(NULL, 'pt_PT'); + +var_dump($c->getTimeZone(1)); + +var_dump(intlcal_get_time_zone($c, 1)); +var_dump(intlcal_get_time_zone(1)); + +--EXPECTF-- + +Warning: IntlCalendar::getTimeZone() expects exactly 0 parameters, 1 given in %s on line %d + +Warning: IntlCalendar::getTimeZone(): intlcal_get_time_zone: bad arguments in %s on line %d +bool(false) + +Warning: intlcal_get_time_zone() expects exactly 1 parameter, 2 given in %s on line %d + +Warning: intlcal_get_time_zone(): intlcal_get_time_zone: bad arguments in %s on line %d +bool(false) + +Catchable fatal error: Argument 1 passed to intlcal_get_time_zone() must be an instance of IntlCalendar, integer given in %s on line %d diff --git a/ext/intl/tests/calendar_getTime_basic.phpt b/ext/intl/tests/calendar_getTime_basic.phpt new file mode 100644 index 0000000000..659c71c961 --- /dev/null +++ b/ext/intl/tests/calendar_getTime_basic.phpt @@ -0,0 +1,29 @@ +--TEST-- +IntlCalendar::getTime() basic test +--INI-- +date.timezone=Atlantic/Azores +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); +ini_set("intl.default_locale", "nl"); + +$intlcal = IntlCalendar::createInstance('UTC'); +$intlcal->clear(); +$intlcal->set(IntlCalendar::FIELD_YEAR, 2012); +$intlcal->set(IntlCalendar::FIELD_MONTH, 1 /* Feb */); +$intlcal->set(IntlCalendar::FIELD_DAY_OF_MONTH, 29); + +$time = strtotime('2012-02-29 00:00:00 +0000'); + +var_dump((float)$time*1000, $intlcal->getTime()); + +?> +==DONE== +--EXPECT-- +float(1330473600000) +float(1330473600000) +==DONE==
\ No newline at end of file diff --git a/ext/intl/tests/calendar_getTime_error.phpt b/ext/intl/tests/calendar_getTime_error.phpt new file mode 100644 index 0000000000..5d27e21101 --- /dev/null +++ b/ext/intl/tests/calendar_getTime_error.phpt @@ -0,0 +1,31 @@ +--TEST-- +IntlCalendar::getTime(): bad arguments +--INI-- +date.timezone=Atlantic/Azores +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); + +$c = new IntlGregorianCalendar(NULL, 'pt_PT'); + +var_dump($c->getTime(1)); + +var_dump(intlcal_get_time($c, 1)); +var_dump(intlcal_get_time(1)); +--EXPECTF-- + +Warning: IntlCalendar::getTime() expects exactly 0 parameters, 1 given in %s on line %d + +Warning: IntlCalendar::getTime(): intlcal_get_time: bad arguments in %s on line %d +bool(false) + +Warning: intlcal_get_time() expects exactly 1 parameter, 2 given in %s on line %d + +Warning: intlcal_get_time(): intlcal_get_time: bad arguments in %s on line %d +bool(false) + +Catchable fatal error: Argument 1 passed to intlcal_get_time() must be an instance of IntlCalendar, integer given in %s on line %d diff --git a/ext/intl/tests/calendar_getType_basic.phpt b/ext/intl/tests/calendar_getType_basic.phpt new file mode 100644 index 0000000000..ba32dd0526 --- /dev/null +++ b/ext/intl/tests/calendar_getType_basic.phpt @@ -0,0 +1,23 @@ +--TEST-- +IntlCalendar::getType() basic test +--INI-- +date.timezone=Atlantic/Azores +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); +ini_set("intl.default_locale", "nl"); + +$intlcal = IntlCalendar::createInstance(); +VAR_DUMP($intlcal->getType()); +$intlcal = IntlCalendar::createInstance(null, "nl_NL@calendar=hebrew"); +VAR_DUMP(intlcal_get_type($intlcal)); +?> +==DONE== +--EXPECT-- +string(9) "gregorian" +string(6) "hebrew" +==DONE==
\ No newline at end of file diff --git a/ext/intl/tests/calendar_getType_error.phpt b/ext/intl/tests/calendar_getType_error.phpt new file mode 100644 index 0000000000..668ebeafb4 --- /dev/null +++ b/ext/intl/tests/calendar_getType_error.phpt @@ -0,0 +1,32 @@ +--TEST-- +IntlCalendar::getType(): bad arguments +--INI-- +date.timezone=Atlantic/Azores +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); + +$c = new IntlGregorianCalendar(NULL, 'pt_PT'); + +var_dump($c->getType(1)); + +var_dump(intlcal_get_type($c, 1)); +var_dump(intlcal_get_type(1)); + +--EXPECTF-- + +Warning: IntlCalendar::getType() expects exactly 0 parameters, 1 given in %s on line %d + +Warning: IntlCalendar::getType(): intlcal_get_type: bad arguments in %s on line %d +bool(false) + +Warning: intlcal_get_type() expects exactly 1 parameter, 2 given in %s on line %d + +Warning: intlcal_get_type(): intlcal_get_type: bad arguments in %s on line %d +bool(false) + +Catchable fatal error: Argument 1 passed to intlcal_get_type() must be an instance of IntlCalendar, integer given in %s on line %d diff --git a/ext/intl/tests/calendar_getWeekendTransition_basic.phpt b/ext/intl/tests/calendar_getWeekendTransition_basic.phpt new file mode 100644 index 0000000000..e725743006 --- /dev/null +++ b/ext/intl/tests/calendar_getWeekendTransition_basic.phpt @@ -0,0 +1,24 @@ +--TEST-- +IntlCalendar::getWeekendTransition() basic test +--INI-- +date.timezone=Atlantic/Azores +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +if (version_compare(INTL_ICU_VERSION, '4.4') < 0) + die('skip for ICU 4.4+'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); +ini_set("intl.default_locale", "nl"); + +$intlcal = IntlCalendar::createInstance(); +var_dump($intlcal->getWeekendTransition(IntlCalendar::DOW_SUNDAY)); +var_dump(intlcal_get_weekend_transition($intlcal, IntlCalendar::DOW_SUNDAY)); +?> +==DONE== +--EXPECT-- +int(86400000) +int(86400000) +==DONE==
\ No newline at end of file diff --git a/ext/intl/tests/calendar_getWeekendTransition_error.phpt b/ext/intl/tests/calendar_getWeekendTransition_error.phpt new file mode 100644 index 0000000000..f7c9cc7ed1 --- /dev/null +++ b/ext/intl/tests/calendar_getWeekendTransition_error.phpt @@ -0,0 +1,44 @@ +--TEST-- +IntlCalendar::getWeekendTransition(): bad arguments +--INI-- +date.timezone=Atlantic/Azores +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +if (version_compare(INTL_ICU_VERSION, '4.4') < 0) + die('skip for ICU 4.4+'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); + +$c = new IntlGregorianCalendar(NULL, 'pt_PT'); + +var_dump($c->getWeekendTransition()); +var_dump($c->getWeekendTransition(1, 2)); +var_dump($c->getWeekendTransition(0)); + +var_dump(intlcal_get_weekend_transition($c)); +var_dump(intlcal_get_weekend_transition(1, 1)); + +--EXPECTF-- + +Warning: IntlCalendar::getWeekendTransition() expects exactly 1 parameter, 0 given in %s on line %d + +Warning: IntlCalendar::getWeekendTransition(): intlcal_get_weekend_transition: bad arguments in %s on line %d +bool(false) + +Warning: IntlCalendar::getWeekendTransition() expects exactly 1 parameter, 2 given in %s on line %d + +Warning: IntlCalendar::getWeekendTransition(): intlcal_get_weekend_transition: bad arguments in %s on line %d +bool(false) + +Warning: IntlCalendar::getWeekendTransition(): intlcal_get_weekend_transition: invalid day of week in %s on line %d +bool(false) + +Warning: intlcal_get_weekend_transition() expects exactly 2 parameters, 1 given in %s on line %d + +Warning: intlcal_get_weekend_transition(): intlcal_get_weekend_transition: bad arguments in %s on line %d +bool(false) + +Catchable fatal error: Argument 1 passed to intlcal_get_weekend_transition() must be an instance of IntlCalendar, integer given in %s on line %d diff --git a/ext/intl/tests/calendar_getXMaximum_basic.phpt b/ext/intl/tests/calendar_getXMaximum_basic.phpt new file mode 100644 index 0000000000..9b840212d9 --- /dev/null +++ b/ext/intl/tests/calendar_getXMaximum_basic.phpt @@ -0,0 +1,34 @@ +--TEST-- +IntlCalendar::getMaximum(), ::getActualMaximum(), ::getLeastMaximum() basic test +--INI-- +date.timezone=Atlantic/Azores +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); +ini_set("intl.default_locale", "nl"); + +$intlcal = IntlCalendar::createInstance('UTC'); +$intlcal->setTime(strtotime('2012-02-29 05:06:07 +0000') * 1000); +var_dump( + $intlcal->getLeastMaximum(IntlCalendar::FIELD_DAY_OF_MONTH), + intlcal_get_least_maximum($intlcal, IntlCalendar::FIELD_DAY_OF_MONTH), + $intlcal->getActualMaximum(IntlCalendar::FIELD_DAY_OF_MONTH), + intlcal_get_actual_maximum($intlcal, IntlCalendar::FIELD_DAY_OF_MONTH), + $intlcal->getMaximum(IntlCalendar::FIELD_DAY_OF_MONTH), + intlcal_get_maximum($intlcal, IntlCalendar::FIELD_DAY_OF_MONTH) +); + +?> +==DONE== +--EXPECT-- +int(28) +int(28) +int(29) +int(29) +int(31) +int(31) +==DONE==
\ No newline at end of file diff --git a/ext/intl/tests/calendar_getXMinimum_basic.phpt b/ext/intl/tests/calendar_getXMinimum_basic.phpt new file mode 100644 index 0000000000..83fd163809 --- /dev/null +++ b/ext/intl/tests/calendar_getXMinimum_basic.phpt @@ -0,0 +1,34 @@ +--TEST-- +IntlCalendar::getMinimum(), ::getActualMinimum(), ::getGreatestMinimum() basic test +--INI-- +date.timezone=Atlantic/Azores +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); +ini_set("intl.default_locale", "nl"); + +$intlcal = IntlCalendar::createInstance('UTC'); +$intlcal->setTime(strtotime('2012-02-29 05:06:07 +0000') * 1000); +var_dump( + $intlcal->getGreatestMinimum(IntlCalendar::FIELD_DAY_OF_MONTH), + intlcal_get_greatest_minimum($intlcal, IntlCalendar::FIELD_DAY_OF_MONTH), + $intlcal->getActualMinimum(IntlCalendar::FIELD_DAY_OF_MONTH), + intlcal_get_actual_minimum($intlcal, IntlCalendar::FIELD_DAY_OF_MONTH), + $intlcal->getMinimum(IntlCalendar::FIELD_DAY_OF_MONTH), + intlcal_get_minimum($intlcal, IntlCalendar::FIELD_DAY_OF_MONTH) +); + +?> +==DONE== +--EXPECT-- +int(1) +int(1) +int(1) +int(1) +int(1) +int(1) +==DONE==
\ No newline at end of file diff --git a/ext/intl/tests/calendar_get_Least_Greatest_Minimum_Maximum_error.phpt b/ext/intl/tests/calendar_get_Least_Greatest_Minimum_Maximum_error.phpt new file mode 100644 index 0000000000..acd9b58c1d --- /dev/null +++ b/ext/intl/tests/calendar_get_Least_Greatest_Minimum_Maximum_error.phpt @@ -0,0 +1,100 @@ +--TEST-- +IntlCalendar::get/Least/Greatest/Minimum/Maximum(): bad arguments +--INI-- +date.timezone=Atlantic/Azores +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); + +$c = new IntlGregorianCalendar(NULL, 'pt_PT'); + +var_dump($c->getLeastMaximum()); +var_dump($c->getMaximum()); +var_dump($c->getGreatestMinimum()); +var_dump($c->getMinimum()); + +var_dump($c->getLeastMaximum(-1)); +var_dump($c->getMaximum(-1)); +var_dump($c->getGreatestMinimum(-1)); +var_dump($c->getMinimum(-1)); + +var_dump(intlcal_get_least_maximum($c, -1)); +var_dump(intlcal_get_maximum($c, -1)); +var_dump(intlcal_get_greatest_minimum($c, -1)); +var_dump(intlcal_get_minimum($c, -1)); + +function eh($errno, $errstr) { +echo "error: $errno, $errstr\n"; +} +set_error_handler('eh'); + +var_dump(intlcal_get_least_maximum(1, 1)); +var_dump(intlcal_get_maximum(1, 1)); +var_dump(intlcal_get_greatest_minimum(1, -1)); +var_dump(intlcal_get_minimum(1, -1)); + +--EXPECTF-- + +Warning: IntlCalendar::getLeastMaximum() expects exactly 1 parameter, 0 given in %s on line %d + +Warning: IntlCalendar::getLeastMaximum(): intlcal_get_least_maximum: bad arguments in %s on line %d +bool(false) + +Warning: IntlCalendar::getMaximum() expects exactly 1 parameter, 0 given in %s on line %d + +Warning: IntlCalendar::getMaximum(): intlcal_get_maximum: bad arguments in %s on line %d +bool(false) + +Warning: IntlCalendar::getGreatestMinimum() expects exactly 1 parameter, 0 given in %s on line %d + +Warning: IntlCalendar::getGreatestMinimum(): intlcal_get_greatest_minimum: bad arguments in %s on line %d +bool(false) + +Warning: IntlCalendar::getMinimum() expects exactly 1 parameter, 0 given in %s on line %d + +Warning: IntlCalendar::getMinimum(): intlcal_get_minimum: bad arguments in %s on line %d +bool(false) + +Warning: IntlCalendar::getLeastMaximum(): intlcal_get_least_maximum: invalid field in %s on line %d +bool(false) + +Warning: IntlCalendar::getMaximum(): intlcal_get_maximum: invalid field in %s on line %d +bool(false) + +Warning: IntlCalendar::getGreatestMinimum(): intlcal_get_greatest_minimum: invalid field in %s on line %d +bool(false) + +Warning: IntlCalendar::getMinimum(): intlcal_get_minimum: invalid field in %s on line %d +bool(false) + +Warning: intlcal_get_least_maximum(): intlcal_get_least_maximum: invalid field in %s on line %d +bool(false) + +Warning: intlcal_get_maximum(): intlcal_get_maximum: invalid field in %s on line %d +bool(false) + +Warning: intlcal_get_greatest_minimum(): intlcal_get_greatest_minimum: invalid field in %s on line %d +bool(false) + +Warning: intlcal_get_minimum(): intlcal_get_minimum: invalid field in %s on line %d +bool(false) +error: 4096, Argument 1 passed to intlcal_get_least_maximum() must be an instance of IntlCalendar, integer given +error: 2, intlcal_get_least_maximum() expects parameter 1 to be IntlCalendar, integer given +error: 2, intlcal_get_least_maximum(): intlcal_get_least_maximum: bad arguments +bool(false) +error: 4096, Argument 1 passed to intlcal_get_maximum() must be an instance of IntlCalendar, integer given +error: 2, intlcal_get_maximum() expects parameter 1 to be IntlCalendar, integer given +error: 2, intlcal_get_maximum(): intlcal_get_maximum: bad arguments +bool(false) +error: 4096, Argument 1 passed to intlcal_get_greatest_minimum() must be an instance of IntlCalendar, integer given +error: 2, intlcal_get_greatest_minimum() expects parameter 1 to be IntlCalendar, integer given +error: 2, intlcal_get_greatest_minimum(): intlcal_get_greatest_minimum: bad arguments +bool(false) +error: 4096, Argument 1 passed to intlcal_get_minimum() must be an instance of IntlCalendar, integer given +error: 2, intlcal_get_minimum() expects parameter 1 to be IntlCalendar, integer given +error: 2, intlcal_get_minimum(): intlcal_get_minimum: bad arguments +bool(false) diff --git a/ext/intl/tests/calendar_get_basic.phpt b/ext/intl/tests/calendar_get_basic.phpt new file mode 100644 index 0000000000..c617639610 --- /dev/null +++ b/ext/intl/tests/calendar_get_basic.phpt @@ -0,0 +1,23 @@ +--TEST-- +IntlCalendar::get() basic test +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); +ini_set("intl.default_locale", "nl"); + +$intlcal = IntlCalendar::createInstance('UTC'); +$intlcal->set(IntlCalendar::FIELD_DAY_OF_MONTH, 4); + +var_dump($intlcal->get(IntlCalendar::FIELD_DAY_OF_MONTH)); +var_dump(intlcal_get($intlcal, IntlCalendar::FIELD_DAY_OF_MONTH)); + +?> +==DONE== +--EXPECT-- +int(4) +int(4) +==DONE==
\ No newline at end of file diff --git a/ext/intl/tests/calendar_get_getActualMaximum_Minumum_error.phpt b/ext/intl/tests/calendar_get_getActualMaximum_Minumum_error.phpt new file mode 100644 index 0000000000..f6ccb128ee --- /dev/null +++ b/ext/intl/tests/calendar_get_getActualMaximum_Minumum_error.phpt @@ -0,0 +1,84 @@ +--TEST-- +IntlCalendar::get/getActualMaximum/getActualMinimum(): bad arguments +--INI-- +date.timezone=Atlantic/Azores +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); + +$c = new IntlGregorianCalendar(NULL, 'pt_PT'); + +var_dump($c->get()); +var_dump($c->getActualMaximum()); +var_dump($c->getActualMinimum()); + +var_dump($c->get(-1)); +var_dump($c->getActualMaximum(-1)); +var_dump($c->getActualMinimum(-1)); + +var_dump($c->get("s")); +var_dump($c->getActualMaximum("s")); +var_dump($c->getActualMinimum("s")); + +var_dump($c->get(1, 2)); +var_dump($c->getActualMaximum(1, 2)); +var_dump($c->getActualMinimum(1, 2)); +--EXPECTF-- + +Warning: IntlCalendar::get() expects exactly 1 parameter, 0 given in %s on line %d + +Warning: IntlCalendar::get(): intlcal_get: bad arguments in %s on line %d +bool(false) + +Warning: IntlCalendar::getActualMaximum() expects exactly 1 parameter, 0 given in %s on line %d + +Warning: IntlCalendar::getActualMaximum(): intlcal_get_actual_maximum: bad arguments in %s on line %d +bool(false) + +Warning: IntlCalendar::getActualMinimum() expects exactly 1 parameter, 0 given in %s on line %d + +Warning: IntlCalendar::getActualMinimum(): intlcal_get_actual_minimum: bad arguments in %s on line %d +bool(false) + +Warning: IntlCalendar::get(): intlcal_get: invalid field in %s on line %d +bool(false) + +Warning: IntlCalendar::getActualMaximum(): intlcal_get_actual_maximum: invalid field in %s on line %d +bool(false) + +Warning: IntlCalendar::getActualMinimum(): intlcal_get_actual_minimum: invalid field in %s on line %d +bool(false) + +Warning: IntlCalendar::get() expects parameter 1 to be long, string given in %s on line %d + +Warning: IntlCalendar::get(): intlcal_get: bad arguments in %s on line %d +bool(false) + +Warning: IntlCalendar::getActualMaximum() expects parameter 1 to be long, string given in %s on line %d + +Warning: IntlCalendar::getActualMaximum(): intlcal_get_actual_maximum: bad arguments in %s on line %d +bool(false) + +Warning: IntlCalendar::getActualMinimum() expects parameter 1 to be long, string given in %s on line %d + +Warning: IntlCalendar::getActualMinimum(): intlcal_get_actual_minimum: bad arguments in %s on line %d +bool(false) + +Warning: IntlCalendar::get() expects exactly 1 parameter, 2 given in %s on line %d + +Warning: IntlCalendar::get(): intlcal_get: bad arguments in %s on line %d +bool(false) + +Warning: IntlCalendar::getActualMaximum() expects exactly 1 parameter, 2 given in %s on line %d + +Warning: IntlCalendar::getActualMaximum(): intlcal_get_actual_maximum: bad arguments in %s on line %d +bool(false) + +Warning: IntlCalendar::getActualMinimum() expects exactly 1 parameter, 2 given in %s on line %d + +Warning: IntlCalendar::getActualMinimum(): intlcal_get_actual_minimum: bad arguments in %s on line %d +bool(false) diff --git a/ext/intl/tests/calendar_get_getActualMaximum_Minumum_error2.phpt b/ext/intl/tests/calendar_get_getActualMaximum_Minumum_error2.phpt new file mode 100644 index 0000000000..a8d1a4aa2f --- /dev/null +++ b/ext/intl/tests/calendar_get_getActualMaximum_Minumum_error2.phpt @@ -0,0 +1,71 @@ +--TEST-- +IntlCalendar::get/getActualMaximum/getActualMinimum(): bad arguments (procedural) +--INI-- +date.timezone=Atlantic/Azores +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); + +$c = new IntlGregorianCalendar(NULL, 'pt_PT'); + +function eh($errno, $errstr) { +echo "error: $errno, $errstr\n"; +} +set_error_handler('eh'); + +var_dump(intlcal_get($c)); +var_dump(intlcal_get_actual_maximum($c)); +var_dump(intlcal_get_actual_minimum($c)); + +var_dump(intlcal_get($c, -1)); +var_dump(intlcal_get_actual_maximum($c, -1)); +var_dump(intlcal_get_actual_minimum($c, -1)); + +var_dump(intlcal_get($c, "s")); +var_dump(intlcal_get_actual_maximum($c, "s")); +var_dump(intlcal_get_actual_minimum($c, "s")); + +var_dump(intlcal_get(1)); +var_dump(intlcal_get_actual_maximum(1)); +var_dump(intlcal_get_actual_minimum(1)); +--EXPECT-- +error: 2, intlcal_get() expects exactly 2 parameters, 1 given +error: 2, intlcal_get(): intlcal_get: bad arguments +bool(false) +error: 2, intlcal_get_actual_maximum() expects exactly 2 parameters, 1 given +error: 2, intlcal_get_actual_maximum(): intlcal_get_actual_maximum: bad arguments +bool(false) +error: 2, intlcal_get_actual_minimum() expects exactly 2 parameters, 1 given +error: 2, intlcal_get_actual_minimum(): intlcal_get_actual_minimum: bad arguments +bool(false) +error: 2, intlcal_get(): intlcal_get: invalid field +bool(false) +error: 2, intlcal_get_actual_maximum(): intlcal_get_actual_maximum: invalid field +bool(false) +error: 2, intlcal_get_actual_minimum(): intlcal_get_actual_minimum: invalid field +bool(false) +error: 2, intlcal_get() expects parameter 2 to be long, string given +error: 2, intlcal_get(): intlcal_get: bad arguments +bool(false) +error: 2, intlcal_get_actual_maximum() expects parameter 2 to be long, string given +error: 2, intlcal_get_actual_maximum(): intlcal_get_actual_maximum: bad arguments +bool(false) +error: 2, intlcal_get_actual_minimum() expects parameter 2 to be long, string given +error: 2, intlcal_get_actual_minimum(): intlcal_get_actual_minimum: bad arguments +bool(false) +error: 4096, Argument 1 passed to intlcal_get() must be an instance of IntlCalendar, integer given +error: 2, intlcal_get() expects exactly 2 parameters, 1 given +error: 2, intlcal_get(): intlcal_get: bad arguments +bool(false) +error: 4096, Argument 1 passed to intlcal_get_actual_maximum() must be an instance of IntlCalendar, integer given +error: 2, intlcal_get_actual_maximum() expects exactly 2 parameters, 1 given +error: 2, intlcal_get_actual_maximum(): intlcal_get_actual_maximum: bad arguments +bool(false) +error: 4096, Argument 1 passed to intlcal_get_actual_minimum() must be an instance of IntlCalendar, integer given +error: 2, intlcal_get_actual_minimum() expects exactly 2 parameters, 1 given +error: 2, intlcal_get_actual_minimum(): intlcal_get_actual_minimum: bad arguments +bool(false) diff --git a/ext/intl/tests/calendar_get_setRepeatedWallTimeOption_basic.phpt b/ext/intl/tests/calendar_get_setRepeatedWallTimeOption_basic.phpt new file mode 100644 index 0000000000..52765433fe --- /dev/null +++ b/ext/intl/tests/calendar_get_setRepeatedWallTimeOption_basic.phpt @@ -0,0 +1,49 @@ +--TEST-- +IntlCalendar::get/setRepeatedWallTimeOption(): basic test +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +if (version_compare(INTL_ICU_VERSION, '49') < 0) + die('skip for ICU 49+'); +--FILE-- + +<?php +ini_set("intl.error_level", E_WARNING); +ini_set("intl.default_locale", "nl"); + +date_default_timezone_set('Europe/Amsterdam'); + +//28 October 2012, transition from DST +$intlcal = new IntlGregorianCalendar(2012, 9, 28, 0, 0, 0); +var_dump($intlcal->setRepeatedWallTimeOption(IntlCalendar::WALLTIME_LAST)); +var_dump($intlcal->getRepeatedWallTimeOption()); +$intlcal->set(IntlCalendar::FIELD_HOUR_OF_DAY, 2); +$intlcal->set(IntlCalendar::FIELD_MINUTE, 30); +var_dump( + strtotime('2012-10-28 02:30:00 +0100'), + (int)($intlcal->getTime() /1000) +); + +var_dump(intlcal_set_repeated_wall_time_option($intlcal, IntlCalendar::WALLTIME_FIRST)); +var_dump(intlcal_get_repeated_wall_time_option($intlcal)); +$intlcal->set(IntlCalendar::FIELD_HOUR_OF_DAY, 2); +$intlcal->set(IntlCalendar::FIELD_MINUTE, 30); +var_dump( + strtotime('2012-10-28 02:30:00 +0200'), + (int)($intlcal->getTime() /1000) +); + +?> +==DONE== +--EXPECT-- + +bool(true) +int(0) +int(1351387800) +int(1351387800) +bool(true) +int(1) +int(1351384200) +int(1351384200) +==DONE==
\ No newline at end of file diff --git a/ext/intl/tests/calendar_get_setSkippedWallTimeOption_basic.phpt b/ext/intl/tests/calendar_get_setSkippedWallTimeOption_basic.phpt new file mode 100644 index 0000000000..bbbf031c88 --- /dev/null +++ b/ext/intl/tests/calendar_get_setSkippedWallTimeOption_basic.phpt @@ -0,0 +1,67 @@ +--TEST-- +IntlCalendar::get/setSkippedWallTimeOption(): basic test +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +if (version_compare(INTL_ICU_VERSION, '49') < 0) + die('skip for ICU 49+'); +--FILE-- + +<?php +ini_set("intl.error_level", E_WARNING); +ini_set("intl.default_locale", "nl"); + +date_default_timezone_set('Europe/Amsterdam'); + +//25 March 2012, transition to DST +$intlcal = new IntlGregorianCalendar(2012, 2, 25, 0, 0, 0); +var_dump($intlcal->getSkippedWallTimeOption()); +$intlcal->set(IntlCalendar::FIELD_HOUR_OF_DAY, 2); +$intlcal->set(IntlCalendar::FIELD_MINUTE, 30); +echo "Should be 3h30\n"; +var_dump( + $intlcal->get(IntlCalendar::FIELD_HOUR_OF_DAY), + $intlcal->get(IntlCalendar::FIELD_MINUTE) +); + +var_dump($intlcal->setSkippedWallTimeOption(IntlCalendar::WALLTIME_FIRST)); +var_dump(intlcal_get_skipped_wall_time_option($intlcal)); +$intlcal->set(IntlCalendar::FIELD_HOUR_OF_DAY, 2); +$intlcal->set(IntlCalendar::FIELD_MINUTE, 30); +echo "Should be 1h30\n"; +var_dump( + $intlcal->get(IntlCalendar::FIELD_HOUR_OF_DAY), + $intlcal->get(IntlCalendar::FIELD_MINUTE) +); + +var_dump(intlcal_set_skipped_wall_time_option($intlcal, IntlCalendar::WALLTIME_NEXT_VALID)); +var_dump($intlcal->getSkippedWallTimeOption()); +$intlcal->set(IntlCalendar::FIELD_HOUR_OF_DAY, 2); +$intlcal->set(IntlCalendar::FIELD_MINUTE, 30); +echo "Should be 3h00\n"; +var_dump( + $intlcal->get(IntlCalendar::FIELD_HOUR_OF_DAY), + $intlcal->get(IntlCalendar::FIELD_MINUTE) +); + + +?> +==DONE== +--EXPECT-- + +int(0) +Should be 3h30 +int(3) +int(30) +bool(true) +int(1) +Should be 1h30 +int(1) +int(30) +bool(true) +int(2) +Should be 3h00 +int(3) +int(0) +==DONE==
\ No newline at end of file diff --git a/ext/intl/tests/calendar_inDaylightTime_basic.phpt b/ext/intl/tests/calendar_inDaylightTime_basic.phpt new file mode 100644 index 0000000000..dff8ef50d3 --- /dev/null +++ b/ext/intl/tests/calendar_inDaylightTime_basic.phpt @@ -0,0 +1,24 @@ +--TEST-- +IntlCalendar::inDaylightTime() basic test +--INI-- +date.timezone=Atlantic/Azores +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); +ini_set("intl.default_locale", "nl"); + +$intlcal = IntlCalendar::createInstance('Europe/Amsterdam'); +$intlcal->setTime(strtotime('2012-01-01') * 1000); +var_dump($intlcal->inDaylightTime()); +$intlcal->setTime(strtotime('2012-04-01') * 1000); +var_dump(intlcal_in_daylight_time($intlcal)); +?> +==DONE== +--EXPECT-- +bool(false) +bool(true) +==DONE==
\ No newline at end of file diff --git a/ext/intl/tests/calendar_inDaylightTime_error.phpt b/ext/intl/tests/calendar_inDaylightTime_error.phpt new file mode 100644 index 0000000000..9af9aa5048 --- /dev/null +++ b/ext/intl/tests/calendar_inDaylightTime_error.phpt @@ -0,0 +1,32 @@ +--TEST-- +IntlCalendar::inDaylightTime(): bad arguments +--INI-- +date.timezone=Atlantic/Azores +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); + +$c = new IntlGregorianCalendar(NULL, 'pt_PT'); + +var_dump($c->inDaylightTime(1)); + +var_dump(intlcal_in_daylight_time($c, 1)); +var_dump(intlcal_in_daylight_time(1)); + +--EXPECTF-- + +Warning: IntlCalendar::inDaylightTime() expects exactly 0 parameters, 1 given in %s on line %d + +Warning: IntlCalendar::inDaylightTime(): intlcal_in_daylight_time: bad arguments in %s on line %d +bool(false) + +Warning: intlcal_in_daylight_time() expects exactly 1 parameter, 2 given in %s on line %d + +Warning: intlcal_in_daylight_time(): intlcal_in_daylight_time: bad arguments in %s on line %d +bool(false) + +Catchable fatal error: Argument 1 passed to intlcal_in_daylight_time() must be an instance of IntlCalendar, integer given in %s on line %d diff --git a/ext/intl/tests/calendar_isEquivalentTo_basic.phpt b/ext/intl/tests/calendar_isEquivalentTo_basic.phpt new file mode 100644 index 0000000000..f71fd8ad5b --- /dev/null +++ b/ext/intl/tests/calendar_isEquivalentTo_basic.phpt @@ -0,0 +1,40 @@ +--TEST-- +IntlCalendar::isEquivalentTo() basic test +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); +ini_set("intl.default_locale", "nl"); + +$intlcal1 = IntlCalendar::createInstance('Europe/Amsterdam'); +$intlcal2 = IntlCalendar::createInstance('Europe/Lisbon'); +$intlcal3 = IntlCalendar::createInstance('Europe/Amsterdam', "nl_NL@calendar=islamic"); +$intlcal4 = IntlCalendar::createInstance('Europe/Amsterdam'); +$intlcal4->roll(IntlCalendar::FIELD_MONTH, true); + +var_dump( + "1 - 1", + $intlcal1->isEquivalentTo($intlcal1), + "1 - 2", + $intlcal1->isEquivalentTo($intlcal2), + "1 - 3", + $intlcal1->isEquivalentTo($intlcal3), + "1 - 4", + $intlcal1->isEquivalentTo($intlcal4) +); + +?> +==DONE== +--EXPECT-- +string(5) "1 - 1" +bool(true) +string(5) "1 - 2" +bool(false) +string(5) "1 - 3" +bool(false) +string(5) "1 - 4" +bool(true) +==DONE==
\ No newline at end of file diff --git a/ext/intl/tests/calendar_isEquivalentTo_error.phpt b/ext/intl/tests/calendar_isEquivalentTo_error.phpt new file mode 100644 index 0000000000..4fa7da5eb6 --- /dev/null +++ b/ext/intl/tests/calendar_isEquivalentTo_error.phpt @@ -0,0 +1,50 @@ +--TEST-- +IntlCalendar::isEquivalentTo(): bad arguments +--INI-- +date.timezone=Atlantic/Azores +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); + +$c = new IntlGregorianCalendar(NULL, 'pt_PT'); + +function eh($errno, $errstr) { +echo "error: $errno, $errstr\n"; +} +set_error_handler('eh'); + +var_dump($c->isEquivalentTo(0)); +var_dump($c->isEquivalentTo($c, 1)); +var_dump($c->isEquivalentTo(1)); + +var_dump(intlcal_is_equivalent_to($c)); +var_dump(intlcal_is_equivalent_to($c, 1)); +var_dump(intlcal_is_equivalent_to(1, $c)); + +--EXPECT-- +error: 4096, Argument 1 passed to IntlCalendar::isEquivalentTo() must be an instance of IntlCalendar, integer given +error: 2, IntlCalendar::isEquivalentTo() expects parameter 1 to be IntlCalendar, integer given +error: 2, IntlCalendar::isEquivalentTo(): intlcal_is_equivalent_to: bad arguments +bool(false) +error: 2, IntlCalendar::isEquivalentTo() expects exactly 1 parameter, 2 given +error: 2, IntlCalendar::isEquivalentTo(): intlcal_is_equivalent_to: bad arguments +bool(false) +error: 4096, Argument 1 passed to IntlCalendar::isEquivalentTo() must be an instance of IntlCalendar, integer given +error: 2, IntlCalendar::isEquivalentTo() expects parameter 1 to be IntlCalendar, integer given +error: 2, IntlCalendar::isEquivalentTo(): intlcal_is_equivalent_to: bad arguments +bool(false) +error: 2, intlcal_is_equivalent_to() expects exactly 2 parameters, 1 given +error: 2, intlcal_is_equivalent_to(): intlcal_is_equivalent_to: bad arguments +bool(false) +error: 4096, Argument 2 passed to intlcal_is_equivalent_to() must be an instance of IntlCalendar, integer given +error: 2, intlcal_is_equivalent_to() expects parameter 2 to be IntlCalendar, integer given +error: 2, intlcal_is_equivalent_to(): intlcal_is_equivalent_to: bad arguments +bool(false) +error: 4096, Argument 1 passed to intlcal_is_equivalent_to() must be an instance of IntlCalendar, integer given +error: 2, intlcal_is_equivalent_to() expects parameter 1 to be IntlCalendar, integer given +error: 2, intlcal_is_equivalent_to(): intlcal_is_equivalent_to: bad arguments +bool(false) diff --git a/ext/intl/tests/calendar_isLenient_error.phpt b/ext/intl/tests/calendar_isLenient_error.phpt new file mode 100644 index 0000000000..7ddde1ae02 --- /dev/null +++ b/ext/intl/tests/calendar_isLenient_error.phpt @@ -0,0 +1,32 @@ +--TEST-- +IntlCalendar::isLenient(): bad arguments +--INI-- +date.timezone=Atlantic/Azores +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); + +$c = new IntlGregorianCalendar(NULL, 'pt_PT'); + +var_dump($c->isLenient(1)); + +var_dump(intlcal_is_lenient($c, 1)); +var_dump(intlcal_is_lenient(1)); + +--EXPECTF-- + +Warning: IntlCalendar::isLenient() expects exactly 0 parameters, 1 given in %s on line %d + +Warning: IntlCalendar::isLenient(): intlcal_is_lenient: bad arguments in %s on line %d +bool(false) + +Warning: intlcal_is_lenient() expects exactly 1 parameter, 2 given in %s on line %d + +Warning: intlcal_is_lenient(): intlcal_is_lenient: bad arguments in %s on line %d +bool(false) + +Catchable fatal error: Argument 1 passed to intlcal_is_lenient() must be an instance of IntlCalendar, integer given in %s on line %d diff --git a/ext/intl/tests/calendar_isSet_basic.phpt b/ext/intl/tests/calendar_isSet_basic.phpt new file mode 100644 index 0000000000..8ef01448d5 --- /dev/null +++ b/ext/intl/tests/calendar_isSet_basic.phpt @@ -0,0 +1,24 @@ +--TEST-- +IntlCalendar::isSet() basic test +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); +ini_set("intl.default_locale", "nl"); + +$intlcal = IntlCalendar::createInstance('UTC'); +var_dump($intlcal->isSet(IntlCalendar::FIELD_MINUTE)); +$intlcal->clear(IntlCalendar::FIELD_MINUTE); +var_dump($intlcal->isSet(IntlCalendar::FIELD_MINUTE)); +$intlcal->set(IntlCalendar::FIELD_MINUTE, 0); +var_dump(intlcal_is_set($intlcal, IntlCalendar::FIELD_MINUTE)); +?> +==DONE== +--EXPECT-- +bool(true) +bool(false) +bool(true) +==DONE==
\ No newline at end of file diff --git a/ext/intl/tests/calendar_isSet_error.phpt b/ext/intl/tests/calendar_isSet_error.phpt new file mode 100644 index 0000000000..f238d776b2 --- /dev/null +++ b/ext/intl/tests/calendar_isSet_error.phpt @@ -0,0 +1,42 @@ +--TEST-- +IntlCalendar::isSet(): bad arguments +--INI-- +date.timezone=Atlantic/Azores +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); + +$c = new IntlGregorianCalendar(NULL, 'pt_PT'); + +var_dump($c->isSet()); +var_dump($c->isSet(1, 2)); +var_dump($c->isSet(-1)); + +var_dump(intlcal_is_set($c)); +var_dump(intlcal_is_set(1, 2)); + +--EXPECTF-- + +Warning: IntlCalendar::isSet() expects exactly 1 parameter, 0 given in %s on line %d + +Warning: IntlCalendar::isSet(): intlcal_is_set: bad arguments in %s on line %d +bool(false) + +Warning: IntlCalendar::isSet() expects exactly 1 parameter, 2 given in %s on line %d + +Warning: IntlCalendar::isSet(): intlcal_is_set: bad arguments in %s on line %d +bool(false) + +Warning: IntlCalendar::isSet(): intlcal_is_set: invalid field in %s on line %d +bool(false) + +Warning: intlcal_is_set() expects exactly 2 parameters, 1 given in %s on line %d + +Warning: intlcal_is_set(): intlcal_is_set: bad arguments in %s on line %d +bool(false) + +Catchable fatal error: Argument 1 passed to intlcal_is_set() must be an instance of IntlCalendar, integer given in %s on line %d diff --git a/ext/intl/tests/calendar_isWeekend_basic.phpt b/ext/intl/tests/calendar_isWeekend_basic.phpt new file mode 100644 index 0000000000..d6452c71f7 --- /dev/null +++ b/ext/intl/tests/calendar_isWeekend_basic.phpt @@ -0,0 +1,26 @@ +--TEST-- +IntlCalendar::isWeekend basic test +--INI-- +date.timezone=Atlantic/Azores +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +if (version_compare(INTL_ICU_VERSION, '4.4') < 0) + die('skip for ICU 4.4+'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); +ini_set("intl.default_locale", "nl"); + +$intlcal = IntlCalendar::createInstance('UTC'); +var_dump($intlcal->isWeekend(strtotime('2012-02-29 12:00:00 +0000') * 1000)); +var_dump(intlcal_is_weekend($intlcal, strtotime('2012-02-29 12:00:00 +0000') * 1000)); +var_dump($intlcal->isWeekend(strtotime('2012-03-11 12:00:00 +0000') * 1000)); +?> +==DONE== +--EXPECT-- +bool(false) +bool(false) +bool(true) +==DONE==
\ No newline at end of file diff --git a/ext/intl/tests/calendar_isWeekend_error.phpt b/ext/intl/tests/calendar_isWeekend_error.phpt new file mode 100644 index 0000000000..7939a66a14 --- /dev/null +++ b/ext/intl/tests/calendar_isWeekend_error.phpt @@ -0,0 +1,38 @@ +--TEST-- +IntlCalendar::isWeekend(): bad arguments +--INI-- +date.timezone=Atlantic/Azores +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +if (version_compare(INTL_ICU_VERSION, '4.4') < 0) + die('skip for ICU 4.4+'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); + +$c = new IntlGregorianCalendar(NULL, 'pt_PT'); + +var_dump($c->isWeekend(1, 2)); +var_dump($c->isWeekend("jhhk")); + +var_dump(intlcal_is_weekend($c, "jj")); +var_dump(intlcal_is_weekend(1)); + +--EXPECTF-- + +Warning: IntlCalendar::isWeekend(): intlcal_is_weekend: bad arguments in %s on line %d +bool(false) + +Warning: IntlCalendar::isWeekend() expects parameter 1 to be double, string given in %s on line %d + +Warning: IntlCalendar::isWeekend(): intlcal_is_weekend: bad arguments in %s on line %d +bool(false) + +Warning: intlcal_is_weekend() expects parameter 2 to be double, string given in %s on line %d + +Warning: intlcal_is_weekend(): intlcal_is_weekend: bad arguments in %s on line %d +bool(false) + +Catchable fatal error: Argument 1 passed to intlcal_is_weekend() must be an instance of IntlCalendar, integer given in %s on line %d diff --git a/ext/intl/tests/calendar_is_set_lenient_basic.phpt b/ext/intl/tests/calendar_is_set_lenient_basic.phpt new file mode 100644 index 0000000000..64f537f9bc --- /dev/null +++ b/ext/intl/tests/calendar_is_set_lenient_basic.phpt @@ -0,0 +1,28 @@ +--TEST-- +IntlCalendar::isLenient(), ::setLenient() basic test +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); +ini_set("intl.default_locale", "nl"); + +$intlcal1 = IntlCalendar::createInstance('UTC'); +var_dump($intlcal1->isLenient()); +var_dump(intlcal_is_lenient($intlcal1)); +var_dump($intlcal1->setLenient(false)); +var_dump($intlcal1->isLenient()); +var_dump(intlcal_set_lenient($intlcal1, true)); +var_dump($intlcal1->isLenient()); +?> +==DONE== +--EXPECT-- +bool(true) +bool(true) +bool(true) +bool(false) +bool(true) +bool(true) +==DONE==
\ No newline at end of file diff --git a/ext/intl/tests/calendar_roll_basic.phpt b/ext/intl/tests/calendar_roll_basic.phpt new file mode 100644 index 0000000000..971c36217b --- /dev/null +++ b/ext/intl/tests/calendar_roll_basic.phpt @@ -0,0 +1,34 @@ +--TEST-- +IntlCalendar::roll() basic test +--INI-- +date.timezone=Atlantic/Azores +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); +ini_set("intl.default_locale", "nl"); + +$intlcal = new IntlGregorianCalendar(2012, 1, 28); +var_dump($intlcal->roll(IntlCalendar::FIELD_DAY_OF_MONTH, 2)); +var_dump($intlcal->get(IntlCalendar::FIELD_MONTH)); //1 (Feb) +var_dump($intlcal->get(IntlCalendar::FIELD_DAY_OF_MONTH)); //1 + +$intlcal = new IntlGregorianCalendar(2012, 1, 28); +var_dump(intlcal_roll($intlcal, IntlCalendar::FIELD_DAY_OF_MONTH, 2)); +var_dump($intlcal->get(IntlCalendar::FIELD_MONTH)); //1 (Feb) +var_dump($intlcal->get(IntlCalendar::FIELD_DAY_OF_MONTH)); //1 + + +?> +==DONE== +--EXPECT-- +bool(true) +int(1) +int(1) +bool(true) +int(1) +int(1) +==DONE==
\ No newline at end of file diff --git a/ext/intl/tests/calendar_roll_error.phpt b/ext/intl/tests/calendar_roll_error.phpt new file mode 100644 index 0000000000..a567394699 --- /dev/null +++ b/ext/intl/tests/calendar_roll_error.phpt @@ -0,0 +1,37 @@ +--TEST-- +IntlCalendar::roll(): bad arguments +--INI-- +date.timezone=Atlantic/Azores +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); + +$c = new IntlGregorianCalendar(NULL, 'pt_PT'); + +var_dump($c->roll(1, 2, 3)); +var_dump($c->roll(-1, 2)); +var_dump($c->roll(1)); + +var_dump(intlcal_roll($c, 1, 2, 3)); +var_dump(intlcal_roll(1, 2, 3)); +--EXPECTF-- + +Warning: IntlCalendar::roll(): intlcal_set: too many arguments in %s on line %d +bool(false) + +Warning: IntlCalendar::roll(): intlcal_roll: invalid field in %s on line %d +bool(false) + +Warning: IntlCalendar::roll() expects exactly 2 parameters, 1 given in %s on line %d + +Warning: IntlCalendar::roll(): intlcal_roll: bad arguments in %s on line %d +bool(false) + +Warning: intlcal_roll(): intlcal_set: too many arguments in %s on line %d +bool(false) + +Catchable fatal error: Argument 1 passed to intlcal_roll() must be an instance of IntlCalendar, integer given in %s on line %d diff --git a/ext/intl/tests/calendar_roll_variation1.phpt b/ext/intl/tests/calendar_roll_variation1.phpt new file mode 100644 index 0000000000..9fb8d75e5a --- /dev/null +++ b/ext/intl/tests/calendar_roll_variation1.phpt @@ -0,0 +1,32 @@ +--TEST-- +IntlCalendar::roll() bool argument variation +--INI-- +date.timezone=Atlantic/Azores +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); +ini_set("intl.default_locale", "nl"); + +$intlcal = new IntlGregorianCalendar(2012, 1, 28); +var_dump($intlcal->roll(IntlCalendar::FIELD_DAY_OF_MONTH, true)); +var_dump($intlcal->get(IntlCalendar::FIELD_MONTH)); //1 (Feb) +var_dump($intlcal->get(IntlCalendar::FIELD_DAY_OF_MONTH)); //29 + +var_dump(intlcal_roll($intlcal, IntlCalendar::FIELD_DAY_OF_MONTH, false)); +var_dump($intlcal->get(IntlCalendar::FIELD_MONTH)); //1 (Feb) +var_dump($intlcal->get(IntlCalendar::FIELD_DAY_OF_MONTH)); //28 + +?> +==DONE== +--EXPECT-- +bool(true) +int(1) +int(29) +bool(true) +int(1) +int(28) +==DONE==
\ No newline at end of file diff --git a/ext/intl/tests/calendar_setFirstDayOfWeek_basic.phpt b/ext/intl/tests/calendar_setFirstDayOfWeek_basic.phpt new file mode 100644 index 0000000000..79b38104e4 --- /dev/null +++ b/ext/intl/tests/calendar_setFirstDayOfWeek_basic.phpt @@ -0,0 +1,28 @@ +--TEST-- +IntlCalendar::setFirstDayOfWeek() basic test +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); +ini_set("intl.default_locale", "nl"); + +$intlcal = IntlCalendar::createInstance('UTC'); +var_dump( + IntlCalendar::DOW_TUESDAY, + $intlcal->setFirstDayOfWeek(IntlCalendar::DOW_TUESDAY), + $intlcal->getFirstDayOfWeek(), + intlcal_set_first_day_of_week($intlcal, IntlCalendar::DOW_WEDNESDAY), + $intlcal->getFirstDayOfWeek() +); +?> +==DONE== +--EXPECT-- +int(3) +bool(true) +int(3) +bool(true) +int(4) +==DONE==
\ No newline at end of file diff --git a/ext/intl/tests/calendar_setFirstDayOfWeek_error.phpt b/ext/intl/tests/calendar_setFirstDayOfWeek_error.phpt new file mode 100644 index 0000000000..98237e56fa --- /dev/null +++ b/ext/intl/tests/calendar_setFirstDayOfWeek_error.phpt @@ -0,0 +1,40 @@ +--TEST-- +IntlCalendar::setFirstDayOfWeek(): bad arguments +--INI-- +date.timezone=Atlantic/Azores +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); + +$c = new IntlGregorianCalendar(NULL, 'pt_PT'); + +var_dump($c->setFirstDayOfWeek()); +var_dump($c->setFirstDayOfWeek(1, 2)); +var_dump($c->setFirstDayOfWeek(0)); + +var_dump(intlcal_set_first_day_of_week($c, 0)); +var_dump(intlcal_set_first_day_of_week(1, 2)); + +--EXPECTF-- + +Warning: IntlCalendar::setFirstDayOfWeek() expects exactly 1 parameter, 0 given in %s on line %d + +Warning: IntlCalendar::setFirstDayOfWeek(): intlcal_set_first_day_of_week: bad arguments in %s on line %d +bool(false) + +Warning: IntlCalendar::setFirstDayOfWeek() expects exactly 1 parameter, 2 given in %s on line %d + +Warning: IntlCalendar::setFirstDayOfWeek(): intlcal_set_first_day_of_week: bad arguments in %s on line %d +bool(false) + +Warning: IntlCalendar::setFirstDayOfWeek(): intlcal_set_first_day_of_week: invalid day of week in %s on line %d +bool(false) + +Warning: intlcal_set_first_day_of_week(): intlcal_set_first_day_of_week: invalid day of week in %s on line %d +bool(false) + +Catchable fatal error: Argument 1 passed to intlcal_set_first_day_of_week() must be an instance of IntlCalendar, integer given in %s on line %d diff --git a/ext/intl/tests/calendar_setLenient_error.phpt b/ext/intl/tests/calendar_setLenient_error.phpt new file mode 100644 index 0000000000..2b1d7b016d --- /dev/null +++ b/ext/intl/tests/calendar_setLenient_error.phpt @@ -0,0 +1,44 @@ +--TEST-- +IntlCalendar::setLenient(): bad arguments +--INI-- +date.timezone=Atlantic/Azores +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); + +$c = new IntlGregorianCalendar(NULL, 'pt_PT'); + +var_dump($c->setLenient()); +var_dump($c->setLenient(array())); +var_dump($c->setLenient(1, 2)); + +var_dump(intlcal_set_lenient($c, array())); +var_dump(intlcal_set_lenient(1, false)); + +--EXPECTF-- + +Warning: IntlCalendar::setLenient() expects exactly 1 parameter, 0 given in %s on line %d + +Warning: IntlCalendar::setLenient(): intlcal_set_lenient: bad arguments in %s on line %d +bool(false) + +Warning: IntlCalendar::setLenient() expects parameter 1 to be boolean, array given in %s on line %d + +Warning: IntlCalendar::setLenient(): intlcal_set_lenient: bad arguments in %s on line %d +bool(false) + +Warning: IntlCalendar::setLenient() expects exactly 1 parameter, 2 given in %s on line %d + +Warning: IntlCalendar::setLenient(): intlcal_set_lenient: bad arguments in %s on line %d +bool(false) + +Warning: intlcal_set_lenient() expects parameter 2 to be boolean, array given in %s on line %d + +Warning: intlcal_set_lenient(): intlcal_set_lenient: bad arguments in %s on line %d +bool(false) + +Catchable fatal error: Argument 1 passed to intlcal_set_lenient() must be an instance of IntlCalendar, integer given in %s on line %d diff --git a/ext/intl/tests/calendar_setSkipped_RepeatedWallTimeOption_error.phpt b/ext/intl/tests/calendar_setSkipped_RepeatedWallTimeOption_error.phpt new file mode 100644 index 0000000000..dab55d2b29 --- /dev/null +++ b/ext/intl/tests/calendar_setSkipped_RepeatedWallTimeOption_error.phpt @@ -0,0 +1,82 @@ +--TEST-- +IntlCalendar::setSkipped/RepeatedWallTimeOption(): bad arguments +--INI-- +date.timezone=Atlantic/Azores +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +if (version_compare(INTL_ICU_VERSION, '49') < 0) + die('skip for ICU 49+'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); + +$c = new IntlGregorianCalendar(NULL, 'pt_PT'); + +var_dump($c->setSkippedWallTimeOption()); +var_dump($c->setRepeatedWallTimeOption()); + +var_dump($c->setSkippedWallTimeOption(1, 2)); +var_dump($c->setRepeatedWallTimeOption(1, 2)); + +var_dump($c->setSkippedWallTimeOption(array())); +var_dump($c->setRepeatedWallTimeOption(array())); + +var_dump($c->setSkippedWallTimeOption(3)); +var_dump($c->setRepeatedWallTimeOption(2)); + +var_dump(intlcal_set_skipped_wall_time_option($c)); +var_dump(intlcal_set_repeated_wall_time_option($c)); + +var_dump(intlcal_set_repeated_wall_time_option(1, 1)); + +--EXPECTF-- + +Warning: IntlCalendar::setSkippedWallTimeOption() expects exactly 1 parameter, 0 given in %s on line %d + +Warning: IntlCalendar::setSkippedWallTimeOption(): intlcal_set_skipped_wall_time_option: bad arguments in %s on line %d +bool(false) + +Warning: IntlCalendar::setRepeatedWallTimeOption() expects exactly 1 parameter, 0 given in %s on line %d + +Warning: IntlCalendar::setRepeatedWallTimeOption(): intlcal_set_repeated_wall_time_option: bad arguments in %s on line %d +bool(false) + +Warning: IntlCalendar::setSkippedWallTimeOption() expects exactly 1 parameter, 2 given in %s on line %d + +Warning: IntlCalendar::setSkippedWallTimeOption(): intlcal_set_skipped_wall_time_option: bad arguments in %s on line %d +bool(false) + +Warning: IntlCalendar::setRepeatedWallTimeOption() expects exactly 1 parameter, 2 given in %s on line %d + +Warning: IntlCalendar::setRepeatedWallTimeOption(): intlcal_set_repeated_wall_time_option: bad arguments in %s on line %d +bool(false) + +Warning: IntlCalendar::setSkippedWallTimeOption() expects parameter 1 to be long, array given in %s on line %d + +Warning: IntlCalendar::setSkippedWallTimeOption(): intlcal_set_skipped_wall_time_option: bad arguments in %s on line %d +bool(false) + +Warning: IntlCalendar::setRepeatedWallTimeOption() expects parameter 1 to be long, array given in %s on line %d + +Warning: IntlCalendar::setRepeatedWallTimeOption(): intlcal_set_repeated_wall_time_option: bad arguments in %s on line %d +bool(false) + +Warning: IntlCalendar::setSkippedWallTimeOption(): intlcal_set_skipped_wall_time_option: invalid option in %s on line %d +bool(false) + +Warning: IntlCalendar::setRepeatedWallTimeOption(): intlcal_set_repeated_wall_time_option: invalid option in %s on line %d +bool(false) + +Warning: intlcal_set_skipped_wall_time_option() expects exactly 2 parameters, 1 given in %s on line %d + +Warning: intlcal_set_skipped_wall_time_option(): intlcal_set_skipped_wall_time_option: bad arguments in %s on line %d +bool(false) + +Warning: intlcal_set_repeated_wall_time_option() expects exactly 2 parameters, 1 given in %s on line %d + +Warning: intlcal_set_repeated_wall_time_option(): intlcal_set_repeated_wall_time_option: bad arguments in %s on line %d +bool(false) + +Catchable fatal error: Argument 1 passed to intlcal_set_repeated_wall_time_option() must be an instance of IntlCalendar, integer given in %s on line %d diff --git a/ext/intl/tests/calendar_setTimeZone_basic.phpt b/ext/intl/tests/calendar_setTimeZone_basic.phpt new file mode 100644 index 0000000000..525840ddd6 --- /dev/null +++ b/ext/intl/tests/calendar_setTimeZone_basic.phpt @@ -0,0 +1,39 @@ +--TEST-- +IntlCalendar::setTimeZone() basic test +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +if (version_compare(INTL_ICU_VERSION, '4.8') < 0) + die('skip for ICU 4.8+'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); +ini_set("intl.default_locale", "nl"); + +$intlcal = IntlCalendar::createInstance('Europe/Amsterdam'); +print_r($intlcal->getTimeZone()->getID()); +echo "\n"; +var_dump($intlcal->get(IntlCalendar::FIELD_ZONE_OFFSET)); + +$intlcal->setTimeZone(IntlTimeZone::getGMT()); +print_r($intlcal->getTimeZone()->getID()); +echo "\n"; +var_dump($intlcal->get(IntlCalendar::FIELD_ZONE_OFFSET)); + +intlcal_set_time_zone($intlcal, + IntlTimeZone::createTimeZone('GMT+05:30')); +print_r($intlcal->getTimeZone()->getID()); +echo "\n"; +var_dump($intlcal->get(IntlCalendar::FIELD_ZONE_OFFSET)); + +?> +==DONE== +--EXPECT-- +Europe/Amsterdam +int(3600000) +GMT +int(0) +GMT+05:30 +int(19800000) +==DONE==
\ No newline at end of file diff --git a/ext/intl/tests/calendar_setTimeZone_error.phpt b/ext/intl/tests/calendar_setTimeZone_error.phpt new file mode 100644 index 0000000000..ebe4d119ea --- /dev/null +++ b/ext/intl/tests/calendar_setTimeZone_error.phpt @@ -0,0 +1,41 @@ +--TEST-- +IntlCalendar::setTimeZone(): bad arguments +--INI-- +date.timezone=Atlantic/Azores +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); + +$c = new IntlGregorianCalendar(NULL, 'pt_PT'); + +$gmt = IntlTimeZone::getGMT(); + +function eh($errno, $errstr) { +echo "error: $errno, $errstr\n"; +} +set_error_handler('eh'); + +var_dump($c->setTimeZone($gmt, 2)); +var_dump($c->setTimeZone()); + +var_dump(intlcal_set_time_zone($c, 1, 2)); +var_dump(intlcal_set_time_zone(1, $gmt)); + +--EXPECT-- +error: 2, IntlCalendar::setTimeZone() expects exactly 1 parameter, 2 given +error: 2, IntlCalendar::setTimeZone(): intlcal_set_time_zone: bad arguments +bool(false) +error: 2, IntlCalendar::setTimeZone() expects exactly 1 parameter, 0 given +error: 2, IntlCalendar::setTimeZone(): intlcal_set_time_zone: bad arguments +bool(false) +error: 2, intlcal_set_time_zone() expects exactly 2 parameters, 3 given +error: 2, intlcal_set_time_zone(): intlcal_set_time_zone: bad arguments +bool(false) +error: 4096, Argument 1 passed to intlcal_set_time_zone() must be an instance of IntlCalendar, integer given +error: 2, intlcal_set_time_zone() expects parameter 1 to be IntlCalendar, integer given +error: 2, intlcal_set_time_zone(): intlcal_set_time_zone: bad arguments +bool(false) diff --git a/ext/intl/tests/calendar_setTimeZone_error2.phpt b/ext/intl/tests/calendar_setTimeZone_error2.phpt new file mode 100644 index 0000000000..aa1eaba209 --- /dev/null +++ b/ext/intl/tests/calendar_setTimeZone_error2.phpt @@ -0,0 +1,29 @@ +--TEST-- +IntlCalendar::setTimeZone(): valid time zones for DateTime but not ICU +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); +ini_set("intl.default_locale", "nl"); +date_default_timezone_set('Europe/Amsterdam'); + +$intlcal = new IntlGregorianCalendar(); + +$pstdate = new DateTime('2012-01-01 00:00:00 WEST'); +$intlcal->setTimeZone($pstdate->getTimeZone()); +var_dump($intlcal->getTimeZone()->getID()); + +$pstdate = new DateTime('2012-01-01 00:00:00 +24:00'); +$intlcal->setTimeZone($pstdate->getTimeZone()); +var_dump($intlcal->getTimeZone()->getID()); + +--EXPECTF-- + +Warning: IntlCalendar::setTimeZone(): intlcal_set_time_zone: time zone id 'WEST' extracted from ext/date DateTimeZone not recognized in %s on line %d +string(16) "Europe/Amsterdam" + +Warning: IntlCalendar::setTimeZone(): intlcal_set_time_zone: object has an time zone offset that's too large in %s on line %d +string(16) "Europe/Amsterdam" diff --git a/ext/intl/tests/calendar_setTimeZone_variation1.phpt b/ext/intl/tests/calendar_setTimeZone_variation1.phpt new file mode 100644 index 0000000000..b1cbb74edf --- /dev/null +++ b/ext/intl/tests/calendar_setTimeZone_variation1.phpt @@ -0,0 +1,30 @@ +--TEST-- +IntlCalendar::setTimeZone() variation with NULL arg +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); +ini_set("intl.default_locale", "nl"); + +$intlcal = IntlCalendar::createInstance('Europe/Amsterdam'); +print_r($intlcal->getTimeZone()->getID()); +echo "\n"; +var_dump($intlcal->get(IntlCalendar::FIELD_ZONE_OFFSET)); + +/* passing NULL has no effect */ +$intlcal->setTimeZone(null); +print_r($intlcal->getTimeZone()->getID()); +echo "\n"; +var_dump($intlcal->get(IntlCalendar::FIELD_ZONE_OFFSET)); + +?> +==DONE== +--EXPECT-- +Europe/Amsterdam +int(3600000) +Europe/Amsterdam +int(3600000) +==DONE==
\ No newline at end of file diff --git a/ext/intl/tests/calendar_setTimeZone_variation2.phpt b/ext/intl/tests/calendar_setTimeZone_variation2.phpt new file mode 100644 index 0000000000..7f4a7ffa37 --- /dev/null +++ b/ext/intl/tests/calendar_setTimeZone_variation2.phpt @@ -0,0 +1,30 @@ +--TEST-- +IntlCalendar::setTimeZone(): different ways to specify time zone +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); +ini_set("intl.default_locale", "nl"); +date_default_timezone_set('Europe/Amsterdam'); + +$intlcal = new IntlGregorianCalendar(); +$intlcal->setTimeZone('Europe/Paris'); +var_dump($intlcal->getTimeZone()->getID()); +$intlcal->setTimeZone(new DateTimeZone('Europe/Madrid')); +var_dump($intlcal->getTimeZone()->getID()); + +$pstdate = new DateTime('2012-01-01 00:00:00 PST'); +$intlcal->setTimeZone($pstdate->getTimeZone()); +var_dump($intlcal->getTimeZone()->getID()); + +$offsetdate = new DateTime('2012-01-01 00:00:00 -02:30'); +$intlcal->setTimeZone($offsetdate->getTimeZone()); +var_dump($intlcal->getTimeZone()->getID()); +--EXPECTF-- +string(12) "Europe/Paris" +string(13) "Europe/Madrid" +string(3) "PST" +string(%d) "GMT-02%S30" diff --git a/ext/intl/tests/calendar_setTime_basic.phpt b/ext/intl/tests/calendar_setTime_basic.phpt new file mode 100644 index 0000000000..f7f213c0d8 --- /dev/null +++ b/ext/intl/tests/calendar_setTime_basic.phpt @@ -0,0 +1,33 @@ +--TEST-- +IntlCalendar::setTime() basic test +--INI-- +date.timezone=Atlantic/Azores +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); +ini_set("intl.default_locale", "nl"); + +$time = strtotime('2012-02-29 00:00:00 +0000'); + +$intlcal = IntlCalendar::createInstance('UTC'); +$intlcal->setTime($time * 1000); + +var_dump( + (float)$time*1000, + $intlcal->getTime()); + +$intlcal = IntlCalendar::createInstance('UTC'); +intlcal_set_time($intlcal,$time * 1000); +var_dump(intlcal_get_time($intlcal)); + +?> +==DONE== +--EXPECT-- +float(1330473600000) +float(1330473600000) +float(1330473600000) +==DONE==
\ No newline at end of file diff --git a/ext/intl/tests/calendar_setTime_error.phpt b/ext/intl/tests/calendar_setTime_error.phpt new file mode 100644 index 0000000000..71c5b0a1bd --- /dev/null +++ b/ext/intl/tests/calendar_setTime_error.phpt @@ -0,0 +1,37 @@ +--TEST-- +IntlCalendar::setTime(): bad arguments +--INI-- +date.timezone=Atlantic/Azores +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); + +$c = new IntlGregorianCalendar(NULL, 'pt_PT'); + +var_dump($c->setTime(1, 2)); +var_dump($c->setTime("jjj")); + +var_dump(intlcal_set_time($c, 1, 2)); +var_dump(intlcal_set_time(1)); +--EXPECTF-- + +Warning: IntlCalendar::setTime() expects exactly 1 parameter, 2 given in %s on line %d + +Warning: IntlCalendar::setTime(): intlcal_set_time: bad arguments in %s on line %d +bool(false) + +Warning: IntlCalendar::setTime() expects parameter 1 to be double, string given in %s on line %d + +Warning: IntlCalendar::setTime(): intlcal_set_time: bad arguments in %s on line %d +bool(false) + +Warning: intlcal_set_time() expects exactly 2 parameters, 3 given in %s on line %d + +Warning: intlcal_set_time(): intlcal_set_time: bad arguments in %s on line %d +bool(false) + +Catchable fatal error: Argument 1 passed to intlcal_set_time() must be an instance of IntlCalendar, integer given in %s on line %d diff --git a/ext/intl/tests/calendar_set_basic.phpt b/ext/intl/tests/calendar_set_basic.phpt new file mode 100644 index 0000000000..8eccb32da6 --- /dev/null +++ b/ext/intl/tests/calendar_set_basic.phpt @@ -0,0 +1,27 @@ +--TEST-- +IntlCalendar::set() basic test +--INI-- +date.timezone=Atlantic/Azores +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); +ini_set("intl.default_locale", "nl"); + +$intlcal = IntlCalendar::createInstance(); +var_dump($intlcal->set(IntlCalendar::FIELD_DAY_OF_MONTH, 2)); +var_dump($intlcal->get(IntlCalendar::FIELD_DAY_OF_MONTH)); +var_dump(intlcal_set($intlcal, IntlCalendar::FIELD_DAY_OF_MONTH, 3)); +var_dump($intlcal->get(IntlCalendar::FIELD_DAY_OF_MONTH)); + +?> +==DONE== +--EXPECT-- +bool(true) +int(2) +bool(true) +int(3) +==DONE==
\ No newline at end of file diff --git a/ext/intl/tests/calendar_set_error.phpt b/ext/intl/tests/calendar_set_error.phpt new file mode 100644 index 0000000000..669b1888e0 --- /dev/null +++ b/ext/intl/tests/calendar_set_error.phpt @@ -0,0 +1,41 @@ +--TEST-- +IntlCalendar::set(): bad arguments +--INI-- +date.timezone=Atlantic/Azores +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); + +$c = new IntlGregorianCalendar(NULL, 'pt_PT'); + +var_dump($c->set(1)); +var_dump($c->set(1, 2, 3, 4)); +var_dump($c->set(1, 2, 3, 4, 5, 6, 7)); +var_dump($c->set(-1, 2)); + +var_dump(intlcal_set($c, -1, 2)); +var_dump(intlcal_set(1, 2, 3)); +--EXPECTF-- + +Warning: IntlCalendar::set() expects at least 2 parameters, 1 given in %s on line %d + +Warning: IntlCalendar::set(): intlcal_set: bad arguments in %s on line %d +bool(false) + +Warning: IntlCalendar::set(): intlcal_set: bad arguments in %s on line %d +bool(false) + +Warning: IntlCalendar::set(): intlcal_set: too many arguments in %s on line %d +bool(false) + +Warning: IntlCalendar::set(): intlcal_set: invalid field in %s on line %d +bool(false) + +Warning: intlcal_set(): intlcal_set: invalid field in %s on line %d +bool(false) + +Catchable fatal error: Argument 1 passed to intlcal_set() must be an instance of IntlCalendar, integer given in %s on line %d diff --git a/ext/intl/tests/calendar_set_variation1.phpt b/ext/intl/tests/calendar_set_variation1.phpt new file mode 100644 index 0000000000..8ea016ed61 --- /dev/null +++ b/ext/intl/tests/calendar_set_variation1.phpt @@ -0,0 +1,41 @@ +--TEST-- +IntlCalendar::set() argument variations +--INI-- +date.timezone=Atlantic/Azores +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); +ini_set("intl.default_locale", "nl"); + +$intlcal = IntlCalendar::createInstance('UTC'); +$intlcal->clear(); +var_dump($intlcal->set(2012, 1, 29)); +var_dump($intlcal->getTime(), + strtotime('2012-02-29 00:00:00 +0000') * 1000.); + +//two minutes to midnight! +var_dump($intlcal->set(2012, 1, 29, 23, 58)); +var_dump($intlcal->getTime(), + strtotime('2012-02-29 23:58:00 +0000') * 1000.); + +var_dump($intlcal->set(2012, 1, 29, 23, 58, 31)); +var_dump($intlcal->getTime(), + strtotime('2012-02-29 23:58:31 +0000') * 1000.); + +?> +==DONE== +--EXPECT-- +bool(true) +float(1330473600000) +float(1330473600000) +bool(true) +float(1330559880000) +float(1330559880000) +bool(true) +float(1330559911000) +float(1330559911000) +==DONE==
\ No newline at end of file diff --git a/ext/intl/tests/calendar_toDateTime_basic.phpt b/ext/intl/tests/calendar_toDateTime_basic.phpt new file mode 100644 index 0000000000..d38487dabf --- /dev/null +++ b/ext/intl/tests/calendar_toDateTime_basic.phpt @@ -0,0 +1,23 @@ +--TEST-- +IntlCalendar::toDateTime(): basic test +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); +//ini_set("intl.default_locale", "nl"); +ini_set('date.timezone', 'Europe/Lisbon'); + +$cal = new IntlGregorianCalendar(2012,04,17,17,35,36); + +$dt = $cal->toDateTime(); + +var_dump($dt->format("c"), $dt->getTimeZone()->getName()); +?> +==DONE== +--EXPECT-- +string(25) "2012-05-17T17:35:36+01:00" +string(13) "Europe/Lisbon" +==DONE==
\ No newline at end of file diff --git a/ext/intl/tests/calendar_toDateTime_error.phpt b/ext/intl/tests/calendar_toDateTime_error.phpt new file mode 100644 index 0000000000..961a9c86a6 --- /dev/null +++ b/ext/intl/tests/calendar_toDateTime_error.phpt @@ -0,0 +1,41 @@ +--TEST-- +IntlCalendar::toDateTime(): bad arguments +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); +ini_set('date.timezone', 'Europe/Lisbon'); + +$cal = new IntlGregorianCalendar(); +var_dump($cal->toDateTime(3)); + +var_dump(intlcal_to_date_time($cal, 3)); + +$cal = new IntlGregorianCalendar("Etc/Unknown"); +try { +var_dump($cal->toDateTime()); +} catch (Exception $e) { +var_dump("exception: {$e->getMessage()}"); +} + +var_dump(intlcal_to_date_time(3)); + +--EXPECTF-- + +Warning: IntlCalendar::toDateTime() expects exactly 0 parameters, 1 given in %s on line %d + +Warning: IntlCalendar::toDateTime(): intlcal_to_date_time: bad arguments in %s on line %d +bool(false) + +Warning: intlcal_to_date_time() expects exactly 1 parameter, 2 given in %s on line %d + +Warning: intlcal_to_date_time(): intlcal_to_date_time: bad arguments in %s on line %d +bool(false) + +Warning: IntlCalendar::toDateTime(): intlcal_to_date_time: DateTimeZone constructor threw exception in %s on line %d +string(77) "exception: DateTimeZone::__construct(): Unknown or bad timezone (Etc/Unknown)" + +Catchable fatal error: Argument 1 passed to intlcal_to_date_time() must be an instance of IntlCalendar, integer given in %s on line %d diff --git a/ext/intl/tests/cpbi_clone_equality.phpt b/ext/intl/tests/cpbi_clone_equality.phpt new file mode 100644 index 0000000000..c62b452747 --- /dev/null +++ b/ext/intl/tests/cpbi_clone_equality.phpt @@ -0,0 +1,33 @@ +--TEST-- +IntlCodePointBreakIterator: clone and equality +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); +ini_set("intl.default_locale", "pt_PT"); + +$text = 'ตัวà¸à¸¢à¹ˆà¸²à¸‡à¸‚้à¸à¸„วาม'; +$text2 = 'foo'; + +$it = IntlBreakIterator::createCodePointInstance(); +$it->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 0000000000..74a07a6292 --- /dev/null +++ b/ext/intl/tests/cpbi_getLastCodePoint_basic.phpt @@ -0,0 +1,82 @@ +--TEST-- +IntlCodepointBreakIterator::getLastCodePoint(): basic test +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); +ini_set("intl.default_locale", "pt_PT"); + +$text = 'ตัวà¸à¸¢à¹ˆà¸²à¸‡à¸‚้à¸à¸„วาม'; + +$codepoint_it = IntlBreakIterator::createCodePointInstance(); +$codepoint_it->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 0000000000..78bd216629 --- /dev/null +++ b/ext/intl/tests/cpbi_getLastCodePoint_error.phpt @@ -0,0 +1,19 @@ +--TEST-- +IntlBreakIterator::getLastCodePoint(): bad args +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); + +$it = IntlBreakIterator::createCodePointInstance(); +var_dump($it->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 0000000000..4754c12371 --- /dev/null +++ b/ext/intl/tests/cpbi_parts_iterator.phpt @@ -0,0 +1,40 @@ +--TEST-- +IntlCodepointBreakIterator's part iterator +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); +ini_set("intl.default_locale", "pt_PT"); + +$text = 'ตัวà¸à¸¢à¹ˆà¸²à¸‡à¸‚้à¸à¸„วาม'; + +$it = IntlBreakIterator::createCodePointInstance()->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== diff --git a/ext/intl/tests/dateformat___construct_bad_tz_cal.phpt b/ext/intl/tests/dateformat___construct_bad_tz_cal.phpt new file mode 100644 index 0000000000..1f682ddb4a --- /dev/null +++ b/ext/intl/tests/dateformat___construct_bad_tz_cal.phpt @@ -0,0 +1,28 @@ +--TEST-- +IntlDateFormatter::__construct(): bad timezone or calendar +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); +ini_set("intl.default_locale", "pt_PT"); +ini_set("date.timezone", 'Atlantic/Azores'); + +var_dump(new IntlDateFormatter(NULL, 0, 0, 'bad timezone')); + +var_dump(new IntlDateFormatter(NULL, 0, 0, NULL, 3)); + +var_dump(new IntlDateFormatter(NULL, 0, 0, NULL, new stdclass)); + + +?> +==DONE== +--EXPECTF-- + +Warning: IntlDateFormatter::__construct(): datefmt_create: no such time zone: 'bad timezone' in %s on line %d +NULL + +Warning: IntlDateFormatter::__construct(): datefmt_create: invalid value for calendar type; it must be one of IntlDateFormatter::TRADITIONAL (locale's default calendar) or IntlDateFormatter::GREGORIAN. Alternatively, it can be an IntlCalendar object in %s on line %d +NULL + +Warning: IntlDateFormatter::__construct(): datefmt_create: Invalid calendar argument; should be an integer or an IntlCalendar instance in %s on line %d +NULL +==DONE== diff --git a/ext/intl/tests/dateformat_calendars.phpt b/ext/intl/tests/dateformat_calendars.phpt index 27f380c718..6af02e51c1 100644 --- a/ext/intl/tests/dateformat_calendars.phpt +++ b/ext/intl/tests/dateformat_calendars.phpt @@ -41,5 +41,5 @@ string(44) "Sunday, January 1, 2012 5:12:00 AM GMT+05:12" string(44) "Sunday, January 1, 2012 5:12:00 AM GMT+05:12" string(42) "Sunday, Tevet 6, 5772 5:12:00 AM GMT+05:12" -Warning: IntlDateFormatter::__construct(): datefmt_create: invalid value for calendar type; it must be one of IntlDateFormatter::TRADITIONAL (locale's default calendar) or IntlDateFormatter::GREGORIAN in %s on line %d +Warning: IntlDateFormatter::__construct(): datefmt_create: invalid value for calendar type; it must be one of IntlDateFormatter::TRADITIONAL (locale's default calendar) or IntlDateFormatter::GREGORIAN. Alternatively, it can be an IntlCalendar object in %s on line %d ==DONE== diff --git a/ext/intl/tests/dateformat_create_cal_arg.phpt b/ext/intl/tests/dateformat_create_cal_arg.phpt new file mode 100644 index 0000000000..8e5f942a6b --- /dev/null +++ b/ext/intl/tests/dateformat_create_cal_arg.phpt @@ -0,0 +1,49 @@ +--TEST-- +IntlDateFormatter: several forms of the calendar arg +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); +ini_set("intl.default_locale", "pt_PT"); +ini_set("date.timezone", 'Atlantic/Azores'); + +$ts = strtotime('2012-01-01 00:00:00 UTC'); + +$cal = new IntlGregorianCalendar('UTC', NULL); +$df = new IntlDateFormatter('es_ES', 0, 0, NULL, $cal); +echo $df->format($ts), "\n"; + +$cal = IntlCalendar::createInstance('UTC', 'en@calendar=islamic'); +$df = new IntlDateFormatter('es_ES', 0, 0, NULL, $cal); +echo $df->format($ts), "\n"; + +//override calendar's timezone +$cal = new IntlGregorianCalendar('UTC', NULL); +$df = new IntlDateFormatter('es_ES', 0, 0, 'Europe/Madrid', $cal); +echo $df->format($ts), "\n"; + +//default calendar is gregorian +$df = new IntlDateFormatter('es_ES@calendar=islamic', 0, 0); +echo $df->format($ts), "\n"; + +//try now with traditional +$df = new IntlDateFormatter('es_ES@calendar=islamic', 0, 0, NULL, IntlDateFormatter::TRADITIONAL); +echo $df->format($ts), "\n"; + +//the timezone can be overridden when not specifying a calendar +$df = new IntlDateFormatter('es_ES@calendar=islamic', 0, 0, 'UTC', IntlDateFormatter::TRADITIONAL); +echo $df->format($ts), "\n"; + +$df = new IntlDateFormatter('es_ES', 0, 0, 'UTC', 0); +echo $df->format($ts), "\n"; + +?> +==DONE== +--EXPECT-- +domingo, 1 de enero de 2012 00:00:00 GMT +domingo, 8 de Safar de 1433 00:00:00 GMT +domingo, 1 de enero de 2012 01:00:00 Hora estándar de Europa Central +sábado, 31 de diciembre de 2011 d.C. 23:00:00 Hora estándar de las Azores +sábado, 7 de Safar de 1433 AH 23:00:00 Hora estándar de las Azores +domingo, 8 de Safar de 1433 AH 00:00:00 GMT +domingo, 1 de enero de 2012 00:00:00 GMT +==DONE== diff --git a/ext/intl/tests/dateformat_format.phpt b/ext/intl/tests/dateformat_format.phpt index e5548196d1..98f9d34c03 100755 --- a/ext/intl/tests/dateformat_format.phpt +++ b/ext/intl/tests/dateformat_format.phpt @@ -5,6 +5,8 @@ datefmt_format_code() --FILE-- <?php +//ini_set("intl.error_level", E_WARNING); + /* * Test for the datefmt_format function */ @@ -12,7 +14,7 @@ datefmt_format_code() function ut_main() { - $timezone = 'GMT-10'; + $timezone = 'GMT-10:00'; $locale_arr = array ( 'en_US' diff --git a/ext/intl/tests/dateformat_format_parse.phpt b/ext/intl/tests/dateformat_format_parse.phpt index bd41d715b9..6bd3d8a8ff 100755 --- a/ext/intl/tests/dateformat_format_parse.phpt +++ b/ext/intl/tests/dateformat_format_parse.phpt @@ -12,7 +12,7 @@ datefmt_format_code() and datefmt_parse_code() function ut_main() { - $timezone = 'GMT+5'; + $timezone = 'GMT+05:00'; $locale_arr = array ( 'en_US' diff --git a/ext/intl/tests/dateformat_getCalendarObject_error.phpt b/ext/intl/tests/dateformat_getCalendarObject_error.phpt new file mode 100644 index 0000000000..22f12cb3fd --- /dev/null +++ b/ext/intl/tests/dateformat_getCalendarObject_error.phpt @@ -0,0 +1,39 @@ +--TEST-- +IntlDateFormatter::getCalendarObject(): bad args +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); +ini_set("intl.default_locale", "pt_PT"); +ini_set("date.timezone", 'Atlantic/Azores'); + +$df = new IntlDateFormatter(NULL, 0, 0); + +var_dump($df->getCalendarObject(9)); +var_dump(datefmt_get_calendar_object($df, 9)); +var_dump(datefmt_get_calendar_object($df, 9)); +var_dump(datefmt_get_calendar_object(new stdclass)); + +?> +==DONE== +--EXPECTF-- + +Warning: IntlDateFormatter::getCalendarObject() expects exactly 0 parameters, 1 given in %s on line %d + +Warning: IntlDateFormatter::getCalendarObject(): datefmt_get_calendar_object: unable to parse input params in %s on line %d +bool(false) + +Warning: datefmt_get_calendar_object() expects exactly 1 parameter, 2 given in %s on line %d + +Warning: datefmt_get_calendar_object(): datefmt_get_calendar_object: unable to parse input params in %s on line %d +bool(false) + +Warning: datefmt_get_calendar_object() expects exactly 1 parameter, 2 given in %s on line %d + +Warning: datefmt_get_calendar_object(): datefmt_get_calendar_object: unable to parse input params in %s on line %d +bool(false) + +Warning: datefmt_get_calendar_object() expects parameter 1 to be IntlDateFormatter, object given in %s on line %d + +Warning: datefmt_get_calendar_object(): datefmt_get_calendar_object: unable to parse input params in %s on line %d +bool(false) +==DONE== diff --git a/ext/intl/tests/dateformat_getTimeZone_error.phpt b/ext/intl/tests/dateformat_getTimeZone_error.phpt new file mode 100644 index 0000000000..c9d49fde43 --- /dev/null +++ b/ext/intl/tests/dateformat_getTimeZone_error.phpt @@ -0,0 +1,39 @@ +--TEST-- +IntlDateFormatter::getTimeZone(): bad args +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); +ini_set("intl.default_locale", "pt_PT"); +ini_set("date.timezone", 'Atlantic/Azores'); + +$df = new IntlDateFormatter(NULL, 0, 0); + +var_dump($df->getTimeZone(9)); +var_dump(datefmt_get_timezone($df, 9)); +var_dump(datefmt_get_timezone($df, 9)); +var_dump(datefmt_get_timezone(new stdclass)); + +?> +==DONE== +--EXPECTF-- + +Warning: IntlDateFormatter::getTimeZone() expects exactly 0 parameters, 1 given in %s on line %d + +Warning: IntlDateFormatter::getTimeZone(): datefmt_get_timezone: unable to parse input params in %s on line %d +bool(false) + +Warning: datefmt_get_timezone() expects exactly 1 parameter, 2 given in %s on line %d + +Warning: datefmt_get_timezone(): datefmt_get_timezone: unable to parse input params in %s on line %d +bool(false) + +Warning: datefmt_get_timezone() expects exactly 1 parameter, 2 given in %s on line %d + +Warning: datefmt_get_timezone(): datefmt_get_timezone: unable to parse input params in %s on line %d +bool(false) + +Warning: datefmt_get_timezone() expects parameter 1 to be IntlDateFormatter, object given in %s on line %d + +Warning: datefmt_get_timezone(): datefmt_get_timezone: unable to parse input params in %s on line %d +bool(false) +==DONE== diff --git a/ext/intl/tests/dateformat_get_set_calendar.phpt b/ext/intl/tests/dateformat_get_set_calendar.phpt index bfd4e578e1..e792ea3799 100755 --- a/ext/intl/tests/dateformat_get_set_calendar.phpt +++ b/ext/intl/tests/dateformat_get_set_calendar.phpt @@ -1,60 +1,51 @@ --TEST-- -datefmt_get_calendar_code() datefmt_set_calendar_code() ---SKIPIF-- -<?php if( !extension_loaded( 'intl' ) ) print 'skip'; ?> +IntlDateFormatter: setCalendar()/getCalendar()/getCalendarObject() --FILE-- <?php +ini_set("intl.error_level", E_WARNING); +ini_set("intl.default_locale", "pt_PT"); +ini_set("date.timezone", 'Atlantic/Azores'); + +$ts = strtotime('2012-01-01 00:00:00 UTC'); + +function d(IntlDateFormatter $df) { +global $ts; +echo $df->format($ts), "\n"; +var_dump($df->getCalendar(), +$df->getCalendarObject()->getType(), +$df->getCalendarObject()->getTimeZone()->getId()); +echo "\n"; +} -/* - * Test for the datefmt_get_calendar and datefmt_set_calendar functions - */ - - -function ut_main() -{ - $calendar_arr = array ( - IntlDateFormatter::GREGORIAN, - IntlDateFormatter::TRADITIONAL, - 3 - ); - - $res_str = ''; - - $start_calendar = IntlDateFormatter::GREGORIAN; - $res_str .= "\nCreating IntlDateFormatter with calendar = $start_calendar"; - $fmt = ut_datefmt_create( "de-DE", IntlDateFormatter::SHORT, IntlDateFormatter::SHORT ,'America/Los_Angeles', IntlDateFormatter::GREGORIAN); - $calendar = ut_datefmt_get_calendar( $fmt); - $res_str .= "\nAfter call to get_calendar : calendar= $calendar"; - $res_str .= "\n-------------------"; - - foreach( $calendar_arr as $calendar_entry ) - { - $res_str .= "\nSetting IntlDateFormatter with calendar = $calendar_entry"; - ut_datefmt_set_calendar( $fmt, $calendar_entry); - $calendar = ut_datefmt_get_calendar( $fmt); - $res_str .= "\nAfter call to get_calendar : calendar= $calendar"; - $res_str .= "\n-------------------"; - } - - return $res_str; +$df = new IntlDateFormatter('fr@calendar=islamic', 0, 0, 'Europe/Minsk'); +d($df); -} -include_once( 'ut_common.inc' ); +//changing the calendar with a cal type should not change tz +$df->setCalendar(IntlDateFormatter::TRADITIONAL); +d($df); + +//but changing with an actual calendar should +$cal = IntlCalendar::createInstance("UTC"); +$df->setCalendar($cal); +d($df); -// Run the test -ut_run(); ?> +==DONE== --EXPECT-- -Creating IntlDateFormatter with calendar = 1 -After call to get_calendar : calendar= 1 -------------------- -Setting IntlDateFormatter with calendar = 1 -After call to get_calendar : calendar= 1 -------------------- -Setting IntlDateFormatter with calendar = 0 -After call to get_calendar : calendar= 0 -------------------- -Setting IntlDateFormatter with calendar = 3 -After call to get_calendar : calendar= 0 --------------------
\ No newline at end of file +dimanche 1 janvier 2012 ap. J.-C. 03:00:00 UTC+03:00 +int(1) +string(9) "gregorian" +string(12) "Europe/Minsk" + +dimanche 8 Safar 1433 AH 03:00:00 UTC+03:00 +int(0) +string(7) "islamic" +string(12) "Europe/Minsk" + +dimanche 1 janvier 2012 ap. J.-C. 00:00:00 UTC +bool(false) +string(9) "gregorian" +string(3) "UTC" + +==DONE== diff --git a/ext/intl/tests/dateformat_get_set_timezone.phpt b/ext/intl/tests/dateformat_get_set_timezone.phpt new file mode 100644 index 0000000000..50b036e36e --- /dev/null +++ b/ext/intl/tests/dateformat_get_set_timezone.phpt @@ -0,0 +1,58 @@ +--TEST-- +IntlDateFormatter: get/setTimeZone() +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); +ini_set("intl.default_locale", "pt_PT"); +ini_set("date.timezone", 'Atlantic/Azores'); + +$ts = strtotime('2012-01-01 00:00:00 UTC'); + +function d(IntlDateFormatter $df) { +global $ts; +echo $df->format($ts), "\n"; +var_dump( +$df->getTimeZoneID(), +$df->getTimeZone()->getID()); +echo "\n"; +} + +$df = new IntlDateFormatter('pt_PT', 0, 0, 'Europe/Minsk'); +d($df); + +$df->setTimeZone(NULL); +d($df); + +$df->setTimeZone('Europe/Madrid'); +d($df); + +$df->setTimeZone(IntlTimeZone::createTimeZone('Europe/Paris')); +d($df); + +$df->setTimeZone(new DateTimeZone('Europe/Amsterdam')); +d($df); + +?> +==DONE== +--EXPECT-- +Domingo, 1 de Janeiro de 2012 3:00:00 GMT+03:00 +string(12) "Europe/Minsk" +string(12) "Europe/Minsk" + +Sábado, 31 de Dezembro de 2011 23:00:00 Hora Padrão dos Açores +string(15) "Atlantic/Azores" +string(15) "Atlantic/Azores" + +Domingo, 1 de Janeiro de 2012 1:00:00 Hora Padrão da Europa Central +string(13) "Europe/Madrid" +string(13) "Europe/Madrid" + +Domingo, 1 de Janeiro de 2012 1:00:00 Hora Padrão da Europa Central +string(12) "Europe/Paris" +string(12) "Europe/Paris" + +Domingo, 1 de Janeiro de 2012 1:00:00 Hora Padrão da Europa Central +string(16) "Europe/Amsterdam" +string(16) "Europe/Amsterdam" + +==DONE== diff --git a/ext/intl/tests/dateformat_get_timezone_id.phpt b/ext/intl/tests/dateformat_get_timezone_id.phpt index 80cbdbbf0f..a9701c3868 100755 --- a/ext/intl/tests/dateformat_get_timezone_id.phpt +++ b/ext/intl/tests/dateformat_get_timezone_id.phpt @@ -1,5 +1,8 @@ --TEST-- datefmt_get_timezone_id_code() +--INI-- +date.timezone=Atlantic/Azores +intl.error_level=E_WARNING --SKIPIF-- <?php if( !extension_loaded( 'intl' ) ) print 'skip'; ?> --FILE-- @@ -14,8 +17,8 @@ function ut_main() { $timezone_id_arr = array ( 'America/New_York', - 'America/Los_Angeles', - 'America/Dallas' + 'US/Pacific', + 'US/Central' ); $res_str = ''; @@ -42,8 +45,8 @@ ut_run(); Creating IntlDateFormatter with timezone_id = America/New_York After call to get_timezone_id : timezone_id= America/New_York -Creating IntlDateFormatter with timezone_id = America/Los_Angeles -After call to get_timezone_id : timezone_id= America/Los_Angeles +Creating IntlDateFormatter with timezone_id = US/Pacific +After call to get_timezone_id : timezone_id= US/Pacific -Creating IntlDateFormatter with timezone_id = America/Dallas -After call to get_timezone_id : timezone_id= America/Dallas +Creating IntlDateFormatter with timezone_id = US/Central +After call to get_timezone_id : timezone_id= US/Central diff --git a/ext/intl/tests/dateformat_setTimeZoneID_deprecation.phpt b/ext/intl/tests/dateformat_setTimeZoneID_deprecation.phpt new file mode 100644 index 0000000000..ccc477d075 --- /dev/null +++ b/ext/intl/tests/dateformat_setTimeZoneID_deprecation.phpt @@ -0,0 +1,18 @@ +--TEST-- +IntlDateFormatter: setTimeZoneID() deprecation +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); +ini_set("intl.default_locale", "pt_PT"); +ini_set("date.timezone", 'Atlantic/Azores'); + +$df = new IntlDateFormatter('pt_PT', 0, 0, 'Europe/Minsk'); + +$df->setTimeZoneId('Europe/Madrid'); + +?> +==DONE== +--EXPECTF-- + +Deprecated: IntlDateFormatter::setTimeZoneId(): Use datefmt_set_timezone() instead, which also accepts a plain time zone identifier and for which this function is now an alias in %s on line %d +==DONE== diff --git a/ext/intl/tests/dateformat_setTimeZone_error.phpt b/ext/intl/tests/dateformat_setTimeZone_error.phpt new file mode 100644 index 0000000000..8200197948 --- /dev/null +++ b/ext/intl/tests/dateformat_setTimeZone_error.phpt @@ -0,0 +1,49 @@ +--TEST-- +IntlDateFormatter::setTimeZone() bad args +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); +ini_set("intl.default_locale", "pt_PT"); +ini_set("date.timezone", 'Atlantic/Azores'); + +$df = new IntlDateFormatter(NULL, 0, 0); + +var_dump($df->setTimeZone()); +var_dump(datefmt_set_timezone()); +var_dump($df->setTimeZone(array())); +var_dump($df->setTimeZone(1, 2)); +var_dump($df->setTimeZone('non existing timezone')); +var_dump(datefmt_set_timezone(new stdclass, 'UTC')); + +?> +==DONE== +--EXPECTF-- + +Warning: IntlDateFormatter::setTimeZone() expects exactly 1 parameter, 0 given in %s on line %d + +Warning: IntlDateFormatter::setTimeZone(): datefmt_set_timezone: unable to parse input params in %s on line %d +bool(false) + +Warning: datefmt_set_timezone() expects exactly 2 parameters, 0 given in %s on line %d + +Warning: datefmt_set_timezone(): datefmt_set_timezone: unable to parse input params in %s on line %d +bool(false) + +Notice: Array to string conversion in %s on line %d + +Warning: IntlDateFormatter::setTimeZone(): datefmt_set_timezone: no such time zone: 'Array' in %s on line %d +bool(false) + +Warning: IntlDateFormatter::setTimeZone() expects exactly 1 parameter, 2 given in %s on line %d + +Warning: IntlDateFormatter::setTimeZone(): datefmt_set_timezone: unable to parse input params in %s on line %d +bool(false) + +Warning: IntlDateFormatter::setTimeZone(): datefmt_set_timezone: no such time zone: 'non existing timezone' in %s on line %d +bool(false) + +Warning: datefmt_set_timezone() expects parameter 1 to be IntlDateFormatter, object given in %s on line %d + +Warning: datefmt_set_timezone(): datefmt_set_timezone: unable to parse input params in %s on line %d +bool(false) +==DONE== diff --git a/ext/intl/tests/dateformat_set_timezone_id2.phpt b/ext/intl/tests/dateformat_set_timezone_id2.phpt index 23aacda90a..ce9b89d1fd 100644 --- a/ext/intl/tests/dateformat_set_timezone_id2.phpt +++ b/ext/intl/tests/dateformat_set_timezone_id2.phpt @@ -1,11 +1,16 @@ --TEST-- datefmt_set_timezone_id_code() icu >= 4.8 +--INI-- +date.timezone=Atlantic/Azores --SKIPIF-- <?php if( !extension_loaded( 'intl' ) ) print 'skip'; ?> <?php if(version_compare(INTL_ICU_VERSION, '4.8') < 0) print 'skip'; ?> --FILE-- <?php +ini_set("intl.error_level", E_WARNING); +ini_set("error_reporting", ~E_DEPRECATED); + /* * Test for the datefmt_set_timezone_id function */ @@ -23,7 +28,7 @@ function ut_main() $res_str = ''; - $fmt = ut_datefmt_create( "en_US", IntlDateFormatter::FULL, IntlDateFormatter::FULL, 'America/San_Francisco' , IntlDateFormatter::GREGORIAN ); + $fmt = ut_datefmt_create( "en_US", IntlDateFormatter::FULL, IntlDateFormatter::FULL, 'US/Pacific' , IntlDateFormatter::GREGORIAN ); $timezone_id = ut_datefmt_get_timezone_id( $fmt ); $res_str .= "\nAfter creation of the dateformatter : timezone_id= $timezone_id\n"; @@ -52,8 +57,13 @@ include_once( 'ut_common.inc' ); // Run the test ut_run(); ?> ---EXPECT-- -After creation of the dateformatter : timezone_id= America/San_Francisco +--EXPECTF-- + +Warning: IntlDateFormatter::setTimeZoneId(): datefmt_set_timezone: no such time zone: 'CN' in %s on line %d + +Warning: datefmt_set_timezone_id(): datefmt_set_timezone: no such time zone: 'CN' in %s on line %d + +After creation of the dateformatter : timezone_id= US/Pacific ----------- Trying to set timezone_id= America/New_York After call to set_timezone_id : timezone_id= America/New_York @@ -71,6 +81,6 @@ Formatting timestamp=0 resulted in Wednesday, December 31, 1969 6:00:00 PM Cent Formatting timestamp=3600 resulted in Wednesday, December 31, 1969 7:00:00 PM Central Standard Time ----------- Trying to set timezone_id= CN -After call to set_timezone_id : timezone_id= CN -Formatting timestamp=0 resulted in Thursday, January 1, 1970 12:00:00 AM GMT -Formatting timestamp=3600 resulted in Thursday, January 1, 1970 1:00:00 AM GMT +After call to set_timezone_id : timezone_id= America/Chicago +Formatting timestamp=0 resulted in Wednesday, December 31, 1969 6:00:00 PM Central Standard Time +Formatting timestamp=3600 resulted in Wednesday, December 31, 1969 7:00:00 PM Central Standard Time diff --git a/ext/intl/tests/dateformat_timezone_arg_variations.phpt b/ext/intl/tests/dateformat_timezone_arg_variations.phpt new file mode 100644 index 0000000000..df3ebd853d --- /dev/null +++ b/ext/intl/tests/dateformat_timezone_arg_variations.phpt @@ -0,0 +1,41 @@ +--TEST-- +IntlDateFormatter: several forms of the timezone arg +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); +ini_set("date.timezone", 'Atlantic/Azores'); + +$ts = strtotime('2012-01-01 00:00:00 UTC'); + +//should use Atlantic/Azores +$df = new IntlDateFormatter('es_ES', 0, 0, NULL); +echo $df->format($ts), "\n"; + +$df = new IntlDateFormatter('es_ES', 0, 0, 'Europe/Amsterdam'); +echo $df->format($ts), "\n"; + +$df = new IntlDateFormatter('es_ES', 0, 0, new DateTimeZone('Europe/Lisbon')); +echo $df->format($ts), "\n"; + +$df = new IntlDateFormatter('es_ES', 0, 0, IntlTimeZone::createTimeZone('America/New_York')); +echo $df->format($ts), "\n"; + +//time zone has priority +$df = new IntlDateFormatter('es_ES', 0, 0, 'Europe/Amsterdam', new IntlGregorianCalendar('Europe/Lisbon')); +echo $df->format($ts), "\n"; + +//calendar has priority +$df = new IntlDateFormatter('es_ES', 0, 0, NULL, new IntlGregorianCalendar('Europe/Lisbon')); +echo $df->format($ts), "\n"; + +$df = new IntlDateFormatter('es_ES', 0, 0, 'Europe/Amsterdam', 0); +echo $df->format($ts), "\n"; + +--EXPECTF-- +sábado%S 31 de diciembre de 2011 23:00:00 Hora%S de las Azores +domingo%S 1 de enero de 2012 01:00:00 Hora estándar de Europa Central +domingo%S 1 de enero de 2012 00:00:00 Hora%S de Europa Occidental +sábado%S 31 de diciembre de 2011 19:00:00 Hora estándar oriental +domingo%S 1 de enero de 2012 01:00:00 Hora estándar de Europa Central +domingo%S 1 de enero de 2012 00:00:00 Hora%S de Europa Occidental +domingo%S 1 de enero de 2012 01:00:00 Hora estándar de Europa Central diff --git a/ext/intl/tests/gregoriancalendar___construct_basic.phpt b/ext/intl/tests/gregoriancalendar___construct_basic.phpt new file mode 100644 index 0000000000..bdbef6725b --- /dev/null +++ b/ext/intl/tests/gregoriancalendar___construct_basic.phpt @@ -0,0 +1,51 @@ +--TEST-- +IntlGregorianCalendar::__construct(): basic +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +if (version_compare(INTL_ICU_VERSION, '4.8') < 0) + die('skip for ICU 4.8+'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); +ini_set("intl.default_locale", "nl"); + +date_default_timezone_set('Europe/Amsterdam'); + +$intlcal = intlgregcal_create_instance(); +var_dump($intlcal->getTimeZone()->getId()); +var_dump($intlcal->getLocale(1)); + +$intlcal = new IntlGregorianCalendar('Europe/Lisbon', NULL); +var_dump($intlcal->getTimeZone()->getId()); +var_dump($intlcal->getLocale(1)); + +$intlcal = new IntlGregorianCalendar(NULL, 'pt_PT'); +var_dump($intlcal->getTimeZone()->getId()); +var_dump($intlcal->getLocale(1)); + +$intlcal = new IntlGregorianCalendar('Europe/Lisbon', 'pt_PT'); +var_dump($intlcal->getTimeZone()->getId()); +var_dump($intlcal->getLocale(1)); + +$intlcal = new IntlGregorianCalendar('Europe/Paris', 'fr_CA', NULL, NULL, NULL, NULL); +var_dump($intlcal->getTimeZone()->getId()); +var_dump($intlcal->getLocale(1)); + +var_dump($intlcal->getType()); +?> +==DONE== +--EXPECT-- +string(16) "Europe/Amsterdam" +string(5) "nl_NL" +string(13) "Europe/Lisbon" +string(5) "nl_NL" +string(16) "Europe/Amsterdam" +string(5) "pt_PT" +string(13) "Europe/Lisbon" +string(5) "pt_PT" +string(12) "Europe/Paris" +string(5) "fr_CA" +string(9) "gregorian" +==DONE==
\ No newline at end of file diff --git a/ext/intl/tests/gregoriancalendar___construct_error.phpt b/ext/intl/tests/gregoriancalendar___construct_error.phpt new file mode 100644 index 0000000000..0e85394a48 --- /dev/null +++ b/ext/intl/tests/gregoriancalendar___construct_error.phpt @@ -0,0 +1,35 @@ +--TEST-- +IntlGregorianCalendar::__construct(): bad arguments +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); + +var_dump(intlgregcal_create_instance(1,2,3,4,5,6,7)); +var_dump(intlgregcal_create_instance(1,2,3,4,5,6,7,8)); +var_dump(intlgregcal_create_instance(1,2,3,4)); +var_dump(new IntlGregorianCalendar(1,2,NULL,4)); +var_dump(new IntlGregorianCalendar(1,2,3,4,NULL,array())); + + +--EXPECTF-- + +Warning: intlgregcal_create_instance(): intlgregcal_create_instance: too many arguments in %s on line %d +NULL + +Warning: intlgregcal_create_instance(): intlgregcal_create_instance: too many arguments in %s on line %d +NULL + +Warning: intlgregcal_create_instance(): intlgregcal_create_instance: no variant with 4 arguments (excluding trailing NULLs) in %s on line %d +NULL + +Warning: IntlGregorianCalendar::__construct(): intlgregcal_create_instance: no variant with 4 arguments (excluding trailing NULLs) in %s on line %d +NULL + +Warning: IntlGregorianCalendar::__construct() expects parameter 6 to be long, array given in %s on line %d + +Warning: IntlGregorianCalendar::__construct(): intlgregcal_create_instance: bad arguments in %s on line %d +NULL diff --git a/ext/intl/tests/gregoriancalendar___construct_variant1.phpt b/ext/intl/tests/gregoriancalendar___construct_variant1.phpt new file mode 100644 index 0000000000..63266b792e --- /dev/null +++ b/ext/intl/tests/gregoriancalendar___construct_variant1.phpt @@ -0,0 +1,30 @@ +--TEST-- +IntlGregorianCalendar::__construct(): argument variants +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); + +date_default_timezone_set('Europe/Amsterdam'); + +$intlcal = intlgregcal_create_instance(2012, 1, 29, 16, 0, NULL); +var_dump($intlcal->getTimeZone()->getId()); +var_dump($intlcal->getTime(), (float)strtotime('2012-02-29 16:00:00') * 1000); + +$intlcal = new IntlGregorianCalendar(2012, 1, 29, 16, 7, 8); +var_dump($intlcal->getTime(), (float)strtotime('2012-02-29 16:07:08') * 1000); + +var_dump($intlcal->getType()); +?> +==DONE== +--EXPECT-- +string(16) "Europe/Amsterdam" +float(1330527600000) +float(1330527600000) +float(1330528028000) +float(1330528028000) +string(9) "gregorian" +==DONE== diff --git a/ext/intl/tests/gregoriancalendar_getGregorianChange_error.phpt b/ext/intl/tests/gregoriancalendar_getGregorianChange_error.phpt new file mode 100644 index 0000000000..58d566223b --- /dev/null +++ b/ext/intl/tests/gregoriancalendar_getGregorianChange_error.phpt @@ -0,0 +1,30 @@ +--TEST-- +IntlGregorianCalendar::getGregorianChange(): bad arguments +--INI-- +date.timezone=Atlantic/Azores +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); + +$c = new IntlGregorianCalendar(NULL, 'pt_PT'); +var_dump($c->getGregorianChange(1)); + +var_dump(intlgregcal_get_gregorian_change($c, 1)); +var_dump(intlgregcal_get_gregorian_change(1)); +--EXPECTF-- + +Warning: IntlGregorianCalendar::getGregorianChange() expects exactly 0 parameters, 1 given in %s on line %d + +Warning: IntlGregorianCalendar::getGregorianChange(): intlgregcal_get_gregorian_change: bad arguments in %s on line %d +bool(false) + +Warning: intlgregcal_get_gregorian_change() expects exactly 1 parameter, 2 given in %s on line %d + +Warning: intlgregcal_get_gregorian_change(): intlgregcal_get_gregorian_change: bad arguments in %s on line %d +bool(false) + +Catchable fatal error: Argument 1 passed to intlgregcal_get_gregorian_change() must be an instance of IntlGregorianCalendar, integer given in %s on line %d diff --git a/ext/intl/tests/gregoriancalendar_get_setGregorianChange_basic.phpt b/ext/intl/tests/gregoriancalendar_get_setGregorianChange_basic.phpt new file mode 100644 index 0000000000..b08ad7981f --- /dev/null +++ b/ext/intl/tests/gregoriancalendar_get_setGregorianChange_basic.phpt @@ -0,0 +1,32 @@ +--TEST-- +IntlGregorianCalendar::get/setGregorianChange(): basic test +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); +ini_set("intl.default_locale", "nl"); + +date_default_timezone_set('Europe/Amsterdam'); + +$intlcal = new IntlGregorianCalendar(); + +var_dump($intlcal->getGregorianChange()); + +var_dump($intlcal->setGregorianChange(0)); +var_dump(intlgregcal_get_gregorian_change($intlcal)); + +var_dump(intlgregcal_set_gregorian_change($intlcal, 1)); +var_dump($intlcal->getGregorianChange()); + +?> +==DONE== +--EXPECT-- +float(-12219292800000) +bool(true) +float(0) +bool(true) +float(1) +==DONE==
\ No newline at end of file diff --git a/ext/intl/tests/gregoriancalendar_isLeapYear_basic.phpt b/ext/intl/tests/gregoriancalendar_isLeapYear_basic.phpt new file mode 100644 index 0000000000..b37452fcba --- /dev/null +++ b/ext/intl/tests/gregoriancalendar_isLeapYear_basic.phpt @@ -0,0 +1,28 @@ +--TEST-- +IntlGregorianCalendar::isLeapYear(): basic test +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); +ini_set("intl.default_locale", "nl"); + +date_default_timezone_set('Europe/Amsterdam'); + +$intlcal = new IntlGregorianCalendar(); + +var_dump($intlcal->isLeapYear(2012)); +var_dump($intlcal->isLeapYear(1900)); + +var_dump(intlgregcal_is_leap_year($intlcal, 2012)); +var_dump(intlgregcal_is_leap_year($intlcal, 1900)); +?> +==DONE== +--EXPECT-- +bool(true) +bool(false) +bool(true) +bool(false) +==DONE==
\ No newline at end of file diff --git a/ext/intl/tests/gregoriancalendar_isLeapYear_error.phpt b/ext/intl/tests/gregoriancalendar_isLeapYear_error.phpt new file mode 100644 index 0000000000..40a6c85396 --- /dev/null +++ b/ext/intl/tests/gregoriancalendar_isLeapYear_error.phpt @@ -0,0 +1,48 @@ +--TEST-- +IntlGregorianCalendar::isLeapYear(): bad arguments +--INI-- +date.timezone=Atlantic/Azores +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); + +$c = new IntlGregorianCalendar(NULL, 'pt_PT'); +var_dump($c->isLeapYear(2000, 2011)); +var_dump($c->isLeapYear()); +var_dump($c->isLeapYear("fgdf")); + +var_dump(intlgregcal_is_leap_year($c, 1, 2)); +var_dump(intlgregcal_is_leap_year($c)); +var_dump(intlgregcal_is_leap_year(1, 2)); +--EXPECTF-- + +Warning: IntlGregorianCalendar::isLeapYear() expects exactly 1 parameter, 2 given in %s on line %d + +Warning: IntlGregorianCalendar::isLeapYear(): intlgregcal_is_leap_year: bad arguments in %s on line %d +bool(false) + +Warning: IntlGregorianCalendar::isLeapYear() expects exactly 1 parameter, 0 given in %s on line %d + +Warning: IntlGregorianCalendar::isLeapYear(): intlgregcal_is_leap_year: bad arguments in %s on line %d +bool(false) + +Warning: IntlGregorianCalendar::isLeapYear() expects parameter 1 to be long, string given in %s on line %d + +Warning: IntlGregorianCalendar::isLeapYear(): intlgregcal_is_leap_year: bad arguments in %s on line %d +bool(false) + +Warning: intlgregcal_is_leap_year() expects exactly 2 parameters, 3 given in %s on line %d + +Warning: intlgregcal_is_leap_year(): intlgregcal_is_leap_year: bad arguments in %s on line %d +bool(false) + +Warning: intlgregcal_is_leap_year() expects exactly 2 parameters, 1 given in %s on line %d + +Warning: intlgregcal_is_leap_year(): intlgregcal_is_leap_year: bad arguments in %s on line %d +bool(false) + +Catchable fatal error: Argument 1 passed to intlgregcal_is_leap_year() must be an instance of IntlGregorianCalendar, integer given in %s on line %d diff --git a/ext/intl/tests/gregoriancalendar_setGregorianChange_error.phpt b/ext/intl/tests/gregoriancalendar_setGregorianChange_error.phpt new file mode 100644 index 0000000000..eac8deb61b --- /dev/null +++ b/ext/intl/tests/gregoriancalendar_setGregorianChange_error.phpt @@ -0,0 +1,42 @@ +--TEST-- +IntlGregorianCalendar::setGregorianChange(): bad arguments +--INI-- +date.timezone=Atlantic/Azores +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); + +$c = new IntlGregorianCalendar(); +var_dump($c->setGregorianChange()); +var_dump($c->setGregorianChange(1, 2)); +var_dump($c->setGregorianChange("sdfds")); + +var_dump(intlgregcal_set_gregorian_change($c)); +var_dump(intlgregcal_set_gregorian_change(1, 4.)); +--EXPECTF-- + +Warning: IntlGregorianCalendar::setGregorianChange() expects exactly 1 parameter, 0 given in %s on line %d + +Warning: IntlGregorianCalendar::setGregorianChange(): intlgregcal_set_gregorian_change: bad arguments in %s on line %d +bool(false) + +Warning: IntlGregorianCalendar::setGregorianChange() expects exactly 1 parameter, 2 given in %s on line %d + +Warning: IntlGregorianCalendar::setGregorianChange(): intlgregcal_set_gregorian_change: bad arguments in %s on line %d +bool(false) + +Warning: IntlGregorianCalendar::setGregorianChange() expects parameter 1 to be double, string given in %s on line %d + +Warning: IntlGregorianCalendar::setGregorianChange(): intlgregcal_set_gregorian_change: bad arguments in %s on line %d +bool(false) + +Warning: intlgregcal_set_gregorian_change() expects exactly 2 parameters, 1 given in %s on line %d + +Warning: intlgregcal_set_gregorian_change(): intlgregcal_set_gregorian_change: bad arguments in %s on line %d +bool(false) + +Catchable fatal error: Argument 1 passed to intlgregcal_set_gregorian_change() must be an instance of IntlGregorianCalendar, integer given in %s on line %d diff --git a/ext/intl/tests/ini_use_exceptions_basic.phpt b/ext/intl/tests/ini_use_exceptions_basic.phpt new file mode 100644 index 0000000000..36ccbcb8a0 --- /dev/null +++ b/ext/intl/tests/ini_use_exceptions_basic.phpt @@ -0,0 +1,21 @@ +--TEST-- +intl.use_exceptions INI setting +--SKIPIF-- +<?php if( !extension_loaded( 'intl' ) ) print 'skip'; ?> +--FILE-- +<?php +ini_set("intl.use_exceptions", true); +$t = transliterator_create('any-hex'); +try { + var_dump($t->transliterate('a', 3)); +} catch (IntlException $intlE) { + var_dump($intlE->getMessage()); +} +ini_set("intl.use_exceptions", false); +ini_set("intl.error_level", E_NOTICE); +var_dump($t->transliterate('a', 3)); +--EXPECTF-- +string(130) "transliterator_transliterate: Neither "start" nor the "end" arguments can exceed the number of UTF-16 code units (in this case, 1)" + +Notice: Transliterator::transliterate(): transliterator_transliterate: Neither "start" nor the "end" arguments can exceed the number of UTF-16 code units (in this case, 1) in %s on line %d +bool(false) diff --git a/ext/intl/tests/locale_get_display_script2.phpt b/ext/intl/tests/locale_get_display_script2.phpt index 92652bde90..2b9e037b78 100644 --- a/ext/intl/tests/locale_get_display_script2.phpt +++ b/ext/intl/tests/locale_get_display_script2.phpt @@ -1,8 +1,8 @@ --TEST-- -locale_get_display_script() icu >= 4.8 +locale_get_display_script() icu = 4.8 --SKIPIF-- <?php if( !extension_loaded( 'intl' ) ) print 'skip'; ?> -<?php if(version_compare(INTL_ICU_VERSION, '4.8') < 0) print 'skip'; ?> +<?php if(version_compare(INTL_ICU_VERSION, '4.8') < 0 || version_compare(INTL_ICU_VERSION, '49') >= 0) print 'skip'; ?> --FILE-- <?php diff --git a/ext/intl/tests/locale_get_display_script3.phpt b/ext/intl/tests/locale_get_display_script3.phpt new file mode 100644 index 0000000000..447766e6bd --- /dev/null +++ b/ext/intl/tests/locale_get_display_script3.phpt @@ -0,0 +1,275 @@ +--TEST-- +locale_get_display_script() icu >= 49 +--SKIPIF-- +<?php if( !extension_loaded( 'intl' ) ) print 'skip'; ?> +<?php if(version_compare(INTL_ICU_VERSION, '49') < 0) print 'skip'; ?> +--FILE-- +<?php + +/* + * Try getting the display_script for different locales + * with Procedural and Object methods. + */ + +function ut_main() +{ + $res_str = ''; + + $disp_locales=array('en','fr','de'); + + $locales = array( + 'uk-ua_CALIFORNIA@currency=;currency=GRN', + 'root', + 'uk@currency=EURO', + 'Hindi', +//Simple language subtag + 'de', + 'fr', + 'ja', + 'i-enochian', //(example of a grandfathered tag) +//Language subtag plus Script subtag: + 'zh-Hant', + 'zh-Hans', + 'sr-Cyrl', + 'sr-Latn', +//Language-Script-Region + 'zh-Hans-CN', + 'sr-Latn-CS', +//Language-Variant + 'sl-rozaj', + 'sl-nedis', +//Language-Region-Variant + 'de-CH-1901', + 'sl-IT-nedis', +//Language-Script-Region-Variant + 'sl-Latn-IT-nedis', +//Language-Region: + 'de-DE', + 'en-US', + 'es-419', +//Private use subtags: + 'de-CH-x-phonebk', + 'az-Arab-x-AZE-derbend', +//Extended language subtags + 'zh-min', + 'zh-min-nan-Hant-CN', +//Private use registry values + 'x-whatever', + 'qaa-Qaaa-QM-x-southern', + 'sr-Latn-QM', + 'sr-Qaaa-CS', +/*Tags that use extensions (examples ONLY: extensions MUST be defined + by revision or update to this document or by RFC): */ + 'en-US-u-islamCal', + 'zh-CN-a-myExt-x-private', + 'en-a-myExt-b-another', +//Some Invalid Tags: + 'de-419-DE', + 'a-DE', + 'ar-a-aaa-b-bbb-a-ccc' + ); + + + $res_str = ''; + + foreach( $locales as $locale ) + { + $res_str .= "locale='$locale'\n"; + foreach( $disp_locales as $disp_locale ) + { + $scr = ut_loc_get_display_script( $locale ,$disp_locale ); + $res_str .= "disp_locale=$disp_locale : display_script=$scr"; + $res_str .= "\n"; + } + $res_str .= "-----------------\n"; + } + + return $res_str; + +} + +include_once( 'ut_common.inc' ); +ut_run(); + +?> +--EXPECT-- +locale='uk-ua_CALIFORNIA@currency=;currency=GRN' +disp_locale=en : display_script= +disp_locale=fr : display_script= +disp_locale=de : display_script= +----------------- +locale='root' +disp_locale=en : display_script= +disp_locale=fr : display_script= +disp_locale=de : display_script= +----------------- +locale='uk@currency=EURO' +disp_locale=en : display_script= +disp_locale=fr : display_script= +disp_locale=de : display_script= +----------------- +locale='Hindi' +disp_locale=en : display_script= +disp_locale=fr : display_script= +disp_locale=de : display_script= +----------------- +locale='de' +disp_locale=en : display_script= +disp_locale=fr : display_script= +disp_locale=de : display_script= +----------------- +locale='fr' +disp_locale=en : display_script= +disp_locale=fr : display_script= +disp_locale=de : display_script= +----------------- +locale='ja' +disp_locale=en : display_script= +disp_locale=fr : display_script= +disp_locale=de : display_script= +----------------- +locale='i-enochian' +disp_locale=en : display_script= +disp_locale=fr : display_script= +disp_locale=de : display_script= +----------------- +locale='zh-Hant' +disp_locale=en : display_script=Traditional Han +disp_locale=fr : display_script=chinois traditionnel +disp_locale=de : display_script=Traditionelles Chinesisch +----------------- +locale='zh-Hans' +disp_locale=en : display_script=Simplified Han +disp_locale=fr : display_script=chinois simplifié +disp_locale=de : display_script=Vereinfachtes Chinesisch +----------------- +locale='sr-Cyrl' +disp_locale=en : display_script=Cyrillic +disp_locale=fr : display_script=cyrillique +disp_locale=de : display_script=Kyrillisch +----------------- +locale='sr-Latn' +disp_locale=en : display_script=Latin +disp_locale=fr : display_script=latin +disp_locale=de : display_script=Lateinisch +----------------- +locale='zh-Hans-CN' +disp_locale=en : display_script=Simplified Han +disp_locale=fr : display_script=chinois simplifié +disp_locale=de : display_script=Vereinfachtes Chinesisch +----------------- +locale='sr-Latn-CS' +disp_locale=en : display_script=Latin +disp_locale=fr : display_script=latin +disp_locale=de : display_script=Lateinisch +----------------- +locale='sl-rozaj' +disp_locale=en : display_script= +disp_locale=fr : display_script= +disp_locale=de : display_script= +----------------- +locale='sl-nedis' +disp_locale=en : display_script= +disp_locale=fr : display_script= +disp_locale=de : display_script= +----------------- +locale='de-CH-1901' +disp_locale=en : display_script= +disp_locale=fr : display_script= +disp_locale=de : display_script= +----------------- +locale='sl-IT-nedis' +disp_locale=en : display_script= +disp_locale=fr : display_script= +disp_locale=de : display_script= +----------------- +locale='sl-Latn-IT-nedis' +disp_locale=en : display_script=Latin +disp_locale=fr : display_script=latin +disp_locale=de : display_script=Lateinisch +----------------- +locale='de-DE' +disp_locale=en : display_script= +disp_locale=fr : display_script= +disp_locale=de : display_script= +----------------- +locale='en-US' +disp_locale=en : display_script= +disp_locale=fr : display_script= +disp_locale=de : display_script= +----------------- +locale='es-419' +disp_locale=en : display_script= +disp_locale=fr : display_script= +disp_locale=de : display_script= +----------------- +locale='de-CH-x-phonebk' +disp_locale=en : display_script= +disp_locale=fr : display_script= +disp_locale=de : display_script= +----------------- +locale='az-Arab-x-AZE-derbend' +disp_locale=en : display_script=Arabic +disp_locale=fr : display_script=arabe +disp_locale=de : display_script=Arabisch +----------------- +locale='zh-min' +disp_locale=en : display_script= +disp_locale=fr : display_script= +disp_locale=de : display_script= +----------------- +locale='zh-min-nan-Hant-CN' +disp_locale=en : display_script= +disp_locale=fr : display_script= +disp_locale=de : display_script= +----------------- +locale='x-whatever' +disp_locale=en : display_script= +disp_locale=fr : display_script= +disp_locale=de : display_script= +----------------- +locale='qaa-Qaaa-QM-x-southern' +disp_locale=en : display_script=Qaaa +disp_locale=fr : display_script=Qaaa +disp_locale=de : display_script=Qaaa +----------------- +locale='sr-Latn-QM' +disp_locale=en : display_script=Latin +disp_locale=fr : display_script=latin +disp_locale=de : display_script=Lateinisch +----------------- +locale='sr-Qaaa-CS' +disp_locale=en : display_script=Qaaa +disp_locale=fr : display_script=Qaaa +disp_locale=de : display_script=Qaaa +----------------- +locale='en-US-u-islamCal' +disp_locale=en : display_script= +disp_locale=fr : display_script= +disp_locale=de : display_script= +----------------- +locale='zh-CN-a-myExt-x-private' +disp_locale=en : display_script= +disp_locale=fr : display_script= +disp_locale=de : display_script= +----------------- +locale='en-a-myExt-b-another' +disp_locale=en : display_script= +disp_locale=fr : display_script= +disp_locale=de : display_script= +----------------- +locale='de-419-DE' +disp_locale=en : display_script= +disp_locale=fr : display_script= +disp_locale=de : display_script= +----------------- +locale='a-DE' +disp_locale=en : display_script= +disp_locale=fr : display_script= +disp_locale=de : display_script= +----------------- +locale='ar-a-aaa-b-bbb-a-ccc' +disp_locale=en : display_script= +disp_locale=fr : display_script= +disp_locale=de : display_script= +----------------- diff --git a/ext/intl/tests/msgfmt_format_datetime.phpt b/ext/intl/tests/msgfmt_format_datetime.phpt new file mode 100644 index 0000000000..07e7d68f14 --- /dev/null +++ b/ext/intl/tests/msgfmt_format_datetime.phpt @@ -0,0 +1,28 @@ +--TEST-- +MessageFormatter::format(): DateTime accepted to format dates and times +--INI-- +date.timezone=Atlantic/Azores +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); +//ini_set("intl.default_locale", "nl"); + +$fmt = <<<EOD +{0,date} {0,time} +EOD; + +$dt = new DateTime("2012-05-06 18:00:42", new DateTimeZone("Europe/Lisbon")); + +$mf = new MessageFormatter('en_US', $fmt); + +var_dump($mf->format(array($dt))); + +?> +==DONE== +--EXPECTF-- +string(%s) "May %d, 2012 %d:%d:42 %s" +==DONE== diff --git a/ext/intl/tests/msgfmt_format_error1.phpt b/ext/intl/tests/msgfmt_format_error1.phpt new file mode 100644 index 0000000000..684b05970a --- /dev/null +++ b/ext/intl/tests/msgfmt_format_error1.phpt @@ -0,0 +1,19 @@ +--TEST-- +MessageFormatter::format() insufficient numeric arguments +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); + +$fmt = <<<EOD +{0} {1} +EOD; + +$mf = new MessageFormatter('en_US', $fmt); +var_dump($mf->format(array(7))); + +--EXPECTF-- +string(5) "7 {1}" diff --git a/ext/intl/tests/msgfmt_format_error2.phpt b/ext/intl/tests/msgfmt_format_error2.phpt new file mode 100644 index 0000000000..85d1b1c83d --- /dev/null +++ b/ext/intl/tests/msgfmt_format_error2.phpt @@ -0,0 +1,23 @@ +--TEST-- +MessageFormatter::format() inconsistent types in named argument +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +if (version_compare(INTL_ICU_VERSION, '4.8') < 0) + die('skip for ICU 4.8+'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); + +$fmt = <<<EOD +{foo,number} {foo} +EOD; + +$mf = new MessageFormatter('en_US', $fmt); +var_dump($mf->format(array(7))); + +--EXPECTF-- + +Warning: MessageFormatter::format(): Inconsistent types declared for an argument in %s on line %d +bool(false) diff --git a/ext/intl/tests/msgfmt_format_error3.phpt b/ext/intl/tests/msgfmt_format_error3.phpt new file mode 100644 index 0000000000..6dfbee3c90 --- /dev/null +++ b/ext/intl/tests/msgfmt_format_error3.phpt @@ -0,0 +1,23 @@ +--TEST-- +MessageFormatter::format() given negative arg key +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +if (version_compare(INTL_ICU_VERSION, '4.8') < 0) + die('skip for ICU 4.8+'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); + +$fmt = <<<EOD +{foo,number,percent} +EOD; + +$mf = new MessageFormatter('en_US', $fmt); +var_dump($mf->format(array("foo" => 7, -1 => "bar"))); + +--EXPECTF-- + +Warning: MessageFormatter::format(): Found negative or too large array key in %s on line %d +bool(false) diff --git a/ext/intl/tests/msgfmt_format_error4.phpt b/ext/intl/tests/msgfmt_format_error4.phpt new file mode 100644 index 0000000000..3b92b48b8b --- /dev/null +++ b/ext/intl/tests/msgfmt_format_error4.phpt @@ -0,0 +1,28 @@ +--TEST-- +MessageFormatter::format() invalid UTF-8 for arg key or value +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +if (version_compare(INTL_ICU_VERSION, '4.8') < 0) + die('skip for ICU 4.8+'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); + +$fmt = <<<EOD +{foo} +EOD; + +$mf = new MessageFormatter('en_US', $fmt); +var_dump($mf->format(array("foo" => 7, "\x80" => "bar"))); + +var_dump($mf->format(array("foo" => "\x80"))); + +--EXPECTF-- + +Warning: MessageFormatter::format(): Invalid UTF-8 data in argument key: '€' in %s on line %d +bool(false) + +Warning: MessageFormatter::format(): Invalid UTF-8 data in string argument: '€' in %s on line %d +bool(false) diff --git a/ext/intl/tests/msgfmt_format_error5.phpt b/ext/intl/tests/msgfmt_format_error5.phpt new file mode 100644 index 0000000000..052d0efd11 --- /dev/null +++ b/ext/intl/tests/msgfmt_format_error5.phpt @@ -0,0 +1,25 @@ +--TEST-- +MessageFormatter::format() invalid date/time argument +--INI-- +date.timezone=Atlantic/Azores +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +if (version_compare(INTL_ICU_VERSION, '4.8') < 0) + die('skip for ICU 4.8+'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); + +$fmt = <<<EOD +{foo,date} +EOD; + +$mf = new MessageFormatter('en_US', $fmt); +var_dump($mf->format(array("foo" => new stdclass()))); + +--EXPECTF-- + +Warning: MessageFormatter::format(): The argument for key 'foo' cannot be used as a date or time in %s on line %d +bool(false) diff --git a/ext/intl/tests/msgfmt_format_error6.phpt b/ext/intl/tests/msgfmt_format_error6.phpt new file mode 100644 index 0000000000..b07d2ab774 --- /dev/null +++ b/ext/intl/tests/msgfmt_format_error6.phpt @@ -0,0 +1,23 @@ +--TEST-- +MessageFormatter::format() invalid type for key not in pattern +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +if (version_compare(INTL_ICU_VERSION, '4.8') < 0) + die('skip for ICU 4.8+'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); + +$fmt = <<<EOD +{foo} +EOD; + +$mf = new MessageFormatter('en_US', $fmt); +var_dump($mf->format(array("foo" => 'bar', 7 => fopen('php://memory', 'r+')))); + +--EXPECTF-- + +Warning: MessageFormatter::format(): No strategy to convert the value given for the argument with key '7' is available in %s on line %d +bool(false) diff --git a/ext/intl/tests/msgfmt_format_intlcalendar.phpt b/ext/intl/tests/msgfmt_format_intlcalendar.phpt new file mode 100644 index 0000000000..6ae78a9140 --- /dev/null +++ b/ext/intl/tests/msgfmt_format_intlcalendar.phpt @@ -0,0 +1,30 @@ +--TEST-- +MessageFormat accepts IntlCalendar args +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); +//ini_set("intl.default_locale", "nl"); +ini_set('date.timezone', 'Europe/Lisbon'); + +$cal = new IntlGregorianCalendar(2012,04,17,17,35,36); + +$msgf = new MessageFormatter('pt_PT', '{0,date,full} {0,time,h:m:s a V}'); +echo $msgf->format(array($cal)), "\n"; + +//NOT FIXED: +/*$msgf = new MessageFormatter('en_US', +'{1, select, date {{0,date,full}} other {{0,time,h:m:s a V}}}'); + +echo "msgf2: ", $msgf->format(array($time, 'date')), " ", + $msgf->format(array($time, 'time')), "\n"; +*/ + +?> +==DONE== +--EXPECT-- +Quinta-feira, 17 de Maio de 2012 5:35:36 p.m. WEST +==DONE==
\ No newline at end of file diff --git a/ext/intl/tests/msgfmt_format_mixed_params.phpt b/ext/intl/tests/msgfmt_format_mixed_params.phpt new file mode 100644 index 0000000000..93412f49e2 --- /dev/null +++ b/ext/intl/tests/msgfmt_format_mixed_params.phpt @@ -0,0 +1,25 @@ +--TEST-- +MessageFormatter::format(): mixed named and numeric parameters +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +if (version_compare(INTL_ICU_VERSION, '4.8') < 0) + die('skip for ICU 4.8+'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); +//ini_set("intl.default_locale", "nl"); + +$mf = new MessageFormatter('en_US', + "{0,number} -- {foo,ordinal}"); + +var_dump($mf->format(array(2.3, "foo" => 1.3))); +var_dump($mf->format(array("foo" => 1.3, 0 => 2.3))); + +?> +==DONE== +--EXPECT-- +string(10) "2.3 -- 1st" +string(10) "2.3 -- 1st" +==DONE==
\ No newline at end of file diff --git a/ext/intl/tests/msgfmt_format_simple_types_numeric_strings.phpt b/ext/intl/tests/msgfmt_format_simple_types_numeric_strings.phpt new file mode 100644 index 0000000000..299ae483a4 --- /dev/null +++ b/ext/intl/tests/msgfmt_format_simple_types_numeric_strings.phpt @@ -0,0 +1,58 @@ +--TEST-- +MessageFormatter::format(): simple types handling with numeric strings +--INI-- +date.timezone=Atlantic/Azores +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +if (version_compare(INTL_ICU_VERSION, '4.8') < 0) + die('skip for ICU 4.8+'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); +//ini_set("intl.default_locale", "nl"); + +$mf = new MessageFormatter('en_US'," + none {a} + number {b,number} + number integer {c,number,integer} + number currency {d,number,currency} + number percent {e,number,percent} + date {f,date} + time {g,time} + spellout {h,spellout} + ordinal {i,ordinal} + duration {j,duration} + "); + +$ex = "1336317965.5 str"; +var_dump($mf->format(array( +'a' => $ex, +'b' => $ex, +'c' => $ex, +'d' => $ex, +'e' => $ex, +'f' => " 1336317965.5", +'g' => " 1336317965.5", +'h' => $ex, +'i' => $ex, +'j' => $ex, +))); + +?> +==DONE== +--EXPECTF-- +string(%d) " + none 1336317965.5 str + number 1,336,317,965.5 + number integer 1,336,317,965 + number currency $1,336,317,965.50 + number percent 133,631,796,550% + date May %d, 2012 + time %d:%d:05 PM + spellout one billion three hundred thirty-six million three hundred seventeen thousand nine hundred sixty-five point five + ordinal 1,336,317,966th + duration 371,199:26:06 + " +==DONE== diff --git a/ext/intl/tests/msgfmt_format_subpatterns.phpt b/ext/intl/tests/msgfmt_format_subpatterns.phpt new file mode 100644 index 0000000000..9f11e3e255 --- /dev/null +++ b/ext/intl/tests/msgfmt_format_subpatterns.phpt @@ -0,0 +1,75 @@ +--TEST-- +msgfmt_format() with subpatterns +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +if (version_compare(INTL_ICU_VERSION, '4.8') < 0) + die('skip for ICU 4.8+'); +--FILE-- +<?php + +/* + * Format a number using misc locales/patterns. + */ + + +function ut_main() +{ + +$pattern=<<<_MSG_ +{0, select, + female {{1, plural, offset:1 + =0 {{2} does not give a party.} + =1 {{2} invites {3} to her party.} + =2 {{2} invites {3} and one other person to her party.} + other {{2} invites {3} as one of the # people invited to her party.}}} + male {{1, plural, offset:1 + =0 {{2} does not give a party.} + =1 {{2} invites {3} to his party.} + =2 {{2} invites {3} and one other person to his party.} + other {{2} invites {3} as one of the # other people invited to his party.}}} + other {{1, plural, offset:1 + =0 {{2} does not give a party.} + =1 {{2} invites {3} to their party.} + =2 {{2} invites {3} and one other person to their party.} + other {{2} invites {3} as one of the # other people invited to their party.}}}} +_MSG_; + + +$args = array( + array('female', 0, 'Alice', 'Bob'), + array('male', 1, 'Alice', 'Bob'), + array('none', 2, 'Alice', 'Bob'), + array('female', 27, 'Alice', 'Bob'), +); + +$str_res = ''; + + $fmt = ut_msgfmt_create( 'en_US', $pattern ); + if(!$fmt) { + $str_res .= dump(intl_get_error_message())."\n"; + return $str_res; + } + foreach ($args as $arg) { + $str_res .= dump( ut_msgfmt_format($fmt, $arg) ). "\n"; + $str_res .= dump( ut_msgfmt_format_message('en_US', $pattern, $arg) ) . "\n"; + } + return $str_res; +} + +include_once( 'ut_common.inc' ); + +// Run the test +ut_run(); + +?> +--EXPECT-- +'Alice does not give a party.' +'Alice does not give a party.' +'Alice invites Bob to his party.' +'Alice invites Bob to his party.' +'Alice invites Bob and one other person to their party.' +'Alice invites Bob and one other person to their party.' +'Alice invites Bob as one of the 26 people invited to her party.' +'Alice invites Bob as one of the 26 people invited to her party.' diff --git a/ext/intl/tests/msgfmt_format_subpatterns_named.phpt b/ext/intl/tests/msgfmt_format_subpatterns_named.phpt new file mode 100644 index 0000000000..f6af02561b --- /dev/null +++ b/ext/intl/tests/msgfmt_format_subpatterns_named.phpt @@ -0,0 +1,75 @@ +--TEST-- +msgfmt_format() with named subpatterns +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +if (version_compare(INTL_ICU_VERSION, '4.8') < 0) + die('skip for ICU 4.8+'); +--FILE-- +<?php + +/* + * Format a number using misc locales/patterns. + */ + + +function ut_main() +{ + +$pattern=<<<_MSG_ +{gender_of_host, select, + female {{num_guests, plural, offset:1 + =0 {{host} does not give a party.} + =1 {{host} invites {guest} to her party.} + =2 {{host} invites {guest} and one other person to her party.} + other {{host} invites {guest} as one of the # people invited to her party.}}} + male {{num_guests, plural, offset:1 + =0 {{host} does not give a party.} + =1 {{host} invites {guest} to his party.} + =2 {{host} invites {guest} and one other person to his party.} + other {{host} invites {guest} as one of the # people invited to his party.}}} + other {{num_guests, plural, offset:1 + =0 {{host} does not give a party.} + =1 {{host} invites {guest} to their party.} + =2 {{host} invites {guest} and one other person to their party.} + other {{host} invites {guest} as one of the # people invited to their party.}}}} +_MSG_; + + +$args = array( + array('gender_of_host' => 'female', 'num_guests' => 0, 'host' => 'Alice', 'guest' => 'Bob'), + array('gender_of_host' => 'male', 'num_guests' => 1, 'host' => 'Alice', 'guest' => 'Bob'), + array('gender_of_host' => 'none', 'num_guests' => 2, 'host' => 'Alice', 'guest' => 'Bob'), + array('gender_of_host' => 'female', 'num_guests' => 27, 'host' => 'Alice', 'guest' => 'Bob'), +); + +$str_res = ''; + + $fmt = ut_msgfmt_create( 'en_US', $pattern ); + if(!$fmt) { + $str_res .= dump(intl_get_error_message())."\n"; + return $str_res; + } + foreach ($args as $arg) { + $str_res .= dump( ut_msgfmt_format($fmt, $arg) ). "\n"; + $str_res .= dump( ut_msgfmt_format_message('en_US', $pattern, $arg) ) . "\n"; + } + return $str_res; +} + +include_once( 'ut_common.inc' ); + +// Run the test +ut_run(); + +?> +--EXPECT-- +'Alice does not give a party.' +'Alice does not give a party.' +'Alice invites Bob to his party.' +'Alice invites Bob to his party.' +'Alice invites Bob and one other person to their party.' +'Alice invites Bob and one other person to their party.' +'Alice invites Bob as one of the 26 people invited to her party.' +'Alice invites Bob as one of the 26 people invited to her party.' diff --git a/ext/intl/tests/msgfmt_get_error.phpt b/ext/intl/tests/msgfmt_get_error.phpt deleted file mode 100755 index 015c50d465..0000000000 --- a/ext/intl/tests/msgfmt_get_error.phpt +++ /dev/null @@ -1,29 +0,0 @@ ---TEST-- -msgmfmt_get_error_message/code() ---SKIPIF-- -<?php if( !extension_loaded( 'intl' ) ) print 'skip'; ?> ---FILE-- -<?php - -/* - * Error handling. - */ - - -function ut_main() -{ - $fmt = ut_msgfmt_create( "en_US", "{0, number} monkeys on {1, number} trees" ); - $num = ut_msgfmt_format( $fmt, array()); - if( $num === false ) - return $fmt->getErrorMessage() . " (" . $fmt->getErrorCode() . ")\n"; - else - return "Ooops, an error should have occured."; -} - -include_once( 'ut_common.inc' ); - -// Run the test -ut_run(); -?> ---EXPECT-- -msgfmt_format: not enough parameters: U_ILLEGAL_ARGUMENT_ERROR (1) diff --git a/ext/intl/tests/msgfmt_millisecond_dates.phpt b/ext/intl/tests/msgfmt_millisecond_dates.phpt new file mode 100644 index 0000000000..7dd051426b --- /dev/null +++ b/ext/intl/tests/msgfmt_millisecond_dates.phpt @@ -0,0 +1,29 @@ +--TEST-- +MessageFrormatter parses and formats dates with millisecond precision +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); +date_default_timezone_set('Europe/Lisbon'); //ignored for now, see bug #58756 + +$d = 1336308097.123; +$mf = new MessageFormatter('en_US', + "On {0,time,yyyy-MM-dd G 'at' HH:mm:ss.SSS zzz} something odd happened"); + +var_dump($mf->format(array(1336310569.123))); + +$p = 'On 2012-05-06 AD at 15:22:49.123 GMT+02:00 something odd happened'; +var_dump($mf->parse($p)); + +?> +==DONE== +--EXPECTF-- +string(%d) "On 2012-05-0%d AD at %d:%d:49.123 %s something odd happened" +array(1) { + [0]=> + float(1336310569.123) +} +==DONE== diff --git a/ext/intl/tests/msgfmt_setPattern_cache.phpt b/ext/intl/tests/msgfmt_setPattern_cache.phpt new file mode 100644 index 0000000000..35ec463c2a --- /dev/null +++ b/ext/intl/tests/msgfmt_setPattern_cache.phpt @@ -0,0 +1,26 @@ +--TEST-- +MessageFormatter::setPattern() invalidates arg types cache +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); +//ini_set("intl.default_locale", "nl"); + +$mf = new MessageFormatter('en_US', + "{0,number} -- {1,ordinal}"); + +var_dump($mf->format(array(1.3, 1.3))); +var_dump($mf->format(array(1.3, 1.3))); +$mf->setPattern("{0,ordinal} -- {1,number}"); +var_dump($mf->format(array(1.3, 1.3))); + +?> +==DONE== +--EXPECT-- +string(10) "1.3 -- 1st" +string(10) "1.3 -- 1st" +string(10) "1st -- 1.3" +==DONE==
\ No newline at end of file diff --git a/ext/intl/tests/rbbiter___construct_basic.phpt b/ext/intl/tests/rbbiter___construct_basic.phpt new file mode 100644 index 0000000000..2b14d826e3 --- /dev/null +++ b/ext/intl/tests/rbbiter___construct_basic.phpt @@ -0,0 +1,27 @@ +--TEST-- +IntlRuleBasedBreakIterator::__construct: basic test +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); +ini_set("intl.default_locale", "pt_PT"); + +$rules = <<<RULES +\$LN = [[:letter:] [:number:]]; +\$S = [.;,:]; + +!!forward; +\$LN+ {1}; +\$S+ {42}; +!!reverse; +\$LN+ {1}; +\$S+ {42}; +!!safe_forward; +!!safe_reverse; +RULES; +$rbbi = new IntlRuleBasedBreakIterator($rules); +var_dump(get_class($rbbi)); +?> +==DONE== +--EXPECT-- +string(26) "IntlRuleBasedBreakIterator" +==DONE==
\ No newline at end of file diff --git a/ext/intl/tests/rbbiter_getBinaryRules_basic.phpt b/ext/intl/tests/rbbiter_getBinaryRules_basic.phpt new file mode 100644 index 0000000000..dce0714d4d --- /dev/null +++ b/ext/intl/tests/rbbiter_getBinaryRules_basic.phpt @@ -0,0 +1,39 @@ +--TEST-- +IntlRuleBasedBreakIterator::getBinaryRules(): basic test +--SKIPIF-- +<?php if( !extension_loaded( 'intl' ) ) print 'skip'; ?> +<?php if(version_compare(INTL_ICU_VERSION, '4.8') < 0) print 'skip ICU >= 4.8 only'; ?> +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); +ini_set("intl.default_locale", "pt_PT"); + +$rules = <<<RULES +\$LN = [[:letter:] [:number:]]; +\$S = [.;,:]; + +!!forward; +\$LN+ {1}; +\$S+ {42}; +!!reverse; +\$LN+ {1}; +\$S+ {42}; +!!safe_forward; +!!safe_reverse; +RULES; +$rbbi = new IntlRuleBasedBreakIterator($rules); +$rbbi->setText('sdfkjsdf88á.... ,;');; + +$br = $rbbi->getBinaryRules(); + +$rbbi2 = new IntlRuleBasedBreakIterator($br, true); + +var_dump($rbbi->getRules(), $rbbi2->getRules()); +var_dump($rbbi->getRules() == $rbbi2->getRules()); +?> +==DONE== +--EXPECT-- +string(128) "$LN = [[:letter:] [:number:]];$S = [.;,:];!!forward;$LN+ {1};$S+ {42};!!reverse;$LN+ {1};$S+ {42};!!safe_forward;!!safe_reverse;" +string(128) "$LN = [[:letter:] [:number:]];$S = [.;,:];!!forward;$LN+ {1};$S+ {42};!!reverse;$LN+ {1};$S+ {42};!!safe_forward;!!safe_reverse;" +bool(true) +==DONE== diff --git a/ext/intl/tests/rbbiter_getRuleStatusVec_basic.phpt b/ext/intl/tests/rbbiter_getRuleStatusVec_basic.phpt new file mode 100644 index 0000000000..a4f3352f9a --- /dev/null +++ b/ext/intl/tests/rbbiter_getRuleStatusVec_basic.phpt @@ -0,0 +1,55 @@ +--TEST-- +IntlRuleBasedBreakIterator::getRuleStatusVec(): basic test +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); +ini_set("intl.default_locale", "pt_PT"); + +$rules = <<<RULES +\$LN = [[:letter:] [:number:]]; +\$S = [.;,:]; + +!!forward; +\$LN+ {1}; +[^.]+ {4}; +\$S+ {42}; +!!reverse; +\$LN+ {1}; +[^.]+ {4}; +\$S+ {42}; +!!safe_forward; +!!safe_reverse; +RULES; +$rbbi = new IntlRuleBasedBreakIterator($rules); +$rbbi->setText('sdfkjsdf88á.... ,;');; + +do { + var_dump($rbbi->current(), $rbbi->getRuleStatusVec()); +} while ($rbbi->next() != IntlBreakIterator::DONE); + +?> +==DONE== +--EXPECT-- +int(0) +array(1) { + [0]=> + int(0) +} +int(12) +array(2) { + [0]=> + int(1) + [1]=> + int(4) +} +int(16) +array(1) { + [0]=> + int(42) +} +int(19) +array(1) { + [0]=> + int(4) +} +==DONE==
\ No newline at end of file diff --git a/ext/intl/tests/rbbiter_getRuleStatus_basic.phpt b/ext/intl/tests/rbbiter_getRuleStatus_basic.phpt new file mode 100644 index 0000000000..6199fdee7c --- /dev/null +++ b/ext/intl/tests/rbbiter_getRuleStatus_basic.phpt @@ -0,0 +1,42 @@ +--TEST-- +IntlRuleBasedBreakIterator::getRuleStatus(): basic test +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); +ini_set("intl.default_locale", "pt_PT"); + +$rules = <<<RULES +\$LN = [[:letter:] [:number:]]; +\$S = [.;,:]; + +!!forward; +\$LN+ {1}; +\$S+ {42}; +!!reverse; +\$LN+ {1}; +\$S+ {42}; +!!safe_forward; +!!safe_reverse; +RULES; +$rbbi = new IntlRuleBasedBreakIterator($rules); +$rbbi->setText('sdfkjsdf88á.... ,;'); + +do { + echo "pos : {$rbbi->current()}\n", + "rule status: {$rbbi->getRuleStatus()}\n"; +} while ($rbbi->next() != IntlBreakIterator::DONE); + +?> +==DONE== +--EXPECT-- +pos : 0 +rule status: 0 +pos : 12 +rule status: 1 +pos : 16 +rule status: 42 +pos : 17 +rule status: 0 +pos : 19 +rule status: 42 +==DONE==
\ No newline at end of file diff --git a/ext/intl/tests/rbbiter_getRules_basic.phpt b/ext/intl/tests/rbbiter_getRules_basic.phpt new file mode 100644 index 0000000000..e115e9b9e2 --- /dev/null +++ b/ext/intl/tests/rbbiter_getRules_basic.phpt @@ -0,0 +1,28 @@ +--TEST-- +IntlRuleBasedBreakIterator::getRules(): basic test +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); +ini_set("intl.default_locale", "pt_PT"); + +$rules = <<<RULES +\$LN = [[:letter:] [:number:]]; +\$S = [.;,:]; + +!!forward; +\$LN+ {1}; +\$S+ {42}; +!!reverse; +\$LN+ {1}; +\$S+ {42}; +!!safe_forward; +!!safe_reverse; +RULES; +$rbbi = new IntlRuleBasedBreakIterator($rules); +var_dump($rbbi->getRules()); + +?> +==DONE== +--EXPECT-- +string(128) "$LN = [[:letter:] [:number:]];$S = [.;,:];!!forward;$LN+ {1};$S+ {42};!!reverse;$LN+ {1};$S+ {42};!!safe_forward;!!safe_reverse;" +==DONE==
\ No newline at end of file diff --git a/ext/intl/tests/timezone_clone_basic.phpt b/ext/intl/tests/timezone_clone_basic.phpt new file mode 100644 index 0000000000..a8ef83f864 --- /dev/null +++ b/ext/intl/tests/timezone_clone_basic.phpt @@ -0,0 +1,51 @@ +--TEST-- +IntlTimeZone clone handler: basic test +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); + +$tz1 = IntlTimeZone::createTimeZone('Europe/Amsterdam'); +print_r($tz1); +print_r(clone $tz1); + +//clone non-owned object +$gmt = IntlTimeZone::getGMT(); +print_r($gmt); +print_r(clone $gmt); + +?> +==DONE== +--EXPECTF-- +IntlTimeZone Object +( + [valid] => 1 + [id] => Europe/Amsterdam + [rawOffset] => 3600000 + [currentOffset] => %d +) +IntlTimeZone Object +( + [valid] => 1 + [id] => Europe/Amsterdam + [rawOffset] => 3600000 + [currentOffset] => %d +) +IntlTimeZone Object +( + [valid] => 1 + [id] => GMT + [rawOffset] => 0 + [currentOffset] => 0 +) +IntlTimeZone Object +( + [valid] => 1 + [id] => GMT + [rawOffset] => 0 + [currentOffset] => 0 +) +==DONE==
\ No newline at end of file diff --git a/ext/intl/tests/timezone_clone_error.phpt b/ext/intl/tests/timezone_clone_error.phpt new file mode 100644 index 0000000000..df501be3b4 --- /dev/null +++ b/ext/intl/tests/timezone_clone_error.phpt @@ -0,0 +1,32 @@ +--TEST-- +IntlTimeZone clone handler: error test +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); + +class A extends IntlTimeZone { +function __construct() {} +} + +$tz = new A(); +var_dump($tz); +try { +var_dump(clone $tz); +} catch (Exception $e) { + var_dump(get_class($e), $e->getMessage()); +} + +?> +==DONE== +--EXPECT-- +object(A)#1 (1) { + ["valid"]=> + bool(false) +} +string(9) "Exception" +string(39) "Cannot clone unconstructed IntlTimeZone" +==DONE==
\ No newline at end of file diff --git a/ext/intl/tests/timezone_countEquivalentIDs_basic.phpt b/ext/intl/tests/timezone_countEquivalentIDs_basic.phpt new file mode 100644 index 0000000000..ec3e4050ab --- /dev/null +++ b/ext/intl/tests/timezone_countEquivalentIDs_basic.phpt @@ -0,0 +1,20 @@ +--TEST-- +IntlTimeZone::countEquivalentIDs(): basic test +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); +$count = IntlTimeZone::countEquivalentIDs('Europe/Lisbon'); +var_dump($count >= 2); + +$count2 = intltz_count_equivalent_ids('Europe/Lisbon'); +var_dump($count2 == $count); +?> +==DONE== +--EXPECT-- +bool(true) +bool(true) +==DONE==
\ No newline at end of file diff --git a/ext/intl/tests/timezone_countEquivalentIDs_error.phpt b/ext/intl/tests/timezone_countEquivalentIDs_error.phpt new file mode 100644 index 0000000000..4d8f4bc3e3 --- /dev/null +++ b/ext/intl/tests/timezone_countEquivalentIDs_error.phpt @@ -0,0 +1,35 @@ +--TEST-- +IntlTimeZone::countEquivalentIDs(): errors +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); + +var_dump(IntlTimeZone::countEquivalentIDs()); +var_dump(IntlTimeZone::countEquivalentIDs(array())); +var_dump(IntlTimeZone::countEquivalentIDs("foo\x80")); +var_dump(IntlTimeZone::countEquivalentIDs("foo bar", 7)); + + +--EXPECTF-- + +Warning: IntlTimeZone::countEquivalentIDs() expects exactly 1 parameter, 0 given in %s on line %d + +Warning: IntlTimeZone::countEquivalentIDs(): intltz_count_equivalent_ids: bad arguments in %s on line %d +bool(false) + +Warning: IntlTimeZone::countEquivalentIDs() expects parameter 1 to be string, array given in %s on line %d + +Warning: IntlTimeZone::countEquivalentIDs(): intltz_count_equivalent_ids: bad arguments in %s on line %d +bool(false) + +Warning: IntlTimeZone::countEquivalentIDs(): intltz_count_equivalent_ids: could not convert time zone id to UTF-16 in %s on line %d +bool(false) + +Warning: IntlTimeZone::countEquivalentIDs() expects exactly 1 parameter, 2 given in %s on line %d + +Warning: IntlTimeZone::countEquivalentIDs(): intltz_count_equivalent_ids: bad arguments in %s on line %d +bool(false) diff --git a/ext/intl/tests/timezone_createDefault_basic.phpt b/ext/intl/tests/timezone_createDefault_basic.phpt new file mode 100644 index 0000000000..a18899fc4f --- /dev/null +++ b/ext/intl/tests/timezone_createDefault_basic.phpt @@ -0,0 +1,31 @@ +--TEST-- +IntlTimeZone::createDefault(): basic test +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); +$tz = IntlTimeZone::createDefault(); +print_r($tz); +$tz = intltz_create_default(); +print_r($tz); +?> +==DONE== +--EXPECTF-- +IntlTimeZone Object +( + [valid] => 1 + [id] => %s + [rawOffset] => %d + [currentOffset] => %d +) +IntlTimeZone Object +( + [valid] => 1 + [id] => %s + [rawOffset] => %d + [currentOffset] => %d +) +==DONE==
\ No newline at end of file diff --git a/ext/intl/tests/timezone_createDefault_error.phpt b/ext/intl/tests/timezone_createDefault_error.phpt new file mode 100644 index 0000000000..0724898219 --- /dev/null +++ b/ext/intl/tests/timezone_createDefault_error.phpt @@ -0,0 +1,19 @@ +--TEST-- +IntlTimeZone::createDefault(): errors +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); + +var_dump(IntlTimeZone::createDefault(4)); + + +--EXPECTF-- + +Warning: IntlTimeZone::createDefault() expects exactly 0 parameters, 1 given in %s on line %d + +Warning: IntlTimeZone::createDefault(): intltz_create_default: bad arguments in %s on line %d +NULL diff --git a/ext/intl/tests/timezone_createEnumeration_basic.phpt b/ext/intl/tests/timezone_createEnumeration_basic.phpt new file mode 100644 index 0000000000..2df32562b1 --- /dev/null +++ b/ext/intl/tests/timezone_createEnumeration_basic.phpt @@ -0,0 +1,26 @@ +--TEST-- +IntlTimeZone::createEnumeration(): basic test +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); +$tz = IntlTimeZone::createEnumeration(); +var_dump(get_class($tz)); +$count = count(iterator_to_array($tz)); +var_dump($count > 300); + +$tz = intltz_create_enumeration(); +var_dump(get_class($tz)); +$count2 = count(iterator_to_array($tz)); +var_dump($count == $count2); +?> +==DONE== +--EXPECT-- +string(12) "IntlIterator" +bool(true) +string(12) "IntlIterator" +bool(true) +==DONE==
\ No newline at end of file diff --git a/ext/intl/tests/timezone_createEnumeration_error.phpt b/ext/intl/tests/timezone_createEnumeration_error.phpt new file mode 100644 index 0000000000..e1e7cb9333 --- /dev/null +++ b/ext/intl/tests/timezone_createEnumeration_error.phpt @@ -0,0 +1,23 @@ +--TEST-- +IntlTimeZone::createEnumeration(): errors +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); + +var_dump(IntlTimeZone::createEnumeration(array())); +var_dump(IntlTimeZone::createEnumeration(1, 2)); + + +--EXPECTF-- + +Warning: IntlTimeZone::createEnumeration(): intltz_create_enumeration: invalid argument type in %s on line %d +bool(false) + +Warning: IntlTimeZone::createEnumeration() expects at most 1 parameter, 2 given in %s on line %d + +Warning: IntlTimeZone::createEnumeration(): intltz_create_enumeration: bad arguments in %s on line %d +bool(false) diff --git a/ext/intl/tests/timezone_createEnumeration_variation1.phpt b/ext/intl/tests/timezone_createEnumeration_variation1.phpt new file mode 100644 index 0000000000..30fc43660e --- /dev/null +++ b/ext/intl/tests/timezone_createEnumeration_variation1.phpt @@ -0,0 +1,24 @@ +--TEST-- +IntlTimeZone::createEnumeration(): variant with offset +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); +$tz = IntlTimeZone::createEnumeration(3600000); +var_dump(get_class($tz)); +$count = count(iterator_to_array($tz)); +var_dump($count > 20); + +$tz->rewind(); +var_dump(in_array('Europe/Amsterdam', iterator_to_array($tz))); + +?> +==DONE== +--EXPECT-- +string(12) "IntlIterator" +bool(true) +bool(true) +==DONE==
\ No newline at end of file diff --git a/ext/intl/tests/timezone_createEnumeration_variation2.phpt b/ext/intl/tests/timezone_createEnumeration_variation2.phpt new file mode 100644 index 0000000000..ddf1a6ece1 --- /dev/null +++ b/ext/intl/tests/timezone_createEnumeration_variation2.phpt @@ -0,0 +1,24 @@ +--TEST-- +IntlTimeZone::createEnumeration(): variant with country +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); +$tz = IntlTimeZone::createEnumeration('NL'); +var_dump(get_class($tz)); +$count = count(iterator_to_array($tz)); +var_dump($count >= 1); + +$tz->rewind(); +var_dump(in_array('Europe/Amsterdam', iterator_to_array($tz))); + +?> +==DONE== +--EXPECT-- +string(12) "IntlIterator" +bool(true) +bool(true) +==DONE==
\ No newline at end of file diff --git a/ext/intl/tests/timezone_createTimeZoneIDEnumeration_basic.phpt b/ext/intl/tests/timezone_createTimeZoneIDEnumeration_basic.phpt new file mode 100644 index 0000000000..9ceffc5289 --- /dev/null +++ b/ext/intl/tests/timezone_createTimeZoneIDEnumeration_basic.phpt @@ -0,0 +1,34 @@ +--TEST-- +IntlTimeZone::createTimeZoneIDEnumeration(): basic test +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +if (version_compare(INTL_ICU_VERSION, '4.8') < 0) + die('skip for ICU 4.8+'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); +$enum = IntlTimeZone::createTimeZoneIDEnumeration( + IntlTimeZone::TYPE_ANY, + 'PT', + -3600000); +print_r(iterator_to_array($enum)); + +$enum = intltz_create_time_zone_id_enumeration( + IntlTimeZone::TYPE_ANY, + 'PT', + -3600000); +print_r(iterator_to_array($enum)); +?> +==DONE== +--EXPECT-- +Array +( + [0] => Atlantic/Azores +) +Array +( + [0] => Atlantic/Azores +) +==DONE==
\ No newline at end of file diff --git a/ext/intl/tests/timezone_createTimeZoneIDEnumeration_error.phpt b/ext/intl/tests/timezone_createTimeZoneIDEnumeration_error.phpt new file mode 100644 index 0000000000..2cc2ac48e7 --- /dev/null +++ b/ext/intl/tests/timezone_createTimeZoneIDEnumeration_error.phpt @@ -0,0 +1,42 @@ +--TEST-- +IntlTimeZone::createTimeZoneIDEnumeration(): errors +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +if (version_compare(INTL_ICU_VERSION, '4.8') < 0) + die('skip for ICU 4.8+'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); + +var_dump(IntlTimeZone::createTimeZoneIDEnumeration()); +var_dump(IntlTimeZone::createTimeZoneIDEnumeration(array())); +var_dump(IntlTimeZone::createTimeZoneIDEnumeration(-1)); +var_dump(IntlTimeZone::createTimeZoneIDEnumeration(IntlTimeZone::TYPE_ANY, array())); +var_dump(IntlTimeZone::createTimeZoneIDEnumeration(IntlTimeZone::TYPE_ANY, "PT", "a80")); + +--EXPECTF-- + +Warning: IntlTimeZone::createTimeZoneIDEnumeration() expects at least 1 parameter, 0 given in %s on line %d + +Warning: IntlTimeZone::createTimeZoneIDEnumeration(): intltz_create_time_zone_id_enumeration: bad arguments in %s on line %d +bool(false) + +Warning: IntlTimeZone::createTimeZoneIDEnumeration() expects parameter 1 to be long, array given in %s on line %d + +Warning: IntlTimeZone::createTimeZoneIDEnumeration(): intltz_create_time_zone_id_enumeration: bad arguments in %s on line %d +bool(false) + +Warning: IntlTimeZone::createTimeZoneIDEnumeration(): intltz_create_time_zone_id_enumeration: bad zone type in %s on line %d +bool(false) + +Warning: IntlTimeZone::createTimeZoneIDEnumeration() expects parameter 2 to be string, array given in %s on line %d + +Warning: IntlTimeZone::createTimeZoneIDEnumeration(): intltz_create_time_zone_id_enumeration: bad arguments in %s on line %d +bool(false) + +Warning: IntlTimeZone::createTimeZoneIDEnumeration() expects parameter 3 to be long, string given in %s on line %d + +Warning: IntlTimeZone::createTimeZoneIDEnumeration(): intltz_create_time_zone_id_enumeration: bad arguments in %s on line %d +bool(false) diff --git a/ext/intl/tests/timezone_createTimeZoneIDEnumeration_variant1.phpt b/ext/intl/tests/timezone_createTimeZoneIDEnumeration_variant1.phpt new file mode 100644 index 0000000000..d57dfbf42f --- /dev/null +++ b/ext/intl/tests/timezone_createTimeZoneIDEnumeration_variant1.phpt @@ -0,0 +1,32 @@ +--TEST-- +IntlTimeZone::createTimeZoneIDEnumeration(): variant without offset +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +if (version_compare(INTL_ICU_VERSION, '4.8') < 0) + die('skip for ICU 4.8+'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); +$enum = IntlTimeZone::createTimeZoneIDEnumeration( + IntlTimeZone::TYPE_ANY, + 'PT'); +$values = iterator_to_array($enum); +var_dump(in_array('Europe/Lisbon', $values)); +var_dump(in_array('Atlantic/Azores', $values)); + +$enum = IntlTimeZone::createTimeZoneIDEnumeration( + IntlTimeZone::TYPE_ANY, + 'PT', + null); +$values2 = iterator_to_array($enum); +var_dump($values2 == $values); + +?> +==DONE== +--EXPECT-- +bool(true) +bool(true) +bool(true) +==DONE==
\ No newline at end of file diff --git a/ext/intl/tests/timezone_createTimeZoneIDEnumeration_variant2.phpt b/ext/intl/tests/timezone_createTimeZoneIDEnumeration_variant2.phpt new file mode 100644 index 0000000000..2afe171c58 --- /dev/null +++ b/ext/intl/tests/timezone_createTimeZoneIDEnumeration_variant2.phpt @@ -0,0 +1,52 @@ +--TEST-- +IntlTimeZone::createTimeZoneIDEnumeration(): variant without region +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +if (version_compare(INTL_ICU_VERSION, '4.8') < 0) + die('skip for ICU 4.8+'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); +$enum = IntlTimeZone::createTimeZoneIDEnumeration( + IntlTimeZone::TYPE_ANY); +$countAny = count(iterator_to_array($enum)); +$enum = IntlTimeZone::createTimeZoneIDEnumeration( + IntlTimeZone::TYPE_CANONICAL); +$countCanonical = count(iterator_to_array($enum)); +$enum = IntlTimeZone::createTimeZoneIDEnumeration( + IntlTimeZone::TYPE_CANONICAL_LOCATION); +$countCanonicalLocation = count(iterator_to_array($enum)); + +var_dump($countAny > $countCanonical); +var_dump($countCanonical > $countCanonicalLocation); + +$enum = IntlTimeZone::createTimeZoneIDEnumeration( + IntlTimeZone::TYPE_ANY, null, null); +$countAny2 = count(iterator_to_array($enum)); +var_dump($countAny == $countAny2); + +$enum = IntlTimeZone::createTimeZoneIDEnumeration( + IntlTimeZone::TYPE_ANY, null, -3600000); +$values = iterator_to_array($enum); + +print_r( +array_values( +array_intersect($values, +array('Etc/GMT+1', 'Atlantic/Azores')) +)); + + +?> +==DONE== +--EXPECT-- +bool(true) +bool(true) +bool(true) +Array +( + [0] => Atlantic/Azores + [1] => Etc/GMT+1 +) +==DONE==
\ No newline at end of file diff --git a/ext/intl/tests/timezone_createTimeZone_basic.phpt b/ext/intl/tests/timezone_createTimeZone_basic.phpt new file mode 100644 index 0000000000..e79f5b58ee --- /dev/null +++ b/ext/intl/tests/timezone_createTimeZone_basic.phpt @@ -0,0 +1,33 @@ +--TEST-- +IntlTimeZone::createTimeZone(): basic test +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +if (version_compare(INTL_ICU_VERSION, '4.8') < 0) + die('skip for ICU 4.8+'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); +$tz = IntlTimeZone::createTimeZone('GMT+01:00'); +print_r($tz); +$tz = intltz_create_time_zone('GMT+01:00'); +print_r($tz); +?> +==DONE== +--EXPECT-- +IntlTimeZone Object +( + [valid] => 1 + [id] => GMT+01:00 + [rawOffset] => 3600000 + [currentOffset] => 3600000 +) +IntlTimeZone Object +( + [valid] => 1 + [id] => GMT+01:00 + [rawOffset] => 3600000 + [currentOffset] => 3600000 +) +==DONE==
\ No newline at end of file diff --git a/ext/intl/tests/timezone_createTimeZone_error.phpt b/ext/intl/tests/timezone_createTimeZone_error.phpt new file mode 100644 index 0000000000..2be821a67e --- /dev/null +++ b/ext/intl/tests/timezone_createTimeZone_error.phpt @@ -0,0 +1,34 @@ +--TEST-- +IntlTimeZone::createTimeZone(): errors +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); + +var_dump(IntlTimeZone::createTimeZone()); +var_dump(IntlTimeZone::createTimeZone(new stdClass)); +var_dump(IntlTimeZone::createTimeZone("foo bar", 4)); +var_dump(IntlTimeZone::createTimeZone("foo\x80")); + +--EXPECTF-- + +Warning: IntlTimeZone::createTimeZone() expects exactly 1 parameter, 0 given in %s on line %d + +Warning: IntlTimeZone::createTimeZone(): intltz_create_time_zone: bad arguments in %s on line %d +NULL + +Warning: IntlTimeZone::createTimeZone() expects parameter 1 to be string, object given in %s on line %d + +Warning: IntlTimeZone::createTimeZone(): intltz_create_time_zone: bad arguments in %s on line %d +NULL + +Warning: IntlTimeZone::createTimeZone() expects exactly 1 parameter, 2 given in %s on line %d + +Warning: IntlTimeZone::createTimeZone(): intltz_create_time_zone: bad arguments in %s on line %d +NULL + +Warning: IntlTimeZone::createTimeZone(): intltz_create_time_zone: could not convert time zone id to UTF-16 in %s on line %d +NULL diff --git a/ext/intl/tests/timezone_equals_basic.phpt b/ext/intl/tests/timezone_equals_basic.phpt new file mode 100644 index 0000000000..105ae8582f --- /dev/null +++ b/ext/intl/tests/timezone_equals_basic.phpt @@ -0,0 +1,33 @@ +--TEST-- +IntlTimeZone equals handler: basic test +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); + +$tz1 = intltz_create_time_zone('Europe/Lisbon'); +$tz2 = intltz_create_time_zone('Europe/Lisbon'); +echo "Comparison to self:\n"; +var_dump($tz1 == $tz1); +echo "Comparison to equal instance:\n"; +var_dump($tz1 == $tz2); +echo "Comparison to equivalent instance:\n"; +var_dump($tz1 == intltz_create_time_zone('Portugal')); +echo "Comparison to GMT:\n"; +var_dump($tz1 == intltz_get_gmt()); + +?> +==DONE== +--EXPECT-- +Comparison to self: +bool(true) +Comparison to equal instance: +bool(true) +Comparison to equivalent instance: +bool(false) +Comparison to GMT: +bool(false) +==DONE==
\ No newline at end of file diff --git a/ext/intl/tests/timezone_equals_error.phpt b/ext/intl/tests/timezone_equals_error.phpt new file mode 100644 index 0000000000..d8d027a761 --- /dev/null +++ b/ext/intl/tests/timezone_equals_error.phpt @@ -0,0 +1,43 @@ +--TEST-- +IntlTimeZone equals handler: error test +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); + +class A extends IntlTimeZone { +function __construct() {} +} + +$tz = new A(); +$tz2 = intltz_get_gmt(); +var_dump($tz, $tz2); +try { +var_dump($tz == $tz2); +} catch (Exception $e) { + var_dump(get_class($e), $e->getMessage()); +} + +?> +==DONE== +--EXPECT-- +object(A)#1 (1) { + ["valid"]=> + bool(false) +} +object(IntlTimeZone)#2 (4) { + ["valid"]=> + bool(true) + ["id"]=> + string(3) "GMT" + ["rawOffset"]=> + int(0) + ["currentOffset"]=> + int(0) +} +string(9) "Exception" +string(63) "Comparison with at least one unconstructed IntlTimeZone operand" +==DONE==
\ No newline at end of file diff --git a/ext/intl/tests/timezone_fromDateTimeZone_basic.phpt b/ext/intl/tests/timezone_fromDateTimeZone_basic.phpt new file mode 100644 index 0000000000..10e2621ae4 --- /dev/null +++ b/ext/intl/tests/timezone_fromDateTimeZone_basic.phpt @@ -0,0 +1,41 @@ +--TEST-- +IntlTimeZone::fromDateTimeZone(): basic test +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); +ini_set("intl.default_locale", "nl"); +date_default_timezone_set('Europe/Lisbon'); + +$tz = IntlTimeZone::fromDateTimeZone(new DateTimeZone('Europe/Amsterdam')); +var_dump($tz->getID(), $tz->getRawOffset()); + + +$dt = new DateTime('2012-01-01 00:00:00 CET'); +$dtz = $dt->getTimeZone(); +/* this is different from new DateTimeZone('CET'), + * which gives a Europe/Berlin timezone */ +var_dump($dtz->getName()); +$tz = IntlTimeZone::fromDateTimeZone($dtz); +var_dump($tz->getID(), $tz->getRawOffset()); + + +$dt = new DateTime('2012-01-01 00:00:00 +0340'); +$dtz = $dt->getTimeZone(); +/* I don't think this timezone can be generated without a DateTime object */ +var_dump($dtz->getName()); +$tz = IntlTimeZone::fromDateTimeZone($dtz); +var_dump($tz->getID(), $tz->getRawOffset() /* (3*60+40)*60000 */); + +--EXPECTF-- +string(16) "Europe/Amsterdam" +int(3600000) +string(3) "CET" +string(3) "CET" +int(3600000) +string(6) "+03:40" +string(%d) "GMT+03%s0" +int(13200000) diff --git a/ext/intl/tests/timezone_fromDateTimeZone_error.phpt b/ext/intl/tests/timezone_fromDateTimeZone_error.phpt new file mode 100644 index 0000000000..031882277e --- /dev/null +++ b/ext/intl/tests/timezone_fromDateTimeZone_error.phpt @@ -0,0 +1,50 @@ +--TEST-- +IntlTimeZone::fromDateTimeZone(): argument errors +--INI-- +date.timezone=Atlantic/Azores +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); + +var_dump(IntlTimeZone::fromDateTimeZone()); +var_dump(IntlTimeZone::fromDateTimeZone(1,2)); +var_dump(IntlTimeZone::fromDateTimeZone('sdfds')); +var_dump(IntlTimeZone::fromDateTimeZone(new stdclass)); +$dt = new DateTime('2012-08-01 00:00:00 WEST'); +var_dump(IntlTimeZone::fromDateTimeZone($dt->getTimeZone())); + +var_dump(intltz_from_date_time_zone()); + +--EXPECTF-- + +Warning: IntlTimeZone::fromDateTimeZone() expects exactly 1 parameter, 0 given in %s on line %d + +Warning: IntlTimeZone::fromDateTimeZone(): intltz_from_date_time_zone: bad arguments in %s on line %d +NULL + +Warning: IntlTimeZone::fromDateTimeZone() expects exactly 1 parameter, 2 given in %s on line %d + +Warning: IntlTimeZone::fromDateTimeZone(): intltz_from_date_time_zone: bad arguments in %s on line %d +NULL + +Warning: IntlTimeZone::fromDateTimeZone() expects parameter 1 to be DateTimeZone, string given in %s on line %d + +Warning: IntlTimeZone::fromDateTimeZone(): intltz_from_date_time_zone: bad arguments in %s on line %d +NULL + +Warning: IntlTimeZone::fromDateTimeZone() expects parameter 1 to be DateTimeZone, object given in %s on line %d + +Warning: IntlTimeZone::fromDateTimeZone(): intltz_from_date_time_zone: bad arguments in %s on line %d +NULL + +Warning: IntlTimeZone::fromDateTimeZone(): intltz_from_date_time_zone: time zone id 'WEST' extracted from ext/date DateTimeZone not recognized in %s on line %d +NULL + +Warning: intltz_from_date_time_zone() expects exactly 1 parameter, 0 given in %s on line %d + +Warning: intltz_from_date_time_zone(): intltz_from_date_time_zone: bad arguments in %s on line %d +NULL diff --git a/ext/intl/tests/timezone_getCanonicalID_basic.phpt b/ext/intl/tests/timezone_getCanonicalID_basic.phpt new file mode 100644 index 0000000000..897e9a9edc --- /dev/null +++ b/ext/intl/tests/timezone_getCanonicalID_basic.phpt @@ -0,0 +1,19 @@ +--TEST-- +IntlTimeZone::getCanonicalID: basic test +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); +print_R(IntlTimeZone::getCanonicalID('Portugal')); +echo "\n"; +print_R(intltz_get_canonical_id('Portugal')); +echo "\n"; +?> +==DONE== +--EXPECT-- +Europe/Lisbon +Europe/Lisbon +==DONE==
\ No newline at end of file diff --git a/ext/intl/tests/timezone_getCanonicalID_error.phpt b/ext/intl/tests/timezone_getCanonicalID_error.phpt new file mode 100644 index 0000000000..c7ffb45b77 --- /dev/null +++ b/ext/intl/tests/timezone_getCanonicalID_error.phpt @@ -0,0 +1,32 @@ +--TEST-- +IntlTimeZone::getCanonicalID(): errors +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); + +var_dump(IntlTimeZone::getCanonicalID()); +var_dump(IntlTimeZone::getCanonicalID(array())); +var_dump(IntlTimeZone::getCanonicalID("foo\x81")); +var_dump(IntlTimeZone::getCanonicalID('foobar', null)); + + +--EXPECTF-- + +Warning: IntlTimeZone::getCanonicalID() expects at least 1 parameter, 0 given in %s on line %d + +Warning: IntlTimeZone::getCanonicalID(): intltz_get_canonical_id: bad arguments in %s on line %d +bool(false) + +Warning: IntlTimeZone::getCanonicalID() expects parameter 1 to be string, array given in %s on line %d + +Warning: IntlTimeZone::getCanonicalID(): intltz_get_canonical_id: bad arguments in %s on line %d +bool(false) + +Warning: IntlTimeZone::getCanonicalID(): intltz_get_canonical_id: could not convert time zone id to UTF-16 in %s on line %d +bool(false) + +Fatal error: Cannot pass parameter 2 by reference in %s on line %d diff --git a/ext/intl/tests/timezone_getCanonicalID_variant1.phpt b/ext/intl/tests/timezone_getCanonicalID_variant1.phpt new file mode 100644 index 0000000000..92a7f07378 --- /dev/null +++ b/ext/intl/tests/timezone_getCanonicalID_variant1.phpt @@ -0,0 +1,24 @@ +--TEST-- +IntlTimeZone::getCanonicalID(): second argument +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); + +var_dump(IntlTimeZone::getCanonicalID('Portugal', $isSystemId)); +var_dump($isSystemId); + +var_dump(IntlTimeZone::getCanonicalID('GMT +01:25', $isSystemId)); +var_dump($isSystemId); + +?> +==DONE== +--EXPECT-- +string(13) "Europe/Lisbon" +bool(true) +string(0) "" +bool(false) +==DONE==
\ No newline at end of file diff --git a/ext/intl/tests/timezone_getDSTSavings_basic.phpt b/ext/intl/tests/timezone_getDSTSavings_basic.phpt new file mode 100644 index 0000000000..8dee5b8e94 --- /dev/null +++ b/ext/intl/tests/timezone_getDSTSavings_basic.phpt @@ -0,0 +1,21 @@ +--TEST-- +IntlTimeZone::getDSTSavings(): basic test +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); + +$lsb = IntlTimeZone::createTimeZone('Europe/Lisbon'); +var_dump($lsb->getDSTSavings()); + +var_dump(intltz_get_dst_savings($lsb)); + +?> +==DONE== +--EXPECT-- +int(3600000) +int(3600000) +==DONE==
\ No newline at end of file diff --git a/ext/intl/tests/timezone_getDSTSavings_error.phpt b/ext/intl/tests/timezone_getDSTSavings_error.phpt new file mode 100644 index 0000000000..e1469f4ac6 --- /dev/null +++ b/ext/intl/tests/timezone_getDSTSavings_error.phpt @@ -0,0 +1,23 @@ +--TEST-- +IntlTimeZone::getDSTSavings(): errors +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); + +$tz = IntlTimeZone::createTimeZone('Europe/Lisbon'); +var_dump($tz->getDSTSavings(array())); + +var_dump(intltz_get_dst_savings(null)); + +--EXPECTF-- + +Warning: IntlTimeZone::getDSTSavings() expects exactly 0 parameters, 1 given in %s on line %d + +Warning: IntlTimeZone::getDSTSavings(): intltz_get_dst_savings: bad arguments in %s on line %d +bool(false) + +Catchable fatal error: Argument 1 passed to intltz_get_dst_savings() must be an instance of IntlTimeZone, null given in %s on line %d diff --git a/ext/intl/tests/timezone_getDisplayName_basic.phpt b/ext/intl/tests/timezone_getDisplayName_basic.phpt new file mode 100644 index 0000000000..e4fc2f37ce --- /dev/null +++ b/ext/intl/tests/timezone_getDisplayName_basic.phpt @@ -0,0 +1,24 @@ +--TEST-- +IntlTimeZone::getDisplayName(): basic test +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); + +$lsb = IntlTimeZone::createTimeZone('Europe/Lisbon'); + +ini_set('intl.default_locale', 'en_US'); +var_dump($lsb->getDisplayName()); + +ini_set('intl.default_locale', 'pt_PT'); +var_dump($lsb->getDisplayName()); + +?> +==DONE== +--EXPECTF-- +string(%d) "Western European%sTime" +string(%d) "Hora%sda Europa Ocidental" +==DONE==
\ No newline at end of file diff --git a/ext/intl/tests/timezone_getDisplayName_error.phpt b/ext/intl/tests/timezone_getDisplayName_error.phpt new file mode 100644 index 0000000000..a12f85c855 --- /dev/null +++ b/ext/intl/tests/timezone_getDisplayName_error.phpt @@ -0,0 +1,45 @@ +--TEST-- +IntlTimeZone::getDisplayName(): errors +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); + +$tz = IntlTimeZone::createTimeZone('Europe/Lisbon'); +var_dump($tz->getDisplayName(array())); +var_dump($tz->getDisplayName(false, array())); +var_dump($tz->getDisplayName(false, -1)); +var_dump($tz->getDisplayName(false, IntlTimeZone::DISPLAY_SHORT, array())); +var_dump($tz->getDisplayName(false, IntlTimeZone::DISPLAY_SHORT, NULL, NULL)); + +var_dump(intltz_get_display_name(null, IntlTimeZone::DISPLAY_SHORT, false, 'pt_PT')); + +--EXPECTF-- + +Warning: IntlTimeZone::getDisplayName() expects parameter 1 to be boolean, array given in %s on line %d + +Warning: IntlTimeZone::getDisplayName(): intltz_get_display_name: bad arguments in %s on line %d +bool(false) + +Warning: IntlTimeZone::getDisplayName() expects parameter 2 to be long, array given in %s on line %d + +Warning: IntlTimeZone::getDisplayName(): intltz_get_display_name: bad arguments in %s on line %d +bool(false) + +Warning: IntlTimeZone::getDisplayName(): intltz_get_display_name: wrong display type in %s on line %d +bool(false) + +Warning: IntlTimeZone::getDisplayName() expects parameter 3 to be string, array given in %s on line %d + +Warning: IntlTimeZone::getDisplayName(): intltz_get_display_name: bad arguments in %s on line %d +bool(false) + +Warning: IntlTimeZone::getDisplayName() expects at most 3 parameters, 4 given in %s on line %d + +Warning: IntlTimeZone::getDisplayName(): intltz_get_display_name: bad arguments in %s on line %d +bool(false) + +Catchable fatal error: Argument 1 passed to intltz_get_display_name() must be an instance of IntlTimeZone, null given in %s on line %d diff --git a/ext/intl/tests/timezone_getDisplayName_variant1.phpt b/ext/intl/tests/timezone_getDisplayName_variant1.phpt new file mode 100644 index 0000000000..83922dd170 --- /dev/null +++ b/ext/intl/tests/timezone_getDisplayName_variant1.phpt @@ -0,0 +1,26 @@ +--TEST-- +IntlTimeZone::getDisplayName(): daylight parameter effect +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); +ini_set("error_reporting", -1); +ini_set("display_errors", 1); + +$lsb = IntlTimeZone::createTimeZone('Europe/Lisbon'); + +ini_set('intl.default_locale', 'en_US'); +var_dump($lsb->getDisplayName()); +var_dump($lsb->getDisplayName(false)); +var_dump($lsb->getDisplayName(true)); + +?> +==DONE== +--EXPECTF-- +string(%d) "Western European%sTime" +string(%d) "Western European%sTime" +string(28) "Western European Summer Time" +==DONE==
\ No newline at end of file diff --git a/ext/intl/tests/timezone_getDisplayName_variant2-49+.phpt b/ext/intl/tests/timezone_getDisplayName_variant2-49+.phpt new file mode 100644 index 0000000000..4ee30aee12 --- /dev/null +++ b/ext/intl/tests/timezone_getDisplayName_variant2-49+.phpt @@ -0,0 +1,38 @@ +--TEST-- +IntlTimeZone::getDisplayName(): type parameter (ICU >= 49) +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +if (version_compare(INTL_ICU_VERSION, '49') < 0) + die('skip for ICU 49+'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); +ini_set("error_reporting", -1); +ini_set("display_errors", 1); + +$lsb = IntlTimeZone::createTimeZone('Europe/Lisbon'); + +ini_set('intl.default_locale', 'en_US'); +var_dump($lsb->getDisplayName(false, IntlTimeZone::DISPLAY_SHORT)); +var_dump($lsb->getDisplayName(false, IntlTimeZone::DISPLAY_LONG)); +var_dump($lsb->getDisplayName(false, IntlTimeZone::DISPLAY_SHORT_GENERIC)); +var_dump($lsb->getDisplayName(false, IntlTimeZone::DISPLAY_LONG_GENERIC)); +var_dump($lsb->getDisplayName(false, IntlTimeZone::DISPLAY_SHORT_GMT)); +var_dump($lsb->getDisplayName(false, IntlTimeZone::DISPLAY_LONG_GMT)); +var_dump($lsb->getDisplayName(false, IntlTimeZone::DISPLAY_SHORT_COMMONLY_USED)); +var_dump($lsb->getDisplayName(false, IntlTimeZone::DISPLAY_GENERIC_LOCATION)); + +?> +==DONE== +--EXPECT-- +string(3) "GMT" +string(30) "Western European Standard Time" +string(22) "Portugal Time (Lisbon)" +string(21) "Western European Time" +string(5) "+0000" +string(3) "GMT" +string(3) "GMT" +string(22) "Portugal Time (Lisbon)" +==DONE==
\ No newline at end of file diff --git a/ext/intl/tests/timezone_getDisplayName_variant2.phpt b/ext/intl/tests/timezone_getDisplayName_variant2.phpt new file mode 100644 index 0000000000..1ccf68767f --- /dev/null +++ b/ext/intl/tests/timezone_getDisplayName_variant2.phpt @@ -0,0 +1,40 @@ +--TEST-- +IntlTimeZone::getDisplayName(): type parameter (ICU < 49) +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +if (version_compare(INTL_ICU_VERSION, '49') >= 0) + die('skip for ICU < 49'); +if (version_compare(INTL_ICU_VERSION, '4.8') < 0) + die('skip for ICU 4.8+'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); +ini_set("error_reporting", -1); +ini_set("display_errors", 1); + +$lsb = IntlTimeZone::createTimeZone('Europe/Lisbon'); + +ini_set('intl.default_locale', 'en_US'); +var_dump($lsb->getDisplayName(false, IntlTimeZone::DISPLAY_SHORT)); +var_dump($lsb->getDisplayName(false, IntlTimeZone::DISPLAY_LONG)); +var_dump($lsb->getDisplayName(false, IntlTimeZone::DISPLAY_SHORT_GENERIC)); +var_dump($lsb->getDisplayName(false, IntlTimeZone::DISPLAY_LONG_GENERIC)); +var_dump($lsb->getDisplayName(false, IntlTimeZone::DISPLAY_SHORT_GMT)); +var_dump($lsb->getDisplayName(false, IntlTimeZone::DISPLAY_LONG_GMT)); +var_dump($lsb->getDisplayName(false, IntlTimeZone::DISPLAY_SHORT_COMMONLY_USED)); +var_dump($lsb->getDisplayName(false, IntlTimeZone::DISPLAY_GENERIC_LOCATION)); + +?> +==DONE== +--EXPECT-- +string(3) "WET" +string(21) "Western European Time" +string(22) "Portugal Time (Lisbon)" +string(22) "Portugal Time (Lisbon)" +string(5) "+0000" +string(3) "GMT" +string(3) "GMT" +string(22) "Portugal Time (Lisbon)" +==DONE==
\ No newline at end of file diff --git a/ext/intl/tests/timezone_getDisplayName_variant3-49+.phpt b/ext/intl/tests/timezone_getDisplayName_variant3-49+.phpt new file mode 100644 index 0000000000..e90cc4748c --- /dev/null +++ b/ext/intl/tests/timezone_getDisplayName_variant3-49+.phpt @@ -0,0 +1,28 @@ +--TEST-- +IntlTimeZone::getDisplayName(): locale parameter +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +if (version_compare(INTL_ICU_VERSION, '49') < 0) + die('skip for ICU 49+'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); +ini_set("error_reporting", -1); +ini_set("display_errors", 1); + +$lsb = IntlTimeZone::createTimeZone('Europe/Lisbon'); + +ini_set('intl.default_locale', 'en_US'); +var_dump($lsb->getDisplayName(false, IntlTimeZone::DISPLAY_LONG)); +var_dump($lsb->getDisplayName(false, IntlTimeZone::DISPLAY_LONG, NULL)); +var_dump($lsb->getDisplayName(false, IntlTimeZone::DISPLAY_LONG, 'pt_PT')); + +?> +==DONE== +--EXPECT-- +string(30) "Western European Standard Time" +string(30) "Western European Standard Time" +string(32) "Hora Padrão da Europa Ocidental" +==DONE== diff --git a/ext/intl/tests/timezone_getDisplayName_variant3.phpt b/ext/intl/tests/timezone_getDisplayName_variant3.phpt new file mode 100644 index 0000000000..c160777583 --- /dev/null +++ b/ext/intl/tests/timezone_getDisplayName_variant3.phpt @@ -0,0 +1,28 @@ +--TEST-- +IntlTimeZone::getDisplayName(): locale parameter +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +if (version_compare(INTL_ICU_VERSION, '49') >= 0) + die('skip for ICU <= 4.8'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); +ini_set("error_reporting", -1); +ini_set("display_errors", 1); + +$lsb = IntlTimeZone::createTimeZone('Europe/Lisbon'); + +ini_set('intl.default_locale', 'en_US'); +var_dump($lsb->getDisplayName(false, IntlTimeZone::DISPLAY_LONG)); +var_dump($lsb->getDisplayName(false, IntlTimeZone::DISPLAY_LONG, NULL)); +var_dump($lsb->getDisplayName(false, IntlTimeZone::DISPLAY_LONG, 'pt_PT')); + +?> +==DONE== +--EXPECT-- +string(21) "Western European Time" +string(21) "Western European Time" +string(24) "Hora da Europa Ocidental" +==DONE==
\ No newline at end of file diff --git a/ext/intl/tests/timezone_getEquivalentID_basic.phpt b/ext/intl/tests/timezone_getEquivalentID_basic.phpt new file mode 100644 index 0000000000..8af1e20897 --- /dev/null +++ b/ext/intl/tests/timezone_getEquivalentID_basic.phpt @@ -0,0 +1,19 @@ +--TEST-- +IntlTimeZone::getEquivalentID(): basic test +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); +print_R(IntlTimeZone::getEquivalentID('Europe/Lisbon', "1")); +echo "\n"; +print_R(intltz_get_equivalent_id('Europe/Lisbon', 1)); +echo "\n"; +?> +==DONE== +--EXPECT-- +Portugal +Portugal +==DONE==
\ No newline at end of file diff --git a/ext/intl/tests/timezone_getEquivalentID_error.phpt b/ext/intl/tests/timezone_getEquivalentID_error.phpt new file mode 100644 index 0000000000..b3f344b54d --- /dev/null +++ b/ext/intl/tests/timezone_getEquivalentID_error.phpt @@ -0,0 +1,34 @@ +--TEST-- +IntlTimeZone::getEquivalentID(): errors +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); + +var_dump(IntlTimeZone::getEquivalentID('foo')); +var_dump(IntlTimeZone::getEquivalentID('foo', 'bar')); +var_dump(IntlTimeZone::getEquivalentID('Europe/Lisbon', 0, 1)); +var_dump(IntlTimeZone::getEquivalentID("foo\x80", 0)); + +--EXPECTF-- + +Warning: IntlTimeZone::getEquivalentID() expects exactly 2 parameters, 1 given in %s on line %d + +Warning: IntlTimeZone::getEquivalentID(): intltz_get_equivalent_id: bad arguments in %s on line %d +bool(false) + +Warning: IntlTimeZone::getEquivalentID() expects parameter 2 to be long, string given in %s on line %d + +Warning: IntlTimeZone::getEquivalentID(): intltz_get_equivalent_id: bad arguments in %s on line %d +bool(false) + +Warning: IntlTimeZone::getEquivalentID() expects exactly 2 parameters, 3 given in %s on line %d + +Warning: IntlTimeZone::getEquivalentID(): intltz_get_equivalent_id: bad arguments in %s on line %d +bool(false) + +Warning: IntlTimeZone::getEquivalentID(): intltz_get_equivalent_id: could not convert time zone id to UTF-16 in %s on line %d +bool(false) diff --git a/ext/intl/tests/timezone_getErrorCodeMessage_basic.phpt b/ext/intl/tests/timezone_getErrorCodeMessage_basic.phpt new file mode 100644 index 0000000000..d3a3dee47d --- /dev/null +++ b/ext/intl/tests/timezone_getErrorCodeMessage_basic.phpt @@ -0,0 +1,31 @@ +--TEST-- +IntlTimeZone::getErrorCode/Message(): basic test +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); + +$lsb = IntlTimeZone::createTimeZone('Europe/Lisbon'); + +var_dump($lsb->getErrorCode()); +var_dump($lsb->getErrorMessage()); + +var_dump($lsb->getOffset(INF, 1, $a, $b)); + +var_dump($lsb->getErrorCode()); +var_dump($lsb->getErrorMessage()); + +?> +==DONE== +--EXPECTF-- +int(0) +string(12) "U_ZERO_ERROR" + +Warning: IntlTimeZone::getOffset(): intltz_get_offset: error obtaining offset in %s on line %d +bool(false) +int(1) +string(67) "intltz_get_offset: error obtaining offset: U_ILLEGAL_ARGUMENT_ERROR" +==DONE==
\ No newline at end of file diff --git a/ext/intl/tests/timezone_getErrorCode_error.phpt b/ext/intl/tests/timezone_getErrorCode_error.phpt new file mode 100644 index 0000000000..b56d3b0a48 --- /dev/null +++ b/ext/intl/tests/timezone_getErrorCode_error.phpt @@ -0,0 +1,23 @@ +--TEST-- +IntlTimeZone::getErrorCode(): errors +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); + +$tz = IntlTimeZone::createTimeZone('Europe/Lisbon'); +var_dump($tz->getErrorCode(array())); + +var_dump(intltz_get_error_code(null)); + +--EXPECTF-- + +Warning: IntlTimeZone::getErrorCode() expects exactly 0 parameters, 1 given in %s on line %d + +Warning: IntlTimeZone::getErrorCode(): intltz_get_error_code: bad arguments in %s on line %d +bool(false) + +Catchable fatal error: Argument 1 passed to intltz_get_error_code() must be an instance of IntlTimeZone, null given in %s on line %d diff --git a/ext/intl/tests/timezone_getErrorMessage_error.phpt b/ext/intl/tests/timezone_getErrorMessage_error.phpt new file mode 100644 index 0000000000..067dcdc13b --- /dev/null +++ b/ext/intl/tests/timezone_getErrorMessage_error.phpt @@ -0,0 +1,23 @@ +--TEST-- +IntlTimeZone::getErrorMessage(): errors +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); + +$tz = IntlTimeZone::createTimeZone('Europe/Lisbon'); +var_dump($tz->getErrorMessage(array())); + +var_dump(intltz_get_error_message(null)); + +--EXPECTF-- + +Warning: IntlTimeZone::getErrorMessage() expects exactly 0 parameters, 1 given in %s on line %d + +Warning: IntlTimeZone::getErrorMessage(): intltz_get_error_message: bad arguments in %s on line %d +bool(false) + +Catchable fatal error: Argument 1 passed to intltz_get_error_message() must be an instance of IntlTimeZone, null given in %s on line %d diff --git a/ext/intl/tests/timezone_getGMT_basic.phpt b/ext/intl/tests/timezone_getGMT_basic.phpt new file mode 100644 index 0000000000..99b3fa22ca --- /dev/null +++ b/ext/intl/tests/timezone_getGMT_basic.phpt @@ -0,0 +1,31 @@ +--TEST-- +IntlTimeZone::getGMT(): basic test +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); +$tz = IntlTimeZone::getGMT(); +print_r($tz); +$tz = intltz_get_gmt(); +print_r($tz); +?> +==DONE== +--EXPECT-- +IntlTimeZone Object +( + [valid] => 1 + [id] => GMT + [rawOffset] => 0 + [currentOffset] => 0 +) +IntlTimeZone Object +( + [valid] => 1 + [id] => GMT + [rawOffset] => 0 + [currentOffset] => 0 +) +==DONE==
\ No newline at end of file diff --git a/ext/intl/tests/timezone_getGMT_error.phpt b/ext/intl/tests/timezone_getGMT_error.phpt new file mode 100644 index 0000000000..15afb765e4 --- /dev/null +++ b/ext/intl/tests/timezone_getGMT_error.phpt @@ -0,0 +1,19 @@ +--TEST-- +IntlTimeZone::getGMT(): errors +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); + +var_dump(IntlTimeZone::getGMT(4)); + + +--EXPECTF-- + +Warning: IntlTimeZone::getGMT() expects exactly 0 parameters, 1 given in %s on line %d + +Warning: IntlTimeZone::getGMT(): intltz_get_gmt: bad arguments in %s on line %d +NULL diff --git a/ext/intl/tests/timezone_getID_error.phpt b/ext/intl/tests/timezone_getID_error.phpt new file mode 100644 index 0000000000..b239b3facf --- /dev/null +++ b/ext/intl/tests/timezone_getID_error.phpt @@ -0,0 +1,23 @@ +--TEST-- +IntlTimeZone::getID(): errors +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); + +$tz = IntlTimeZone::createTimeZone('Europe/Lisbon'); +var_dump($tz->getID('foo')); +intltz_get_id(null); + + +--EXPECTF-- + +Warning: IntlTimeZone::getID() expects exactly 0 parameters, 1 given in %s on line %d + +Warning: IntlTimeZone::getID(): intltz_get_id: bad arguments in %s on line %d +bool(false) + +Catchable fatal error: Argument 1 passed to intltz_get_id() must be an instance of IntlTimeZone, null given in %s on line %d diff --git a/ext/intl/tests/timezone_getOffset_basic.phpt b/ext/intl/tests/timezone_getOffset_basic.phpt new file mode 100644 index 0000000000..582d45cad9 --- /dev/null +++ b/ext/intl/tests/timezone_getOffset_basic.phpt @@ -0,0 +1,33 @@ +--TEST-- +IntlTimeZone::getOffset(): basic test +--INI-- +date.timezone=Atlantic/Azores +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); +$ams = IntlTimeZone::createTimeZone('Europe/Amsterdam'); + +$date = strtotime("1 July 2012 +0000"); + +var_dump($ams->getOffset($date *1000., true, $rawOffset, $dstOffset), + $rawOffset, $dstOffset); + +$lsb = IntlTimeZone::createTimeZone('Europe/Lisbon'); + +var_dump(intltz_get_offset($lsb, $date *1000., true, $rawOffset, $dstOffset), + $rawOffset, $dstOffset); + +?> +==DONE== +--EXPECT-- +bool(true) +int(3600000) +int(3600000) +bool(true) +int(0) +int(3600000) +==DONE==
\ No newline at end of file diff --git a/ext/intl/tests/timezone_getOffset_error.phpt b/ext/intl/tests/timezone_getOffset_error.phpt new file mode 100644 index 0000000000..73555002c0 --- /dev/null +++ b/ext/intl/tests/timezone_getOffset_error.phpt @@ -0,0 +1,33 @@ +--TEST-- +IntlTimeZone::getOffset(): errors +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); + +$tz = IntlTimeZone::createTimeZone('Europe/Lisbon'); +var_dump($tz->getOffset(INF, true, $a, $a)); +var_dump($tz->getOffset(time()*1000, true, $a)); +var_dump($tz->getOffset(time()*1000, true, $a, $a, $a)); + +intltz_get_offset(null, time()*1000, false, $a, $a); + +--EXPECTF-- + +Warning: IntlTimeZone::getOffset(): intltz_get_offset: error obtaining offset in %s on line %d +bool(false) + +Warning: IntlTimeZone::getOffset() expects exactly 4 parameters, 3 given in %s on line %d + +Warning: IntlTimeZone::getOffset(): intltz_get_offset: bad arguments in %s on line %d +bool(false) + +Warning: IntlTimeZone::getOffset() expects exactly 4 parameters, 5 given in %s on line %d + +Warning: IntlTimeZone::getOffset(): intltz_get_offset: bad arguments in %s on line %d +bool(false) + +Catchable fatal error: Argument 1 passed to intltz_get_offset() must be an instance of IntlTimeZone, null given in %s on line %d diff --git a/ext/intl/tests/timezone_getRawOffset_basic.phpt b/ext/intl/tests/timezone_getRawOffset_basic.phpt new file mode 100644 index 0000000000..a2b4debf2b --- /dev/null +++ b/ext/intl/tests/timezone_getRawOffset_basic.phpt @@ -0,0 +1,21 @@ +--TEST-- +IntlTimeZone::getRawOffset(): basic test +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); +$ams = IntlTimeZone::createTimeZone('Europe/Amsterdam'); +var_dump($ams->getRawOffset()); + +$lsb = IntlTimeZone::createTimeZone('Europe/Lisbon'); +var_dump(intltz_get_raw_offset($lsb)); + +?> +==DONE== +--EXPECT-- +int(3600000) +int(0) +==DONE==
\ No newline at end of file diff --git a/ext/intl/tests/timezone_getRawOffset_error.phpt b/ext/intl/tests/timezone_getRawOffset_error.phpt new file mode 100644 index 0000000000..eb6aac02cd --- /dev/null +++ b/ext/intl/tests/timezone_getRawOffset_error.phpt @@ -0,0 +1,23 @@ +--TEST-- +IntlTimeZone::getRawOffset(): errors +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); + +$tz = IntlTimeZone::createTimeZone('Europe/Lisbon'); +var_dump($tz->getRawOffset('foo')); + +intltz_get_raw_offset(null); + +--EXPECTF-- + +Warning: IntlTimeZone::getRawOffset() expects exactly 0 parameters, 1 given in %s on line %d + +Warning: IntlTimeZone::getRawOffset(): intltz_get_raw_offset: bad arguments in %s on line %d +bool(false) + +Catchable fatal error: Argument 1 passed to intltz_get_raw_offset() must be an instance of IntlTimeZone, null given in %s on line %d diff --git a/ext/intl/tests/timezone_getRegion_basic.phpt b/ext/intl/tests/timezone_getRegion_basic.phpt new file mode 100644 index 0000000000..1a41ae8d58 --- /dev/null +++ b/ext/intl/tests/timezone_getRegion_basic.phpt @@ -0,0 +1,21 @@ +--TEST-- +IntlTimeZone::getRegion(): basic test +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +if (version_compare(INTL_ICU_VERSION, '4.8') < 0) + die('skip for ICU 4.8+'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); +print_R(IntlTimeZone::getRegion('Europe/Amsterdam')); +echo "\n"; +print_R(intltz_get_region('Europe/Amsterdam')); +echo "\n"; +?> +==DONE== +--EXPECT-- +NL +NL +==DONE==
\ No newline at end of file diff --git a/ext/intl/tests/timezone_getRegion_error.phpt b/ext/intl/tests/timezone_getRegion_error.phpt new file mode 100644 index 0000000000..34911d9abc --- /dev/null +++ b/ext/intl/tests/timezone_getRegion_error.phpt @@ -0,0 +1,42 @@ +--TEST-- +IntlTimeZone::getRegion(): errors +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +if (version_compare(INTL_ICU_VERSION, '4.8') < 0) + die('skip for ICU 4.8+'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); + +var_dump(IntlTimeZone::getRegion()); +var_dump(IntlTimeZone::getRegion(array())); +var_dump(IntlTimeZone::getRegion('Europe/Lisbon', 4)); +var_dump(IntlTimeZone::getRegion("foo\x81")); +var_dump(IntlTimeZone::getRegion("foo")); + + + +--EXPECTF-- + +Warning: IntlTimeZone::getRegion() expects exactly 1 parameter, 0 given in %s on line %d + +Warning: IntlTimeZone::getRegion(): intltz_get_region: bad arguments in %s on line %d +bool(false) + +Warning: IntlTimeZone::getRegion() expects parameter 1 to be string, array given in %s on line %d + +Warning: IntlTimeZone::getRegion(): intltz_get_region: bad arguments in %s on line %d +bool(false) + +Warning: IntlTimeZone::getRegion() expects exactly 1 parameter, 2 given in %s on line %d + +Warning: IntlTimeZone::getRegion(): intltz_get_region: bad arguments in %s on line %d +bool(false) + +Warning: IntlTimeZone::getRegion(): intltz_get_region: could not convert time zone id to UTF-16 in %s on line %d +bool(false) + +Warning: IntlTimeZone::getRegion(): intltz_get_region: Error obtaining region in %s on line %d +bool(false) diff --git a/ext/intl/tests/timezone_getTZDataVersion_error.phpt b/ext/intl/tests/timezone_getTZDataVersion_error.phpt new file mode 100644 index 0000000000..258b8807b7 --- /dev/null +++ b/ext/intl/tests/timezone_getTZDataVersion_error.phpt @@ -0,0 +1,18 @@ +--TEST-- +IntlTimeZone::getTZDataVersion(): errors +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); + +var_dump(IntlTimeZone::getTZDataVersion('foo')); + +--EXPECTF-- + +Warning: IntlTimeZone::getTZDataVersion() expects exactly 0 parameters, 1 given in %s on line %d + +Warning: IntlTimeZone::getTZDataVersion(): intltz_get_tz_data_version: bad arguments in %s on line %d +bool(false) diff --git a/ext/intl/tests/timezone_getTZData_basic.phpt b/ext/intl/tests/timezone_getTZData_basic.phpt new file mode 100644 index 0000000000..dea5b7c4b3 --- /dev/null +++ b/ext/intl/tests/timezone_getTZData_basic.phpt @@ -0,0 +1,19 @@ +--TEST-- +IntlTimeZone::getTZDataVersion: basic test +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); +print_R(IntlTimeZone::getTZDataVersion()); +echo "\n"; +print_R(intltz_get_tz_data_version()); +echo "\n"; +?> +==DONE== +--EXPECTF-- +20%d%s +20%d%s +==DONE==
\ No newline at end of file diff --git a/ext/intl/tests/timezone_getUnknown_basic.phpt b/ext/intl/tests/timezone_getUnknown_basic.phpt new file mode 100644 index 0000000000..aef1a54561 --- /dev/null +++ b/ext/intl/tests/timezone_getUnknown_basic.phpt @@ -0,0 +1,35 @@ +--TEST-- +IntlCalendar::getUnknown(): basic test +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +if (version_compare(INTL_ICU_VERSION, '49') < 0) + die('skip for ICU 49+'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); +ini_set("intl.default_locale", "nl"); + +$tz = IntlTimeZone::getUnknown(); +print_r($tz); +$tz = intltz_get_unknown(); +print_r($tz); +?> +==DONE== +--EXPECT-- +IntlTimeZone Object +( + [valid] => 1 + [id] => Etc/Unknown + [rawOffset] => 0 + [currentOffset] => 0 +) +IntlTimeZone Object +( + [valid] => 1 + [id] => Etc/Unknown + [rawOffset] => 0 + [currentOffset] => 0 +) +==DONE==
\ No newline at end of file diff --git a/ext/intl/tests/timezone_getUnknown_error.phpt b/ext/intl/tests/timezone_getUnknown_error.phpt new file mode 100644 index 0000000000..704b1b096f --- /dev/null +++ b/ext/intl/tests/timezone_getUnknown_error.phpt @@ -0,0 +1,29 @@ +--TEST-- +IntlCalendar::getUnknown(): bad arguments +--INI-- +date.timezone=Atlantic/Azores +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +if (version_compare(INTL_ICU_VERSION, '49') < 0) + die('skip for ICU 49+'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); + +$c = new IntlGregorianCalendar(NULL, 'pt_PT'); + +IntlTimeZone::getUnknown(1); + +intltz_get_unknown(1); + +--EXPECTF-- + +Warning: IntlTimeZone::getUnknown() expects exactly 0 parameters, 1 given in %s on line %d + +Warning: IntlTimeZone::getUnknown(): intltz_get_unknown: bad arguments in %s on line %d + +Warning: intltz_get_unknown() expects exactly 0 parameters, 1 given in %s on line %d + +Warning: intltz_get_unknown(): intltz_get_unknown: bad arguments in %s on line %d diff --git a/ext/intl/tests/timezone_hasSameRules_basic.phpt b/ext/intl/tests/timezone_hasSameRules_basic.phpt new file mode 100644 index 0000000000..55faaf760b --- /dev/null +++ b/ext/intl/tests/timezone_hasSameRules_basic.phpt @@ -0,0 +1,35 @@ +--TEST-- +IntlTimeZone::hasSameRules(): basic test +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); + +$lsb = IntlTimeZone::createTimeZone('Europe/Lisbon'); +$prt = IntlTimeZone::createTimeZone('Portugal'); +$azo = IntlTimeZone::createTimeZone('Atlantic/Azores'); + +echo "Europe/Lisbon has same rules as itself:\n"; +var_dump($lsb->hasSameRules($lsb)); + +echo "\nEurope/Lisbon has same rules as Portugal:\n"; +var_dump($lsb->hasSameRules($prt)); + +echo "\nEurope/Lisbon has same rules as Atlantic/Azores:\n"; +var_dump(intltz_has_same_rules($lsb, $azo)); + +?> +==DONE== +--EXPECT-- +Europe/Lisbon has same rules as itself: +bool(true) + +Europe/Lisbon has same rules as Portugal: +bool(true) + +Europe/Lisbon has same rules as Atlantic/Azores: +bool(false) +==DONE==
\ No newline at end of file diff --git a/ext/intl/tests/timezone_hasSameRules_error.phpt b/ext/intl/tests/timezone_hasSameRules_error.phpt new file mode 100644 index 0000000000..35a29be5db --- /dev/null +++ b/ext/intl/tests/timezone_hasSameRules_error.phpt @@ -0,0 +1,37 @@ +--TEST-- +IntlTimeZone::hasSameRules(): errors +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); + +function error_handler($errno, $errstr, $errfile, $errline) +{ + var_dump($errno, $errstr); + return true; +} +set_error_handler("error_handler"); + +$tz = IntlTimeZone::createTimeZone('Europe/Lisbon'); +var_dump($tz->hasSameRules('foo')); + +var_dump(intltz_has_same_rules(null, $tz)); + +--EXPECT-- +int(4096) +string(99) "Argument 1 passed to IntlTimeZone::hasSameRules() must be an instance of IntlTimeZone, string given" +int(2) +string(81) "IntlTimeZone::hasSameRules() expects parameter 1 to be IntlTimeZone, string given" +int(2) +string(66) "IntlTimeZone::hasSameRules(): intltz_has_same_rules: bad arguments" +bool(false) +int(4096) +string(92) "Argument 1 passed to intltz_has_same_rules() must be an instance of IntlTimeZone, null given" +int(2) +string(74) "intltz_has_same_rules() expects parameter 1 to be IntlTimeZone, null given" +int(2) +string(61) "intltz_has_same_rules(): intltz_has_same_rules: bad arguments" +bool(false) diff --git a/ext/intl/tests/timezone_toDateTimeZone_basic.phpt b/ext/intl/tests/timezone_toDateTimeZone_basic.phpt new file mode 100644 index 0000000000..d22aa689dc --- /dev/null +++ b/ext/intl/tests/timezone_toDateTimeZone_basic.phpt @@ -0,0 +1,38 @@ +--TEST-- +IntlTimeZone::toDateTimeZone(): basic test +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); +ini_set("intl.default_locale", "nl"); +date_default_timezone_set('Europe/Lisbon'); + +function do_test(IntlTimeZone $tz, $proc = false) { + var_dump($tz->getID(), $tz->getRawOffset()); + if (!$proc) + $dtz = $tz->toDateTimeZone(); + else + $dtz = intltz_to_date_time_zone($tz); + var_dump($dtz->getName(), $dtz->getOffset(new DateTime('2012-01-01 00:00:00'))); +} + +do_test(IntlTimeZone::createTimeZone('CET')); +do_test(IntlTimeZone::createTimeZone('Europe/Amsterdam')); +do_test(IntlTimeZone::createTimeZone('GMT+0405'), true); + +--EXPECTF-- +string(3) "CET" +int(3600000) +string(13) "Europe/Berlin" +int(3600) +string(16) "Europe/Amsterdam" +int(3600000) +string(16) "Europe/Amsterdam" +int(3600) +string(%s) "GMT+04%s5" +int(14700000) +string(6) "+04:05" +int(14700) diff --git a/ext/intl/tests/timezone_toDateTimeZone_error.phpt b/ext/intl/tests/timezone_toDateTimeZone_error.phpt new file mode 100644 index 0000000000..e48d7aca92 --- /dev/null +++ b/ext/intl/tests/timezone_toDateTimeZone_error.phpt @@ -0,0 +1,38 @@ +--TEST-- +IntlTimeZone::toDateTimeZone(): errors +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); + +$tz = IntlTimeZone::createTimeZone('Etc/Unknown'); + +var_dump($tz->toDateTimeZone('')); +try { + var_dump($tz->toDateTimeZone()); +} catch (Exception $e) { + var_dump($e->getMessage()); +} + +var_dump(intltz_to_date_time_zone()); +var_dump(intltz_to_date_time_zone(1)); + +--EXPECTF-- + +Warning: IntlTimeZone::toDateTimeZone() expects exactly 0 parameters, 1 given in %s on line %d + +Warning: IntlTimeZone::toDateTimeZone(): intltz_to_date_time_zone: bad arguments in %s on line %d +bool(false) + +Warning: IntlTimeZone::toDateTimeZone(): intltz_to_date_time_zone: DateTimeZone constructor threw exception in %s on line %d +string(66) "DateTimeZone::__construct(): Unknown or bad timezone (Etc/Unknown)" + +Warning: intltz_to_date_time_zone() expects exactly 1 parameter, 0 given in %s on line %d + +Warning: intltz_to_date_time_zone(): intltz_to_date_time_zone: bad arguments in %s on line %d +bool(false) + +Catchable fatal error: Argument 1 passed to intltz_to_date_time_zone() must be an instance of IntlTimeZone, integer given in %s on line %d diff --git a/ext/intl/tests/timezone_useDaylightTime_basic.phpt b/ext/intl/tests/timezone_useDaylightTime_basic.phpt new file mode 100644 index 0000000000..15baf108b3 --- /dev/null +++ b/ext/intl/tests/timezone_useDaylightTime_basic.phpt @@ -0,0 +1,25 @@ +--TEST-- +IntlTimeZone::useDaylightTime: basic test +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); +$lsb = IntlTimeZone::createTimeZone('Europe/Lisbon'); +$gmt = IntlTimeZone::getGMT(); + +var_dump($lsb->useDaylightTime()); +var_dump($gmt->useDaylightTime()); + +var_dump(intltz_use_daylight_time($lsb)); +var_dump(intltz_use_daylight_time($gmt)); +?> +==DONE== +--EXPECT-- +bool(true) +bool(false) +bool(true) +bool(false) +==DONE==
\ No newline at end of file diff --git a/ext/intl/tests/timezone_useDaylightTime_error.phpt b/ext/intl/tests/timezone_useDaylightTime_error.phpt new file mode 100644 index 0000000000..aa5ca6cfca --- /dev/null +++ b/ext/intl/tests/timezone_useDaylightTime_error.phpt @@ -0,0 +1,22 @@ +--TEST-- +IntlTimeZone::useDaylightTime(): errors +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); + +$tz = IntlTimeZone::createTimeZone('Europe/Lisbon'); +var_dump($tz->useDaylightTime('foo')); +intltz_use_daylight_time(null); + +--EXPECTF-- + +Warning: IntlTimeZone::useDaylightTime() expects exactly 0 parameters, 1 given in %s on line %d + +Warning: IntlTimeZone::useDaylightTime(): intltz_use_daylight_time: bad arguments in %s on line %d +bool(false) + +Catchable fatal error: Argument 1 passed to intltz_use_daylight_time() must be an instance of IntlTimeZone, null given in %s on line %d diff --git a/ext/intl/timezone/timezone_class.cpp b/ext/intl/timezone/timezone_class.cpp new file mode 100644 index 0000000000..6e62c34f6d --- /dev/null +++ b/ext/intl/timezone/timezone_class.cpp @@ -0,0 +1,611 @@ +/* + +----------------------------------------------------------------------+ + | 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 <cataphract@php.net> | + +----------------------------------------------------------------------+ +*/ + + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "../intl_cppshims.h" + +#include <unicode/timezone.h> +#include <unicode/calendar.h> +#include "../intl_convertcpp.h" + +extern "C" { +#include "../intl_convert.h" +#define USE_TIMEZONE_POINTER 1 +#include "timezone_class.h" +#include "timezone_methods.h" +#include <zend_exceptions.h> +#include <zend_interfaces.h> +#include <ext/date/php_date.h> +} + +/* {{{ Global variables */ +U_CDECL_BEGIN +zend_class_entry *TimeZone_ce_ptr = NULL; +zend_object_handlers TimeZone_handlers; +U_CDECL_END +/* }}} */ + +/* {{{ timezone_object_construct */ +U_CFUNC void timezone_object_construct(const TimeZone *zone, zval *object, int owned TSRMLS_DC) +{ + TimeZone_object *to; + + object_init_ex(object, TimeZone_ce_ptr); + TIMEZONE_METHOD_FETCH_OBJECT_NO_CHECK; /* fetch zend object from zval "object" into "to" */ + to->utimezone = zone; + to->should_delete = owned; +} +/* }}} */ + +/* {{{ timezone_convert_datetimezone + * The timezone in DateTime and DateTimeZone is not unified. */ +U_CFUNC TimeZone *timezone_convert_datetimezone(int type, + void *object, + int is_datetime, + intl_error *outside_error, + const char *func TSRMLS_DC) +{ + char *id = NULL, + offset_id[] = "GMT+00:00"; + int id_len = 0; + char *message; + TimeZone *timeZone; + + switch (type) { + case TIMELIB_ZONETYPE_ID: + id = is_datetime + ? ((php_date_obj*)object)->time->tz_info->name + : ((php_timezone_obj*)object)->tzi.tz->name; + id_len = strlen(id); + break; + case TIMELIB_ZONETYPE_OFFSET: { + int offset_mins = is_datetime + ? -((php_date_obj*)object)->time->z + : -(int)((php_timezone_obj*)object)->tzi.utc_offset, + hours = offset_mins / 60, + minutes = offset_mins - hours * 60; + minutes *= minutes > 0 ? 1 : -1; + + if (offset_mins <= -24 * 60 || offset_mins >= 24 * 60) { + spprintf(&message, 0, "%s: object has an time zone offset " + "that's too large", func); + intl_errors_set(outside_error, U_ILLEGAL_ARGUMENT_ERROR, + message, 1 TSRMLS_CC); + efree(message); + return NULL; + } + + id = offset_id; + id_len = slprintf(id, sizeof(offset_id), "GMT%+03d:%02d", + hours, minutes); + break; + } + case TIMELIB_ZONETYPE_ABBR: + id = is_datetime + ? ((php_date_obj*)object)->time->tz_abbr + : ((php_timezone_obj*)object)->tzi.z.abbr; + id_len = strlen(id); + break; + } + + UnicodeString s = UnicodeString(id, id_len, US_INV); + timeZone = TimeZone::createTimeZone(s); +#if U_ICU_VERSION_MAJOR_NUM >= 49 + if (*timeZone == TimeZone::getUnknown()) { +#else + UnicodeString resultingId; + timeZone->getID(resultingId); + if (resultingId == UnicodeString("Etc/Unknown", -1, US_INV) + || resultingId == UnicodeString("GMT", -1, US_INV)) { +#endif + spprintf(&message, 0, "%s: time zone id '%s' " + "extracted from ext/date DateTimeZone not recognized", func, id); + intl_errors_set(outside_error, U_ILLEGAL_ARGUMENT_ERROR, + message, 1 TSRMLS_CC); + efree(message); + delete timeZone; + return NULL; + } + return timeZone; +} +/* }}} */ + +/* {{{ timezone_convert_to_datetimezone + * Convert from TimeZone to DateTimeZone object */ +U_CFUNC zval *timezone_convert_to_datetimezone(const TimeZone *timeZone, + intl_error *outside_error, + const char *func TSRMLS_DC) +{ + zval *ret = NULL; + UnicodeString id; + char *message = NULL; + php_timezone_obj *tzobj; + zval arg = zval_used_for_init; + + timeZone->getID(id); + if (id.isBogus()) { + spprintf(&message, 0, "%s: could not obtain TimeZone id", func); + intl_errors_set(outside_error, U_ILLEGAL_ARGUMENT_ERROR, + message, 1 TSRMLS_CC); + goto error; + } + + MAKE_STD_ZVAL(ret); + object_init_ex(ret, php_date_get_timezone_ce()); + tzobj = (php_timezone_obj *)zend_objects_get_address(ret TSRMLS_CC); + + if (id.compare(0, 3, UnicodeString("GMT", sizeof("GMT")-1, US_INV)) == 0) { + /* The DateTimeZone constructor doesn't support offset time zones, + * so we must mess with DateTimeZone structure ourselves */ + tzobj->initialized = 1; + tzobj->type = TIMELIB_ZONETYPE_OFFSET; + //convert offset from milliseconds to minutes + tzobj->tzi.utc_offset = -1 * timeZone->getRawOffset() / (60 * 1000); + } else { + /* Call the constructor! */ + Z_TYPE(arg) = IS_STRING; + if (intl_charFromString(id, &Z_STRVAL(arg), &Z_STRLEN(arg), + &INTL_ERROR_CODE(*outside_error)) == FAILURE) { + spprintf(&message, 0, "%s: could not convert id to UTF-8", func); + intl_errors_set(outside_error, INTL_ERROR_CODE(*outside_error), + message, 1 TSRMLS_CC); + goto error; + } + zend_call_method_with_1_params(&ret, NULL, NULL, "__construct", + NULL, &arg); + if (EG(exception)) { + spprintf(&message, 0, + "%s: DateTimeZone constructor threw exception", func); + intl_errors_set(outside_error, U_ILLEGAL_ARGUMENT_ERROR, + message, 1 TSRMLS_CC); + zend_object_store_ctor_failed(ret TSRMLS_CC); + goto error; + } + } + + if (0) { +error: + if (ret) { + zval_ptr_dtor(&ret); + } + ret = NULL; + } + + if (message) { + efree(message); + } + if (Z_TYPE(arg) == IS_STRING) { + zval_dtor(&arg); + } + return ret; +} +/* }}} */ + +/* {{{ timezone_process_timezone_argument + * TimeZone argument processor. outside_error may be NULL (for static functions/constructors) */ +U_CFUNC TimeZone *timezone_process_timezone_argument(zval **zv_timezone, + intl_error *outside_error, + const char *func TSRMLS_DC) +{ + zval local_zv_tz = zval_used_for_init, + *local_zv_tz_p = &local_zv_tz; + char *message = NULL; + TimeZone *timeZone; + + if (zv_timezone == NULL || Z_TYPE_PP(zv_timezone) == IS_NULL) { + timelib_tzinfo *tzinfo = get_timezone_info(TSRMLS_C); + ZVAL_STRING(&local_zv_tz, tzinfo->name, 0); + zv_timezone = &local_zv_tz_p; + } + + if (Z_TYPE_PP(zv_timezone) == IS_OBJECT && + instanceof_function(Z_OBJCE_PP(zv_timezone), TimeZone_ce_ptr TSRMLS_CC)) { + TimeZone_object *to = (TimeZone_object*)zend_objects_get_address( + *zv_timezone TSRMLS_CC); + if (to->utimezone == NULL) { + spprintf(&message, 0, "%s: passed IntlTimeZone is not " + "properly constructed", func); + if (message) { + intl_errors_set(outside_error, U_ILLEGAL_ARGUMENT_ERROR, message, 1 TSRMLS_CC); + efree(message); + } + return NULL; + } + timeZone = to->utimezone->clone(); + if (timeZone == NULL) { + spprintf(&message, 0, "%s: could not clone TimeZone", func); + if (message) { + intl_errors_set(outside_error, U_MEMORY_ALLOCATION_ERROR, message, 1 TSRMLS_CC); + efree(message); + } + return NULL; + } + } else if (Z_TYPE_PP(zv_timezone) == IS_OBJECT && + instanceof_function(Z_OBJCE_PP(zv_timezone), php_date_get_timezone_ce() TSRMLS_CC)) { + + php_timezone_obj *tzobj = (php_timezone_obj *)zend_objects_get_address( + *zv_timezone TSRMLS_CC); + + return timezone_convert_datetimezone(tzobj->type, tzobj, 0, + outside_error, func TSRMLS_CC); + } else { + UnicodeString id, + gottenId; + UErrorCode status = U_ZERO_ERROR; /* outside_error may be NULL */ + convert_to_string_ex(zv_timezone); + if (intl_stringFromChar(id, Z_STRVAL_PP(zv_timezone), Z_STRLEN_PP(zv_timezone), + &status) == FAILURE) { + spprintf(&message, 0, "%s: Time zone identifier given is not a " + "valid UTF-8 string", func); + if (message) { + intl_errors_set(outside_error, status, message, 1 TSRMLS_CC); + efree(message); + } + return NULL; + } + timeZone = TimeZone::createTimeZone(id); + if (timeZone == NULL) { + spprintf(&message, 0, "%s: could not create time zone", func); + if (message) { + intl_errors_set(outside_error, U_MEMORY_ALLOCATION_ERROR, message, 1 TSRMLS_CC); + efree(message); + } + return NULL; + } + if (timeZone->getID(gottenId) != id) { + spprintf(&message, 0, "%s: no such time zone: '%s'", + func, Z_STRVAL_PP(zv_timezone)); + if (message) { + intl_errors_set(outside_error, U_ILLEGAL_ARGUMENT_ERROR, message, 1 TSRMLS_CC); + efree(message); + } + delete timeZone; + return NULL; + } + } + + return timeZone; +} +/* }}} */ + +/* {{{ clone handler for TimeZone */ +static zend_object_value TimeZone_clone_obj(zval *object TSRMLS_DC) +{ + TimeZone_object *to_orig, + *to_new; + zend_object_value ret_val; + intl_error_reset(NULL TSRMLS_CC); + + to_orig = (TimeZone_object*)zend_object_store_get_object(object TSRMLS_CC); + intl_error_reset(TIMEZONE_ERROR_P(to_orig) TSRMLS_CC); + + ret_val = TimeZone_ce_ptr->create_object(TimeZone_ce_ptr TSRMLS_CC); + to_new = (TimeZone_object*)zend_object_store_get_object_by_handle( + ret_val.handle TSRMLS_CC); + + zend_objects_clone_members(&to_new->zo, ret_val, + &to_orig->zo, Z_OBJ_HANDLE_P(object) TSRMLS_CC); + + if (to_orig->utimezone != NULL) { + TimeZone *newTimeZone; + + newTimeZone = to_orig->utimezone->clone(); + to_new->should_delete = 1; + if (!newTimeZone) { + char *err_msg; + intl_errors_set_code(TIMEZONE_ERROR_P(to_orig), + U_MEMORY_ALLOCATION_ERROR TSRMLS_CC); + intl_errors_set_custom_msg(TIMEZONE_ERROR_P(to_orig), + "Could not clone IntlTimeZone", 0 TSRMLS_CC); + err_msg = intl_error_get_message(TIMEZONE_ERROR_P(to_orig) TSRMLS_CC); + zend_throw_exception(NULL, err_msg, 0 TSRMLS_CC); + efree(err_msg); + } else { + to_new->utimezone = newTimeZone; + } + } else { + zend_throw_exception(NULL, "Cannot clone unconstructed IntlTimeZone", 0 TSRMLS_CC); + } + + return ret_val; +} +/* }}} */ + +/* {{{ compare_objects handler for TimeZone + * Can't be used for >, >=, <, <= comparisons */ +static int TimeZone_compare_objects(zval *object1, zval *object2 TSRMLS_DC) +{ + TimeZone_object *to1, + *to2; + to1 = (TimeZone_object*)zend_object_store_get_object(object1 TSRMLS_CC); + to2 = (TimeZone_object*)zend_object_store_get_object(object2 TSRMLS_CC); + + if (to1->utimezone == NULL || to2->utimezone == NULL) { + zend_throw_exception(NULL, "Comparison with at least one unconstructed " + "IntlTimeZone operand", 0 TSRMLS_CC); + /* intentionally not returning */ + } else { + if (*to1->utimezone == *to2->utimezone) { + return 0; + } + } + + return 1; +} +/* }}} */ + +/* {{{ get_debug_info handler for TimeZone */ +static HashTable *TimeZone_get_debug_info(zval *object, int *is_temp TSRMLS_DC) +{ + zval zv = zval_used_for_init; + TimeZone_object *to; + const TimeZone *tz; + UnicodeString ustr; + char *str; + int str_len; + UErrorCode uec = U_ZERO_ERROR; + + *is_temp = 1; + + array_init_size(&zv, 4); + + to = (TimeZone_object*)zend_object_store_get_object(object TSRMLS_CC); + tz = to->utimezone; + + if (tz == NULL) { + add_assoc_bool_ex(&zv, "valid", sizeof("valid"), 0); + return Z_ARRVAL(zv); + } + + add_assoc_bool_ex(&zv, "valid", sizeof("valid"), 1); + + tz->getID(ustr); + intl_convert_utf16_to_utf8(&str, &str_len, + ustr.getBuffer(), ustr.length(), &uec); + if (U_FAILURE(uec)) { + return Z_ARRVAL(zv); + } + add_assoc_stringl_ex(&zv, "id", sizeof("id"), str, str_len, 0); + + int32_t rawOffset, dstOffset; + UDate now = Calendar::getNow(); + tz->getOffset(now, FALSE, rawOffset, dstOffset, uec); + if (U_FAILURE(uec)) { + return Z_ARRVAL(zv); + } + + add_assoc_long_ex(&zv, "rawOffset", sizeof("rawOffset"), (long)rawOffset); + add_assoc_long_ex(&zv, "currentOffset", sizeof("currentOffset"), + (long)(rawOffset + dstOffset)); + + return Z_ARRVAL(zv); +} +/* }}} */ + +/* {{{ void TimeZone_object_init(TimeZone_object* to) + * Initialize internals of TImeZone_object not specific to zend standard objects. + */ +static void TimeZone_object_init(TimeZone_object *to TSRMLS_DC) +{ + intl_error_init(TIMEZONE_ERROR_P(to) TSRMLS_CC); + to->utimezone = NULL; + to->should_delete = 0; +} +/* }}} */ + +/* {{{ TimeZone_objects_dtor */ +static void TimeZone_objects_dtor(zend_object *object, + zend_object_handle handle TSRMLS_DC) +{ + zend_objects_destroy_object(object, handle TSRMLS_CC); +} +/* }}} */ + +/* {{{ TimeZone_objects_free */ +static void TimeZone_objects_free(zend_object *object TSRMLS_DC) +{ + TimeZone_object* to = (TimeZone_object*) object; + + if (to->utimezone && to->should_delete) { + delete to->utimezone; + to->utimezone = NULL; + } + intl_error_reset(TIMEZONE_ERROR_P(to) TSRMLS_CC); + + zend_object_std_dtor(&to->zo TSRMLS_CC); + + efree(to); +} +/* }}} */ + +/* {{{ TimeZone_object_create */ +static zend_object_value TimeZone_object_create(zend_class_entry *ce TSRMLS_DC) +{ + zend_object_value retval; + TimeZone_object* intern; + + intern = (TimeZone_object*)ecalloc(1, sizeof(TimeZone_object)); + + zend_object_std_init(&intern->zo, ce TSRMLS_CC); +#if PHP_VERSION_ID < 50399 + zend_hash_copy(intern->zo.properties, &(ce->default_properties), + (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval*)); +#else + object_properties_init((zend_object*) intern, ce); +#endif + TimeZone_object_init(intern TSRMLS_CC); + + retval.handle = zend_objects_store_put( + intern, + (zend_objects_store_dtor_t) TimeZone_objects_dtor, + (zend_objects_free_object_storage_t) TimeZone_objects_free, + NULL TSRMLS_CC); + + retval.handlers = &TimeZone_handlers; + + return retval; +} +/* }}} */ + +/* {{{ TimeZone methods arguments info */ + +ZEND_BEGIN_ARG_INFO_EX(ainfo_tz_idarg, 0, 0, 1) + ZEND_ARG_INFO(0, zoneId) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(ainfo_tz_fromDateTimeZone, 0, 0, 1) + ZEND_ARG_OBJ_INFO(0, otherTimeZone, IntlTimeZone, 0) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(ainfo_tz_createEnumeration, 0, 0, 0) + ZEND_ARG_INFO(0, countryOrRawOffset) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(ainfo_tz_countEquivalentIDs, 0, 0, 1) + ZEND_ARG_INFO(0, zoneId) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(ainfo_tz_createTimeZoneIDEnumeration, 0, 0, 1) + ZEND_ARG_INFO(0, zoneType) + ZEND_ARG_INFO(0, region) + ZEND_ARG_INFO(0, rawOffset) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(ainfo_tz_getCanonicalID, 0, 0, 1) + ZEND_ARG_INFO(0, zoneId) + ZEND_ARG_INFO(1, isSystemID) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(ainfo_tz_getEquivalentID, 0, 0, 2) + ZEND_ARG_INFO(0, zoneId) + ZEND_ARG_INFO(0, index) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(ainfo_tz_getOffset, 0, 0, 4) + ZEND_ARG_INFO(0, date) + ZEND_ARG_INFO(0, local) + ZEND_ARG_INFO(1, rawOffset) + ZEND_ARG_INFO(1, dstOffset) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(ainfo_tz_hasSameRules, 0, 0, 1) + ZEND_ARG_OBJ_INFO(0, otherTimeZone, IntlTimeZone, 0) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(ainfo_tz_getDisplayName, 0, 0, 0) + ZEND_ARG_INFO(0, isDaylight) + ZEND_ARG_INFO(0, style) + ZEND_ARG_INFO(0, locale) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(ainfo_tz_void, 0, 0, 0) +ZEND_END_ARG_INFO() + +/* }}} */ + +/* {{{ TimeZone_class_functions + * Every 'IntlTimeZone' class method has an entry in this table + */ +static zend_function_entry TimeZone_class_functions[] = { + PHP_ME(IntlTimeZone, __construct, ainfo_tz_void, ZEND_ACC_PRIVATE) + PHP_ME_MAPPING(createTimeZone, intltz_create_time_zone, ainfo_tz_idarg, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC) + PHP_ME_MAPPING(fromDateTimeZone, intltz_from_date_time_zone, ainfo_tz_idarg, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC) + PHP_ME_MAPPING(createDefault, intltz_create_default, ainfo_tz_void, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC) + PHP_ME_MAPPING(getGMT, intltz_get_gmt, ainfo_tz_void, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC) +#if U_ICU_VERSION_MAJOR_NUM >= 49 + PHP_ME_MAPPING(getUnknown, intltz_get_unknown, ainfo_tz_void, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC) +#endif + PHP_ME_MAPPING(createEnumeration, intltz_create_enumeration, ainfo_tz_createEnumeration, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC) + PHP_ME_MAPPING(countEquivalentIDs, intltz_count_equivalent_ids, ainfo_tz_idarg, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC) +#if U_ICU_VERSION_MAJOR_NUM * 10 + U_ICU_VERSION_MINOR_NUM >= 48 + PHP_ME_MAPPING(createTimeZoneIDEnumeration, intltz_create_time_zone_id_enumeration, ainfo_tz_createTimeZoneIDEnumeration, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC) +#endif + PHP_ME_MAPPING(getCanonicalID, intltz_get_canonical_id, ainfo_tz_getCanonicalID, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC) +#if U_ICU_VERSION_MAJOR_NUM * 10 + U_ICU_VERSION_MINOR_NUM >= 48 + PHP_ME_MAPPING(getRegion, intltz_get_region, ainfo_tz_idarg, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC) +#endif + PHP_ME_MAPPING(getTZDataVersion, intltz_get_tz_data_version, ainfo_tz_void, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC) + PHP_ME_MAPPING(getEquivalentID, intltz_get_equivalent_id, ainfo_tz_getEquivalentID, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC) + + PHP_ME_MAPPING(getID, intltz_get_id, ainfo_tz_void, ZEND_ACC_PUBLIC) + PHP_ME_MAPPING(useDaylightTime, intltz_use_daylight_time, ainfo_tz_void, ZEND_ACC_PUBLIC) + PHP_ME_MAPPING(getOffset, intltz_get_offset, ainfo_tz_getOffset, ZEND_ACC_PUBLIC) + PHP_ME_MAPPING(getRawOffset, intltz_get_raw_offset, ainfo_tz_void, ZEND_ACC_PUBLIC) + PHP_ME_MAPPING(hasSameRules, intltz_has_same_rules, ainfo_tz_hasSameRules, ZEND_ACC_PUBLIC) + PHP_ME_MAPPING(getDisplayName, intltz_get_display_name, ainfo_tz_getDisplayName, ZEND_ACC_PUBLIC) + PHP_ME_MAPPING(getDSTSavings, intltz_get_dst_savings, ainfo_tz_void, ZEND_ACC_PUBLIC) + PHP_ME_MAPPING(toDateTimeZone, intltz_to_date_time_zone, ainfo_tz_void, ZEND_ACC_PUBLIC) + PHP_ME_MAPPING(getErrorCode, intltz_get_error_code, ainfo_tz_void, ZEND_ACC_PUBLIC) + PHP_ME_MAPPING(getErrorMessage, intltz_get_error_message, ainfo_tz_void, ZEND_ACC_PUBLIC) + PHP_FE_END +}; +/* }}} */ + +/* {{{ timezone_register_IntlTimeZone_class + * Initialize 'IntlTimeZone' class + */ +U_CFUNC void timezone_register_IntlTimeZone_class(TSRMLS_D) +{ + zend_class_entry ce; + + /* Create and register 'IntlTimeZone' class. */ + INIT_CLASS_ENTRY(ce, "IntlTimeZone", TimeZone_class_functions); + ce.create_object = TimeZone_object_create; + TimeZone_ce_ptr = zend_register_internal_class(&ce TSRMLS_CC); + if (!TimeZone_ce_ptr) { + //can't happen now without bigger problems before + php_error_docref0(NULL TSRMLS_CC, E_ERROR, + "IntlTimeZone: class registration has failed."); + return; + } + + memcpy(&TimeZone_handlers, zend_get_std_object_handlers(), + sizeof TimeZone_handlers); + TimeZone_handlers.clone_obj = TimeZone_clone_obj; + TimeZone_handlers.compare_objects = TimeZone_compare_objects; + TimeZone_handlers.get_debug_info = TimeZone_get_debug_info; + + /* Declare 'IntlTimeZone' class constants */ +#define TIMEZONE_DECL_LONG_CONST(name, val) \ + zend_declare_class_constant_long(TimeZone_ce_ptr, name, sizeof(name) - 1, \ + val TSRMLS_CC) + + TIMEZONE_DECL_LONG_CONST("DISPLAY_SHORT", TimeZone::SHORT); + TIMEZONE_DECL_LONG_CONST("DISPLAY_LONG", TimeZone::LONG); + +#if U_ICU_VERSION_MAJOR_NUM * 10 + U_ICU_VERSION_MINOR_NUM >= 44 + TIMEZONE_DECL_LONG_CONST("DISPLAY_SHORT_GENERIC", TimeZone::SHORT_GENERIC); + TIMEZONE_DECL_LONG_CONST("DISPLAY_LONG_GENERIC", TimeZone::LONG_GENERIC); + TIMEZONE_DECL_LONG_CONST("DISPLAY_SHORT_GMT", TimeZone::SHORT_GMT); + TIMEZONE_DECL_LONG_CONST("DISPLAY_LONG_GMT", TimeZone::LONG_GMT); + TIMEZONE_DECL_LONG_CONST("DISPLAY_SHORT_COMMONLY_USED", TimeZone::SHORT_COMMONLY_USED); + TIMEZONE_DECL_LONG_CONST("DISPLAY_GENERIC_LOCATION", TimeZone::GENERIC_LOCATION); +#endif + +#if U_ICU_VERSION_MAJOR_NUM * 10 + U_ICU_VERSION_MINOR_NUM >= 48 + TIMEZONE_DECL_LONG_CONST("TYPE_ANY", UCAL_ZONE_TYPE_ANY); + TIMEZONE_DECL_LONG_CONST("TYPE_CANONICAL", UCAL_ZONE_TYPE_CANONICAL); + TIMEZONE_DECL_LONG_CONST("TYPE_CANONICAL_LOCATION", UCAL_ZONE_TYPE_CANONICAL_LOCATION); +#endif + + /* Declare 'IntlTimeZone' class properties */ + +} +/* }}} */ diff --git a/ext/intl/timezone/timezone_class.h b/ext/intl/timezone/timezone_class.h new file mode 100644 index 0000000000..0d3c0edde4 --- /dev/null +++ b/ext/intl/timezone/timezone_class.h @@ -0,0 +1,73 @@ +/* + +----------------------------------------------------------------------+ + | 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 <cataphract@netcabo.pt> | + +----------------------------------------------------------------------+ + */ + +#ifndef TIMEZONE_CLASS_H +#define TIMEZONE_CLASS_H + +//redefinition of inline in PHP headers causes problems, so include this before +#include <math.h> + +//fixes the build on windows for old versions of ICU +#include <stdio.h> + +#include <php.h> +#include "intl_error.h" +#include "intl_data.h" + +#ifndef USE_TIMEZONE_POINTER +typedef void TimeZone; +#endif + +typedef struct { + zend_object zo; + + // error handling + intl_error err; + + // ICU TimeZone + const TimeZone *utimezone; + + //whether to delete the timezone on object free + zend_bool should_delete; +} TimeZone_object; + +#define TIMEZONE_ERROR(to) (to)->err +#define TIMEZONE_ERROR_P(to) &(TIMEZONE_ERROR(to)) + +#define TIMEZONE_ERROR_CODE(co) INTL_ERROR_CODE(TIMEZONE_ERROR(to)) +#define TIMEZONE_ERROR_CODE_P(co) &(INTL_ERROR_CODE(TIMEZONE_ERROR(to))) + +#define TIMEZONE_METHOD_INIT_VARS INTL_METHOD_INIT_VARS(TimeZone, to) +#define TIMEZONE_METHOD_FETCH_OBJECT_NO_CHECK INTL_METHOD_FETCH_OBJECT(TimeZone, to) +#define TIMEZONE_METHOD_FETCH_OBJECT\ + TIMEZONE_METHOD_FETCH_OBJECT_NO_CHECK; \ + if (to->utimezone == NULL) { \ + intl_errors_set(&to->err, U_ILLEGAL_ARGUMENT_ERROR, "Found unconstructed IntlTimeZone", 0 TSRMLS_CC); \ + RETURN_FALSE; \ + } + +TimeZone *timezone_convert_datetimezone(int type, void *object, int is_datetime, intl_error *outside_error, const char *func TSRMLS_DC); +zval *timezone_convert_to_datetimezone(const TimeZone *timeZone, intl_error *outside_error, const char *func TSRMLS_DC); +TimeZone *timezone_process_timezone_argument(zval **zv_timezone, intl_error *error, const char *func TSRMLS_DC); + +void timezone_object_construct(const TimeZone *zone, zval *object, int owned TSRMLS_DC); + +void timezone_register_IntlTimeZone_class(TSRMLS_D); + +extern zend_class_entry *TimeZone_ce_ptr; +extern zend_object_handlers TimeZone_handlers; + +#endif /* #ifndef TIMEZONE_CLASS_H */ diff --git a/ext/intl/timezone/timezone_methods.cpp b/ext/intl/timezone/timezone_methods.cpp new file mode 100644 index 0000000000..caf5dcdedc --- /dev/null +++ b/ext/intl/timezone/timezone_methods.cpp @@ -0,0 +1,656 @@ +/* + +----------------------------------------------------------------------+ + | 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 <cataphract@php.net> | + +----------------------------------------------------------------------+ +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "../intl_cppshims.h" + +#include <unicode/locid.h> +#include <unicode/timezone.h> +#include <unicode/ustring.h> +#include "intl_convertcpp.h" +extern "C" { +#include "../php_intl.h" +#define USE_TIMEZONE_POINTER 1 +#include "timezone_class.h" +#include "intl_convert.h" +#include <zend_exceptions.h> +#include <ext/date/php_date.h> +} +#include "common/common_enum.h" + +U_CFUNC PHP_METHOD(IntlTimeZone, __construct) +{ + zend_throw_exception( NULL, + "An object of this type cannot be created with the new operator", + 0 TSRMLS_CC ); +} + +U_CFUNC PHP_FUNCTION(intltz_create_time_zone) +{ + char *str_id; + int str_id_len; + intl_error_reset(NULL TSRMLS_CC); + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", + &str_id, &str_id_len) == FAILURE) { + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, + "intltz_create_time_zone: bad arguments", 0 TSRMLS_CC); + RETURN_NULL(); + } + + UErrorCode status = UErrorCode(); + UnicodeString id = UnicodeString(); + if (intl_stringFromChar(id, str_id, str_id_len, &status) == FAILURE) { + intl_error_set(NULL, status, + "intltz_create_time_zone: could not convert time zone id to UTF-16", 0 TSRMLS_CC); + RETURN_NULL(); + } + + //guaranteed non-null; GMT if timezone cannot be understood + TimeZone *tz = TimeZone::createTimeZone(id); + timezone_object_construct(tz, return_value, 1 TSRMLS_CC); +} + +U_CFUNC PHP_FUNCTION(intltz_from_date_time_zone) +{ + zval *zv_timezone; + TimeZone *tz; + php_timezone_obj *tzobj; + intl_error_reset(NULL TSRMLS_CC); + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", + &zv_timezone, php_date_get_timezone_ce()) == FAILURE) { + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, + "intltz_from_date_time_zone: bad arguments", 0 TSRMLS_CC); + RETURN_NULL(); + } + + tzobj = (php_timezone_obj *)zend_objects_get_address(zv_timezone TSRMLS_CC); + if (!tzobj->initialized) { + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, + "intltz_from_date_time_zone: DateTimeZone object is unconstructed", + 0 TSRMLS_CC); + RETURN_NULL(); + } + + tz = timezone_convert_datetimezone(tzobj->type, tzobj, FALSE, NULL, + "intltz_from_date_time_zone" TSRMLS_CC); + if (tz == NULL) { + RETURN_NULL(); + } + + timezone_object_construct(tz, return_value, 1 TSRMLS_CC); +} + +U_CFUNC PHP_FUNCTION(intltz_create_default) +{ + intl_error_reset(NULL TSRMLS_CC); + + if (zend_parse_parameters_none() == FAILURE) { + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, + "intltz_create_default: bad arguments", 0 TSRMLS_CC); + RETURN_NULL(); + } + + TimeZone *tz = TimeZone::createDefault(); + timezone_object_construct(tz, return_value, 1 TSRMLS_CC); +} + +U_CFUNC PHP_FUNCTION(intltz_get_gmt) +{ + intl_error_reset(NULL TSRMLS_CC); + + if (zend_parse_parameters_none() == FAILURE) { + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, + "intltz_get_gmt: bad arguments", 0 TSRMLS_CC); + RETURN_NULL(); + } + + timezone_object_construct(TimeZone::getGMT(), return_value, 0 TSRMLS_CC); +} + +#if U_ICU_VERSION_MAJOR_NUM >= 49 +U_CFUNC PHP_FUNCTION(intltz_get_unknown) +{ + intl_error_reset(NULL TSRMLS_CC); + + if (zend_parse_parameters_none() == FAILURE) { + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, + "intltz_get_unknown: bad arguments", 0 TSRMLS_CC); + RETURN_NULL(); + } + + timezone_object_construct(&TimeZone::getUnknown(), return_value, 0 TSRMLS_CC); +} +#endif + +U_CFUNC PHP_FUNCTION(intltz_create_enumeration) +{ + zval **arg = NULL; + StringEnumeration *se = NULL; + intl_error_reset(NULL TSRMLS_CC); + + /* double indirection to have the zend engine destroy the new zval that + * results from separation */ + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|Z", &arg) == FAILURE) { + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, + "intltz_create_enumeration: bad arguments", 0 TSRMLS_CC); + RETURN_FALSE; + } + + if (arg == NULL || Z_TYPE_PP(arg) == IS_NULL) { + se = TimeZone::createEnumeration(); + } else if (Z_TYPE_PP(arg) == IS_LONG) { +int_offset: + if (Z_LVAL_PP(arg) < (long)INT32_MIN || + Z_LVAL_PP(arg) > (long)INT32_MAX) { + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, + "intltz_create_enumeration: value is out of range", 0 TSRMLS_CC); + RETURN_FALSE; + } else { + se = TimeZone::createEnumeration((int32_t) Z_LVAL_PP(arg)); + } + } else if (Z_TYPE_PP(arg) == IS_DOUBLE) { +double_offset: + convert_to_long_ex(arg); + goto int_offset; + } else if (Z_TYPE_PP(arg) == IS_OBJECT || Z_TYPE_PP(arg) == IS_STRING) { + long lval; + double dval; + convert_to_string_ex(arg); + switch (is_numeric_string(Z_STRVAL_PP(arg), Z_STRLEN_PP(arg), &lval, &dval, 0)) { + case IS_DOUBLE: + SEPARATE_ZVAL(arg); + zval_dtor(*arg); + Z_TYPE_PP(arg) = IS_DOUBLE; + Z_DVAL_PP(arg) = dval; + goto double_offset; + case IS_LONG: + SEPARATE_ZVAL(arg); + zval_dtor(*arg); + Z_TYPE_PP(arg) = IS_LONG; + Z_LVAL_PP(arg) = lval; + goto int_offset; + } + /* else call string version */ + se = TimeZone::createEnumeration(Z_STRVAL_PP(arg)); + } else { + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, + "intltz_create_enumeration: invalid argument type", 0 TSRMLS_CC); + RETURN_FALSE; + } + + if (se) { + IntlIterator_from_StringEnumeration(se, return_value TSRMLS_CC); + } else { + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, + "intltz_create_enumeration: error obtaining enumeration", 0 TSRMLS_CC); + RETVAL_FALSE; + } +} + +U_CFUNC PHP_FUNCTION(intltz_count_equivalent_ids) +{ + char *str_id; + int str_id_len; + intl_error_reset(NULL TSRMLS_CC); + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", + &str_id, &str_id_len) == FAILURE) { + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, + "intltz_count_equivalent_ids: bad arguments", 0 TSRMLS_CC); + RETURN_FALSE; + } + + UErrorCode status = UErrorCode(); + UnicodeString id = UnicodeString(); + if (intl_stringFromChar(id, str_id, str_id_len, &status) == FAILURE) { + intl_error_set(NULL, status, + "intltz_count_equivalent_ids: could not convert time zone id to UTF-16", 0 TSRMLS_CC); + RETURN_FALSE; + } + + int32_t result = TimeZone::countEquivalentIDs(id); + RETURN_LONG((long)result); +} + +#if U_ICU_VERSION_MAJOR_NUM * 10 + U_ICU_VERSION_MINOR_NUM >= 48 +U_CFUNC PHP_FUNCTION(intltz_create_time_zone_id_enumeration) +{ + long zoneType, + offset_arg; + char *region = NULL; + int region_len = 0; + int32_t offset, + *offsetp = NULL; + int arg3isnull = 0; + intl_error_reset(NULL TSRMLS_CC); + + /* must come before zpp because zpp would convert the arg in the stack to 0 */ + if (ZEND_NUM_ARGS() == 3) { + zval **dummy, **zvoffset; + arg3isnull = zend_get_parameters_ex(3, &dummy, &dummy, &zvoffset) + != FAILURE && Z_TYPE_PP(zvoffset) == IS_NULL; + } + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l|s!l", + &zoneType, ®ion, ®ion_len, &offset_arg) == FAILURE) { + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, + "intltz_create_time_zone_id_enumeration: bad arguments", 0 TSRMLS_CC); + RETURN_FALSE; + } + + if (zoneType != UCAL_ZONE_TYPE_ANY && zoneType != UCAL_ZONE_TYPE_CANONICAL + && zoneType != UCAL_ZONE_TYPE_CANONICAL_LOCATION) { + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, + "intltz_create_time_zone_id_enumeration: bad zone type", 0 TSRMLS_CC); + RETURN_FALSE; + } + + if (ZEND_NUM_ARGS() == 3) { + if (offset_arg < (long)INT32_MIN || offset_arg > (long)INT32_MAX) { + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, + "intltz_create_time_zone_id_enumeration: offset out of bounds", 0 TSRMLS_CC); + RETURN_FALSE; + } + + if (!arg3isnull) { + offset = (int32_t)offset_arg; + offsetp = &offset; + } //else leave offsetp NULL + } + + StringEnumeration *se; + UErrorCode uec = UErrorCode(); + se = TimeZone::createTimeZoneIDEnumeration((USystemTimeZoneType)zoneType, + region, offsetp, uec); + INTL_CHECK_STATUS(uec, "intltz_create_time_zone_id_enumeration: " + "Error obtaining time zone id enumeration") + + IntlIterator_from_StringEnumeration(se, return_value TSRMLS_CC); +} +#endif + +U_CFUNC PHP_FUNCTION(intltz_get_canonical_id) +{ + char *str_id; + int str_id_len; + zval *is_systemid = NULL; + intl_error_reset(NULL TSRMLS_CC); + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|z", + &str_id, &str_id_len, &is_systemid) == FAILURE) { + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, + "intltz_get_canonical_id: bad arguments", 0 TSRMLS_CC); + RETURN_FALSE; + } + + UErrorCode status = UErrorCode(); + UnicodeString id; + if (intl_stringFromChar(id, str_id, str_id_len, &status) == FAILURE) { + intl_error_set(NULL, status, + "intltz_get_canonical_id: could not convert time zone id to UTF-16", 0 TSRMLS_CC); + RETURN_FALSE; + } + + UnicodeString result; + UBool isSystemID; + TimeZone::getCanonicalID(id, result, isSystemID, status); + INTL_CHECK_STATUS(status, "intltz_get_canonical_id: error obtaining canonical ID"); + + intl_convert_utf16_to_utf8(&Z_STRVAL_P(return_value), &Z_STRLEN_P(return_value), + result.getBuffer(), result.length(), &status); + INTL_CHECK_STATUS(status, + "intltz_get_canonical_id: could not convert time zone id to UTF-16"); + Z_TYPE_P(return_value) = IS_STRING; + + if (is_systemid) { /* by-ref argument passed */ + zval_dtor(is_systemid); + ZVAL_BOOL(is_systemid, isSystemID); + } +} + +#if U_ICU_VERSION_MAJOR_NUM * 10 + U_ICU_VERSION_MINOR_NUM >= 48 +U_CFUNC PHP_FUNCTION(intltz_get_region) +{ + char *str_id; + int str_id_len; + char outbuf[3]; + intl_error_reset(NULL TSRMLS_CC); + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", + &str_id, &str_id_len) == FAILURE) { + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, + "intltz_get_region: bad arguments", 0 TSRMLS_CC); + RETURN_FALSE; + } + + UErrorCode status = UErrorCode(); + UnicodeString id; + if (intl_stringFromChar(id, str_id, str_id_len, &status) == FAILURE) { + intl_error_set(NULL, status, + "intltz_get_region: could not convert time zone id to UTF-16", 0 TSRMLS_CC); + RETURN_FALSE; + } + + int32_t region_len = TimeZone::getRegion(id, outbuf, sizeof(outbuf), status); + INTL_CHECK_STATUS(status, "intltz_get_region: Error obtaining region"); + + RETURN_STRINGL(outbuf, region_len, 1); +} +#endif + +U_CFUNC PHP_FUNCTION(intltz_get_tz_data_version) +{ + intl_error_reset(NULL TSRMLS_CC); + + if (zend_parse_parameters_none() == FAILURE) { + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, + "intltz_get_tz_data_version: bad arguments", 0 TSRMLS_CC); + RETURN_FALSE; + } + + UErrorCode status = UErrorCode(); + const char *res = TimeZone::getTZDataVersion(status); + INTL_CHECK_STATUS(status, "intltz_get_tz_data_version: " + "Error obtaining time zone data version"); + + RETURN_STRING(res, 1); +} + +U_CFUNC PHP_FUNCTION(intltz_get_equivalent_id) +{ + char *str_id; + int str_id_len; + long index; + intl_error_reset(NULL TSRMLS_CC); + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sl", + &str_id, &str_id_len, &index) == FAILURE || + index < (long)INT32_MIN || index > (long)INT32_MAX) { + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, + "intltz_get_equivalent_id: bad arguments", 0 TSRMLS_CC); + RETURN_FALSE; + } + + UErrorCode status = UErrorCode(); + UnicodeString id; + if (intl_stringFromChar(id, str_id, str_id_len, &status) == FAILURE) { + intl_error_set(NULL, status, + "intltz_get_equivalent_id: could not convert time zone id to UTF-16", 0 TSRMLS_CC); + RETURN_FALSE; + } + + const UnicodeString result = TimeZone::getEquivalentID(id, (int32_t)index); + intl_convert_utf16_to_utf8(&Z_STRVAL_P(return_value), &Z_STRLEN_P(return_value), + result.getBuffer(), result.length(), &status); + INTL_CHECK_STATUS(status, "intltz_get_equivalent_id: " + "could not convert resulting time zone id to UTF-16"); + Z_TYPE_P(return_value) = IS_STRING; +} + +U_CFUNC PHP_FUNCTION(intltz_get_id) +{ + TIMEZONE_METHOD_INIT_VARS; + + if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O", + &object, TimeZone_ce_ptr) == FAILURE) { + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, + "intltz_get_id: bad arguments", 0 TSRMLS_CC); + RETURN_FALSE; + } + + TIMEZONE_METHOD_FETCH_OBJECT; + + UnicodeString id_us; + to->utimezone->getID(id_us); + + char *id = NULL; + int id_len = 0; + + intl_convert_utf16_to_utf8(&id, &id_len, + id_us.getBuffer(), id_us.length(), TIMEZONE_ERROR_CODE_P(to)); + INTL_METHOD_CHECK_STATUS(to, "intltz_get_id: Could not convert id to UTF-8"); + + RETURN_STRINGL(id, id_len, 0); +} + +U_CFUNC PHP_FUNCTION(intltz_use_daylight_time) +{ + TIMEZONE_METHOD_INIT_VARS; + + if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O", + &object, TimeZone_ce_ptr) == FAILURE) { + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, + "intltz_use_daylight_time: bad arguments", 0 TSRMLS_CC); + RETURN_FALSE; + } + + TIMEZONE_METHOD_FETCH_OBJECT; + + RETURN_BOOL(to->utimezone->useDaylightTime()); +} + +U_CFUNC PHP_FUNCTION(intltz_get_offset) +{ + UDate date; + zend_bool local; + zval *rawOffsetArg, + *dstOffsetArg; + int32_t rawOffset, + dstOffset; + TIMEZONE_METHOD_INIT_VARS; + + if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), + "Odbzz", &object, TimeZone_ce_ptr, &date, &local, &rawOffsetArg, + &dstOffsetArg) == FAILURE) { + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, + "intltz_get_offset: bad arguments", 0 TSRMLS_CC); + RETURN_FALSE; + } + + TIMEZONE_METHOD_FETCH_OBJECT; + + to->utimezone->getOffset(date, (UBool) local, rawOffset, dstOffset, + TIMEZONE_ERROR_CODE(to)); + + INTL_METHOD_CHECK_STATUS(to, "intltz_get_offset: error obtaining offset"); + + zval_dtor(rawOffsetArg); + ZVAL_LONG(rawOffsetArg, rawOffset); + zval_dtor(dstOffsetArg); + ZVAL_LONG(dstOffsetArg, dstOffset); + + RETURN_TRUE; +} + +U_CFUNC PHP_FUNCTION(intltz_get_raw_offset) +{ + TIMEZONE_METHOD_INIT_VARS; + + if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), + "O", &object, TimeZone_ce_ptr) == FAILURE) { + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, + "intltz_get_raw_offset: bad arguments", 0 TSRMLS_CC); + RETURN_FALSE; + } + + TIMEZONE_METHOD_FETCH_OBJECT; + + RETURN_LONG(to->utimezone->getRawOffset()); +} + +U_CFUNC PHP_FUNCTION(intltz_has_same_rules) +{ + zval *other_object; + TimeZone_object *other_to; + TIMEZONE_METHOD_INIT_VARS; + + if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), + "OO", &object, TimeZone_ce_ptr, &other_object, TimeZone_ce_ptr) + == FAILURE) { + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, + "intltz_has_same_rules: bad arguments", 0 TSRMLS_CC); + RETURN_FALSE; + } + TIMEZONE_METHOD_FETCH_OBJECT; + other_to = (TimeZone_object *) zend_object_store_get_object(other_object TSRMLS_CC); + if (other_to->utimezone == NULL) { + intl_errors_set(&to->err, U_ILLEGAL_ARGUMENT_ERROR, + "intltz_has_same_rules: The second IntlTimeZone is unconstructed", 0 TSRMLS_CC); + RETURN_FALSE; + } + + RETURN_BOOL(to->utimezone->hasSameRules(*other_to->utimezone)); +} + +static const TimeZone::EDisplayType display_types[] = { + TimeZone::SHORT, TimeZone::LONG, +#if U_ICU_VERSION_MAJOR_NUM * 10 + U_ICU_VERSION_MINOR_NUM >= 44 + TimeZone::SHORT_GENERIC, TimeZone::LONG_GENERIC, + TimeZone::SHORT_GMT, TimeZone::LONG_GMT, + TimeZone::SHORT_COMMONLY_USED, TimeZone::GENERIC_LOCATION +#endif +}; + +U_CFUNC PHP_FUNCTION(intltz_get_display_name) +{ + zend_bool daylight = 0; + long display_type = TimeZone::LONG; + const char *locale_str = NULL; + int dummy = 0; + TIMEZONE_METHOD_INIT_VARS; + + if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), + "O|bls!", &object, TimeZone_ce_ptr, &daylight, &display_type, + &locale_str, &dummy) == FAILURE) { + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, + "intltz_get_display_name: bad arguments", 0 TSRMLS_CC); + RETURN_FALSE; + } + + bool found = false; + for (int i = 0; !found && i < sizeof(display_types)/sizeof(*display_types); i++) { + if (display_types[i] == display_type) + found = true; + } + if (!found) { + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, + "intltz_get_display_name: wrong display type", 0 TSRMLS_CC); + RETURN_FALSE; + } + + if (!locale_str) { + locale_str = intl_locale_get_default(TSRMLS_C); + } + + TIMEZONE_METHOD_FETCH_OBJECT; + + UnicodeString result; + to->utimezone->getDisplayName((UBool)daylight, (TimeZone::EDisplayType)display_type, + Locale::createFromName(locale_str), result); + + intl_convert_utf16_to_utf8(&Z_STRVAL_P(return_value), &Z_STRLEN_P(return_value), + result.getBuffer(), result.length(), TIMEZONE_ERROR_CODE_P(to)); + INTL_METHOD_CHECK_STATUS(to, "intltz_get_display_name: " + "could not convert resulting time zone id to UTF-16"); + + Z_TYPE_P(return_value) = IS_STRING; +} + +U_CFUNC PHP_FUNCTION(intltz_get_dst_savings) +{ + TIMEZONE_METHOD_INIT_VARS; + + if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), + "O", &object, TimeZone_ce_ptr) == FAILURE) { + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, + "intltz_get_dst_savings: bad arguments", 0 TSRMLS_CC); + RETURN_FALSE; + } + + TIMEZONE_METHOD_FETCH_OBJECT; + + RETURN_LONG((long)to->utimezone->getDSTSavings()); +} + +U_CFUNC PHP_FUNCTION(intltz_to_date_time_zone) +{ + TIMEZONE_METHOD_INIT_VARS; + + if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), + "O", &object, TimeZone_ce_ptr) == FAILURE) { + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, + "intltz_to_date_time_zone: bad arguments", 0 TSRMLS_CC); + RETURN_FALSE; + } + + TIMEZONE_METHOD_FETCH_OBJECT; + + zval *ret = timezone_convert_to_datetimezone(to->utimezone, + &TIMEZONE_ERROR(to), "intltz_to_date_time_zone" TSRMLS_CC); + + if (ret) { + RETURN_ZVAL(ret, 1, 1); + } else { + RETURN_FALSE; + } +} + +U_CFUNC PHP_FUNCTION(intltz_get_error_code) +{ + TIMEZONE_METHOD_INIT_VARS + + if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O", + &object, TimeZone_ce_ptr) == FAILURE) { + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, + "intltz_get_error_code: bad arguments", 0 TSRMLS_CC); + RETURN_FALSE; + } + + /* Fetch the object (without resetting its last error code ). */ + to = (TimeZone_object*)zend_object_store_get_object(object TSRMLS_CC); + if (to == NULL) + RETURN_FALSE; + + RETURN_LONG((long)TIMEZONE_ERROR_CODE(to)); +} + +U_CFUNC PHP_FUNCTION(intltz_get_error_message) +{ + const char* message = NULL; + TIMEZONE_METHOD_INIT_VARS + + if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O", + &object, TimeZone_ce_ptr) == FAILURE) { + intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR, + "intltz_get_error_message: bad arguments", 0 TSRMLS_CC ); + RETURN_FALSE; + } + + + /* Fetch the object (without resetting its last error code ). */ + to = (TimeZone_object*)zend_object_store_get_object(object TSRMLS_CC); + if (to == NULL) + RETURN_FALSE; + + /* Return last error message. */ + message = intl_error_get_message(TIMEZONE_ERROR_P(to) TSRMLS_CC); + RETURN_STRING(message, 0); +} diff --git a/ext/intl/timezone/timezone_methods.h b/ext/intl/timezone/timezone_methods.h new file mode 100644 index 0000000000..28c39f4fd7 --- /dev/null +++ b/ext/intl/timezone/timezone_methods.h @@ -0,0 +1,68 @@ +/* + +----------------------------------------------------------------------+ + | 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 <cataphract@netcabo.pt> | + +----------------------------------------------------------------------+ + */ + +#ifndef TIMEZONE_METHODS_H +#define TIMEZONE_METHODS_H + +#include <php.h> + +PHP_METHOD(IntlTimeZone, __construct); + +PHP_FUNCTION(intltz_create_time_zone); + +PHP_FUNCTION(intltz_from_date_time_zone); + +PHP_FUNCTION(intltz_create_default); + +PHP_FUNCTION(intltz_get_id); + +PHP_FUNCTION(intltz_get_gmt); + +PHP_FUNCTION(intltz_get_unknown); + +PHP_FUNCTION(intltz_create_enumeration); + +PHP_FUNCTION(intltz_count_equivalent_ids); + +PHP_FUNCTION(intltz_create_time_zone_id_enumeration); + +PHP_FUNCTION(intltz_get_canonical_id); + +PHP_FUNCTION(intltz_get_region); + +PHP_FUNCTION(intltz_get_tz_data_version); + +PHP_FUNCTION(intltz_get_equivalent_id); + +PHP_FUNCTION(intltz_use_daylight_time); + +PHP_FUNCTION(intltz_get_offset); + +PHP_FUNCTION(intltz_get_raw_offset); + +PHP_FUNCTION(intltz_has_same_rules); + +PHP_FUNCTION(intltz_get_display_name); + +PHP_FUNCTION(intltz_get_dst_savings); + +PHP_FUNCTION(intltz_to_date_time_zone); + +PHP_FUNCTION(intltz_get_error_code); + +PHP_FUNCTION(intltz_get_error_message); + +#endif /* #ifndef TIMEZONE_METHODS_H */ diff --git a/ext/intl/transliterator/transliterator.c b/ext/intl/transliterator/transliterator.c index 75c9eaabda..8ee49e1e51 100644 --- a/ext/intl/transliterator/transliterator.c +++ b/ext/intl/transliterator/transliterator.c @@ -49,85 +49,6 @@ void transliterator_register_constants( INIT_FUNC_ARGS ) } /* }}} */ -/* {{{ transliterator_parse_error_to_string - * Transforms parse errors in strings. - */ -smart_str transliterator_parse_error_to_string( UParseError* pe ) -{ - smart_str ret = {0}; - char *buf; - int u8len; - UErrorCode status; - int any = 0; - - assert( pe != NULL ); - - smart_str_appends( &ret, "parse error " ); - if( pe->line > 0 ) - { - smart_str_appends( &ret, "on line " ); - smart_str_append_long( &ret, (long ) pe->line ); - any = 1; - } - if( pe->offset >= 0 ) { - if( any ) - smart_str_appends( &ret, ", " ); - else - smart_str_appends( &ret, "at " ); - - smart_str_appends( &ret, "offset " ); - smart_str_append_long( &ret, (long ) pe->offset ); - any = 1; - } - - if (pe->preContext[0] != 0 ) { - if( any ) - smart_str_appends( &ret, ", " ); - - smart_str_appends( &ret, "after \"" ); - intl_convert_utf16_to_utf8( &buf, &u8len, pe->preContext, -1, &status ); - if( U_FAILURE( status ) ) - { - smart_str_appends( &ret, "(could not convert parser error pre-context to UTF-8)" ); - } - else { - smart_str_appendl( &ret, buf, u8len ); - efree( buf ); - } - smart_str_appends( &ret, "\"" ); - any = 1; - } - - if( pe->postContext[0] != 0 ) - { - if( any ) - smart_str_appends( &ret, ", " ); - - smart_str_appends( &ret, "before or at \"" ); - intl_convert_utf16_to_utf8( &buf, &u8len, pe->postContext, -1, &status ); - if( U_FAILURE( status ) ) - { - smart_str_appends( &ret, "(could not convert parser error post-context to UTF-8)" ); - } - else - { - smart_str_appendl( &ret, buf, u8len ); - efree( buf ); - } - smart_str_appends( &ret, "\"" ); - any = 1; - } - - if( !any ) - { - smart_str_free( &ret ); - smart_str_appends( &ret, "no parse error" ); - } - - smart_str_0( &ret ); - return ret; -} - /* * Local variables: * tab-width: 4 diff --git a/ext/intl/transliterator/transliterator_methods.c b/ext/intl/transliterator/transliterator_methods.c index d0cfb9790d..1aa39c54b9 100644 --- a/ext/intl/transliterator/transliterator_methods.c +++ b/ext/intl/transliterator/transliterator_methods.c @@ -183,7 +183,7 @@ PHP_FUNCTION( transliterator_create_from_rules ) { char *msg = NULL; smart_str parse_error_str; - parse_error_str = transliterator_parse_error_to_string( &parse_error ); + parse_error_str = intl_parse_error_to_string( &parse_error ); spprintf( &msg, 0, "transliterator_create_from_rules: unable to " "create ICU transliterator from rules (%s)", parse_error_str.c ); smart_str_free( &parse_error_str ); |
