diff options
Diffstat (limited to 'ext/intl')
296 files changed, 17744 insertions, 770 deletions
diff --git a/ext/intl/ERROR.CONVENTIONS b/ext/intl/ERROR.CONVENTIONS new file mode 100644 index 0000000000..6f9079c56d --- /dev/null +++ b/ext/intl/ERROR.CONVENTIONS @@ -0,0 +1,115 @@ +The intl extension has particular conventions regarding error reporting. +These conventions are enumerated in this document. + +:: The last error is always stored globally. + +The global error code can be obtained in userland with intl_get_error_code(). +This is a U_* error code defined by ICU, but it does not have necessarily to be +returned obtained after a call to an ICU function. That is to say, the internal +PHP wrapper functions can set these error codes when appropriate. For instance, +in response to bad arguments (e.g. zend_parse_parameters() failure), the PHP +wrapper function should set the global error code to U_ILLEGAL_ARGUMENT_ERROR). + +The error code (an integer) can be converter to the corresponding enum name +string in userland with intl_error_name(). + +The associated message can be obtained with intl_get_error_message(). This is a +message set by the PHP wrapping code, not by ICU. The message should include the +name of the function that failed in order to make debugging easier (though if +you activate warnings with intl.error_level or exceptions with +intl.use_exceptions you get more fine-grained information about where the +error ocurred). + +The internal PHP code can set the global last error with: +void intl_error_set_code(intl_error* err, UErrorCode err_code TSRMLS_DC); +void intl_error_set_custom_msg(intl_error* err, char* msg, int copyMsg TSRMLS_DC); +void intl_error_set(intl_error* err, UErrorCode code, char* msg, int copyMsg TSRMLS_DC); + +and by passing NULL as the first parameter. The last function is a combination +of the first two. If the message is not a static buffer, copyMsg should be 1. +This makes the message string be copied and freed when no longer needed. There's +no way to pass ownership of the string without it being copied. + + +:: The last is ALSO stored in the object whose method call triggered the error, + unless the error is due to bad arguments, in which case only the global error + should be set + +Objects store an intl_error structed in their private data. For instance: +typedef struct { + zend_object zo; + intl_error err; + Calendar* ucal; +} Calendar_object; + +The global error and the object error can be SIMULTANEOUSLY set with these +functions: +void intl_errors_set_custom_msg(intl_error* err, char* msg, int copyMsg TSRMLS_DC); +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); + +by passing a pointer to the object's intl_error structed as the first parameter. +Node the extra 's' in the functions' names ('errors', not 'error'). + +Static methods should only set the global error. + + +:: Intl classes that can be instantiated should provide ::getErrorCode() and + getErrorMessage() methods + +These methods are used to retrieve the error codes stored in the object's +private intl_error structured and mirror the global intl_get_error_code() and +intl_get_error_message(). + + +:: Intl methods and functions should return FALSE on error (even argument + parsing errors), not NULL. Constructors and factory methods are the + exception; these should return NULL, not FALSE. + +Not that constructors in Intl generally (always?) don't throws exceptions. +They instead destroy the object to that the result of new IntlClass() can +be NULL. This may be surprising. + + +:: Intl functions and methods should reset the global error before doing + anything else (even parse the arguments); instance methods should also reset + the object's private error + +Errors should be lost after a function call. This is different from the way +ICU operates, where functions return immediately if an error is set. + +Error resetting can be done with: +void intl_error_reset(NULL TSRMLS_DC); /* reset global error */ +void intl_errors_reset(intl_error* err TSRMLS_DC ); /* reset global and object error */ + +In practice, intl_errors_reset() is not used because most classes have also +plain functions mapped to the same internal functions as their instance methods. +Fetching of the object is done with zend_parse_method_parameters() instead of +directly using getThis(). Therefore, no reference to object is obtained until +the arguments are fully parsed. Without a reference to the object, there's no +way to reset the object's internal error code. Instead, resetting of the +object's internal error code is done upon fetching the object from its zval. + +Example: +U_CFUNC PHP_FUNCTION(breakiter_set_text) +{ + /* ... variable declations ... */ + BREAKITER_METHOD_INIT_VARS; /* macro also resets global error */ + 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; + } + + /* ... */ + + BREAKITER_METHOD_FETCH_OBJECT; /* macro also resets object's error */ + + /* ... */ +} + +Implementations of ::getErrorCode() and ::getErrorMessage() should not reset the +object's error code. diff --git a/ext/intl/breakiterator/breakiterator_class.cpp b/ext/intl/breakiterator/breakiterator_class.cpp new file mode 100644 index 0000000000..7bf271a344 --- /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_get_locale, 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..454e5249fd --- /dev/null +++ b/ext/intl/breakiterator/rulebasedbreakiterator_methods.cpp @@ -0,0 +1,221 @@ +/* + +----------------------------------------------------------------------+ + | 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_intlrbbi_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); + delete rbbi; + 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); + delete rbbi; + 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_intlrbbi_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..2d33bd1952 --- /dev/null +++ b/ext/intl/calendar/calendar_methods.cpp @@ -0,0 +1,1328 @@ +/* + +----------------------------------------------------------------------+ + | 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" +#include "../common/common_date.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_errors_set(CALENDAR_ERROR_P(co), 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_create.c b/ext/intl/collator/collator_create.c index b2a9968af4..b2a8c7f6ba 100644 --- a/ext/intl/collator/collator_create.c +++ b/ext/intl/collator/collator_create.c @@ -48,7 +48,7 @@ static void collator_ctor(INTERNAL_FUNCTION_PARAMETERS) COLLATOR_METHOD_FETCH_OBJECT; if(locale_len == 0) { - locale = INTL_G(default_locale); + locale = intl_locale_get_default(TSRMLS_C); } /* Open ICU collator. */ diff --git a/ext/intl/collator/collator_sort.c b/ext/intl/collator/collator_sort.c index 0785111c96..04a24f013e 100644 --- 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_date.cpp b/ext/intl/common/common_date.cpp new file mode 100644 index 0000000000..ee998818d9 --- /dev/null +++ b/ext/intl/common/common_date.cpp @@ -0,0 +1,250 @@ +/* + +----------------------------------------------------------------------+ + | 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> + +extern "C" { +#include "../php_intl.h" +#define USE_CALENDAR_POINTER 1 +#include "../calendar/calendar_class.h" +#include <ext/date/php_date.h> +} + +#ifndef INFINITY +#define INFINITY (DBL_MAX+DBL_MAX) +#endif + +#ifndef NAN +#define NAN (INFINITY-INFINITY) +#endif + +/* {{{ 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; +} +/* }}} */ + +U_CFUNC int intl_datetime_decompose(zval *z, double *millis, TimeZone **tz, + intl_error *err, const char *func TSRMLS_DC) +{ + zval retval; + zval *zfuncname; + char *message; + + if (err && U_FAILURE(err->code)) { + return FAILURE; + } + + if (millis) { + *millis = NAN; + } + if (tz) { + *tz = NULL; + } + + if (millis) { + 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) { + spprintf(&message, 0, "%s: error calling ::getTimeStamp() on the " + "object", func); + intl_errors_set(err, U_INTERNAL_PROGRAM_ERROR, + message, 1 TSRMLS_CC); + efree(message); + zval_ptr_dtor(&zfuncname); + return FAILURE; + } + + *millis = U_MILLIS_PER_SECOND * (double)Z_LVAL(retval); + zval_ptr_dtor(&zfuncname); + } + + if (tz) { + php_date_obj *datetime; + datetime = (php_date_obj*)zend_object_store_get_object(z TSRMLS_CC); + if (!datetime->time) { + spprintf(&message, 0, "%s: the DateTime object is not properly " + "initialized", func); + intl_errors_set(err, U_ILLEGAL_ARGUMENT_ERROR, + message, 1 TSRMLS_CC); + efree(message); + return FAILURE; + } + if (!datetime->time->is_localtime) { + *tz = TimeZone::getGMT()->clone(); + } else { + *tz = timezone_convert_datetimezone(datetime->time->zone_type, + datetime, 1, NULL, func TSRMLS_CC); + if (*tz == NULL) { + spprintf(&message, 0, "%s: could not convert DateTime's " + "time zone", func); + intl_errors_set(err, U_ILLEGAL_ARGUMENT_ERROR, + message, 1 TSRMLS_CC); + efree(message); + return FAILURE; + } + } + } + + return SUCCESS; +} + +U_CFUNC double intl_zval_to_millis(zval *z, intl_error *err, const char *func TSRMLS_DC) +{ + double rv = NAN; + long lv; + int type; + char *message; + + if (err && U_FAILURE(err->code)) { + 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 { + spprintf(&message, 0, "%s: string '%s' is not numeric, " + "which would be required for it to be a valid date", func, + Z_STRVAL_P(z)); + intl_errors_set(err, U_ILLEGAL_ARGUMENT_ERROR, + message, 1 TSRMLS_CC); + efree(message); + } + 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)) { + intl_datetime_decompose(z, &rv, NULL, err, func TSRMLS_CC); + } 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) { + spprintf(&message, 0, "%s: IntlCalendar object is not properly " + "constructed", func); + intl_errors_set(err, U_ILLEGAL_ARGUMENT_ERROR, + message, 1 TSRMLS_CC); + efree(message); + } else { + UErrorCode status = UErrorCode(); + rv = (double)co->ucal->getTime(status); + if (U_FAILURE(status)) { + spprintf(&message, 0, "%s: call to internal " + "Calendar::getTime() has failed", func); + intl_errors_set(err, status, message, 1 TSRMLS_CC); + efree(message); + } + } + } else { + /* TODO: try with cast(), get() to obtain a number */ + spprintf(&message, 0, "%s: invalid object type for date/time " + "(only IntlCalendar and DateTime permitted)", func); + intl_errors_set(err, U_ILLEGAL_ARGUMENT_ERROR, + message, 1 TSRMLS_CC); + efree(message); + } + break; + default: + spprintf(&message, 0, "%s: invalid PHP type for date", func); + intl_errors_set(err, U_ILLEGAL_ARGUMENT_ERROR, + message, 1 TSRMLS_CC); + efree(message); + break; + } + + return rv; +} + diff --git a/ext/intl/common/common_date.h b/ext/intl/common/common_date.h new file mode 100644 index 0000000000..d2396cbf5a --- /dev/null +++ b/ext/intl/common/common_date.h @@ -0,0 +1,40 @@ +/* + +----------------------------------------------------------------------+ + | 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 COMMON_DATE_H +#define COMMON_DATE_H + +#include <unicode/umachine.h> + +U_CDECL_BEGIN +#include <php.h> +#include "../intl_error.h" +U_CDECL_END + +#ifdef __cplusplus + +#include <unicode/timezone.h> + +U_CFUNC TimeZone *timezone_convert_datetimezone(int type, void *object, int is_datetime, intl_error *outside_error, const char *func TSRMLS_DC); +U_CFUNC int intl_datetime_decompose(zval *z, double *millis, TimeZone **tz, + intl_error *err, const char *func TSRMLS_DC); + +#endif + +U_CFUNC double intl_zval_to_millis(zval *z, intl_error *err, const char *func TSRMLS_DC); + +#endif /* COMMON_DATE_H */ + 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/common/common_error.c b/ext/intl/common/common_error.c index 282172224c..a0ee7c145f 100644 --- a/ext/intl/common/common_error.c +++ b/ext/intl/common/common_error.c @@ -240,9 +240,7 @@ void intl_expose_icu_error_codes( INIT_FUNC_ARGS ) INTL_EXPOSE_CONST( U_IDNA_ACE_PREFIX_ERROR ); INTL_EXPOSE_CONST( U_IDNA_VERIFICATION_ERROR ); INTL_EXPOSE_CONST( U_IDNA_LABEL_TOO_LONG_ERROR ); -#if U_ICU_VERSION_MAJOR_NUM > 3 || U_ICU_VERSION_MAJOR_NUM == 3 && U_ICU_VERSION_MINOR_NUM >= 6 INTL_EXPOSE_CONST( U_IDNA_ZERO_LENGTH_LABEL_ERROR ); -#endif #if U_ICU_VERSION_MAJOR_NUM > 3 || U_ICU_VERSION_MAJOR_NUM == 3 && U_ICU_VERSION_MINOR_NUM >= 8 INTL_EXPOSE_CONST( U_IDNA_DOMAIN_NAME_TOO_LONG_ERROR ); #endif diff --git a/ext/intl/config.m4 b/ext/intl/config.m4 index 0477c7f59d..4630a302ef 100644 --- 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,9 @@ if test "$PHP_INTL" != "no"; then collator/collator_is_numeric.c \ collator/collator_error.c \ common/common_error.c \ + common/common_enum.cpp \ + common/common_date.cpp \ + converter/converter.c \ formatter/formatter.c \ formatter/formatter_main.c \ formatter/formatter_class.c \ @@ -49,7 +53,11 @@ if test "$PHP_INTL" != "no"; then dateformat/dateformat_attr.c \ dateformat/dateformat_data.c \ dateformat/dateformat_format.c \ + dateformat/dateformat_format_object.cpp \ 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,9 +73,21 @@ 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/converter) PHP_ADD_BUILD_DIR($ext_builddir/common) PHP_ADD_BUILD_DIR($ext_builddir/formatter) PHP_ADD_BUILD_DIR($ext_builddir/normalizer) @@ -77,6 +97,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..bb1dca8124 100644 --- 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,11 @@ if (PHP_INTL != "no") { ", "intl"); ADD_SOURCES(configure_module_dirname + "/common", "\ common_error.c \ + common_enum.cpp \ + common_date.cpp \ + ", "intl"); + ADD_SOURCES(configure_module_dirname + "/converter", "\ + converter.c \ ", "intl"); ADD_SOURCES(configure_module_dirname + "/formatter", "\ formatter.c \ @@ -60,8 +65,12 @@ if (PHP_INTL != "no") { dateformat_class.c \ dateformat_attr.c \ dateformat_format.c \ + dateformat_format_object.cpp \ 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 +96,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/converter/converter.c b/ext/intl/converter/converter.c new file mode 100644 index 0000000000..5f2d1e7fa7 --- /dev/null +++ b/ext/intl/converter/converter.c @@ -0,0 +1,1173 @@ +/* + +----------------------------------------------------------------------+ + | 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: Sara Golemon <pollita@php.net> | + +----------------------------------------------------------------------+ + */ + +#include "converter.h" +#include "zend_exceptions.h" + +#include <unicode/utypes.h> +#include <unicode/ucnv.h> +#include <unicode/ustring.h> + +#include "../intl_error.h" + +typedef struct _php_converter_object { + zend_object obj; +#ifdef ZTS + void ***tsrm_ls; +#endif + UConverter *src, *dest; + zend_fcall_info to_cb, from_cb; + zend_fcall_info_cache to_cache, from_cache; + intl_error error; +} php_converter_object; + +static zend_class_entry *php_converter_ce; +static zend_object_handlers php_converter_object_handlers; + +#define CONV_GET(pzv) ((php_converter_object*)zend_objects_get_address((pzv) TSRMLS_CC)) +#define THROW_UFAILURE(obj, fname, error) php_converter_throw_failure(obj, error TSRMLS_CC, \ + fname "() returned error %ld: %s", (long)error, u_errorName(error)) + +/* {{{ php_converter_throw_failure */ +static inline void php_converter_throw_failure(php_converter_object *objval, UErrorCode error TSRMLS_DC, const char *format, ...) { + intl_error *err = objval ? &(objval->error) : NULL; + char message[1024]; + va_list vargs; + + va_start(vargs, format); + vsnprintf(message, sizeof(message), format, vargs); + va_end(vargs); + + intl_errors_set(err, error, message, 1 TSRMLS_CC); +} +/* }}} */ + +/* {{{ php_converter_default_callback */ +static void php_converter_default_callback(zval *return_value, zval *zobj, long reason, zval *error TSRMLS_DC) { + /* Basic functionality so children can call parent::toUCallback() */ + switch (reason) { + case UCNV_UNASSIGNED: + case UCNV_ILLEGAL: + case UCNV_IRREGULAR: + { + php_converter_object *objval = (php_converter_object*)CONV_GET(zobj); + char chars[127]; + int8_t chars_len = sizeof(chars); + UErrorCode error = U_ZERO_ERROR; + + /* Yes, this is fairly wasteful at first glance, + * but considering that the alternative is to store + * what's sent into setSubstChars() and the fact + * that this is an extremely unlikely codepath + * I'd rather take the CPU hit here, than waste time + * storing a value I'm unlikely to use. + */ + ucnv_getSubstChars(objval->src, chars, &chars_len, &error); + if (U_FAILURE(error)) { + THROW_UFAILURE(objval, "ucnv_getSubstChars", error); + chars[0] = 0x1A; + chars[1] = 0; + chars_len = 1; + } + RETVAL_STRINGL(chars, chars_len, 1); + } + } + zval_dtor(error); + ZVAL_LONG(error, U_ZERO_ERROR); +} +/* }}} */ + +/* {{{ proto void UConverter::toUCallback(long $reason, + string $source, string $codeUnits, + long &$error) */ +ZEND_BEGIN_ARG_INFO_EX(php_converter_toUCallback_arginfo, 0, ZEND_RETURN_VALUE, 4) + ZEND_ARG_INFO(0, reason) + ZEND_ARG_INFO(0, source) + ZEND_ARG_INFO(0, codeUnits) + ZEND_ARG_INFO(1, error) +ZEND_END_ARG_INFO(); +static PHP_METHOD(UConverter, toUCallback) { + long reason; + zval *source, *codeUnits, *error; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "lzzz", + &reason, &source, &codeUnits, &error) == FAILURE) { + return; + } + + php_converter_default_callback(return_value, getThis(), reason, error TSRMLS_CC); +} +/* }}} */ + +/* {{{ proto void UConverter::fromUCallback(long $reason, + Array $source, long $codePoint, + long &$error) */ +ZEND_BEGIN_ARG_INFO_EX(php_converter_fromUCallback_arginfo, 0, ZEND_RETURN_VALUE, 4) + ZEND_ARG_INFO(0, reason) + ZEND_ARG_INFO(0, source) + ZEND_ARG_INFO(0, codePoint) + ZEND_ARG_INFO(1, error) +ZEND_END_ARG_INFO(); +static PHP_METHOD(UConverter, fromUCallback) { + long reason; + zval *source, *codePoint, *error; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "lzzz", + &reason, &source, &codePoint, &error) == FAILURE) { + return; + } + + php_converter_default_callback(return_value, getThis(), reason, error TSRMLS_CC); +} +/* }}} */ + +/* {{{ php_converter_check_limits */ +static inline zend_bool php_converter_check_limits(php_converter_object *objval, long available, long needed TSRMLS_DC) { + if (available < needed) { + php_converter_throw_failure(objval, U_BUFFER_OVERFLOW_ERROR TSRMLS_CC, "Buffer overrun %ld bytes needed, %ld available", needed, available); + return 0; + } + return 1; +} +/* }}} */ + +#define TARGET_CHECK(cnvargs, needed) php_converter_check_limits(objval, cnvargs->targetLimit - cnvargs->target, needed TSRMLS_CC) + +/* {{{ php_converter_append_toUnicode_target */ +static void php_converter_append_toUnicode_target(zval *val, UConverterToUnicodeArgs *args, php_converter_object *objval TSRMLS_DC) { + switch (Z_TYPE_P(val)) { + case IS_NULL: + /* Code unit is being skipped */ + return; + case IS_LONG: + { + long lval = Z_LVAL_P(val); + if ((lval < 0) || (lval > 0x10FFFF)) { + php_converter_throw_failure(objval, U_ILLEGAL_ARGUMENT_ERROR TSRMLS_CC, "Invalid codepoint U+%04lx", lval); + return; + } + if (lval > 0xFFFF) { + /* Supplemental planes U+010000 - U+10FFFF */ + if (TARGET_CHECK(args, 2)) { + /* TODO: Find the ICU call which does this properly */ + *(args->target++) = (UChar)(((lval - 0x10000) >> 10) | 0xD800); + *(args->target++) = (UChar)(((lval - 0x10000) & 0x3FF) | 0xDC00); + } + return; + } + /* Non-suggogate BMP codepoint */ + if (TARGET_CHECK(args, 1)) { + *(args->target++) = (UChar)lval; + } + return; + } + case IS_STRING: + { + const char *strval = Z_STRVAL_P(val); + int i = 0, strlen = Z_STRLEN_P(val); + + while((i != strlen) && TARGET_CHECK(args, 1)) { + UChar c; + U8_NEXT(strval, i, strlen, c); + *(args->target++) = c; + } + return; + } + case IS_ARRAY: + { + HashTable *ht = Z_ARRVAL_P(val); + HashPosition pos; + zval **tmpzval; + + for(zend_hash_internal_pointer_reset_ex(ht, &pos); + zend_hash_get_current_data_ex(ht, (void**)&tmpzval, &pos) == SUCCESS; + zend_hash_move_forward_ex(ht, &pos)) { + php_converter_append_toUnicode_target(*tmpzval, args, objval TSRMLS_CC); + } + return; + } + default: + php_converter_throw_failure(objval, U_ILLEGAL_ARGUMENT_ERROR TSRMLS_CC, + "toUCallback() specified illegal type for substitution character"); + } +} +/* }}} */ + +/* {{{ php_converter_to_u_callback */ +static void php_converter_to_u_callback(const void *context, + UConverterToUnicodeArgs *args, + const char *codeUnits, int32_t length, + UConverterCallbackReason reason, + UErrorCode *pErrorCode) { + php_converter_object *objval = (php_converter_object*)context; + zval *zreason, *zsource, *zcodeunits, *zerror, *retval = NULL; + zval **zargs[4]; +#ifdef ZTS + TSRMLS_D = objval->tsrm_ls; +#endif + + MAKE_STD_ZVAL(zreason); + ZVAL_LONG(zreason, reason); + zargs[0] = &zreason; + + MAKE_STD_ZVAL(zsource); + ZVAL_STRINGL(zsource, args->source, args->sourceLimit - args->source, 1); + zargs[1] = &zsource; + + MAKE_STD_ZVAL(zcodeunits); + ZVAL_STRINGL(zcodeunits, codeUnits, length, 1); + zargs[2] = &zcodeunits; + + MAKE_STD_ZVAL(zerror); + ZVAL_LONG(zerror, *pErrorCode); + zargs[3] = &zerror; + + objval->to_cb.param_count = 4; + objval->to_cb.params = zargs; + objval->to_cb.retval_ptr_ptr = &retval; + objval->to_cb.no_separation = 0; + if (zend_call_function(&(objval->to_cb), &(objval->to_cache) TSRMLS_CC) == FAILURE) { + /* Unlikely */ + php_converter_throw_failure(objval, U_INTERNAL_PROGRAM_ERROR TSRMLS_CC, "Unexpected failure calling toUCallback()"); + } else if (retval) { + php_converter_append_toUnicode_target(retval, args, objval TSRMLS_CC); + zval_ptr_dtor(&retval); + } + + if (Z_TYPE_P(zerror) == IS_LONG) { + *pErrorCode = Z_LVAL_P(zerror); + } + + zval_ptr_dtor(&zreason); + zval_ptr_dtor(&zsource); + zval_ptr_dtor(&zcodeunits); + zval_ptr_dtor(&zerror); +} +/* }}} */ + +/* {{{ php_converter_append_fromUnicode_target */ +static void php_converter_append_fromUnicode_target(zval *val, UConverterFromUnicodeArgs *args, php_converter_object *objval TSRMLS_DC) { + switch (Z_TYPE_P(val)) { + case IS_NULL: + /* Ignore */ + return; + case IS_LONG: + if (TARGET_CHECK(args, 1)) { + *(args->target++) = Z_LVAL_P(val); + } + return; + case IS_STRING: + { + int vallen = Z_STRLEN_P(val); + if (TARGET_CHECK(args, vallen)) { + memcpy(args->target, Z_STRVAL_P(val), vallen); + args->target += vallen; + } + return; + } + case IS_ARRAY: + { + HashTable *ht = Z_ARRVAL_P(val); + HashPosition pos; + zval **tmpzval; + for(zend_hash_internal_pointer_reset_ex(ht, &pos); + zend_hash_get_current_data_ex(ht, (void**)&tmpzval, &pos) == SUCCESS; + zend_hash_move_forward_ex(ht, &pos)) { + php_converter_append_fromUnicode_target(*tmpzval, args, objval TSRMLS_CC); + } + return; + } + default: + php_converter_throw_failure(objval, U_ILLEGAL_ARGUMENT_ERROR TSRMLS_CC, "fromUCallback() specified illegal type for substitution character"); + } +} +/* }}} */ + +/* {{{ php_converter_from_u_callback */ +static void php_converter_from_u_callback(const void *context, + UConverterFromUnicodeArgs *args, + const UChar *codeUnits, int32_t length, UChar32 codePoint, + UConverterCallbackReason reason, + UErrorCode *pErrorCode) { + php_converter_object *objval = (php_converter_object*)context; + zval *zreason, *zsource, *zcodepoint, *zerror, *retval = NULL; + zval **zargs[4]; + int i; +#ifdef ZTS + TSRMLS_D = objval->tsrm_ls; +#endif + + MAKE_STD_ZVAL(zreason); + ZVAL_LONG(zreason, reason); + zargs[0] = &zreason; + + MAKE_STD_ZVAL(zsource); + array_init(zsource); + i = 0; + while (i < length) { + UChar32 c; + U16_NEXT(codeUnits, i, length, c); + add_next_index_long(zsource, c); + } + zargs[1] = &zsource; + + MAKE_STD_ZVAL(zcodepoint); + ZVAL_LONG(zcodepoint, codePoint); + zargs[2] = &zcodepoint; + + MAKE_STD_ZVAL(zerror); + ZVAL_LONG(zerror, *pErrorCode); + zargs[3] = &zerror; + + objval->from_cb.param_count = 4; + objval->from_cb.params = zargs; + objval->from_cb.retval_ptr_ptr = &retval; + objval->from_cb.no_separation = 0; + if (zend_call_function(&(objval->from_cb), &(objval->from_cache) TSRMLS_CC) == FAILURE) { + /* Unlikely */ + php_converter_throw_failure(objval, U_INTERNAL_PROGRAM_ERROR TSRMLS_CC, "Unexpected failure calling fromUCallback()"); + } else if (retval) { + php_converter_append_fromUnicode_target(retval, args, objval TSRMLS_CC); + zval_ptr_dtor(&retval); + } + + if (Z_TYPE_P(zerror) == IS_LONG) { + *pErrorCode = Z_LVAL_P(zerror); + } + + zval_ptr_dtor(&zreason); + zval_ptr_dtor(&zsource); + zval_ptr_dtor(&zcodepoint); + zval_ptr_dtor(&zerror); +} +/* }}} */ + +/* {{{ php_converter_set_callbacks */ +static inline zend_bool php_converter_set_callbacks(php_converter_object *objval, UConverter *cnv TSRMLS_DC) { + zend_bool ret = 1; + UErrorCode error = U_ZERO_ERROR; + + if (objval->obj.ce == php_converter_ce) { + /* Short-circuit having to go through method calls and data marshalling + * when we're using default behavior + */ + return 1; + } + + ucnv_setToUCallBack(cnv, (UConverterToUCallback)php_converter_to_u_callback, (const void*)objval, + NULL, NULL, &error); + if (U_FAILURE(error)) { + THROW_UFAILURE(objval, "ucnv_setToUCallBack", error); + ret = 0; + } + + error = U_ZERO_ERROR; + ucnv_setFromUCallBack(cnv, (UConverterFromUCallback)php_converter_from_u_callback, (const void*)objval, + NULL, NULL, &error); + if (U_FAILURE(error)) { + THROW_UFAILURE(objval, "ucnv_setFromUCallBack", error); + ret = 0; + } + return ret; +} +/* }}} */ + +/* {{{ php_converter_set_encoding */ +static zend_bool php_converter_set_encoding(php_converter_object *objval, + UConverter **pcnv, + const char *enc, int enc_len + TSRMLS_DC) { + UErrorCode error = U_ZERO_ERROR; + UConverter *cnv = ucnv_open(enc, &error); + + if (error == U_AMBIGUOUS_ALIAS_WARNING) { + UErrorCode getname_error = U_ZERO_ERROR; + const char *actual_encoding = ucnv_getName(cnv, &getname_error); + if (U_FAILURE(getname_error)) { + /* Should never happen */ + actual_encoding = "(unknown)"; + } + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Ambiguous encoding specified, using %s", actual_encoding); + } else if (U_FAILURE(error)) { + if (objval) { + THROW_UFAILURE(objval, "ucnv_open", error); + } else { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error setting encoding: %d - %s", (int)error, u_errorName(error)); + } + return 0; + } + + if (objval && !php_converter_set_callbacks(objval, cnv TSRMLS_CC)) { + return 0; + } + + if (*pcnv) { + ucnv_close(*pcnv); + } + *pcnv = cnv; + return 1; +} +/* }}} */ + +/* {{{ php_converter_do_set_encoding */ +ZEND_BEGIN_ARG_INFO_EX(php_converter_set_encoding_arginfo, 0, ZEND_RETURN_VALUE, 1) + ZEND_ARG_INFO(0, encoding) +ZEND_END_ARG_INFO(); +static void php_converter_do_set_encoding(UConverter *cnv, INTERNAL_FUNCTION_PARAMETERS) { + php_converter_object *objval = CONV_GET(getThis()); + char *enc; + int enc_len; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &enc, &enc_len) == FAILURE) { + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, "Bad arguments, " + "expected one string argument", 0 TSRMLS_CC); + RETURN_FALSE; + } + intl_errors_reset(&objval->error TSRMLS_CC); + + RETURN_BOOL(php_converter_set_encoding(objval, &(objval->src), enc, enc_len TSRMLS_CC)); +} +/* }}} */ + +/* {{{ proto bool UConverter::setSourceEncoding(string encoding) */ +static PHP_METHOD(UConverter, setSourceEncoding) { + php_converter_object *objval = CONV_GET(getThis()); + php_converter_do_set_encoding(objval->src, INTERNAL_FUNCTION_PARAM_PASSTHRU); +} +/* }}} */ + +/* {{{ proto bool UConverter::setDestinationEncoding(string encoding) */ +static PHP_METHOD(UConverter, setDestinationEncoding) { + php_converter_object *objval = CONV_GET(getThis()); + php_converter_do_set_encoding(objval->dest, INTERNAL_FUNCTION_PARAM_PASSTHRU); +} +/* }}} */ + +/* {{{ php_converter_do_get_encoding */ +ZEND_BEGIN_ARG_INFO_EX(php_converter_get_encoding_arginfo, 0, ZEND_RETURN_VALUE, 0) +ZEND_END_ARG_INFO(); +static void php_converter_do_get_encoding(php_converter_object *objval, UConverter *cnv, INTERNAL_FUNCTION_PARAMETERS) { + const char *name; + + if (zend_parse_parameters_none() == FAILURE) { + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, "Expected no arguments", 0 TSRMLS_CC); + RETURN_FALSE; + } + + intl_errors_reset(&objval->error TSRMLS_CC); + + if (!cnv) { + RETURN_NULL(); + } + + name = ucnv_getName(cnv, &objval->error.code); + if (U_FAILURE(objval->error.code)) { + THROW_UFAILURE(objval, "ucnv_getName()", objval->error.code); + RETURN_FALSE; + } + + RETURN_STRING(name, 1); +} +/* }}} */ + +/* {{{ proto string UConverter::getSourceEncoding() */ +static PHP_METHOD(UConverter, getSourceEncoding) { + php_converter_object *objval = CONV_GET(getThis()); + php_converter_do_get_encoding(objval, objval->src, INTERNAL_FUNCTION_PARAM_PASSTHRU); +} +/* }}} */ + +/* {{{ proto string UConverter::getDestinationEncoding() */ +static PHP_METHOD(UConverter, getDestinationEncoding) { + php_converter_object *objval = CONV_GET(getThis()); + php_converter_do_get_encoding(objval, objval->dest, INTERNAL_FUNCTION_PARAM_PASSTHRU); +} +/* }}} */ + +/* {{{ php_converter_do_get_type */ +ZEND_BEGIN_ARG_INFO_EX(php_converter_get_type_arginfo, 0, ZEND_RETURN_VALUE, 0) +ZEND_END_ARG_INFO(); +static void php_converter_do_get_type(php_converter_object *objval, UConverter *cnv, INTERNAL_FUNCTION_PARAMETERS) { + UConverterType t; + + if (zend_parse_parameters_none() == FAILURE) { + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, "Expected no arguments", 0 TSRMLS_CC); + RETURN_FALSE; + } + intl_errors_reset(&objval->error TSRMLS_CC); + + if (!cnv) { + RETURN_NULL(); + } + + t = ucnv_getType(cnv); + if (U_FAILURE(objval->error.code)) { + THROW_UFAILURE(objval, "ucnv_getType", objval->error.code); + RETURN_FALSE; + } + + RETURN_LONG(t); +} +/* }}} */ + +/* {{{ proto long UConverter::getSourceType() */ +static PHP_METHOD(UConverter, getSourceType) { + php_converter_object *objval = CONV_GET(getThis()); + php_converter_do_get_type(objval, objval->src, INTERNAL_FUNCTION_PARAM_PASSTHRU); +} +/* }}} */ + +/* {{{ proto long UConverter::getDestinationType() */ +static PHP_METHOD(UConverter, getDestinationType) { + php_converter_object *objval = CONV_GET(getThis()); + php_converter_do_get_type(objval, objval->dest, INTERNAL_FUNCTION_PARAM_PASSTHRU); +} +/* }}} */ + +/* {{{ php_converter_resolve_callback */ +static void php_converter_resolve_callback(zval *zobj, + php_converter_object *objval, + const char *callback_name, + zend_fcall_info *finfo, + zend_fcall_info_cache *fcache TSRMLS_DC) { + char *errstr = NULL; + zval caller; + + array_init(&caller); + Z_ADDREF_P(zobj); + add_index_zval(&caller, 0, zobj); + add_index_string(&caller, 1, callback_name, 1); + if (zend_fcall_info_init(&caller, 0, finfo, fcache, NULL, &errstr TSRMLS_CC) == FAILURE) { + php_converter_throw_failure(objval, U_INTERNAL_PROGRAM_ERROR TSRMLS_CC, "Error setting converter callback: %s", errstr); + } + zval_dtor(&caller); + if (errstr) { + efree(errstr); + } +} +/* }}} */ + +/* {{{ proto void UConverter::__construct([string dest = 'utf-8',[string src = 'utf-8']]) */ +ZEND_BEGIN_ARG_INFO_EX(php_converter_arginfo, 0, ZEND_RETURN_VALUE, 0) + ZEND_ARG_INFO(0, destination_encoding) + ZEND_ARG_INFO(0, source_encoding) +ZEND_END_ARG_INFO(); + +static PHP_METHOD(UConverter, __construct) { + php_converter_object *objval = CONV_GET(getThis()); + char *src = "utf-8"; + int src_len = sizeof("utf-8") - 1; + char *dest = src; + int dest_len = src_len; + + intl_error_reset(NULL TSRMLS_CC); + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s!s!", + &dest, &dest_len, &src, &src_len) == FAILURE) { + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, + "UConverter::__construct(): bad arguments", 0 TSRMLS_CC); + return; + } + + php_converter_set_encoding(objval, &(objval->src), src, src_len TSRMLS_CC); + php_converter_set_encoding(objval, &(objval->dest), dest, dest_len TSRMLS_CC); + php_converter_resolve_callback(getThis(), objval, "toUCallback", &(objval->to_cb), &(objval->to_cache) TSRMLS_CC); + php_converter_resolve_callback(getThis(), objval, "fromUCallback", &(objval->from_cb), &(objval->from_cache) TSRMLS_CC); +} +/* }}} */ + +/* {{{ proto bool UConverter::setSubstChars(string $chars) */ +ZEND_BEGIN_ARG_INFO_EX(php_converter_setSubstChars_arginfo, 0, ZEND_RETURN_VALUE, 1) + ZEND_ARG_INFO(0, chars) +ZEND_END_ARG_INFO(); + +static PHP_METHOD(UConverter, setSubstChars) { + php_converter_object *objval = CONV_GET(getThis()); + char *chars; + int chars_len, ret = 1; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &chars, &chars_len) == FAILURE) { + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, + "UConverter::setSubstChars(): bad arguments", 0 TSRMLS_CC); + RETURN_FALSE; + } + intl_errors_reset(&objval->error TSRMLS_CC); + + if (objval->src) { + UErrorCode error = U_ZERO_ERROR; + ucnv_setSubstChars(objval->src, chars, chars_len, &error); + if (U_FAILURE(error)) { + THROW_UFAILURE(objval, "ucnv_setSubstChars", error); + ret = 0; + } + } else { + php_converter_throw_failure(objval, U_INVALID_STATE_ERROR TSRMLS_CC, "Source Converter has not been initialized yet"); + ret = 0; + } + + if (objval->dest) { + UErrorCode error = U_ZERO_ERROR; + ucnv_setSubstChars(objval->dest, chars, chars_len, &error); + if (U_FAILURE(error)) { + THROW_UFAILURE(objval, "ucnv_setSubstChars", error); + ret = 0; + } + } else { + php_converter_throw_failure(objval, U_INVALID_STATE_ERROR TSRMLS_CC, "Destination Converter has not been initialized yet"); + ret = 0; + } + + RETURN_BOOL(ret); +} +/* }}} */ + +/* {{{ proto string UConverter::getSubstChars() */ +ZEND_BEGIN_ARG_INFO_EX(php_converter_getSubstChars_arginfo, 0, ZEND_RETURN_VALUE, 0) +ZEND_END_ARG_INFO(); + +static PHP_METHOD(UConverter, getSubstChars) { + php_converter_object *objval = CONV_GET(getThis()); + char chars[127]; + int8_t chars_len = sizeof(chars); + UErrorCode error = U_ZERO_ERROR; + + if (zend_parse_parameters_none() == FAILURE) { + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, + "UConverter::getSubstChars(): expected no arguments", 0 TSRMLS_CC); + RETURN_FALSE; + } + intl_errors_reset(&objval->error TSRMLS_CC); + + if (!objval->src) { + RETURN_NULL(); + } + + /* src and dest get the same subst chars set, + * so it doesn't really matter which one we read from + */ + ucnv_getSubstChars(objval->src, chars, &chars_len, &error); + if (U_FAILURE(error)) { + THROW_UFAILURE(objval, "ucnv_getSubstChars", error); + RETURN_FALSE; + } + + RETURN_STRINGL(chars, chars_len, 1); +} +/* }}} */ + +/* {{{ php_converter_do_convert */ +static zend_bool php_converter_do_convert(UConverter *dest_cnv, char **pdest, int32_t *pdest_len, + UConverter *src_cnv, const char *src, int32_t src_len, + php_converter_object *objval + TSRMLS_DC) { + UErrorCode error = U_ZERO_ERROR; + int32_t dest_len, + temp_len; + char *dest; + UChar *temp; + + if (!src_cnv || !dest_cnv) { + php_converter_throw_failure(objval, U_INVALID_STATE_ERROR TSRMLS_CC, + "Internal converters not initialized"); + return 0; + } + + /* Get necessary buffer size first */ + temp_len = 1 + ucnv_toUChars(src_cnv, NULL, 0, src, src_len, &error); + if (U_FAILURE(error) && error != U_BUFFER_OVERFLOW_ERROR) { + THROW_UFAILURE(objval, "ucnv_toUChars", error); + return 0; + } + temp = safe_emalloc(sizeof(UChar), temp_len, sizeof(UChar)); + + /* Convert to intermediate UChar* array */ + error = U_ZERO_ERROR; + temp_len = ucnv_toUChars(src_cnv, temp, temp_len, src, src_len, &error); + if (U_FAILURE(error)) { + THROW_UFAILURE(objval, "ucnv_toUChars", error); + efree(temp); + return 0; + } + temp[temp_len] = 0; + + /* Get necessary output buffer size */ + dest_len = 1 + ucnv_fromUChars(dest_cnv, NULL, 0, temp, temp_len, &error); + if (U_FAILURE(error) && error != U_BUFFER_OVERFLOW_ERROR) { + THROW_UFAILURE(objval, "ucnv_fromUChars", error); + efree(temp); + return 0; + } + dest = safe_emalloc(sizeof(char), dest_len, sizeof(char)); + + /* Convert to final encoding */ + error = U_ZERO_ERROR; + dest_len = ucnv_fromUChars(dest_cnv, dest, dest_len, temp, temp_len, &error); + efree(temp); + if (U_FAILURE(error)) { + THROW_UFAILURE(objval, "ucnv_fromUChars", error); + efree(dest); + return 0; + } + + *pdest = dest; + if (pdest_len) { + *pdest_len = dest_len; + } + + return 1; +} +/* }}} */ + +/* {{{ proto string UConverter::reasonText(long reason) */ +#define UCNV_REASON_CASE(v) case (UCNV_ ## v) : RETURN_STRINGL( "REASON_" #v , sizeof( "REASON_" #v ) - 1, 1); +ZEND_BEGIN_ARG_INFO_EX(php_converter_reasontext_arginfo, 0, ZEND_RETURN_VALUE, 0) + ZEND_ARG_INFO(0, reason) +ZEND_END_ARG_INFO(); +static PHP_METHOD(UConverter, reasonText) { + long reason; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &reason) == FAILURE) { + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, + "UConverter::reasonText(): bad arguments", 0 TSRMLS_CC); + RETURN_FALSE; + } + intl_error_reset(NULL TSRMLS_CC); + + switch (reason) { + UCNV_REASON_CASE(UNASSIGNED) + UCNV_REASON_CASE(ILLEGAL) + UCNV_REASON_CASE(IRREGULAR) + UCNV_REASON_CASE(RESET) + UCNV_REASON_CASE(CLOSE) + UCNV_REASON_CASE(CLONE) + default: + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown UConverterCallbackReason: %ld", reason); + RETURN_FALSE; + } +} +/* }}} */ + +/* {{{ proto string UConverter::convert(string str[, bool reverse]) */ +ZEND_BEGIN_ARG_INFO_EX(php_converter_convert_arginfo, 0, ZEND_RETURN_VALUE, 1) + ZEND_ARG_INFO(0, str) + ZEND_ARG_INFO(0, reverse) +ZEND_END_ARG_INFO(); + +static PHP_METHOD(UConverter, convert) { + php_converter_object *objval = CONV_GET(getThis()); + char *str, *dest; + int str_len, dest_len; + zend_bool reverse = 0; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|b", + &str, &str_len, &reverse) == FAILURE) { + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, + "UConverter::convert(): bad arguments", 0 TSRMLS_CC); + RETURN_FALSE; + } + intl_errors_reset(&objval->error TSRMLS_CC); + + if (php_converter_do_convert(reverse ? objval->src : objval->dest, + &dest, &dest_len, + reverse ? objval->dest : objval->src, + str, str_len, + objval TSRMLS_CC)) { + RETURN_STRINGL(dest, dest_len, 0); + } else { + RETURN_FALSE; + } +} +/* }}} */ + +/* {{{ proto string UConverter::transcode(string $str, string $toEncoding, string $fromEncoding[, Array $options = array()]) */ +ZEND_BEGIN_ARG_INFO_EX(php_converter_transcode_arginfo, 0, ZEND_RETURN_VALUE, 3) + ZEND_ARG_INFO(0, str) + ZEND_ARG_INFO(0, toEncoding) + ZEND_ARG_INFO(0, fromEncoding) + ZEND_ARG_ARRAY_INFO(0, options, 1) +ZEND_END_ARG_INFO(); + +static PHP_METHOD(UConverter, transcode) { + char *str, *src, *dest; + int str_len, src_len, dest_len; + zval *options = NULL; + UConverter *src_cnv = NULL, *dest_cnv = NULL; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sss|a!", + &str, &str_len, &dest, &dest_len, &src, &src_len, &options) == FAILURE) { + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, + "UConverter::transcode(): bad arguments", 0 TSRMLS_CC); + RETURN_FALSE; + } + intl_error_reset(NULL TSRMLS_CC); + + if (php_converter_set_encoding(NULL, &src_cnv, src, src_len TSRMLS_CC) && + php_converter_set_encoding(NULL, &dest_cnv, dest, dest_len TSRMLS_CC)) { + char *out = NULL; + int out_len = 0; + UErrorCode error = U_ZERO_ERROR; + + if (options && zend_hash_num_elements(Z_ARRVAL_P(options))) { + zval **tmpzval; + + if (U_SUCCESS(error) && + zend_hash_find(Z_ARRVAL_P(options), "from_subst", sizeof("from_subst"), (void**)&tmpzval) == SUCCESS && + Z_TYPE_PP(tmpzval) == IS_STRING) { + error = U_ZERO_ERROR; + ucnv_setSubstChars(src_cnv, Z_STRVAL_PP(tmpzval), Z_STRLEN_PP(tmpzval) & 0x7F, &error); + } + if (U_SUCCESS(error) && + zend_hash_find(Z_ARRVAL_P(options), "to_subst", sizeof("to_subst"), (void**)&tmpzval) == SUCCESS && + Z_TYPE_PP(tmpzval) == IS_STRING) { + error = U_ZERO_ERROR; + ucnv_setSubstChars(dest_cnv, Z_STRVAL_PP(tmpzval), Z_STRLEN_PP(tmpzval) & 0x7F, &error); + } + } + + if (U_SUCCESS(error) && + php_converter_do_convert(dest_cnv, &out, &out_len, src_cnv, str, str_len, NULL TSRMLS_CC)) { + RETVAL_STRINGL(out, out_len, 0); + } + + if (U_FAILURE(error)) { + THROW_UFAILURE(NULL, "transcode", error); + RETVAL_FALSE; + } + } else { + RETVAL_FALSE; + } + + if (src_cnv) { + ucnv_close(src_cnv); + } + if (dest_cnv) { + ucnv_close(dest_cnv); + } +} +/* }}} */ + +/* {{{ proto int UConverter::getErrorCode() */ +ZEND_BEGIN_ARG_INFO_EX(php_converter_geterrorcode_arginfo, 0, ZEND_RETURN_VALUE, 0) +ZEND_END_ARG_INFO(); +static PHP_METHOD(UConverter, getErrorCode) { + php_converter_object *objval = CONV_GET(getThis()); + + if (zend_parse_parameters_none() == FAILURE) { + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, + "UConverter::getErrorCode(): expected no arguments", 0 TSRMLS_CC); + RETURN_FALSE; + } + + RETURN_LONG(intl_error_get_code(&(objval->error) TSRMLS_CC)); +} +/* }}} */ + +/* {{{ proto string UConverter::getErrorMessage() */ +ZEND_BEGIN_ARG_INFO_EX(php_converter_geterrormsg_arginfo, 0, ZEND_RETURN_VALUE, 0) +ZEND_END_ARG_INFO(); +static PHP_METHOD(UConverter, getErrorMessage) { + php_converter_object *objval = CONV_GET(getThis()); + char *message = intl_error_get_message(&(objval->error) TSRMLS_CC); + + if (zend_parse_parameters_none() == FAILURE) { + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, + "UConverter::getErrorMessage(): expected no arguments", 0 TSRMLS_CC); + RETURN_FALSE; + } + + if (message) { + RETURN_STRING(message, 1); + } else { + RETURN_NULL(); + } +} +/* }}} */ + +/* {{{ proto array UConverter::getAvailable() */ +ZEND_BEGIN_ARG_INFO_EX(php_converter_getavailable_arginfo, 0, ZEND_RETURN_VALUE, 0) +ZEND_END_ARG_INFO(); +static PHP_METHOD(UConverter, getAvailable) { + int32_t i, + count = ucnv_countAvailable(); + + if (zend_parse_parameters_none() == FAILURE) { + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, + "UConverter::getErrorMessage(): expected no arguments", 0 TSRMLS_CC); + RETURN_FALSE; + } + intl_error_reset(NULL TSRMLS_CC); + + array_init(return_value); + for(i = 0; i < count; i++) { + const char *name = ucnv_getAvailableName(i); + add_next_index_string(return_value, name, 1); + } +} +/* }}} */ + +/* {{{ proto array UConverter::getAliases(string name) */ +ZEND_BEGIN_ARG_INFO_EX(php_converter_getaliases_arginfo, 0, ZEND_RETURN_VALUE, 0) + ZEND_ARG_INFO(0, name) +ZEND_END_ARG_INFO(); +static PHP_METHOD(UConverter, getAliases) { + char *name; + int name_len; + UErrorCode error = U_ZERO_ERROR; + uint16_t i, count; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &name, &name_len) == FAILURE) { + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, + "UConverter::getAliases(): bad arguments", 0 TSRMLS_CC); + RETURN_FALSE; + } + intl_error_reset(NULL TSRMLS_CC); + + count = ucnv_countAliases(name, &error); + if (U_FAILURE(error)) { + THROW_UFAILURE(NULL, "ucnv_countAliases", error); + RETURN_FALSE; + } + + array_init(return_value); + for(i = 0; i < count; i++) { + const char *alias; + + error = U_ZERO_ERROR; + alias = ucnv_getAlias(name, i, &error); + if (U_FAILURE(error)) { + THROW_UFAILURE(NULL, "ucnv_getAlias", error); + zval_dtor(return_value); + RETURN_NULL(); + } + add_next_index_string(return_value, alias, 1); + } +} +/* }}} */ + +/* {{{ proto array UConverter::getStandards() */ +ZEND_BEGIN_ARG_INFO_EX(php_converter_getstandards_arginfo, 0, ZEND_RETURN_VALUE, 0) +ZEND_END_ARG_INFO(); +static PHP_METHOD(UConverter, getStandards) { + uint16_t i, count; + + if (zend_parse_parameters_none() == FAILURE) { + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, + "UConverter::getStandards(): expected no arguments", 0 TSRMLS_CC); + RETURN_FALSE; + } + intl_error_reset(NULL TSRMLS_CC); + + array_init(return_value); + count = ucnv_countStandards(); + for(i = 0; i < count; i++) { + UErrorCode error = U_ZERO_ERROR; + const char *name = ucnv_getStandard(i, &error); + if (U_FAILURE(error)) { + THROW_UFAILURE(NULL, "ucnv_getStandard", error); + zval_dtor(return_value); + RETURN_NULL(); + } + add_next_index_string(return_value, name, 1); + } +} +/* }}} */ + +static zend_function_entry php_converter_methods[] = { + PHP_ME(UConverter, __construct, php_converter_arginfo, ZEND_ACC_PUBLIC | ZEND_ACC_CTOR) + + /* Encoding selection */ + PHP_ME(UConverter, setSourceEncoding, php_converter_set_encoding_arginfo, ZEND_ACC_PUBLIC) + PHP_ME(UConverter, setDestinationEncoding, php_converter_set_encoding_arginfo, ZEND_ACC_PUBLIC) + PHP_ME(UConverter, getSourceEncoding, php_converter_get_encoding_arginfo, ZEND_ACC_PUBLIC) + PHP_ME(UConverter, getDestinationEncoding, php_converter_get_encoding_arginfo, ZEND_ACC_PUBLIC) + + /* Introspection for algorithmic converters */ + PHP_ME(UConverter, getSourceType, php_converter_get_type_arginfo, ZEND_ACC_PUBLIC) + PHP_ME(UConverter, getDestinationType, php_converter_get_type_arginfo, ZEND_ACC_PUBLIC) + + /* Basic codeunit error handling */ + PHP_ME(UConverter, getSubstChars, php_converter_getSubstChars_arginfo, ZEND_ACC_PUBLIC) + PHP_ME(UConverter, setSubstChars, php_converter_setSubstChars_arginfo, ZEND_ACC_PUBLIC) + + /* Default callback handlers */ + PHP_ME(UConverter, toUCallback, php_converter_toUCallback_arginfo, ZEND_ACC_PUBLIC) + PHP_ME(UConverter, fromUCallback, php_converter_fromUCallback_arginfo, ZEND_ACC_PUBLIC) + + /* Core conversion workhorses */ + PHP_ME(UConverter, convert, php_converter_convert_arginfo, ZEND_ACC_PUBLIC) + PHP_ME(UConverter, transcode, php_converter_transcode_arginfo, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC) + + /* Error inspection */ + PHP_ME(UConverter, getErrorCode, php_converter_geterrorcode_arginfo, ZEND_ACC_PUBLIC) + PHP_ME(UConverter, getErrorMessage, php_converter_geterrormsg_arginfo, ZEND_ACC_PUBLIC) + + /* Ennumeration and lookup */ + PHP_ME(UConverter, reasonText, php_converter_reasontext_arginfo, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC) + PHP_ME(UConverter, getAvailable, php_converter_getavailable_arginfo, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC) + PHP_ME(UConverter, getAliases, php_converter_getaliases_arginfo, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC) + PHP_ME(UConverter, getStandards, php_converter_getstandards_arginfo, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC) + { NULL, NULL, NULL } +}; + +/* {{{ Converter create/clone/destroy */ +static void php_converter_free_object(php_converter_object *objval TSRMLS_DC) { + if (objval->src) { + ucnv_close(objval->src); + } + + if (objval->dest) { + ucnv_close(objval->dest); + } + + intl_error_reset(&(objval->error) TSRMLS_CC); + zend_object_std_dtor(&(objval->obj) TSRMLS_CC); + + efree(objval); +} + +static zend_object_value php_converter_object_ctor(zend_class_entry *ce, php_converter_object **pobjval TSRMLS_DC) { + php_converter_object *objval; + zend_object_value retval; + + objval = ecalloc(1, sizeof(php_converter_object)); + objval->obj.ce = ce; + +#ifdef ZTS + objval->tsrm_ls = TSRMLS_C; +#endif + intl_error_init(&(objval->error) TSRMLS_CC); + + retval.handle = zend_objects_store_put(objval, NULL, (zend_objects_free_object_storage_t)php_converter_free_object, NULL TSRMLS_CC); + retval.handlers = &php_converter_object_handlers; + *pobjval = objval; + + return retval; +} + +static zend_object_value php_converter_create_object(zend_class_entry *ce TSRMLS_DC) { + php_converter_object *objval = NULL; + zend_object_value retval = php_converter_object_ctor(ce, &objval TSRMLS_CC); + + object_properties_init(&(objval->obj), ce); + + return retval; +} + +static zend_object_value php_converter_clone_object(zval *object TSRMLS_DC) { + php_converter_object *objval, *oldobj = (php_converter_object*)zend_objects_get_address(object TSRMLS_CC); + zend_object_value retval = php_converter_object_ctor(Z_OBJCE_P(object), &objval TSRMLS_CC); + UErrorCode error = U_ZERO_ERROR; + + intl_errors_reset(&oldobj->error TSRMLS_CC); + + objval->src = ucnv_safeClone(oldobj->src, NULL, NULL, &error); + if (U_SUCCESS(error)) { + error = U_ZERO_ERROR; + objval->dest = ucnv_safeClone(oldobj->dest, NULL, NULL, &error); + } + if (U_FAILURE(error)) { + char *err_msg; + THROW_UFAILURE(oldobj, "ucnv_safeClone", error); + + err_msg = intl_error_get_message(&oldobj->error TSRMLS_CC); + zend_throw_exception(NULL, err_msg, 0 TSRMLS_CC); + efree(err_msg); + + return retval; + } + + /* Update contexts for converter error handlers */ + php_converter_set_callbacks(objval, objval->src TSRMLS_CC); + php_converter_set_callbacks(objval, objval->dest TSRMLS_CC); + + zend_objects_clone_members(&(objval->obj), retval, &(oldobj->obj), Z_OBJ_HANDLE_P(object) TSRMLS_CC); + + /* Newly cloned object deliberately does not inherit error state from original object */ + + return retval; +} +/* }}} */ + +#define CONV_REASON_CONST(v) zend_declare_class_constant_long(php_converter_ce, "REASON_" #v, sizeof("REASON_" #v) - 1, UCNV_ ## v TSRMLS_CC) +#define CONV_TYPE_CONST(v) zend_declare_class_constant_long(php_converter_ce, #v , sizeof(#v) - 1, UCNV_ ## v TSRMLS_CC) + +/* {{{ php_converter_minit */ +int php_converter_minit(INIT_FUNC_ARGS) { + zend_class_entry ce; + + INIT_CLASS_ENTRY(ce, "UConverter", php_converter_methods); + php_converter_ce = zend_register_internal_class(&ce TSRMLS_CC); + php_converter_ce->create_object = php_converter_create_object; + memcpy(&php_converter_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers)); + php_converter_object_handlers.clone_obj = php_converter_clone_object; + + /* enum UConverterCallbackReason */ + CONV_REASON_CONST(UNASSIGNED); + CONV_REASON_CONST(ILLEGAL); + CONV_REASON_CONST(IRREGULAR); + CONV_REASON_CONST(RESET); + CONV_REASON_CONST(CLOSE); + CONV_REASON_CONST(CLONE); + + /* enum UConverterType */ + CONV_TYPE_CONST(UNSUPPORTED_CONVERTER); + CONV_TYPE_CONST(SBCS); + CONV_TYPE_CONST(DBCS); + CONV_TYPE_CONST(MBCS); + CONV_TYPE_CONST(LATIN_1); + CONV_TYPE_CONST(UTF8); + CONV_TYPE_CONST(UTF16_BigEndian); + CONV_TYPE_CONST(UTF16_LittleEndian); + CONV_TYPE_CONST(UTF32_BigEndian); + CONV_TYPE_CONST(UTF32_LittleEndian); + CONV_TYPE_CONST(EBCDIC_STATEFUL); + CONV_TYPE_CONST(ISO_2022); + CONV_TYPE_CONST(LMBCS_1); + CONV_TYPE_CONST(LMBCS_2); + CONV_TYPE_CONST(LMBCS_3); + CONV_TYPE_CONST(LMBCS_4); + CONV_TYPE_CONST(LMBCS_5); + CONV_TYPE_CONST(LMBCS_6); + CONV_TYPE_CONST(LMBCS_8); + CONV_TYPE_CONST(LMBCS_11); + CONV_TYPE_CONST(LMBCS_16); + CONV_TYPE_CONST(LMBCS_17); + CONV_TYPE_CONST(LMBCS_18); + CONV_TYPE_CONST(LMBCS_19); + CONV_TYPE_CONST(LMBCS_LAST); + CONV_TYPE_CONST(HZ); + CONV_TYPE_CONST(SCSU); + CONV_TYPE_CONST(ISCII); + CONV_TYPE_CONST(US_ASCII); + CONV_TYPE_CONST(UTF7); + CONV_TYPE_CONST(BOCU1); + CONV_TYPE_CONST(UTF16); + CONV_TYPE_CONST(UTF32); + CONV_TYPE_CONST(CESU8); + CONV_TYPE_CONST(IMAP_MAILBOX); + + return SUCCESS; +} +/* }}} */ + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + * vim600: noet sw=4 ts=4 fdm=marker + * vim<600: noet sw=4 ts=4 + */ diff --git a/ext/intl/converter/converter.h b/ext/intl/converter/converter.h new file mode 100644 index 0000000000..bd316fcf98 --- /dev/null +++ b/ext/intl/converter/converter.h @@ -0,0 +1,28 @@ +/* + +----------------------------------------------------------------------+ + | 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: Sara Golemon <pollita@php.net> | + +----------------------------------------------------------------------+ +*/ + +#ifndef PHP_INTL_CONVERTER_H +#define PHP_INTL_CONVERTER_H + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "php.h" + +int php_converter_minit(INIT_FUNC_ARGS); + +#endif /* PHP_INTL_CONVERTER_H */ diff --git a/ext/intl/dateformat/dateformat.c b/ext/intl/dateformat/dateformat.c index 8aded18bd6..fb83eeef05 100644 --- 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_NO_CHECK; - - 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 b8c5f25e3a..bf6b544667 100644 --- a/ext/intl/dateformat/dateformat_attr.c +++ b/ext/intl/dateformat/dateformat_attr.c @@ -25,39 +25,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. }}} */ @@ -111,97 +78,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 ) @@ -370,43 +246,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 100644 --- 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 49f316f787..211c87f59f 100644 --- a/ext/intl/dateformat/dateformat_class.c +++ b/ext/intl/dateformat/dateformat_class.c @@ -19,9 +19,11 @@ #include "php_intl.h" #include "dateformat_data.h" #include "dateformat_format.h" +#include "dateformat_format_object.h" #include "dateformat_parse.h" #include "dateformat.h" #include "dateformat_attr.h" +#include "dateformat_attrcpp.h" #include <zend_exceptions.h> @@ -46,12 +48,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 ); } /* }}} */ @@ -66,10 +68,10 @@ zend_object_value IntlDateFormatter_object_create(zend_class_entry *ce TSRMLS_DC dateformat_data_init( &intern->datef_data TSRMLS_CC ); zend_object_std_init( &intern->zo, ce TSRMLS_CC ); object_properties_init(&intern->zo, ce); - 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, @@ -127,6 +129,12 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_intldateformatter_format, 0, 0, 0) ZEND_ARG_INFO(0, array) ZEND_END_ARG_INFO() +ZEND_BEGIN_ARG_INFO_EX(arginfo_intldateformatter_format_object, 0, 0, 1) + ZEND_ARG_INFO(0, object) + ZEND_ARG_INFO(0, format) + ZEND_ARG_INFO(0, locale) +ZEND_END_ARG_INFO() + ZEND_BEGIN_ARG_INFO(arginfo_intldateformatter_getdatetype, 0) ZEND_END_ARG_INFO() @@ -165,15 +173,19 @@ 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 ) PHP_NAMED_FE( setLenient, ZEND_FN( datefmt_set_lenient ), arginfo_intldateformatter_setlenient ) PHP_NAMED_FE( isLenient, ZEND_FN( datefmt_is_lenient ), arginfo_intldateformatter_getdatetype ) PHP_NAMED_FE( format, ZEND_FN( datefmt_format ), arginfo_intldateformatter_format ) + PHP_ME_MAPPING( formatObject, datefmt_format_object, arginfo_intldateformatter_format_object, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) PHP_NAMED_FE( parse, ZEND_FN( datefmt_parse), datefmt_parse_args ) PHP_NAMED_FE( localtime, ZEND_FN( datefmt_localtime ), datefmt_parse_args ) PHP_NAMED_FE( getErrorCode, ZEND_FN( datefmt_get_error_code ), arginfo_intldateformatter_getdatetype ) diff --git a/ext/intl/dateformat/dateformat_class.h b/ext/intl/dateformat/dateformat_class.h index d58abe42f5..b4304660e2 100644 --- 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..a2899f7974 --- /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; + + const 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_locale_get_default(TSRMLS_C); + } + locale = Locale::createFromName(locale_str); + + DATE_FORMAT_METHOD_FETCH_OBJECT_NO_CHECK; + + 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..ffae15518b 100644 --- a/ext/intl/dateformat/dateformat_format.c +++ b/ext/intl/dateformat/dateformat_format.c @@ -21,13 +21,13 @@ #include <unicode/ustring.h> #include <unicode/ucal.h> -#include "php_intl.h" -#include "intl_convert.h" +#include "../php_intl.h" +#include "../intl_convert.h" +#include "../common/common_date.h" #include "dateformat.h" #include "dateformat_class.h" #include "dateformat_format.h" #include "dateformat_data.h" -#include "ext/date/php_date.h" /* {{{ * Internal function which calls the udat_format @@ -59,20 +59,38 @@ static void internal_format(IntlDateFormatter_object *dfo, UDate timestamp, zval /* {{{ * Internal function which fetches an element from the passed array for the key_name passed */ -static double internal_get_arr_ele(IntlDateFormatter_object *dfo, HashTable* hash_arr, char* key_name TSRMLS_DC) +static int32_t internal_get_arr_ele(IntlDateFormatter_object *dfo, + HashTable* hash_arr, char* key_name, intl_error *err TSRMLS_DC) { - zval** ele_value = NULL; - UDate result = -1; - - if( zend_hash_find( hash_arr, key_name, strlen(key_name) + 1, (void **)&ele_value ) == SUCCESS ){ - if( Z_TYPE_PP(ele_value)!= IS_LONG ){ - intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR, - "datefmt_format: parameter array does not contain a long element.", 0 TSRMLS_CC ); - }else{ - result = Z_LVAL_PP(ele_value); + zval **ele_value = NULL; + int32_t result = 0; + char *message; + + if (U_FAILURE(err->code)) { + return result; + } + + if (zend_hash_find(hash_arr, key_name, strlen(key_name) + 1, + (void **)&ele_value) == SUCCESS) { + if(Z_TYPE_PP(ele_value) != IS_LONG) { + spprintf(&message, 0, "datefmt_format: parameter array contains " + "a non-integer element for key '%s'", key_name); + intl_errors_set(err, U_ILLEGAL_ARGUMENT_ERROR, message, 1 TSRMLS_CC); + efree(message); + } else { + if (Z_LVAL_PP(ele_value) > INT32_MAX || + Z_LVAL_PP(ele_value) < INT32_MIN) { + spprintf(&message, 0, "datefmt_format: value %ld is out of " + "bounds for a 32-bit integer in key '%s'", + Z_LVAL_PP(ele_value), key_name); + intl_errors_set(err, U_ILLEGAL_ARGUMENT_ERROR, message, 1 TSRMLS_CC); + efree(message); + } else { + result = Z_LVAL_PP(ele_value); + } } } - /* printf("\n Inside internal_get_arr_ele key_name= %s, result = %g \n", key_name, result); */ + return result; } /* }}} */ @@ -80,41 +98,51 @@ static double internal_get_arr_ele(IntlDateFormatter_object *dfo, HashTable* has /* {{{ * Internal function which sets UCalendar from the passed array and retrieves timestamp */ -static UDate internal_get_timestamp(IntlDateFormatter_object *dfo, HashTable* hash_arr TSRMLS_DC) +static UDate internal_get_timestamp(IntlDateFormatter_object *dfo, + HashTable *hash_arr TSRMLS_DC) { - long year =0; - long month =0; - long hour =0; - long minute =0; - long second =0; - long wday =0; - long yday =0; - long mday =0; - UBool isInDST = FALSE; - UCalendar *pcal; + int32_t year, + month, + hour, + minute, + second, + mday; + UCalendar *pcal; + UDate result; + intl_error *err = &dfo->datef_data.error; + +#define INTL_GET_ELEM(elem) \ + internal_get_arr_ele(dfo, hash_arr, (elem), err TSRMLS_CC) /* 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 */ + year = INTL_GET_ELEM(CALENDAR_YEAR) + 1900; /* tm_year is years since 1900 */ /* Month in ICU and PHP starts from January =0 */ - month = internal_get_arr_ele( dfo, hash_arr, CALENDAR_MON TSRMLS_CC); - hour = internal_get_arr_ele( dfo, hash_arr, CALENDAR_HOUR TSRMLS_CC); - minute = internal_get_arr_ele( dfo, hash_arr, CALENDAR_MIN TSRMLS_CC); - second = internal_get_arr_ele( dfo, hash_arr, CALENDAR_SEC TSRMLS_CC); - wday = internal_get_arr_ele( dfo, hash_arr, CALENDAR_WDAY TSRMLS_CC); - yday = internal_get_arr_ele( dfo, hash_arr, CALENDAR_YDAY TSRMLS_CC); - isInDST = internal_get_arr_ele( dfo, hash_arr, CALENDAR_ISDST TSRMLS_CC); + month = INTL_GET_ELEM(CALENDAR_MON); + hour = INTL_GET_ELEM(CALENDAR_HOUR); + minute = INTL_GET_ELEM(CALENDAR_MIN); + second = INTL_GET_ELEM(CALENDAR_SEC); /* For the ucal_setDateTime() function, this is the 'date' value */ - mday = internal_get_arr_ele( dfo, hash_arr, CALENDAR_MDAY TSRMLS_CC); + mday = INTL_GET_ELEM(CALENDAR_MDAY); - pcal = udat_getCalendar(DATE_FORMAT_OBJECT(dfo)); - /* set the incoming values for the calendar */ - ucal_setDateTime( pcal, year, month, mday, hour, minute, second, &INTL_DATA_ERROR_CODE(dfo)); - if( INTL_DATA_ERROR_CODE(dfo) != U_ZERO_ERROR){ +#undef INTL_GET_ELEM + + pcal = ucal_clone(udat_getCalendar(DATE_FORMAT_OBJECT(dfo)), + &INTL_DATA_ERROR_CODE(dfo)); + + if (INTL_DATA_ERROR_CODE(dfo) != U_ZERO_ERROR) { + intl_errors_set(err, INTL_DATA_ERROR_CODE(dfo), "datefmt_format: " + "error cloning calendar", 0 TSRMLS_CC); return 0; } - + + /* set the incoming values for the calendar */ + ucal_setDateTime(pcal, year, month, mday, hour, minute, second, &INTL_DATA_ERROR_CODE(dfo)); + /* actually, ucal_setDateTime cannot fail */ + /* Fetch the timestamp from the UCalendar */ - return ucal_getMillis(pcal, &INTL_DATA_ERROR_CODE(dfo) ); + result = ucal_getMillis(pcal, &INTL_DATA_ERROR_CODE(dfo)); + ucal_close(pcal); + return result; } @@ -124,70 +152,39 @@ static UDate internal_get_timestamp(IntlDateFormatter_object *dfo, HashTable* ha * Format the time value as a string. }}}*/ PHP_FUNCTION(datefmt_format) { - UDate timestamp =0; - UDate p_timestamp =0; - HashTable* hash_arr = NULL; - zval* zarg = NULL; + UDate timestamp = 0; + HashTable *hash_arr = NULL; + zval *zarg = NULL; DATE_FORMAT_METHOD_INIT_VARS; /* Parse parameters. */ - if( zend_parse_method_parameters( ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Oz", &object, IntlDateFormatter_ce_ptr,&zarg ) == FAILURE ) - { - intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR, "datefmt_format: unable to parse input params", 0 TSRMLS_CC ); + if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Oz", + &object, IntlDateFormatter_ce_ptr, &zarg) == FAILURE) { + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, "datefmt_format: unable " + "to parse input params", 0 TSRMLS_CC ); RETURN_FALSE; } - /* Fetch the object. */ DATE_FORMAT_METHOD_FETCH_OBJECT; - switch(Z_TYPE_P(zarg) ){ - case IS_LONG: - p_timestamp = Z_LVAL_P(zarg) ; - timestamp = p_timestamp * 1000; - break; - case IS_DOUBLE: - /* timestamp*1000 since ICU expects it in milliseconds */ - p_timestamp = Z_DVAL_P(zarg) ; - timestamp = p_timestamp * 1000; - break; - case IS_ARRAY: - hash_arr = Z_ARRVAL_P(zarg); - if( !hash_arr || zend_hash_num_elements( hash_arr ) == 0 ) - RETURN_FALSE; - - timestamp = internal_get_timestamp(dfo, hash_arr TSRMLS_CC); - INTL_METHOD_CHECK_STATUS( dfo, "datefmt_format: Date formatting failed" ) - break; - case IS_OBJECT: { - zend_class_entry *date_ce = php_date_get_date_ce(); - zval retval; - zval *zfuncname; - if(!instanceof_function(Z_OBJCE_P(zarg), date_ce TSRMLS_CC)) { - intl_errors_set(INTL_DATA_ERROR_P(dfo), U_ILLEGAL_ARGUMENT_ERROR, "datefmt_format: object must be an instance of DateTime", 0 TSRMLS_CC ); - RETURN_FALSE; - } - INIT_ZVAL(retval); - MAKE_STD_ZVAL(zfuncname); - ZVAL_STRING(zfuncname, "getTimestamp", 1); - if(call_user_function(NULL, &zarg, zfuncname, &retval, 0, NULL TSRMLS_CC) != SUCCESS || Z_TYPE(retval) != IS_LONG) { - intl_errors_set(INTL_DATA_ERROR_P(dfo), U_ILLEGAL_ARGUMENT_ERROR, "datefmt_format: cannot get timestamp", 0 TSRMLS_CC ); - zval_ptr_dtor(&zfuncname); - RETURN_FALSE; - } - zval_ptr_dtor(&zfuncname); - p_timestamp = Z_LVAL(retval); - timestamp = p_timestamp*1000; + if (Z_TYPE_P(zarg) == IS_ARRAY) { + hash_arr = Z_ARRVAL_P(zarg); + if (!hash_arr || zend_hash_num_elements(hash_arr) == 0) { + RETURN_FALSE; } - break; - default: - intl_errors_set( INTL_DATA_ERROR_P(dfo), U_ILLEGAL_ARGUMENT_ERROR, - "datefmt_format: takes either an array or an integer timestamp value or a DateTime object", 0 TSRMLS_CC ); + + timestamp = internal_get_timestamp(dfo, hash_arr TSRMLS_CC); + INTL_METHOD_CHECK_STATUS(dfo, "datefmt_format: date formatting failed") + } else { + timestamp = intl_zval_to_millis(zarg, INTL_DATA_ERROR_P(dfo), + "datefmt_format" TSRMLS_CC); + if (U_FAILURE(INTL_DATA_ERROR_CODE(dfo))) { RETURN_FALSE; + } } - - internal_format( dfo, timestamp, return_value TSRMLS_CC); + internal_format( dfo, timestamp, return_value TSRMLS_CC); } /* }}} */ diff --git a/ext/intl/dateformat/dateformat_format_object.cpp b/ext/intl/dateformat/dateformat_format_object.cpp new file mode 100644 index 0000000000..e8981faa26 --- /dev/null +++ b/ext/intl/dateformat/dateformat_format_object.cpp @@ -0,0 +1,230 @@ +/* + +----------------------------------------------------------------------+ + | 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 <unicode/datefmt.h> +#include <unicode/smpdtfmt.h> +#include <unicode/locid.h> + +#include "../intl_convertcpp.h" + +extern "C" { +#include "../php_intl.h" +#include "../locale/locale.h" +#define USE_CALENDAR_POINTER 1 +#include "../calendar/calendar_class.h" +#include <ext/date/php_date.h> +#include "../common/common_date.h" +} + +static const DateFormat::EStyle valid_styles[] = { + DateFormat::kNone, + DateFormat::kFull, + DateFormat::kLong, + DateFormat::kMedium, + DateFormat::kShort, + DateFormat::kFullRelative, + DateFormat::kLongRelative, + DateFormat::kMediumRelative, + DateFormat::kShortRelative, +}; + +static bool valid_format(zval **z) { + if (Z_TYPE_PP(z) == IS_LONG) { + long lval = Z_LVAL_PP(z); + for (int i = 0; i < sizeof(valid_styles) / sizeof(*valid_styles); i++) { + if ((long)valid_styles[i] == lval) { + return true; + } + } + } + + return false; +} + +U_CFUNC PHP_FUNCTION(datefmt_format_object) +{ + zval *object, + **format = NULL; + const char *locale_str = NULL; + int locale_len; + bool pattern = false; + UDate date; + TimeZone *timeZone = NULL; + UErrorCode status = U_ZERO_ERROR; + DateFormat *df = NULL; + Calendar *cal = NULL; + DateFormat::EStyle dateStyle = DateFormat::kDefault, + timeStyle = DateFormat::kDefault; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "o|Zs!", + &object, &format, &locale_str, &locale_len) == FAILURE) { + RETURN_FALSE; + } + + if (!locale_str) { + locale_str = intl_locale_get_default(TSRMLS_C); + } + + if (format == NULL || Z_TYPE_PP(format) == IS_NULL) { + //nothing + } else if (Z_TYPE_PP(format) == IS_ARRAY) { + HashTable *ht = Z_ARRVAL_PP(format); + HashPosition pos = {0}; + zval **z; + if (zend_hash_num_elements(ht) != 2) { + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, + "datefmt_format_object: bad format; if array, it must have " + "two elements", 0 TSRMLS_CC); + RETURN_FALSE; + } + + zend_hash_internal_pointer_reset_ex(ht, &pos); + zend_hash_get_current_data_ex(ht, (void**)&z, &pos); + if (!valid_format(z)) { + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, + "datefmt_format_object: bad format; the date format (first " + "element of the array) is not valid", 0 TSRMLS_CC); + RETURN_FALSE; + } + dateStyle = (DateFormat::EStyle)Z_LVAL_PP(z); + + zend_hash_move_forward_ex(ht, &pos); + zend_hash_get_current_data_ex(ht, (void**)&z, &pos); + if (!valid_format(z)) { + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, + "datefmt_format_object: bad format; the time format (" + "second element of the array) is not valid", 0 TSRMLS_CC); + RETURN_FALSE; + } + timeStyle = (DateFormat::EStyle)Z_LVAL_PP(z); + } else if (Z_TYPE_PP(format) == IS_LONG) { + if (!valid_format(format)) { + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, + "datefmt_format_object: the date/time format type is invalid", + 0 TSRMLS_CC); + RETURN_FALSE; + } + dateStyle = timeStyle = (DateFormat::EStyle)Z_LVAL_PP(format); + } else { + convert_to_string_ex(format); + if (Z_STRLEN_PP(format) == 0) { + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, + "datefmt_format_object: the format is empty", 0 TSRMLS_CC); + RETURN_FALSE; + } + pattern = true; + } + + //there's no support for relative time in ICU yet + timeStyle = (DateFormat::EStyle)(timeStyle & ~DateFormat::kRelative); + + zend_class_entry *instance_ce = Z_OBJCE_P(object); + if (instanceof_function(instance_ce, Calendar_ce_ptr TSRMLS_CC)) { + Calendar *obj_cal = calendar_fetch_native_calendar(object TSRMLS_CC); + if (obj_cal == NULL) { + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, + "datefmt_format_object: bad IntlCalendar instance: " + "not initialized properly", 0 TSRMLS_CC); + RETURN_FALSE; + } + timeZone = obj_cal->getTimeZone().clone(); + date = obj_cal->getTime(status); + if (U_FAILURE(status)) { + intl_error_set(NULL, status, + "datefmt_format_object: error obtaining instant from " + "IntlCalendar", 0 TSRMLS_CC); + RETVAL_FALSE; + goto cleanup; + } + cal = obj_cal->clone(); + } else if (instanceof_function(instance_ce, php_date_get_date_ce() TSRMLS_CC)) { + if (intl_datetime_decompose(object, &date, &timeZone, NULL, + "datefmt_format_object" TSRMLS_CC) == FAILURE) { + RETURN_FALSE; + } + cal = new GregorianCalendar(Locale::createFromName(locale_str), status); + if (U_FAILURE(status)) { + intl_error_set(NULL, status, + "datefmt_format_object: could not create GregorianCalendar", + 0 TSRMLS_CC); + RETVAL_FALSE; + goto cleanup; + } + } else { + intl_error_set(NULL, status, "datefmt_format_object: the passed object " + "must be an instance of either IntlCalendar or DateTime", + 0 TSRMLS_CC); + RETURN_FALSE; + } + + if (pattern) { + df = new SimpleDateFormat( + UnicodeString(Z_STRVAL_PP(format), Z_STRLEN_PP(format), + UnicodeString::kInvariant), + Locale::createFromName(locale_str), + status); + + if (U_FAILURE(status)) { + intl_error_set(NULL, status, + "datefmt_format_object: could not create SimpleDateFormat", + 0 TSRMLS_CC); + RETVAL_FALSE; + goto cleanup; + } + } else { + df = DateFormat::createDateTimeInstance(dateStyle, timeStyle, + Locale::createFromName(locale_str)); + + if (df == NULL) { /* according to ICU sources, this should never happen */ + intl_error_set(NULL, status, + "datefmt_format_object: could not create DateFormat", + 0 TSRMLS_CC); + RETVAL_FALSE; + goto cleanup; + } + } + + //must be in this order (or have the cal adopt the tz) + df->adoptCalendar(cal); + cal = NULL; + df->adoptTimeZone(timeZone); + timeZone = NULL; + + { + UnicodeString result = UnicodeString(); + df->format(date, result); + + Z_TYPE_P(return_value) = IS_STRING; + if (intl_charFromString(result, &Z_STRVAL_P(return_value), + &Z_STRLEN_P(return_value), &status) == FAILURE) { + intl_error_set(NULL, status, + "datefmt_format_object: error converting result to UTF-8", + 0 TSRMLS_CC); + RETVAL_FALSE; + goto cleanup; + } + } + + +cleanup: + delete df; + delete timeZone; + delete cal; +} diff --git a/ext/intl/dateformat/dateformat_format_object.h b/ext/intl/dateformat/dateformat_format_object.h new file mode 100644 index 0000000000..d80ea87e0f --- /dev/null +++ b/ext/intl/dateformat/dateformat_format_object.h @@ -0,0 +1,19 @@ +/* + +----------------------------------------------------------------------+ + | 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 <php.h> + +PHP_FUNCTION(datefmt_format_object); 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/formatter/formatter_main.c b/ext/intl/formatter/formatter_main.c index 5cb6483326..d0671a88b5 100644 --- a/ext/intl/formatter/formatter_main.c +++ b/ext/intl/formatter/formatter_main.c @@ -56,7 +56,7 @@ static void numfmt_ctor(INTERNAL_FUNCTION_PARAMETERS) } if(locale_len == 0) { - locale = INTL_G(default_locale); + locale = intl_locale_get_default(TSRMLS_C); } /* Create an ICU number formatter. */ diff --git a/ext/intl/grapheme/grapheme.h b/ext/intl/grapheme/grapheme.h index c0e697ac1e..756ce9173e 100644 --- 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 100644 --- 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 100644 --- 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..d1a86d8ee2 100644 --- 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 ); } /* }}} */ @@ -393,7 +390,7 @@ static void get_icu_value_src_php( char* tag_name, INTERNAL_FUNCTION_PARAMETERS) } if(loc_name_len == 0) { - loc_name = INTL_G(default_locale); + loc_name = intl_locale_get_default(TSRMLS_C); } /* Call ICU get */ @@ -499,7 +496,7 @@ static void get_icu_disp_value_src_php( char* tag_name, INTERNAL_FUNCTION_PARAME } if(loc_name_len == 0) { - loc_name = INTL_G(default_locale); + loc_name = intl_locale_get_default(TSRMLS_C); } if( strcmp(tag_name, DISP_NAME) != 0 ){ @@ -521,7 +518,7 @@ static void get_icu_disp_value_src_php( char* tag_name, INTERNAL_FUNCTION_PARAME /* Check if disp_loc_name passed , if not use default locale */ if( !disp_loc_name){ - disp_loc_name = estrdup(INTL_G(default_locale)); + disp_loc_name = estrdup(intl_locale_get_default(TSRMLS_C)); free_loc_name = 1; } @@ -693,7 +690,7 @@ PHP_FUNCTION( locale_get_keywords ) } if(loc_name_len == 0) { - loc_name = INTL_G(default_locale); + loc_name = intl_locale_get_default(TSRMLS_C); } /* Get the keywords */ @@ -1100,7 +1097,7 @@ PHP_FUNCTION(locale_parse) } if(loc_name_len == 0) { - loc_name = INTL_G(default_locale); + loc_name = intl_locale_get_default(TSRMLS_C); } array_init( return_value ); @@ -1148,7 +1145,7 @@ PHP_FUNCTION(locale_get_all_variants) } if(loc_name_len == 0) { - loc_name = INTL_G(default_locale); + loc_name = intl_locale_get_default(TSRMLS_C); } @@ -1254,7 +1251,7 @@ PHP_FUNCTION(locale_filter_matches) } if(loc_range_len == 0) { - loc_range = INTL_G(default_locale); + loc_range = intl_locale_get_default(TSRMLS_C); } if( strcmp(loc_range,"*")==0){ @@ -1540,7 +1537,7 @@ PHP_FUNCTION(locale_lookup) } if(loc_range_len == 0) { - loc_range = INTL_G(default_locale); + loc_range = intl_locale_get_default(TSRMLS_C); } hash_arr = HASH_OF(arr); diff --git a/ext/intl/msgformat/msgformat.c b/ext/intl/msgformat/msgformat.c index e3fb9425a9..6a9f04f32b 100644 --- a/ext/intl/msgformat/msgformat.c +++ b/ext/intl/msgformat/msgformat.c @@ -61,7 +61,7 @@ static void msgfmt_ctor(INTERNAL_FUNCTION_PARAMETERS) } if(locale_len == 0) { - locale = INTL_G(default_locale); + locale = intl_locale_get_default(TSRMLS_C); } #ifdef MSG_FORMAT_QUOTE_APOS diff --git a/ext/intl/msgformat/msgformat_attr.c b/ext/intl/msgformat/msgformat_attr.c index ed2dae27d1..c333a24ee1 100644 --- 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 100644 --- 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 100644 --- 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..4b81cfe2b4 100644 --- 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); + } } /* }}} */ @@ -151,7 +134,7 @@ PHP_FUNCTION( msgfmt_format_message ) } if(slocale_len == 0) { - slocale = INTL_G(default_locale); + slocale = intl_locale_get_default(TSRMLS_C); } #ifdef MSG_FORMAT_QUOTE_APOS diff --git a/ext/intl/msgformat/msgformat_helpers.cpp b/ext/intl/msgformat/msgformat_helpers.cpp index 1895de2c86..9ee1cdcfb0 100644 --- a/ext/intl/msgformat/msgformat_helpers.cpp +++ b/ext/intl/msgformat/msgformat_helpers.cpp @@ -18,9 +18,20 @@ #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" +#include "../common/common_date.h" extern "C" { #include "php_intl.h" @@ -28,8 +39,14 @@ extern "C" { #include "msgformat_format.h" #include "msgformat_helpers.h" #include "intl_convert.h" +#define USE_TIMEZONE_POINTER +#include "../timezone/timezone_class.h" } +#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 +57,578 @@ 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 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; + } + } + + if (U_FAILURE(err.code)) { + zend_hash_destroy(ret); + efree(ret); + + return NULL; + } + + mfo->mf_data.arg_types = ret; - 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]); + 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; + } + } 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; } - fargs[i].setInt64(tInt64); + 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 = intl_zval_to_millis(*elem, &err, "msgfmt_format" 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; + } + } 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 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; + 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 +653,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 100644 --- 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/msgformat/msgformat_parse.c b/ext/intl/msgformat/msgformat_parse.c index f540b1d0c4..413d3b1f15 100644 --- a/ext/intl/msgformat/msgformat_parse.c +++ b/ext/intl/msgformat/msgformat_parse.c @@ -126,7 +126,7 @@ PHP_FUNCTION( msgfmt_parse_message ) } if(slocale_len == 0) { - slocale = INTL_G(default_locale); + slocale = intl_locale_get_default(TSRMLS_C); } #ifdef MSG_FORMAT_QUOTE_APOS diff --git a/ext/intl/php_intl.c b/ext/intl/php_intl.c index 90e3573c1b..a2c4d77651 100644 --- a/ext/intl/php_intl.c +++ b/ext/intl/php_intl.c @@ -34,6 +34,8 @@ #include "collator/collator_create.h" #include "collator/collator_error.h" +#include "converter/converter.h" + #include "formatter/formatter.h" #include "formatter/formatter_class.h" #include "formatter/formatter_attr.h" @@ -41,6 +43,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,7 +62,9 @@ #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_format_object.h" #include "dateformat/dateformat_parse.h" #include "dateformat/dateformat_data.h" @@ -68,6 +74,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 * 1000 + U_ICU_VERSION_MINOR_NUM >= 4002 @@ -79,8 +95,10 @@ #include "msgformat/msgformat.h" #include "common/common_error.h" +#include "common/common_enum.h" #include <unicode/uloc.h> +#include <unicode/uclean.h> #include <ext/standard/info.h> #include "php_ini.h" @@ -98,6 +116,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 +339,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) @@ -323,6 +354,13 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_datefmt_format, 0, 0, 0) ZEND_ARG_INFO(0, array) ZEND_END_ARG_INFO() +ZEND_BEGIN_ARG_INFO_EX(arginfo_datefmt_format_object, 0, 0, 1) + ZEND_ARG_INFO(0, object) + ZEND_ARG_INFO(0, format) + ZEND_ARG_INFO(0, locale) +ZEND_END_ARG_INFO() + + ZEND_BEGIN_ARG_INFO_EX(arginfo_datefmt_create, 0, 0, 3) ZEND_ARG_INFO(0, locale) ZEND_ARG_INFO(0, date_type) @@ -402,6 +440,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,15 +705,19 @@ 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 ) PHP_FE( datefmt_set_lenient, arginfo_msgfmt_get_locale ) PHP_FE( datefmt_format, arginfo_datefmt_format ) + PHP_FE( datefmt_format_object, arginfo_datefmt_format_object ) PHP_FE( datefmt_parse, datefmt_parse_args ) PHP_FE( datefmt_localtime , datefmt_parse_args ) PHP_FE( datefmt_get_error_code, arginfo_msgfmt_get_error_code ) @@ -530,6 +755,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 ) @@ -540,16 +855,14 @@ zend_function_entry intl_functions[] = { }; /* }}} */ - /* {{{ INI Settings */ 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() /* }}} */ - static PHP_GINIT_FUNCTION(intl); /* {{{ intl_module_entry */ @@ -640,6 +953,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,25 +972,44 @@ 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 ); - /* Set the default_locale value */ - if( INTL_G(default_locale) == NULL ) { - INTL_G(default_locale) = pestrdup(uloc_getDefault(), 1) ; - } + /* 'Converter' class for codepage conversions */ + php_converter_minit(INIT_FUNC_ARGS_PASSTHRU); return SUCCESS; } /* }}} */ +#define EXPLICIT_CLEANUP_ENV_VAR "INTL_EXPLICIT_CLEANUP" + /* {{{ PHP_MSHUTDOWN_FUNCTION */ PHP_MSHUTDOWN_FUNCTION( intl ) { + const char *cleanup; /* For the default locale php.ini setting */ UNREGISTER_INI_ENTRIES(); + cleanup = getenv(EXPLICIT_CLEANUP_ENV_VAR); + if (cleanup != NULL && !(cleanup[0] == '0' && cleanup[1] == '\0')) { + u_cleanup(); + } + return SUCCESS; } /* }}} */ @@ -680,10 +1018,6 @@ PHP_MSHUTDOWN_FUNCTION( intl ) */ PHP_RINIT_FUNCTION( intl ) { - /* Set the default_locale value */ - if( INTL_G(default_locale) == NULL ) { - INTL_G(default_locale) = pestrdup(uloc_getDefault(), 1) ; - } return SUCCESS; } /* }}} */ diff --git a/ext/intl/php_intl.h b/ext/intl/php_intl.h index 4ede069e2a..7a7112317d 100644 --- 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 a6a73f5f04..db46bf5b16 100644 --- a/ext/intl/resourcebundle/resourcebundle_class.c +++ b/ext/intl/resourcebundle/resourcebundle_class.c @@ -79,13 +79,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); @@ -104,7 +102,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) { @@ -117,6 +115,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 100644 --- 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..a818075a30 --- /dev/null +++ b/ext/intl/tests/breakiter___construct.phpt @@ -0,0 +1,14 @@ +--TEST-- +IntlBreakIterator::__construct() should not be callable +--SKIPIF-- +<?php +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..d838f81217 --- /dev/null +++ b/ext/intl/tests/breakiter_clone_basic.phpt @@ -0,0 +1,27 @@ +--TEST-- +IntlBreakIterator: clone handler +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +--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..2ce6da7697 --- /dev/null +++ b/ext/intl/tests/breakiter_current_basic.phpt @@ -0,0 +1,28 @@ +--TEST-- +IntlBreakIterator::current(): 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"); + +$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..dcfcedef0c --- /dev/null +++ b/ext/intl/tests/breakiter_factories_basic.phpt @@ -0,0 +1,46 @@ +--TEST-- +IntlBreakIterator factories: basic tests +--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", "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..c35339f7a0 --- /dev/null +++ b/ext/intl/tests/breakiter_factories_error.phpt @@ -0,0 +1,43 @@ +--TEST-- +IntlBreakIterator factory methods: argument errors +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +--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..364d5f2fa6 --- /dev/null +++ b/ext/intl/tests/breakiter_first_basic.phpt @@ -0,0 +1,22 @@ +--TEST-- +IntlBreakIterator::first(): basic test +--SKIPIF-- +<?php +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..2ab681228e --- /dev/null +++ b/ext/intl/tests/breakiter_first_last_previous_current_error.phpt @@ -0,0 +1,39 @@ +--TEST-- +IntlBreakIterator::first()/last()/previous()/current(): arg errors +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +--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..30798d99a3 --- /dev/null +++ b/ext/intl/tests/breakiter_following_basic.phpt @@ -0,0 +1,24 @@ +--TEST-- +IntlBreakIterator::following(): 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"); + +$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..5550ccf0a0 --- /dev/null +++ b/ext/intl/tests/breakiter_following_preceding_isBoundary_error.phpt @@ -0,0 +1,51 @@ +--TEST-- +IntlBreakIterator::following()/preceding()/isBoundary(): arg errors +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +--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..b0112cc847 --- /dev/null +++ b/ext/intl/tests/breakiter_getLocale_basic.phpt @@ -0,0 +1,21 @@ +--TEST-- +IntlBreakIterator::getLocale(): 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"); + +$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..9acd08ab63 --- /dev/null +++ b/ext/intl/tests/breakiter_getLocale_error.phpt @@ -0,0 +1,33 @@ +--TEST-- +IntlBreakIterator::getLocale(): arg errors +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +--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..36ad80d5fb --- /dev/null +++ b/ext/intl/tests/breakiter_getPartsIterator_basic.phpt @@ -0,0 +1,37 @@ +--TEST-- +IntlBreakIterator::getPartsIterator(): 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"); + +$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..0e5a26c16a --- /dev/null +++ b/ext/intl/tests/breakiter_getText_basic.phpt @@ -0,0 +1,17 @@ +--TEST-- +IntlBreakIterator::getText(): basic test +--SKIPIF-- +<?php +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..91e9919c15 --- /dev/null +++ b/ext/intl/tests/breakiter_getText_error.phpt @@ -0,0 +1,19 @@ +--TEST-- +IntlBreakIterator::getText(): arg errors +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +--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..1f416630a0 --- /dev/null +++ b/ext/intl/tests/breakiter_isBoundary_basic.phpt @@ -0,0 +1,28 @@ +--TEST-- +IntlBreakIterator::isBoundary(): 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"); + +$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..cf816c3670 --- /dev/null +++ b/ext/intl/tests/breakiter_last_basic.phpt @@ -0,0 +1,20 @@ +--TEST-- +IntlBreakIterator::last(): basic test +--SKIPIF-- +<?php +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..4deb4144e3 --- /dev/null +++ b/ext/intl/tests/breakiter_next_basic.phpt @@ -0,0 +1,30 @@ +--TEST-- +IntlBreakIterator::next(): 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"); + +$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..ed718bc2a5 --- /dev/null +++ b/ext/intl/tests/breakiter_next_error.phpt @@ -0,0 +1,27 @@ +--TEST-- +IntlBreakIterator::next(): arg errors +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +--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..6fa8dd7fa7 --- /dev/null +++ b/ext/intl/tests/breakiter_preceding_basic.phpt @@ -0,0 +1,24 @@ +--TEST-- +IntlBreakIterator::preceding(): 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"); + +$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..c3343af57c --- /dev/null +++ b/ext/intl/tests/breakiter_previous_basic.phpt @@ -0,0 +1,22 @@ +--TEST-- +IntlBreakIterator::previous(): 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"); + +$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..a5e4f86b65 --- /dev/null +++ b/ext/intl/tests/breakiter_setText_basic.phpt @@ -0,0 +1,36 @@ +--TEST-- +IntlBreakIterator::setText(): basic test +--SKIPIF-- +<?php +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..a7a73a08d8 --- /dev/null +++ b/ext/intl/tests/breakiter_setText_error.phpt @@ -0,0 +1,44 @@ +--TEST-- +IntlBreakIterator::setText(): arg errors +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +--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/bug62915.phpt b/ext/intl/tests/bug62915.phpt new file mode 100644 index 0000000000..e541d72d63 --- /dev/null +++ b/ext/intl/tests/bug62915.phpt @@ -0,0 +1,24 @@ +--TEST-- +Bug #62915: incomplete cloning of IntlTimeZone objects +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +--FILE-- +<?php + +class foo extends IntlTimeZone { + public $foo = 'test'; + + public function __construct() { } +} + +$x = new foo; + +try { + $z = clone $x; +} catch (Exception $e) { + var_dump($e->getMessage()); +} +--EXPECT-- +string(39) "Cannot clone unconstructed IntlTimeZone" 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..cfd9338717 --- /dev/null +++ b/ext/intl/tests/dateformat___construct_bad_tz_cal.phpt @@ -0,0 +1,32 @@ +--TEST-- +IntlDateFormatter::__construct(): bad timezone or calendar +--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"); +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..53fb084af9 --- /dev/null +++ b/ext/intl/tests/dateformat_create_cal_arg.phpt @@ -0,0 +1,53 @@ +--TEST-- +IntlDateFormatter: several forms of the calendar 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", "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== +--EXPECTF-- +domingo%S 1 de enero de 2012 00:00:00 GMT +domingo%S 8 de Safar de 1433 00:00:00 GMT +domingo%S 1 de enero de 2012 01:00:00 Hora estándar de Europa Central +sábado%S 31 de diciembre de 2011 d.C. 23:00:00 Hora %Sde las Azores +sábado%S 7 de Safar de 1433 AH 23:00:00 Hora %Sde las Azores +domingo%S 8 de Safar de 1433 AH 00:00:00 GMT +domingo%S 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..8664eea319 100644 --- 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' @@ -397,24 +399,24 @@ Formatted DateTime is : 20001230 05:04 PM Date is: stdClass::__set_state(array( )) ------------ -Error while formatting as: 'datefmt_format: object must be an instance of DateTime: U_ILLEGAL_ARGUMENT_ERROR' +Error while formatting as: 'datefmt_format: invalid object type for date/time (only IntlCalendar and DateTime permitted): U_ILLEGAL_ARGUMENT_ERROR' ------------ Date is: stdClass::__set_state(array( )) ------------ -Error while formatting as: 'datefmt_format: object must be an instance of DateTime: U_ILLEGAL_ARGUMENT_ERROR' +Error while formatting as: 'datefmt_format: invalid object type for date/time (only IntlCalendar and DateTime permitted): U_ILLEGAL_ARGUMENT_ERROR' ------------ Date is: stdClass::__set_state(array( )) ------------ -Error while formatting as: 'datefmt_format: object must be an instance of DateTime: U_ILLEGAL_ARGUMENT_ERROR' +Error while formatting as: 'datefmt_format: invalid object type for date/time (only IntlCalendar and DateTime permitted): U_ILLEGAL_ARGUMENT_ERROR' ------------ Date is: stdClass::__set_state(array( )) ------------ -Error while formatting as: 'datefmt_format: object must be an instance of DateTime: U_ILLEGAL_ARGUMENT_ERROR' +Error while formatting as: 'datefmt_format: invalid object type for date/time (only IntlCalendar and DateTime permitted): U_ILLEGAL_ARGUMENT_ERROR' ------------ Date is: stdClass::__set_state(array( )) ------------ -Error while formatting as: 'datefmt_format: object must be an instance of DateTime: U_ILLEGAL_ARGUMENT_ERROR' +Error while formatting as: 'datefmt_format: invalid object type for date/time (only IntlCalendar and DateTime permitted): U_ILLEGAL_ARGUMENT_ERROR' diff --git a/ext/intl/tests/dateformat_formatObject_calendar.phpt b/ext/intl/tests/dateformat_formatObject_calendar.phpt new file mode 100644 index 0000000000..0c61e4f2d0 --- /dev/null +++ b/ext/intl/tests/dateformat_formatObject_calendar.phpt @@ -0,0 +1,41 @@ +--TEST--
+IntlDateFormatter::formatObject(): IntlCalendar tests
+--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"); +ini_set("date.timezone", "Europe/Lisbon"); + +$cal = IntlCalendar::fromDateTime('2012-01-01 00:00:00'); //Europe/Lisbon +echo IntlDateFormatter::formatObject($cal), "\n"; +echo IntlDateFormatter::formatObject($cal, IntlDateFormatter::FULL), "\n"; +echo IntlDateFormatter::formatObject($cal, null, "en-US"), "\n"; +echo IntlDateFormatter::formatObject($cal, array(IntlDateFormatter::SHORT, IntlDateFormatter::FULL), "en-US"), "\n"; +echo IntlDateFormatter::formatObject($cal, 'E y-MM-d HH,mm,ss.SSS v', "en-US"), "\n"; + +$cal = IntlCalendar::fromDateTime('2012-01-01 05:00:00+03:00'); +echo datefmt_format_object($cal, IntlDateFormatter::FULL), "\n"; + +$cal = IntlCalendar::createInstance(null,'en-US@calendar=islamic-civil'); +$cal->setTime(strtotime('2012-01-01 00:00:00')*1000.); +echo IntlDateFormatter::formatObject($cal), "\n"; +echo IntlDateFormatter::formatObject($cal, IntlDateFormatter::FULL, "en-US"), "\n"; + +?> +==DONE== +
+--EXPECTF--
+01/01/2012 00:00:00 +Domingo, 1 de Janeiro de 2012 0:00:00 Hora %Sda Europa Ocidental +Jan 1, 2012 12:00:00 AM +1/1/12 12:00:00 AM Western European %STime +Sun 2012-01-1 00,00,00.000 Portugal Time (Lisbon) +Domingo, 1 de Janeiro de 2012 5:00:00 GMT+03:00 +06/02/1433 00:00:00 +Sunday, Safar 6, 1433 12:00:00 AM Western European %STime +==DONE== +
diff --git a/ext/intl/tests/dateformat_formatObject_datetime.phpt b/ext/intl/tests/dateformat_formatObject_datetime.phpt new file mode 100644 index 0000000000..6427ad5a98 --- /dev/null +++ b/ext/intl/tests/dateformat_formatObject_datetime.phpt @@ -0,0 +1,34 @@ +--TEST--
+IntlDateFormatter::formatObject(): DateTime tests
+--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"); +ini_set("date.timezone", "Europe/Lisbon"); + +$dt = new DateTime('2012-01-01 00:00:00'); //Europe/Lisbon +echo IntlDateFormatter::formatObject($dt), "\n"; +echo IntlDateFormatter::formatObject($dt, IntlDateFormatter::FULL), "\n"; +echo IntlDateFormatter::formatObject($dt, null, "en-US"), "\n"; +echo IntlDateFormatter::formatObject($dt, array(IntlDateFormatter::SHORT, IntlDateFormatter::FULL), "en-US"), "\n"; +echo IntlDateFormatter::formatObject($dt, 'E y-MM-d HH,mm,ss.SSS v', "en-US"), "\n"; + +$dt = new DateTime('2012-01-01 05:00:00+03:00'); +echo IntlDateFormatter::formatObject($dt, IntlDateFormatter::FULL), "\n"; + +?> +==DONE== +
+--EXPECTF--
+01/01/2012 00:00:00 +Domingo, 1 de Janeiro de 2012 0:00:00 Hora %Sda Europa Ocidental +Jan 1, 2012 12:00:00 AM +1/1/12 12:00:00 AM Western European %STime +Sun 2012-01-1 00,00,00.000 Portugal Time (Lisbon) +Domingo, 1 de Janeiro de 2012 5:00:00 GMT+03:00 +==DONE== +
diff --git a/ext/intl/tests/dateformat_formatObject_error.phpt b/ext/intl/tests/dateformat_formatObject_error.phpt new file mode 100644 index 0000000000..7aaf69e54e --- /dev/null +++ b/ext/intl/tests/dateformat_formatObject_error.phpt @@ -0,0 +1,74 @@ +--TEST--
+IntlDateFormatter::formatObject(): error conditions
+--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"); +ini_set("date.timezone", "Europe/Lisbon"); + +var_dump(IntlDateFormatter::formatObject()); +var_dump(IntlDateFormatter::formatObject(1)); +var_dump(IntlDateFormatter::formatObject(new stdclass)); + +class A extends IntlCalendar {function __construct(){}} +var_dump(IntlDateFormatter::formatObject(new A)); +class B extends DateTime {function __construct(){}} +var_dump(IntlDateFormatter::formatObject(new B)); + +$cal = IntlCalendar::createInstance(); +var_dump(IntlDateFormatter::formatObject($cal, -2)); +var_dump(IntlDateFormatter::formatObject($cal, array())); +var_dump(IntlDateFormatter::formatObject($cal, array(1,2,3))); +var_dump(IntlDateFormatter::formatObject($cal, array(array(), 1))); +var_dump(IntlDateFormatter::formatObject($cal, array(1, -2))); +var_dump(IntlDateFormatter::formatObject($cal, "")); +var_dump(IntlDateFormatter::formatObject($cal, "YYYY", array())); + +?> +==DONE== +
+--EXPECTF--
+ +Warning: IntlDateFormatter::formatObject() expects at least 1 parameter, 0 given in %s on line %d +bool(false) + +Warning: IntlDateFormatter::formatObject() expects parameter 1 to be object, integer given in %s on line %d +bool(false) + +Warning: IntlDateFormatter::formatObject(): datefmt_format_object: the passed object must be an instance of either IntlCalendar or DateTime in %s on line %d +bool(false) + +Warning: IntlDateFormatter::formatObject(): datefmt_format_object: bad IntlCalendar instance: not initialized properly in %s on line %d +bool(false) + +Warning: DateTime::getTimestamp(): The DateTime object has not been correctly initialized by its constructor in %s on line %d + +Warning: IntlDateFormatter::formatObject(): datefmt_format_object: error calling ::getTimeStamp() on the object in %s on line %d +bool(false) + +Warning: IntlDateFormatter::formatObject(): datefmt_format_object: the date/time format type is invalid in %s on line %d +bool(false) + +Warning: IntlDateFormatter::formatObject(): datefmt_format_object: bad format; if array, it must have two elements in %s on line %d +bool(false) + +Warning: IntlDateFormatter::formatObject(): datefmt_format_object: bad format; if array, it must have two elements in %s on line %d +bool(false) + +Warning: IntlDateFormatter::formatObject(): datefmt_format_object: bad format; the date format (first element of the array) is not valid in %s on line %d +bool(false) + +Warning: IntlDateFormatter::formatObject(): datefmt_format_object: bad format; the time format (second element of the array) is not valid in %s on line %d +bool(false) + +Warning: IntlDateFormatter::formatObject(): datefmt_format_object: the format is empty in %s on line %d +bool(false) + +Warning: IntlDateFormatter::formatObject() expects parameter 3 to be string, array given in %s on line %d +bool(false) +==DONE== +
diff --git a/ext/intl/tests/dateformat_format_parse.phpt b/ext/intl/tests/dateformat_format_parse.phpt index bd41d715b9..6bd3d8a8ff 100644 --- 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..d2ad66c829 --- /dev/null +++ b/ext/intl/tests/dateformat_getCalendarObject_error.phpt @@ -0,0 +1,43 @@ +--TEST-- +IntlDateFormatter::getCalendarObject(): 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"); +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..4ac5555d88 --- /dev/null +++ b/ext/intl/tests/dateformat_getTimeZone_error.phpt @@ -0,0 +1,43 @@ +--TEST-- +IntlDateFormatter::getTimeZone(): 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"); +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..dbb3e6cd23 100644 --- a/ext/intl/tests/dateformat_get_set_calendar.phpt +++ b/ext/intl/tests/dateformat_get_set_calendar.phpt @@ -1,60 +1,55 @@ --TEST-- -datefmt_get_calendar_code() datefmt_set_calendar_code() +IntlDateFormatter: setCalendar()/getCalendar()/getCalendarObject() --SKIPIF-- -<?php if( !extension_loaded( 'intl' ) ) print 'skip'; ?> +<?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"); +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..41aa35b9cf --- /dev/null +++ b/ext/intl/tests/dateformat_get_set_timezone.phpt @@ -0,0 +1,62 @@ +--TEST-- +IntlDateFormatter: get/setTimeZone() +--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"); +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== +--EXPECTF-- +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 Hor%s %Sdos Açores +string(15) "Atlantic/Azores" +string(15) "Atlantic/Azores" + +Domingo, 1 de Janeiro de 2012 1:00:00 Hor%s %Sda Europa Central +string(13) "Europe/Madrid" +string(13) "Europe/Madrid" + +Domingo, 1 de Janeiro de 2012 1:00:00 Hor%s %Sda Europa Central +string(12) "Europe/Paris" +string(12) "Europe/Paris" + +Domingo, 1 de Janeiro de 2012 1:00:00 Hor%s %Sda 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 100644 --- 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..5ee5b94d24 --- /dev/null +++ b/ext/intl/tests/dateformat_setTimeZoneID_deprecation.phpt @@ -0,0 +1,22 @@ +--TEST-- +IntlDateFormatter: setTimeZoneID() deprecation +--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"); +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..bd37031325 --- /dev/null +++ b/ext/intl/tests/dateformat_setTimeZone_error.phpt @@ -0,0 +1,53 @@ +--TEST-- +IntlDateFormatter::setTimeZone() 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"); +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..ccfb5e1964 --- /dev/null +++ b/ext/intl/tests/dateformat_timezone_arg_variations.phpt @@ -0,0 +1,45 @@ +--TEST-- +IntlDateFormatter: several forms of the timezone arg +--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", '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/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..ebbd4550e8 --- /dev/null +++ b/ext/intl/tests/msgfmt_format_error5.phpt @@ -0,0 +1,26 @@ +--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(): msgfmt_format: invalid object type for date/time (only IntlCalendar and DateTime permitted) in %s on line %d + +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 100644 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..6fb584fdee --- /dev/null +++ b/ext/intl/tests/rbbiter___construct_basic.phpt @@ -0,0 +1,31 @@ +--TEST-- +IntlRuleBasedBreakIterator::__construct: 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"); + +$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..a56f6bc488 --- /dev/null +++ b/ext/intl/tests/rbbiter_getRuleStatusVec_basic.phpt @@ -0,0 +1,59 @@ +--TEST-- +IntlRuleBasedBreakIterator::getRuleStatusVec(): 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"); + +$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..80eedbfba5 --- /dev/null +++ b/ext/intl/tests/rbbiter_getRuleStatus_basic.phpt @@ -0,0 +1,46 @@ +--TEST-- +IntlRuleBasedBreakIterator::getRuleStatus(): 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"); + +$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..2f7a40eb71 --- /dev/null +++ b/ext/intl/tests/rbbiter_getRules_basic.phpt @@ -0,0 +1,32 @@ +--TEST-- +IntlRuleBasedBreakIterator::getRules(): 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"); + +$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..1988d3b9e5 --- /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] => %i + [currentOffset] => %i +) +IntlTimeZone Object +( + [valid] => 1 + [id] => %s + [rawOffset] => %i + [currentOffset] => %i +) +==DONE==
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/tests/uconverter___construct_error.phpt b/ext/intl/tests/uconverter___construct_error.phpt new file mode 100644 index 0000000000..1b2480818b --- /dev/null +++ b/ext/intl/tests/uconverter___construct_error.phpt @@ -0,0 +1,14 @@ +--TEST-- +Basic UConverter::convert() usage +--INI-- +intl.error_level = E_WARNING +--SKIPIF-- +<?php if( !extension_loaded( 'intl' ) ) print 'skip'; ?> +--FILE-- +<?php +$c = new UConverter('utf-8', "\x80"); +var_dump($c); +--EXPECTF-- +Warning: UConverter::__construct(): ucnv_open() returned error 4: U_FILE_ACCESS_ERROR in %s on line %d +object(UConverter)#%d (0) { +} diff --git a/ext/intl/tests/uconverter_enum.phpt b/ext/intl/tests/uconverter_enum.phpt new file mode 100644 index 0000000000..67e02c9d75 --- /dev/null +++ b/ext/intl/tests/uconverter_enum.phpt @@ -0,0 +1,21 @@ +--TEST-- +UConverter Enumerations +--SKIPIF-- +<?php if( !extension_loaded( 'intl' ) ) print 'skip'; ?> +--FILE-- +<?php +$avail = UConverter::getAvailable(); +var_dump(count($avail) > 100); +var_dump(in_array('UTF-7', $avail)); +var_dump(in_array('CESU-8', $avail)); +var_dump(in_array('ISO-8859-1', $avail)); + +$latin1 = UConverter::getAliases('latin1'); +var_dump(in_array('ISO-8859-1', $latin1)); + +--EXPECT-- +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) diff --git a/ext/intl/tests/uconverter_func_basic.phpt b/ext/intl/tests/uconverter_func_basic.phpt new file mode 100644 index 0000000000..da8956beae --- /dev/null +++ b/ext/intl/tests/uconverter_func_basic.phpt @@ -0,0 +1,17 @@ +--TEST-- +Basic UConverter::transcode() usage +--SKIPIF-- +<?php if( !extension_loaded( 'intl' ) ) print 'skip'; ?> +--FILE-- +<?php +var_dump(UConverter::transcode("This is an ascii string", 'utf-8', 'latin1')); +// urlencode so that non-ascii shows up parsable in phpt file +var_dump(urlencode(UConverter::transcode("Espa\xF1ol", 'utf-8', 'latin1'))); +var_dump(urlencode(UConverter::transcode("Stra\xDFa", 'utf-8', 'latin1'))); + +var_dump(bin2hex(UConverter::transcode("\xE4", 'utf-8', 'koi8-r'))); +--EXPECT-- +string(23) "This is an ascii string" +string(12) "Espa%C3%B1ol" +string(11) "Stra%C3%9Fa" +string(4) "d094" diff --git a/ext/intl/tests/uconverter_func_subst.phpt b/ext/intl/tests/uconverter_func_subst.phpt new file mode 100644 index 0000000000..5cac5ce59c --- /dev/null +++ b/ext/intl/tests/uconverter_func_subst.phpt @@ -0,0 +1,31 @@ +--TEST-- +Basic UConverter::convert() w/ Subsitution +--SKIPIF-- +<?php if( !extension_loaded( 'intl' ) ) print 'skip'; ?> +--INI-- +intl.use_exceptions=false +--FILE-- +<?php +foreach(array('?','','??') as $subst) { + $opts = array('to_subst' => $subst); + $ret = UConverter::transcode("This is an ascii string", 'ascii', 'utf-8', $opts); + if ($ret === FALSE) { + echo "Error: ", intl_get_error_message(), "\n"; + } else { + var_dump($ret); + } + $ret = UConverter::transcode("Snowman: (\xE2\x98\x83)", 'ascii', 'utf-8', $opts); + if ($ret === FALSE) { + echo "Error: ", intl_get_error_message(), "\n"; + } else { + var_dump($ret); + } +} + +--EXPECTF-- +string(23) "This is an ascii string" +string(12) "Snowman: (?)" +Error: transcode() returned error 1: U_ILLEGAL_ARGUMENT_ERROR: U_ILLEGAL_ARGUMENT_ERROR +Error: transcode() returned error 1: U_ILLEGAL_ARGUMENT_ERROR: U_ILLEGAL_ARGUMENT_ERROR +Error: transcode() returned error 1: U_ILLEGAL_ARGUMENT_ERROR: U_ILLEGAL_ARGUMENT_ERROR +Error: transcode() returned error 1: U_ILLEGAL_ARGUMENT_ERROR: U_ILLEGAL_ARGUMENT_ERROR diff --git a/ext/intl/tests/uconverter_oop_algo.phpt b/ext/intl/tests/uconverter_oop_algo.phpt new file mode 100644 index 0000000000..349182ce32 --- /dev/null +++ b/ext/intl/tests/uconverter_oop_algo.phpt @@ -0,0 +1,18 @@ +--TEST-- +UConverter Algorithmic converters +--SKIPIF-- +<?php if( !extension_loaded( 'intl' ) ) print 'skip'; ?> +--FILE-- +<?php +$c = new UConverter('utf-8', 'latin1'); +var_dump(UConverter::LATIN_1 === $c->getSourceType()); +var_dump(UConverter::UTF8 === $c->getDestinationType()); + +$c = new UConverter('koi8-r', 'utf-32be'); +var_dump(UConverter::UTF32_BigEndian === $c->getSourceType()); +var_dump(UConverter::SBCS === $c->getDestinationType()); +--EXPECT-- +bool(true) +bool(true) +bool(true) +bool(true) diff --git a/ext/intl/tests/uconverter_oop_basic.phpt b/ext/intl/tests/uconverter_oop_basic.phpt new file mode 100644 index 0000000000..2b8909ff31 --- /dev/null +++ b/ext/intl/tests/uconverter_oop_basic.phpt @@ -0,0 +1,21 @@ +--TEST-- +Basic UConverter::convert() usage +--SKIPIF-- +<?php if( !extension_loaded( 'intl' ) ) print 'skip'; ?> +--FILE-- +<?php +$c = new UConverter('utf-8', 'latin1'); +var_dump($c->convert("This is an ascii string")); +// urlencode so that non-ascii shows up parsable in phpt file +var_dump(urlencode($c->convert("Espa\xF1ol"))); // U+00F1 LATIN SMALL LETTER N WITH TILDE +var_dump(urlencode($c->convert("Stra\xDFa"))); // U+00DF LATIN SMALL LETTER SHARP S +var_dump(urlencode($c->convert("Stra\xC3\x9Fa", true))); // Reverse prior op + +$k = new UConverter('utf-8', 'koi8-r'); +var_dump(bin2hex($k->convert("\xE4"))); // U+0414 CYRILLIC CAPITAL LETTER DE +--EXPECT-- +string(23) "This is an ascii string" +string(12) "Espa%C3%B1ol" +string(11) "Stra%C3%9Fa" +string(8) "Stra%DFa" +string(4) "d094" diff --git a/ext/intl/tests/uconverter_oop_callback.phpt b/ext/intl/tests/uconverter_oop_callback.phpt new file mode 100644 index 0000000000..47daf43305 --- /dev/null +++ b/ext/intl/tests/uconverter_oop_callback.phpt @@ -0,0 +1,52 @@ +--TEST-- +UConverter::convert() w/ Callback Reasons +--SKIPIF-- +<?php if( !extension_loaded( 'intl' ) ) print 'skip'; ?> +--FILE-- +<?php +class MyConverter extends UConverter { + /** + * Called during conversion from source encoding to internal UChar representation + */ + public function toUCallback($reason, $source, $codeUnits, &$error) { + echo "toUCallback(", UConverter::reasonText($reason), ", ...)\n"; + return parent::toUCallback($reason, $source, $codeUnits, $error); + } + + /** + * Called during conversion from internal UChar to destination encoding + */ + public function fromUCallback($reason, $source, $codePoint, &$error) { + echo "fromUCallback(", UConverter::reasonText($reason), ", ...)\n"; + return parent::fromUCallback($reason, $source, $codePoint, $error); + } + +} + +$c = new MyConverter('ascii', 'utf-8'); +foreach(array("regular", "irregul\xC1\xA1r", "\xC2\xA1unsupported!") as $word) { + $c->convert($word); +} +--EXPECT-- +toUCallback(REASON_RESET, ...) +toUCallback(REASON_RESET, ...) +fromUCallback(REASON_RESET, ...) +fromUCallback(REASON_RESET, ...) +toUCallback(REASON_RESET, ...) +toUCallback(REASON_ILLEGAL, ...) +toUCallback(REASON_RESET, ...) +toUCallback(REASON_ILLEGAL, ...) +fromUCallback(REASON_RESET, ...) +fromUCallback(REASON_UNASSIGNED, ...) +fromUCallback(REASON_RESET, ...) +fromUCallback(REASON_UNASSIGNED, ...) +toUCallback(REASON_RESET, ...) +toUCallback(REASON_RESET, ...) +fromUCallback(REASON_RESET, ...) +fromUCallback(REASON_UNASSIGNED, ...) +fromUCallback(REASON_RESET, ...) +fromUCallback(REASON_UNASSIGNED, ...) +toUCallback(REASON_CLOSE, ...) +fromUCallback(REASON_CLOSE, ...) +toUCallback(REASON_CLOSE, ...) +fromUCallback(REASON_CLOSE, ...) diff --git a/ext/intl/tests/uconverter_oop_callback_return.phpt b/ext/intl/tests/uconverter_oop_callback_return.phpt new file mode 100644 index 0000000000..cd7e7a5834 --- /dev/null +++ b/ext/intl/tests/uconverter_oop_callback_return.phpt @@ -0,0 +1,40 @@ +--TEST-- +UConverter::convert() w/ Callback Return Values +--SKIPIF-- +<?php if( !extension_loaded( 'intl' ) ) print 'skip'; ?> +--FILE-- +<?php +class MyConverter extends UConverter { + public function toUCallback($reason, $source, $codeUnits, &$error) { + $error = U_ZERO_ERROR; + switch ($codeUnits) { + case "\x80": return NULL; + case "\x81": return 'a'; + case "\x82": return ord('b'); + case "\x83": return array('c'); + } + } + + /** + * Called during conversion from internal UChar to destination encoding + */ + public function fromUCallback($reason, $source, $codePoint, &$error) { + $error = U_ZERO_ERROR; + switch ($codePoint) { + case 0x00F1: return "A"; + case 0x00F2: return ord("B"); + case 0x00F3: return array("C"); + case 0x00F4: return NULL; + } + } + +} + +$c = new MyConverter('ascii', 'utf-8'); +// This line will trigger toUCallback +var_dump($c->convert("\x80\x81\x82\x83")); +// This line will trigger fromUCallback +var_dump($c->convert("\xC3\xB1\xC3\xB2\xC3\xB3\xC3\xB4")); +--EXPECT-- +string(3) "abc" +string(3) "ABC" diff --git a/ext/intl/tests/uconverter_oop_subst.phpt b/ext/intl/tests/uconverter_oop_subst.phpt new file mode 100644 index 0000000000..d21d95f8d0 --- /dev/null +++ b/ext/intl/tests/uconverter_oop_subst.phpt @@ -0,0 +1,24 @@ +--TEST-- +Basic UConverter::convert() w/ Subsitution +--SKIPIF-- +<?php if( !extension_loaded( 'intl' ) ) print 'skip'; ?> +--INI-- +intl.use_exceptions=false +--FILE-- +<?php +$c = new UConverter('ascii', 'utf-8'); + +foreach(array('?','','<unknown>') as $subst) { + if (!$c->setSubstChars($subst)) { + echo "**Disallowed\n"; + continue; + } + var_dump($c->convert("This is an ascii string")); + var_dump($c->convert("Snowman: (\xE2\x98\x83)")); +} + +--EXPECT-- +string(23) "This is an ascii string" +string(12) "Snowman: (?)" +**Disallowed +**Disallowed diff --git a/ext/intl/timezone/timezone_class.cpp b/ext/intl/timezone/timezone_class.cpp new file mode 100644 index 0000000000..374b163851 --- /dev/null +++ b/ext/intl/timezone/timezone_class.cpp @@ -0,0 +1,540 @@ +/* + +----------------------------------------------------------------------+ + | 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" + +#include "../common/common_date.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_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(Z_OBJCE_P(object) 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..a638f6dbf4 --- /dev/null +++ b/ext/intl/timezone/timezone_class.h @@ -0,0 +1,72 @@ +/* + +----------------------------------------------------------------------+ + | 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; \ + } + +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..9ca6b44c89 --- /dev/null +++ b/ext/intl/timezone/timezone_methods.cpp @@ -0,0 +1,659 @@ +/* + +----------------------------------------------------------------------+ + | 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" + +#include "../common/common_date.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_class.c b/ext/intl/transliterator/transliterator_class.c index 5ef80fb482..9891b35f4c 100644 --- a/ext/intl/transliterator/transliterator_class.c +++ b/ext/intl/transliterator/transliterator_class.c @@ -39,7 +39,7 @@ int transliterator_object_construct( zval *object, char *str_id; int str_id_len; Transliterator_object *to; - + TRANSLITERATOR_METHOD_FETCH_OBJECT_NO_CHECK; assert( to->utrans == NULL ); @@ -54,7 +54,7 @@ int transliterator_object_construct( zval *object, { return FAILURE; } - + zend_update_property_stringl( Transliterator_ce_ptr, object, "id", sizeof( "id" ) - 1, str_id, str_id_len TSRMLS_CC ); efree( str_id ); @@ -126,7 +126,7 @@ static zend_object_value Transliterator_object_create( Transliterator_object* intern; intern = ecalloc( 1, sizeof( Transliterator_object ) ); - + zend_object_std_init( &intern->zo, ce TSRMLS_CC ); #if PHP_VERSION_ID < 50399 zend_hash_copy( intern->zo.properties, &(ce->default_properties ), @@ -247,7 +247,7 @@ err: #if PHP_VERSION_ID < 50399 static zval **Transliterator_get_property_ptr_ptr( zval *object, zval *member TSRMLS_DC ) #else -static zval **Transliterator_get_property_ptr_ptr( zval *object, zval *member, +static zval **Transliterator_get_property_ptr_ptr( zval *object, zval *member, int type, const struct _zend_literal *key TSRMLS_DC ) #endif { @@ -265,7 +265,7 @@ static zval **Transliterator_get_property_ptr_ptr( zval *object, zval *member, #if PHP_VERSION_ID < 50399 retval = std_object_handlers.get_property_ptr_ptr( object, member TSRMLS_CC ); #else - retval = std_object_handlers.get_property_ptr_ptr( object, member, key TSRMLS_CC ); + retval = std_object_handlers.get_property_ptr_ptr( object, member, type, key TSRMLS_CC ); #endif } 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 ); |