summaryrefslogtreecommitdiff
path: root/ext/intl
diff options
context:
space:
mode:
Diffstat (limited to 'ext/intl')
-rw-r--r--ext/intl/ERROR.CONVENTIONS20
-rw-r--r--ext/intl/calendar/calendar_class.cpp4
-rw-r--r--ext/intl/calendar/calendar_methods.cpp56
-rw-r--r--ext/intl/collator/collator_convert.c8
-rw-r--r--ext/intl/collator/collator_is_numeric.c15
-rw-r--r--ext/intl/collator/collator_sort.c15
-rw-r--r--ext/intl/common/common_enum.cpp2
-rw-r--r--ext/intl/dateformat/dateformat_create.cpp74
-rw-r--r--ext/intl/dateformat/dateformat_format_object.cpp14
-rw-r--r--ext/intl/formatter/formatter_format.c1
-rw-r--r--ext/intl/grapheme/grapheme_string.c42
-rw-r--r--ext/intl/intl_data.h12
-rw-r--r--ext/intl/locale/locale_methods.c127
-rw-r--r--ext/intl/msgformat/msgformat.c1
-rw-r--r--ext/intl/msgformat/msgformat_attr.c2
-rw-r--r--ext/intl/msgformat/msgformat_format.c3
-rw-r--r--ext/intl/msgformat/msgformat_helpers.cpp4
-rw-r--r--ext/intl/msgformat/msgformat_parse.c3
-rw-r--r--ext/intl/php_intl.c2
-rw-r--r--ext/intl/php_intl.h12
-rw-r--r--ext/intl/resourcebundle/resourcebundle_class.c2
-rw-r--r--ext/intl/tests/bug53735.phpt32
-rw-r--r--ext/intl/tests/bug67052.phpt4
-rw-r--r--ext/intl/tests/bug69374.phpt24
-rw-r--r--ext/intl/tests/bug69398.phpt22
-rw-r--r--ext/intl/tests/bug70451.phpt12
-rw-r--r--ext/intl/tests/bug70452.phpt21
-rw-r--r--ext/intl/tests/bug71020.phpt15
-rw-r--r--ext/intl/tests/bug72061.phpt15
-rw-r--r--ext/intl/tests/bug72241.phpt14
-rw-r--r--ext/intl/tests/calendar_before_after_error.phpt4
-rw-r--r--ext/intl/tests/calendar_clear_error.phpt3
-rw-r--r--ext/intl/tests/calendar_equals_error.phpt8
-rw-r--r--ext/intl/tests/calendar_get_Least_Greatest_Minimum_Maximum_error.phpt8
-rw-r--r--ext/intl/tests/calendar_get_getActualMaximum_Minumum_error2.phpt6
-rw-r--r--ext/intl/tests/calendar_isEquivalentTo_error.phpt8
-rw-r--r--ext/intl/tests/calendar_isWeekend_error.phpt1
-rw-r--r--ext/intl/tests/calendar_setTimeZone_error.phpt2
-rw-r--r--ext/intl/tests/collator_get_sort_key_variant4.phpt2
-rw-r--r--ext/intl/tests/collator_get_sort_key_variant5.phpt1
-rw-r--r--ext/intl/tests/collator_get_sort_key_variant6.phpt98
-rw-r--r--ext/intl/tests/dateformat_bug68893.phpt19
-rw-r--r--ext/intl/tests/dateformat_bug71516.phpt25
-rw-r--r--ext/intl/tests/formatter_format5.phpt3
-rw-r--r--ext/intl/tests/formatter_format6.phpt130
-rw-r--r--ext/intl/tests/formatter_get_set_text_attribute.phpt3
-rw-r--r--ext/intl/tests/formatter_get_set_text_attribute_var2.phpt122
-rw-r--r--ext/intl/tests/grapheme.phpt24
-rw-r--r--ext/intl/tests/locale_bug66289.phpt27
-rw-r--r--ext/intl/tests/msgfmt_bug70484.phpt97
-rw-r--r--ext/intl/tests/timezone_IDforWindowsID_basic.phpt46
-rw-r--r--ext/intl/tests/timezone_getCanonicalID_error.phpt6
-rw-r--r--ext/intl/tests/timezone_hasSameRules_error.phpt4
-rw-r--r--ext/intl/tests/timezone_windowsID_basic.phpt43
-rw-r--r--ext/intl/tests/uconverter_getAvailable_wrongparam_001.phpt8
-rw-r--r--ext/intl/timezone/timezone_class.cpp15
-rw-r--r--ext/intl/timezone/timezone_methods.cpp82
-rw-r--r--ext/intl/timezone/timezone_methods.h5
-rw-r--r--ext/intl/transliterator/transliterator_class.c8
-rw-r--r--ext/intl/transliterator/transliterator_methods.c1
-rw-r--r--ext/intl/uchar/tests/basic-functionality.phpt2
-rw-r--r--ext/intl/uchar/tests/bug70453.phpt18
-rw-r--r--ext/intl/uchar/tests/bug70454.phpt18
-rw-r--r--ext/intl/uchar/tests/bug70455.phpt13
-rw-r--r--ext/intl/uchar/uchar.c50
65 files changed, 1223 insertions, 265 deletions
diff --git a/ext/intl/ERROR.CONVENTIONS b/ext/intl/ERROR.CONVENTIONS
index 41cd14ec06..a7ef53665e 100644
--- a/ext/intl/ERROR.CONVENTIONS
+++ b/ext/intl/ERROR.CONVENTIONS
@@ -21,9 +21,9 @@ intl.use_exceptions you get more fine-grained information about where the
error occurred).
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);
+void intl_error_set_code(intl_error* err, UErrorCode err_code);
+void intl_error_set_custom_msg(intl_error* err, char* msg, int copyMsg);
+void intl_error_set(intl_error* err, UErrorCode code, char* msg, int copyMsg);
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.
@@ -44,9 +44,9 @@ typedef struct {
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);
+void intl_errors_set_custom_msg(intl_error* err, char* msg, int copyMsg);
+void intl_errors_set_code(intl_error* err, UErrorCode err_code);
+void intl_errors_set(intl_error* err, UErrorCode code, char* msg, int copyMsg);
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').
@@ -79,8 +79,8 @@ 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 */
+void intl_error_reset(NULL); /* reset global error */
+void intl_errors_reset(intl_error* err); /* 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.
@@ -97,10 +97,10 @@ U_CFUNC PHP_FUNCTION(breakiter_set_text)
BREAKITER_METHOD_INIT_VARS; /* macro also resets global error */
object = getThis();
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s",
+ if (zend_parse_parameters(ZEND_NUM_ARGS(), "s",
&text, &text_len) == FAILURE) {
intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
- "breakiter_set_text: bad arguments", 0 TSRMLS_CC);
+ "breakiter_set_text: bad arguments", 0);
RETURN_FALSE;
}
diff --git a/ext/intl/calendar/calendar_class.cpp b/ext/intl/calendar/calendar_class.cpp
index 6b6feef8d9..574f9a0fc3 100644
--- a/ext/intl/calendar/calendar_class.cpp
+++ b/ext/intl/calendar/calendar_class.cpp
@@ -177,7 +177,7 @@ static HashTable *Calendar_get_debug_info(zval *object, int *is_temp)
HashTable *debug_info_tz;
timezone_object_construct(&cal->getTimeZone(), &ztz , 0);
- debug_info = Z_OBJ_HANDLER(ztz, get_debug_info)(&ztz, &is_tmp);
+ debug_info_tz = Z_OBJ_HANDLER(ztz, get_debug_info)(&ztz, &is_tmp);
assert(is_tmp == 1);
array_init(&ztz_debug);
@@ -505,8 +505,6 @@ void calendar_register_IntlCalendar_class(void)
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);
diff --git a/ext/intl/calendar/calendar_methods.cpp b/ext/intl/calendar/calendar_methods.cpp
index ac5b33a89c..155ed5f7f4 100644
--- a/ext/intl/calendar/calendar_methods.cpp
+++ b/ext/intl/calendar/calendar_methods.cpp
@@ -522,48 +522,28 @@ U_CFUNC PHP_FUNCTION(intlcal_roll)
U_CFUNC PHP_FUNCTION(intlcal_clear)
{
- zval args_a[2] = {0},
- *args = &args_a[0];
- zend_long field;
- int variant;
+ zend_long field;
+ zend_bool field_is_null = 1;
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);
- RETURN_FALSE;
- }
- if (!getThis()) {
- args++;
- }
- if (Z_ISUNDEF(args[0]) || Z_TYPE(args[0]) == IS_NULL) {
- zval *dummy; /* we know it's null */
- if (zend_parse_method_parameters(ZEND_NUM_ARGS(),
- getThis(), "O|z", &object, Calendar_ce_ptr, &dummy) == FAILURE) {
- intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
- "intlcal_clear: bad arguments", 0);
- RETURN_FALSE;
- }
- variant = 0;
- } else if (zend_parse_method_parameters(ZEND_NUM_ARGS(),
- getThis(), "Ol", &object, Calendar_ce_ptr, &field) == FAILURE) {
+ if (zend_parse_method_parameters(ZEND_NUM_ARGS(),
+ getThis(), "O|l!", &object, Calendar_ce_ptr, &field, &field_is_null) == FAILURE) {
intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
"intlcal_clear: bad arguments", 0);
RETURN_FALSE;
- } else if (field < 0 || field >= UCAL_FIELD_COUNT) {
- intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
- "intlcal_clear: invalid field", 0);
- RETURN_FALSE;
- } else {
- variant = 1;
}
CALENDAR_METHOD_FETCH_OBJECT;
- if (variant == 0) {
+ if (field_is_null) {
co->ucal->clear();
} else {
+ if (field < 0 || field >= UCAL_FIELD_COUNT) {
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "intlcal_clear: invalid field", 0);
+ RETURN_FALSE;
+ }
+
co->ucal->clear((UCalendarDateFields)field);
}
@@ -614,7 +594,7 @@ U_CFUNC PHP_FUNCTION(intlcal_get_actual_minimum)
#if U_ICU_VERSION_MAJOR_NUM * 10 + U_ICU_VERSION_MINOR_NUM >= 44
U_CFUNC PHP_FUNCTION(intlcal_get_day_of_week_type)
{
- zend_ulong dow;
+ zend_long dow;
CALENDAR_METHOD_INIT_VARS;
if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(),
@@ -923,15 +903,11 @@ U_CFUNC PHP_FUNCTION(intlcal_is_set)
U_CFUNC PHP_FUNCTION(intlcal_is_weekend)
{
double date;
- zval *rawDate = NULL;
+ zend_bool date_is_null = 1;
CALENDAR_METHOD_INIT_VARS;
- if (zend_parse_method_parameters_ex(ZEND_PARSE_PARAMS_QUIET,
- ZEND_NUM_ARGS(), getThis(),
- "O|z!", &object, Calendar_ce_ptr, &rawDate) == FAILURE
- || (rawDate != NULL &&
- zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(),
- "O|d", &object, Calendar_ce_ptr, &date) == FAILURE)) {
+ if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(),
+ "O|d!", &object, Calendar_ce_ptr, &date, &date_is_null) == FAILURE) {
intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
"intlcal_is_weekend: bad arguments", 0);
RETURN_FALSE;
@@ -939,7 +915,7 @@ U_CFUNC PHP_FUNCTION(intlcal_is_weekend)
CALENDAR_METHOD_FETCH_OBJECT;
- if (rawDate == NULL) {
+ if (date_is_null) {
RETURN_BOOL((int)co->ucal->isWeekend());
} else {
UBool ret = co->ucal->isWeekend((UDate)date, CALENDAR_ERROR_CODE(co));
diff --git a/ext/intl/collator/collator_convert.c b/ext/intl/collator/collator_convert.c
index 8f06c8f1ca..2d431a19d6 100644
--- a/ext/intl/collator/collator_convert.c
+++ b/ext/intl/collator/collator_convert.c
@@ -28,12 +28,6 @@
#include <unicode/ustring.h>
#include <php.h>
-#if PHP_VERSION_ID <= 50100
-#define CAST_OBJECT_SHOULD_FREE ,0
-#else
-#define CAST_OBJECT_SHOULD_FREE
-#endif
-
#define COLLATOR_CONVERT_RETURN_FAILED(retval) { \
Z_TRY_ADDREF_P(retval); \
return retval; \
@@ -258,7 +252,7 @@ zval* collator_convert_object_to_string( zval* obj, zval *rv )
{
zstr = rv;
- if( Z_OBJ_HT_P(obj)->cast_object( obj, zstr, IS_STRING CAST_OBJECT_SHOULD_FREE ) == FAILURE )
+ if( Z_OBJ_HT_P(obj)->cast_object( obj, zstr, IS_STRING ) == FAILURE )
{
/* cast_object failed => bail out. */
zval_ptr_dtor( zstr );
diff --git a/ext/intl/collator/collator_is_numeric.c b/ext/intl/collator/collator_is_numeric.c
index 6b0568dd64..4f6efbfa6d 100644
--- a/ext/intl/collator/collator_is_numeric.c
+++ b/ext/intl/collator/collator_is_numeric.c
@@ -17,17 +17,6 @@
#include "collator_is_numeric.h"
-#if ZEND_MODULE_API_NO < 20071006
-/* not 5.3 */
-#ifndef ALLOCA_FLAG
-#define ALLOCA_FLAG(use_heap)
-#endif
-#define _do_alloca(x, y) do_alloca((x))
-#define _free_alloca(x, y) free_alloca((x))
-#else
-#define _do_alloca do_alloca
-#define _free_alloca free_alloca
-#endif
/* {{{ collator_u_strtod
* Taken from PHP6:zend_u_strtod()
*/
@@ -87,7 +76,7 @@ static double collator_u_strtod(const UChar *nptr, UChar **endptr) /* {{{ */
if (length < sizeof(buf)) {
numbuf = buf;
} else {
- numbuf = (char *) _do_alloca(length + 1, use_heap);
+ numbuf = (char *) do_alloca(length + 1, use_heap);
}
bufpos = numbuf;
@@ -100,7 +89,7 @@ static double collator_u_strtod(const UChar *nptr, UChar **endptr) /* {{{ */
value = zend_strtod(numbuf, NULL);
if (numbuf != buf) {
- _free_alloca(numbuf, use_heap);
+ free_alloca(numbuf, use_heap);
}
if (endptr != NULL) {
diff --git a/ext/intl/collator/collator_sort.c b/ext/intl/collator/collator_sort.c
index 8727c1d8ab..1ad42d3660 100644
--- a/ext/intl/collator/collator_sort.c
+++ b/ext/intl/collator/collator_sort.c
@@ -144,7 +144,6 @@ static int collator_regular_compare_function(zval *result, zval *op1, zval *op2)
*/
static int collator_numeric_compare_function(zval *result, zval *op1, zval *op2)
{
- int rc = SUCCESS;
zval num1, num2;
zval *num1_p = NULL;
zval *num2_p = NULL;
@@ -161,14 +160,14 @@ static int collator_numeric_compare_function(zval *result, zval *op1, zval *op2)
op2 = num2_p;
}
- rc = numeric_compare_function( result, op1, op2);
+ ZVAL_LONG(result, numeric_compare_function(op1, op2));
if( num1_p )
zval_ptr_dtor( num1_p );
if( num2_p )
zval_ptr_dtor( num2_p );
- return rc;
+ return SUCCESS;
}
/* }}} */
@@ -310,7 +309,7 @@ static void collator_sort_internal( int renumber, INTERNAL_FUNCTION_PARAMETERS )
/* Set 'compare function' according to sort flags. */
INTL_G(compare_func) = collator_get_compare_function( sort_flags );
- hash = HASH_OF( array );
+ hash = Z_ARRVAL_P( array );
/* Convert strings in the specified array from UTF-8 to UTF-16. */
collator_convert_hash_from_utf8_to_utf16( hash, COLLATOR_ERROR_CODE_P( co ) );
@@ -364,6 +363,7 @@ static void collator_sortkey_swap(collator_sort_key_index_t *p, collator_sort_ke
PHP_FUNCTION( collator_sort_with_sort_keys )
{
zval* array = NULL;
+ zval garbage;
HashTable* hash = NULL;
zval* hashData = NULL; /* currently processed item of input hash */
@@ -385,8 +385,6 @@ PHP_FUNCTION( collator_sort_with_sort_keys )
int utf16_buf_size = DEF_UTF16_BUF_SIZE; /* the length of utf16_buf */
int utf16_len = 0; /* length of converted string */
- HashTable* sortedHash = NULL;
-
COLLATOR_METHOD_INIT_VARS
/* Parse parameters. */
@@ -414,7 +412,7 @@ PHP_FUNCTION( collator_sort_with_sort_keys )
/*
* Sort specified array.
*/
- hash = HASH_OF( array );
+ hash = Z_ARRVAL_P( array );
if( !hash || zend_hash_num_elements( hash ) == 0 )
RETURN_TRUE;
@@ -508,7 +506,7 @@ PHP_FUNCTION( collator_sort_with_sort_keys )
zend_sort( sortKeyIndxBuf, sortKeyCount,
sortKeyIndxSize, collator_cmp_sort_keys, (swap_func_t)collator_sortkey_swap);
- zval_ptr_dtor( array );
+ ZVAL_COPY_VALUE(&garbage, array);
/* for resulting hash we'll assign new hash keys rather then reordering */
array_init(array);
@@ -521,6 +519,7 @@ PHP_FUNCTION( collator_sort_with_sort_keys )
if( utf16_buf )
efree( utf16_buf );
+ zval_ptr_dtor(&garbage);
efree( sortKeyIndxBuf );
efree( sortKeyBuf );
diff --git a/ext/intl/common/common_enum.cpp b/ext/intl/common/common_enum.cpp
index e76f3b830f..0531a6b933 100644
--- a/ext/intl/common/common_enum.cpp
+++ b/ext/intl/common/common_enum.cpp
@@ -183,7 +183,7 @@ static zend_object_iterator *IntlIterator_get_iterator(
return NULL;
}
- ++GC_REFCOUNT(ii->iterator);
+ ++GC_REFCOUNT(&ii->iterator->std);
return ii->iterator;
}
diff --git a/ext/intl/dateformat/dateformat_create.cpp b/ext/intl/dateformat/dateformat_create.cpp
index 1999b6a8c1..00a5cc593c 100644
--- a/ext/intl/dateformat/dateformat_create.cpp
+++ b/ext/intl/dateformat/dateformat_create.cpp
@@ -36,46 +36,51 @@ extern "C" {
#include "dateformat_helpers.h"
#include "zend_exceptions.h"
+#if U_ICU_VERSION_MAJOR_NUM < 50
+#define UDAT_PATTERN 0
+#endif
+
+#define INTL_UDATE_FMT_OK(i) \
+ (UDAT_FULL == (i) || UDAT_LONG == (i) || \
+ UDAT_MEDIUM == (i) || UDAT_SHORT == (i) || \
+ UDAT_RELATIVE == (i) || UDAT_FULL_RELATIVE == (i) || \
+ UDAT_LONG_RELATIVE == (i) || UDAT_MEDIUM_RELATIVE == (i) || \
+ UDAT_SHORT_RELATIVE == (i) || UDAT_NONE == (i) || \
+ UDAT_PATTERN == (i))
+
/* {{{ */
static int datefmt_ctor(INTERNAL_FUNCTION_PARAMETERS, zend_bool is_constructor)
{
zval *object;
-
const char *locale_str;
- size_t locale_len = 0;
+ size_t locale_len = 0;
Locale locale;
- zend_long date_type = 0;
- zend_long time_type = 0;
+ zend_long date_type = 0;
+ zend_long time_type = 0;
zval *calendar_zv = NULL;
- Calendar *calendar = NULL;
+ Calendar *calendar = NULL;
zend_long calendar_type;
bool calendar_owned;
zval *timezone_zv = NULL;
- TimeZone *timezone = NULL;
+ TimeZone *timezone = NULL;
bool explicit_tz;
- char* pattern_str = NULL;
- size_t pattern_str_len = 0;
- UChar* svalue = NULL; /* UTF-16 pattern_str */
- int32_t slength = 0;
+ char* pattern_str = NULL;
+ size_t pattern_str_len = 0;
+ UChar* svalue = NULL; /* UTF-16 pattern_str */
+ int32_t slength = 0;
IntlDateFormatter_object* dfo;
int zpp_flags = is_constructor ? ZEND_PARSE_PARAMS_THROW : 0;
intl_error_reset(NULL);
object = return_value;
/* Parse parameters. */
- if (zend_parse_parameters_ex(zpp_flags, ZEND_NUM_ARGS(), "sll|zzs",
+ if (zend_parse_parameters_ex(zpp_flags, ZEND_NUM_ARGS(), "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);
return FAILURE;
- }
-
- INTL_CHECK_LOCALE_LEN_OR_FAILURE(locale_len);
- if (locale_len == 0) {
- locale_str = intl_locale_get_default();
}
- locale = Locale::createFromName(locale_str);
DATE_FORMAT_METHOD_FETCH_OBJECT_NO_CHECK;
@@ -85,6 +90,21 @@ static int datefmt_ctor(INTERNAL_FUNCTION_PARAMETERS, zend_bool is_constructor)
return FAILURE;
}
+ if (!INTL_UDATE_FMT_OK(date_type)) {
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, "datefmt_create: invalid date format style", 0);
+ return FAILURE;
+ }
+ if (!INTL_UDATE_FMT_OK(time_type)) {
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, "datefmt_create: invalid time format style", 0);
+ return FAILURE;
+ }
+
+ INTL_CHECK_LOCALE_LEN_OR_FAILURE(locale_len);
+ if (locale_len == 0) {
+ locale_str = intl_locale_get_default();
+ }
+ locale = Locale::createFromName(locale_str);
+
/* process calendar */
if (datefmt_process_calendar_arg(calendar_zv, locale, "datefmt_create",
INTL_DATA_ERROR_P(dfo), calendar, calendar_type,
@@ -117,17 +137,19 @@ static int datefmt_ctor(INTERNAL_FUNCTION_PARAMETERS, zend_bool is_constructor)
}
}
+ DATE_FORMAT_OBJECT(dfo) = udat_open((UDateFormatStyle)time_type,
+ (UDateFormatStyle)date_type, locale_str, NULL, 0, svalue,
+ slength, &INTL_DATA_ERROR_CODE(dfo));
+
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));
+ udat_applyPattern(DATE_FORMAT_OBJECT(dfo), true, svalue, slength);
+ if (U_FAILURE(INTL_DATA_ERROR_CODE(dfo))) {
+ intl_error_set(NULL, INTL_DATA_ERROR_CODE(dfo), "datefmt_create: error applying pattern", 0);
+ goto error;
+ }
}
- if (!U_FAILURE(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);
@@ -139,7 +161,7 @@ static int datefmt_ctor(INTERNAL_FUNCTION_PARAMETERS, zend_bool is_constructor)
if (timezone != NULL) {
df->adoptTimeZone(timezone);
}
- } else {
+ } else {
intl_error_set(NULL, INTL_DATA_ERROR_CODE(dfo), "datefmt_create: date "
"formatter creation failed", 0);
goto error;
diff --git a/ext/intl/dateformat/dateformat_format_object.cpp b/ext/intl/dateformat/dateformat_format_object.cpp
index 3be76332a8..e96ebe8243 100644
--- a/ext/intl/dateformat/dateformat_format_object.cpp
+++ b/ext/intl/dateformat/dateformat_format_object.cpp
@@ -146,7 +146,9 @@ U_CFUNC PHP_FUNCTION(datefmt_format_object)
}
//there's no support for relative time in ICU yet
- timeStyle = (DateFormat::EStyle)(timeStyle & ~DateFormat::kRelative);
+ if (timeStyle != DateFormat::NONE) {
+ timeStyle = (DateFormat::EStyle)(timeStyle & ~DateFormat::kRelative);
+ }
zend_class_entry *instance_ce = Z_OBJCE_P(object);
if (instanceof_function(instance_ce, Calendar_ce_ptr)) {
@@ -188,11 +190,11 @@ U_CFUNC PHP_FUNCTION(datefmt_format_object)
}
if (pattern) {
- df = new SimpleDateFormat(
- UnicodeString(Z_STRVAL_P(format), Z_STRLEN_P(format),
- UnicodeString::kInvariant),
- Locale::createFromName(locale_str),
- status);
+ StringPiece sp(Z_STRVAL_P(format));
+ df = new SimpleDateFormat(
+ UnicodeString::fromUTF8(sp),
+ Locale::createFromName(locale_str),
+ status);
if (U_FAILURE(status)) {
intl_error_set(NULL, status,
diff --git a/ext/intl/formatter/formatter_format.c b/ext/intl/formatter/formatter_format.c
index 5307e426eb..369756ebdb 100644
--- a/ext/intl/formatter/formatter_format.c
+++ b/ext/intl/formatter/formatter_format.c
@@ -68,7 +68,6 @@ PHP_FUNCTION( numfmt_format )
}
if(Z_TYPE_P(number) != IS_DOUBLE && Z_TYPE_P(number) != IS_LONG) {
- SEPARATE_ZVAL_IF_NOT_REF(number);
convert_scalar_to_number(number );
}
diff --git a/ext/intl/grapheme/grapheme_string.c b/ext/intl/grapheme/grapheme_string.c
index b5a1902025..0735a7e822 100644
--- a/ext/intl/grapheme/grapheme_string.c
+++ b/ext/intl/grapheme/grapheme_string.c
@@ -110,7 +110,7 @@ PHP_FUNCTION(grapheme_strpos)
size_t haystack_len, needle_len;
const char *found;
zend_long loffset = 0;
- int32_t offset = 0;
+ int32_t offset = 0, noffset = 0;
zend_long ret_pos;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "ss|l", &haystack, &haystack_len, &needle, &needle_len, &loffset) == FAILURE) {
@@ -126,6 +126,7 @@ PHP_FUNCTION(grapheme_strpos)
/* we checked that it will fit: */
offset = (int32_t) loffset;
+ noffset = offset >= 0 ? offset : haystack_len + offset;
/* the offset is 'grapheme count offset' so it still might be invalid - we'll check it later */
@@ -134,20 +135,21 @@ PHP_FUNCTION(grapheme_strpos)
RETURN_FALSE;
}
+ if (offset >= 0) {
+ /* quick check to see if the string might be there
+ * I realize that 'offset' is 'grapheme count offset' but will work in spite of that
+ */
+ found = php_memnstr(haystack + noffset, needle, needle_len, haystack + haystack_len);
- /* quick check to see if the string might be there
- * I realize that 'offset' is 'grapheme count offset' but will work in spite of that
- */
- found = php_memnstr(haystack + offset, needle, needle_len, haystack + haystack_len);
-
- /* if it isn't there the we are done */
- if (!found) {
- RETURN_FALSE;
- }
+ /* if it isn't there the we are done */
+ if (!found) {
+ RETURN_FALSE;
+ }
- /* if it is there, and if the haystack is ascii, we are all done */
- if ( grapheme_ascii_check((unsigned char *)haystack, haystack_len) >= 0 ) {
- RETURN_LONG(found - haystack);
+ /* if it is there, and if the haystack is ascii, we are all done */
+ if ( grapheme_ascii_check((unsigned char *)haystack, haystack_len) >= 0 ) {
+ RETURN_LONG(found - haystack);
+ }
}
/* do utf16 part of the strpos */
@@ -195,16 +197,16 @@ PHP_FUNCTION(grapheme_stripos)
RETURN_FALSE;
}
-
is_ascii = ( grapheme_ascii_check((unsigned char*)haystack, haystack_len) >= 0 );
if ( is_ascii ) {
+ int32_t noffset = offset >= 0 ? offset : haystack_len + offset;
needle_dup = estrndup(needle, needle_len);
php_strtolower(needle_dup, needle_len);
haystack_dup = estrndup(haystack, haystack_len);
php_strtolower(haystack_dup, haystack_len);
- found = php_memnstr(haystack_dup + offset, needle_dup, needle_len, haystack_dup + haystack_len);
+ found = php_memnstr(haystack_dup + noffset, needle_dup, needle_len, haystack_dup + haystack_len);
efree(haystack_dup);
efree(needle_dup);
@@ -383,9 +385,9 @@ PHP_FUNCTION(grapheme_substr)
UBreakIterator* bi = NULL;
int sub_str_start_pos, sub_str_end_pos;
int32_t (*iter_func)(UBreakIterator *);
- int no_length = 1;
+ zend_bool no_length = 1;
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "sl|l!", (char **)&str, &str_len, &lstart, &length, &no_length) == FAILURE) {
+ if (zend_parse_parameters(ZEND_NUM_ARGS(), "sl|l!", &str, &str_len, &lstart, &length, &no_length) == FAILURE) {
intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,
"grapheme_substr: unable to parse input param", 0 );
RETURN_FALSE;
@@ -802,6 +804,10 @@ PHP_FUNCTION(grapheme_extract)
RETURN_FALSE;
}
+ if (lstart < 0) {
+ lstart += str_len;
+ }
+
if ( NULL != next ) {
if ( !Z_ISREF_P(next) ) {
intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,
@@ -810,7 +816,7 @@ PHP_FUNCTION(grapheme_extract)
} else {
ZVAL_DEREF(next);
/* initialize next */
- SEPARATE_ZVAL(next);
+ SEPARATE_ZVAL_NOREF(next);
zval_dtor(next);
ZVAL_LONG(next, lstart);
}
diff --git a/ext/intl/intl_data.h b/ext/intl/intl_data.h
index 12e0a9924e..74b7092fbb 100644
--- a/ext/intl/intl_data.h
+++ b/ext/intl/intl_data.h
@@ -45,7 +45,7 @@ typedef struct _intl_data {
obj = Z_##oclass##_P( object ); \
intl_error_reset( INTL_DATA_ERROR_P(obj) ); \
-/* Check status by error code, if error - exit */
+/* Check status by error code, if error return false */
#define INTL_CHECK_STATUS(err, msg) \
intl_error_set_code( NULL, (err) ); \
if( U_FAILURE((err)) ) \
@@ -54,6 +54,16 @@ typedef struct _intl_data {
RETURN_FALSE; \
}
+/* Check status by error code, if error return null */
+#define INTL_CHECK_STATUS_OR_NULL(err, msg) \
+ intl_error_set_code( NULL, (err) ); \
+ if( U_FAILURE((err)) ) \
+ { \
+ intl_error_set_custom_msg( NULL, msg, 0 ); \
+ RETURN_NULL(); \
+ }
+
+
/* Check status in object, if error return false */
#define INTL_METHOD_CHECK_STATUS(obj, msg) \
intl_error_set_code( NULL, INTL_DATA_ERROR_CODE((obj)) ); \
diff --git a/ext/intl/locale/locale_methods.c b/ext/intl/locale/locale_methods.c
index 895d803ef9..857c14a005 100644
--- a/ext/intl/locale/locale_methods.c
+++ b/ext/intl/locale/locale_methods.c
@@ -256,9 +256,9 @@ PHP_NAMED_FUNCTION(zif_locale_set_default)
* common code shared by get_primary_language,get_script or get_region or get_variant
* result = 0 if error, 1 if successful , -1 if no value
*/
-static char* get_icu_value_internal( const char* loc_name , char* tag_name, int* result , int fromParseLocale)
+static zend_string* get_icu_value_internal( const char* loc_name , char* tag_name, int* result , int fromParseLocale)
{
- char* tag_value = NULL;
+ zend_string* tag_value = NULL;
int32_t tag_value_len = 512;
int singletonPos = 0;
@@ -274,7 +274,7 @@ static char* get_icu_value_internal( const char* loc_name , char* tag_name, int*
grOffset = findOffset( LOC_GRANDFATHERED , loc_name );
if( grOffset >= 0 ){
if( strcmp(tag_name , LOC_LANG_TAG)==0 ){
- return estrdup(loc_name);
+ return zend_string_init(loc_name, strlen(loc_name), 0);
} else {
/* Since Grandfathered , no value , do nothing , retutn NULL */
return NULL;
@@ -285,7 +285,7 @@ static char* get_icu_value_internal( const char* loc_name , char* tag_name, int*
/* Handle singletons */
if( strcmp(tag_name , LOC_LANG_TAG)==0 ){
if( strlen(loc_name)>1 && (isIDPrefix(loc_name) == 1) ){
- return estrdup(loc_name);
+ return zend_string_init(loc_name, strlen(loc_name), 0);
}
}
@@ -308,36 +308,41 @@ static char* get_icu_value_internal( const char* loc_name , char* tag_name, int*
}
/* Proceed to ICU */
- do{
- tag_value = erealloc( tag_value , buflen );
+ do{
+ if (tag_value) {
+ tag_value = zend_string_realloc( tag_value , buflen, 0);
+ } else {
+ tag_value = zend_string_alloc( buflen, 0);
+ }
tag_value_len = buflen;
if( strcmp(tag_name , LOC_SCRIPT_TAG)==0 ){
- buflen = uloc_getScript ( mod_loc_name ,tag_value , tag_value_len , &status);
+ buflen = uloc_getScript ( mod_loc_name , tag_value->val , tag_value_len , &status);
}
if( strcmp(tag_name , LOC_LANG_TAG )==0 ){
- buflen = uloc_getLanguage ( mod_loc_name ,tag_value , tag_value_len , &status);
+ buflen = uloc_getLanguage ( mod_loc_name , tag_value->val , tag_value_len , &status);
}
if( strcmp(tag_name , LOC_REGION_TAG)==0 ){
- buflen = uloc_getCountry ( mod_loc_name ,tag_value , tag_value_len , &status);
+ buflen = uloc_getCountry ( mod_loc_name , tag_value->val , tag_value_len , &status);
}
if( strcmp(tag_name , LOC_VARIANT_TAG)==0 ){
- buflen = uloc_getVariant ( mod_loc_name ,tag_value , tag_value_len , &status);
+ buflen = uloc_getVariant ( mod_loc_name , tag_value->val , tag_value_len , &status);
}
if( strcmp(tag_name , LOC_CANONICALIZE_TAG)==0 ){
- buflen = uloc_canonicalize ( mod_loc_name ,tag_value , tag_value_len , &status);
+ buflen = uloc_canonicalize ( mod_loc_name , tag_value->val , tag_value_len , &status);
}
if( U_FAILURE( status ) ) {
if( status == U_BUFFER_OVERFLOW_ERROR ) {
status = U_ZERO_ERROR;
+ buflen++; /* add space for \0 */
continue;
}
/* Error in retriving data */
*result = 0;
if( tag_value ){
- efree( tag_value );
+ zend_string_release( tag_value );
}
if( mod_loc_name ){
efree( mod_loc_name);
@@ -350,7 +355,7 @@ static char* get_icu_value_internal( const char* loc_name , char* tag_name, int*
/* No value found */
*result = -1;
if( tag_value ){
- efree( tag_value );
+ zend_string_release( tag_value );
}
if( mod_loc_name ){
efree( mod_loc_name);
@@ -363,6 +368,8 @@ static char* get_icu_value_internal( const char* loc_name , char* tag_name, int*
if( mod_loc_name ){
efree( mod_loc_name);
}
+
+ tag_value->len = strlen(tag_value->val);
return tag_value;
}
/* }}} */
@@ -377,7 +384,7 @@ static void get_icu_value_src_php( char* tag_name, INTERNAL_FUNCTION_PARAMETERS)
const char* loc_name = NULL;
size_t loc_name_len = 0;
- char* tag_value = NULL;
+ zend_string* tag_value = NULL;
char* empty_result = "";
int result = 0;
@@ -406,16 +413,14 @@ static void get_icu_value_src_php( char* tag_name, INTERNAL_FUNCTION_PARAMETERS)
/* No value found */
if( result == -1 ) {
if( tag_value){
- efree( tag_value);
+ zend_string_release( tag_value);
}
RETURN_STRING( empty_result);
}
/* value found */
if( tag_value){
- RETVAL_STRING( tag_value );
- //???
- efree(tag_value);
+ RETVAL_STR( tag_value );
return;
}
@@ -822,7 +827,7 @@ static int append_multiple_key_values(smart_str* loc_name, HashTable* hash_arr,
smart_str_appendl(loc_name, Z_STRVAL_P(ele_value) , Z_STRLEN_P(ele_value));
return SUCCESS;
} else if(Z_TYPE_P(ele_value) == IS_ARRAY ) {
- HashTable *arr = HASH_OF(ele_value);
+ HashTable *arr = Z_ARRVAL_P(ele_value);
zval *data;
ZEND_HASH_FOREACH_VAL(arr, data) {
@@ -918,7 +923,7 @@ PHP_FUNCTION(locale_compose)
RETURN_FALSE;
}
- hash_arr = HASH_OF( arr );
+ hash_arr = Z_ARRVAL_P( arr );
if( !hash_arr || zend_hash_num_elements( hash_arr ) == 0 )
RETURN_FALSE;
@@ -985,9 +990,9 @@ PHP_FUNCTION(locale_compose)
* e.g. for locale='en_US-x-prv1-prv2-prv3'
* returns a pointer to the string 'prv1-prv2-prv3'
*/
-static char* get_private_subtags(const char* loc_name)
+static zend_string* get_private_subtags(const char* loc_name)
{
- char* result =NULL;
+ zend_string* result =NULL;
int singletonPos = 0;
int len =0;
const char* mod_loc_name =NULL;
@@ -1005,7 +1010,7 @@ static char* get_private_subtags(const char* loc_name)
}
else{
/* result = mod_loc_name + singletonPos +2; */
- result = estrndup(mod_loc_name + singletonPos+2 , (len -( singletonPos +2) ) );
+ result = zend_string_init(mod_loc_name + singletonPos+2 , (len -( singletonPos +2) ), 0);
}
break;
}
@@ -1032,7 +1037,7 @@ static char* get_private_subtags(const char* loc_name)
*/
static int add_array_entry(const char* loc_name, zval* hash_arr, char* key_name)
{
- char* key_value = NULL;
+ zend_string* key_value = NULL;
char* cur_key_name = NULL;
char* token = NULL;
char* last_ptr = NULL;
@@ -1052,7 +1057,7 @@ static int add_array_entry(const char* loc_name, zval* hash_arr, char* key_name)
( strcmp(key_name , LOC_VARIANT_TAG)==0) ){
if( result > 0 && key_value){
/* Tokenize on the "_" or "-" */
- token = php_strtok_r( key_value , DELIMITER ,&last_ptr);
+ token = php_strtok_r( key_value->val , DELIMITER ,&last_ptr);
if( cur_key_name ){
efree( cur_key_name);
}
@@ -1069,10 +1074,15 @@ static int add_array_entry(const char* loc_name, zval* hash_arr, char* key_name)
}
*/
}
+ if (key_value) {
+ zend_string_release(key_value);
+ }
} else {
if( result == 1 ){
- add_assoc_string( hash_arr, key_name , key_value);
+ add_assoc_str( hash_arr, key_name , key_value);
cur_result = 1;
+ } else if (key_value) {
+ zend_string_release(key_value);
}
}
@@ -1080,9 +1090,6 @@ static int add_array_entry(const char* loc_name, zval* hash_arr, char* key_name)
efree( cur_key_name);
}
/*if( key_name != LOC_PRIVATE_TAG && key_value){*/
- if( key_value){
- efree(key_value);
- }
return cur_result;
}
/* }}} */
@@ -1144,7 +1151,7 @@ PHP_FUNCTION(locale_get_all_variants)
int result = 0;
char* token = NULL;
- char* variant = NULL;
+ zend_string* variant = NULL;
char* saved_ptr = NULL;
intl_error_reset( NULL );
@@ -1174,7 +1181,7 @@ PHP_FUNCTION(locale_get_all_variants)
variant = get_icu_value_internal( loc_name , LOC_VARIANT_TAG , &result ,0);
if( result > 0 && variant){
/* Tokenize on the "_" or "-" */
- token = php_strtok_r( variant , DELIMITER , &saved_ptr);
+ token = php_strtok_r( variant->val , DELIMITER , &saved_ptr);
add_next_index_stringl( return_value, token , strlen(token));
/* tokenize on the "_" or "-" and stop at singleton if any */
while( (token = php_strtok_r(NULL , DELIMITER, &saved_ptr)) && (strlen(token)>1) ){
@@ -1182,7 +1189,7 @@ PHP_FUNCTION(locale_get_all_variants)
}
}
if( variant ){
- efree( variant );
+ zend_string_release( variant );
}
}
@@ -1241,8 +1248,8 @@ PHP_FUNCTION(locale_filter_matches)
char* token = 0;
char* chrcheck = NULL;
- char* can_lang_tag = NULL;
- char* can_loc_range = NULL;
+ zend_string* can_lang_tag = NULL;
+ zend_string* can_loc_range = NULL;
char* cur_lang_tag = NULL;
char* cur_loc_range = NULL;
@@ -1288,23 +1295,23 @@ PHP_FUNCTION(locale_filter_matches)
}
/* Convert to lower case for case-insensitive comparison */
- cur_lang_tag = ecalloc( 1, strlen(can_lang_tag) + 1);
+ cur_lang_tag = ecalloc( 1, can_lang_tag->len + 1);
/* Convert to lower case for case-insensitive comparison */
- result = strToMatch( can_lang_tag , cur_lang_tag);
+ result = strToMatch( can_lang_tag->val , cur_lang_tag);
if( result == 0) {
efree( cur_lang_tag );
- efree( can_lang_tag );
+ zend_string_release( can_lang_tag );
RETURN_FALSE;
}
- cur_loc_range = ecalloc( 1, strlen(can_loc_range) + 1);
- result = strToMatch( can_loc_range , cur_loc_range );
+ cur_loc_range = ecalloc( 1, can_loc_range->len + 1);
+ result = strToMatch( can_loc_range->val , cur_loc_range );
if( result == 0) {
efree( cur_lang_tag );
- efree( can_lang_tag );
+ zend_string_release( can_lang_tag );
efree( cur_loc_range );
- efree( can_loc_range );
+ zend_string_release( can_loc_range );
RETURN_FALSE;
}
@@ -1322,10 +1329,10 @@ PHP_FUNCTION(locale_filter_matches)
efree( cur_loc_range );
}
if( can_lang_tag){
- efree( can_lang_tag );
+ zend_string_release( can_lang_tag );
}
if( can_loc_range){
- efree( can_loc_range );
+ zend_string_release( can_loc_range );
}
RETURN_TRUE;
}
@@ -1339,10 +1346,10 @@ PHP_FUNCTION(locale_filter_matches)
efree( cur_loc_range );
}
if( can_lang_tag){
- efree( can_lang_tag );
+ zend_string_release( can_lang_tag );
}
if( can_loc_range){
- efree( can_loc_range );
+ zend_string_release( can_loc_range );
}
RETURN_FALSE;
@@ -1416,12 +1423,12 @@ static zend_string* lookup_loc_range(const char* loc_range, HashTable* hash_arr,
int cur_arr_len = 0;
int result = 0;
- char* lang_tag = NULL;
+ zend_string* lang_tag = NULL;
zval* ele_value = NULL;
char** cur_arr = NULL;
char* cur_loc_range = NULL;
- char* can_loc_range = NULL;
+ zend_string* can_loc_range = NULL;
int saved_pos = 0;
zend_string* return_value = NULL;
@@ -1448,16 +1455,16 @@ static zend_string* lookup_loc_range(const char* loc_range, HashTable* hash_arr,
if(canonicalize) {
for(i=0; i<cur_arr_len; i++) {
lang_tag = get_icu_value_internal(cur_arr[i*2], LOC_CANONICALIZE_TAG, &result, 0);
- if(result != 1 || lang_tag == NULL || !lang_tag[0]) {
+ if(result != 1 || lang_tag == NULL || !lang_tag->val[0]) {
if(lang_tag) {
- efree(lang_tag);
+ zend_string_release(lang_tag);
}
intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, "lookup_loc_range: unable to canonicalize lang_tag" , 0);
LOOKUP_CLEAN_RETURN(NULL);
}
- cur_arr[i*2] = erealloc(cur_arr[i*2], strlen(lang_tag)+1);
- result = strToMatch(lang_tag, cur_arr[i*2]);
- efree(lang_tag);
+ cur_arr[i*2] = erealloc(cur_arr[i*2], lang_tag->len+1);
+ result = strToMatch(lang_tag->val, cur_arr[i*2]);
+ zend_string_release(lang_tag);
if(result == 0) {
intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, "lookup_loc_range: unable to canonicalize lang_tag" , 0);
LOOKUP_CLEAN_RETURN(NULL);
@@ -1469,15 +1476,15 @@ static zend_string* lookup_loc_range(const char* loc_range, HashTable* hash_arr,
if(canonicalize) {
/* Canonicalize the loc_range */
can_loc_range = get_icu_value_internal(loc_range, LOC_CANONICALIZE_TAG, &result , 0);
- if( result != 1 || can_loc_range == NULL || !can_loc_range[0]) {
+ if( result != 1 || can_loc_range == NULL || !can_loc_range->val[0]) {
/* Error */
intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, "lookup_loc_range: unable to canonicalize loc_range" , 0 );
if(can_loc_range) {
- efree(can_loc_range);
+ zend_string_release(can_loc_range);
}
LOOKUP_CLEAN_RETURN(NULL);
} else {
- loc_range = can_loc_range;
+ loc_range = can_loc_range->val;
}
}
@@ -1485,7 +1492,7 @@ static zend_string* lookup_loc_range(const char* loc_range, HashTable* hash_arr,
/* convert to lower and replace hyphens */
result = strToMatch(loc_range, cur_loc_range);
if(can_loc_range) {
- efree(can_loc_range);
+ zend_string_release(can_loc_range);
}
if(result == 0) {
intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, "lookup_loc_range: unable to canonicalize lang_tag" , 0);
@@ -1542,10 +1549,14 @@ PHP_FUNCTION(locale_lookup)
}
if(loc_range_len == 0) {
- loc_range = intl_locale_get_default();
+ if(fallback_loc_str) {
+ loc_range = ZSTR_VAL(fallback_loc_str);
+ } else {
+ loc_range = intl_locale_get_default();
+ }
}
- hash_arr = HASH_OF(arr);
+ hash_arr = Z_ARRVAL_P(arr);
if( !hash_arr || zend_hash_num_elements( hash_arr ) == 0 ) {
RETURN_EMPTY_STRING();
diff --git a/ext/intl/msgformat/msgformat.c b/ext/intl/msgformat/msgformat.c
index e0919ec42b..d3f8416c03 100644
--- a/ext/intl/msgformat/msgformat.c
+++ b/ext/intl/msgformat/msgformat.c
@@ -23,6 +23,7 @@
#include "php_intl.h"
#include "msgformat_class.h"
+#include "msgformat_data.h"
#include "intl_convert.h"
/* {{{ */
diff --git a/ext/intl/msgformat/msgformat_attr.c b/ext/intl/msgformat/msgformat_attr.c
index a20a7e411d..78eb727c61 100644
--- a/ext/intl/msgformat/msgformat_attr.c
+++ b/ext/intl/msgformat/msgformat_attr.c
@@ -21,11 +21,11 @@
#include "php_intl.h"
#include "msgformat_class.h"
#include "msgformat_attr.h"
+#include "msgformat_data.h"
#include "intl_convert.h"
#include <unicode/ustring.h>
-
/* {{{ proto string MessageFormatter::getPattern( )
* Get formatter pattern. }}} */
/* {{{ proto string msgfmt_get_pattern( MessageFormatter $mf )
diff --git a/ext/intl/msgformat/msgformat_format.c b/ext/intl/msgformat/msgformat_format.c
index 5aa68e2735..959a4fd5a0 100644
--- a/ext/intl/msgformat/msgformat_format.c
+++ b/ext/intl/msgformat/msgformat_format.c
@@ -104,7 +104,7 @@ PHP_FUNCTION( msgfmt_format_message )
size_t pattern_len = 0;
const char *slocale = NULL;
size_t slocale_len = 0;
- MessageFormatter_object mf = {0};
+ MessageFormatter_object mf;
MessageFormatter_object *mfo = &mf;
/* Parse parameters. */
@@ -117,6 +117,7 @@ PHP_FUNCTION( msgfmt_format_message )
RETURN_FALSE;
}
+ memset(mfo, 0, sizeof(*mfo));
msgformat_data_init(&mfo->mf_data);
if(pattern && pattern_len) {
diff --git a/ext/intl/msgformat/msgformat_helpers.cpp b/ext/intl/msgformat/msgformat_helpers.cpp
index ed63105fa7..ce7899edd9 100644
--- a/ext/intl/msgformat/msgformat_helpers.cpp
+++ b/ext/intl/msgformat/msgformat_helpers.cpp
@@ -264,6 +264,10 @@ static HashTable *umsg_parse_format(MessageFormatter_object *mfo,
type = Formattable::kDouble;
} else if (argType == UMSGPAT_ARG_TYPE_SELECT) {
type = Formattable::kString;
+#if U_ICU_VERSION_MAJOR_NUM >= 50
+ } else if (argType == UMSGPAT_ARG_TYPE_SELECTORDINAL) {
+ type = Formattable::kDouble;
+#endif
} else {
type = Formattable::kString;
}
diff --git a/ext/intl/msgformat/msgformat_parse.c b/ext/intl/msgformat/msgformat_parse.c
index 4d63a0169a..349633912b 100644
--- a/ext/intl/msgformat/msgformat_parse.c
+++ b/ext/intl/msgformat/msgformat_parse.c
@@ -97,7 +97,7 @@ PHP_FUNCTION( msgfmt_parse_message )
size_t slocale_len = 0;
char *source = NULL;
size_t src_len = 0;
- MessageFormatter_object mf = {0};
+ MessageFormatter_object mf;
MessageFormatter_object *mfo = &mf;
/* Parse parameters. */
@@ -110,6 +110,7 @@ PHP_FUNCTION( msgfmt_parse_message )
RETURN_FALSE;
}
+ memset(mfo, 0, sizeof(*mfo));
msgformat_data_init(&mfo->mf_data);
if(pattern && pattern_len) {
diff --git a/ext/intl/php_intl.c b/ext/intl/php_intl.c
index 12bd9fdc74..fd35e57120 100644
--- a/ext/intl/php_intl.c
+++ b/ext/intl/php_intl.c
@@ -892,7 +892,7 @@ zend_module_entry intl_module_entry = {
#ifdef COMPILE_DL_INTL
#ifdef ZTS
-ZEND_TSRMLS_CACHE_DEFINE();
+ZEND_TSRMLS_CACHE_DEFINE()
#endif
ZEND_GET_MODULE( intl )
#endif
diff --git a/ext/intl/php_intl.h b/ext/intl/php_intl.h
index 638fdef1ca..e672e54087 100644
--- a/ext/intl/php_intl.h
+++ b/ext/intl/php_intl.h
@@ -55,17 +55,13 @@ ZEND_BEGIN_MODULE_GLOBALS(intl)
zend_bool use_exceptions;
ZEND_END_MODULE_GLOBALS(intl)
-/* Macro to access request-wide global variables. */
-#ifdef ZTS
-#define INTL_G(v) ZEND_TSRMG(intl_globals_id, zend_intl_globals *, v)
-#ifdef COMPILE_DL_INTL
-ZEND_TSRMLS_CACHE_EXTERN();
-#endif
-#else
-#define INTL_G(v) (intl_globals.v)
+#if defined(ZTS) && defined(COMPILE_DL_INTL)
+ZEND_TSRMLS_CACHE_EXTERN()
#endif
ZEND_EXTERN_MODULE_GLOBALS(intl)
+/* Macro to access request-wide global variables. */
+#define INTL_G(v) ZEND_MODULE_GLOBALS_ACCESSOR(intl, v)
PHP_MINIT_FUNCTION(intl);
PHP_MSHUTDOWN_FUNCTION(intl);
diff --git a/ext/intl/resourcebundle/resourcebundle_class.c b/ext/intl/resourcebundle/resourcebundle_class.c
index d6b071a249..fd255d57cd 100644
--- a/ext/intl/resourcebundle/resourcebundle_class.c
+++ b/ext/intl/resourcebundle/resourcebundle_class.c
@@ -49,8 +49,6 @@ static void ResourceBundle_object_destroy( zend_object *object )
if (rb->child) {
ures_close( rb->child );
}
-
- //???zend_object_std_dtor( object );
}
/* }}} */
diff --git a/ext/intl/tests/bug53735.phpt b/ext/intl/tests/bug53735.phpt
new file mode 100644
index 0000000000..5fc14e978c
--- /dev/null
+++ b/ext/intl/tests/bug53735.phpt
@@ -0,0 +1,32 @@
+--TEST--
+Bug #53735 NumberFormatter returns NaN when converting float point
+--SKIPIF--
+<?php if( !extension_loaded( 'intl' ) ) print 'skip'; ?>
+<?php if (version_compare(INTL_ICU_VERSION, '51.2') < 0) die('skip for ICU >= 51.2'); ?>
+--FILE--
+<?php
+
+$fmt = numfmt_create("da_DK", \NumberFormatter::CURRENCY);
+
+var_dump(numfmt_format($fmt, 5.5));
+setlocale(LC_ALL, "da_DK.UTF-8");
+
+var_dump(numfmt_format($fmt, 5.5));
+var_dump(numfmt_format($fmt, "5,5"));
+
+
+$fmt = new \NumberFormatter("de_DE", \NumberFormatter::DECIMAL);
+var_dump($fmt->format(23.25));
+
+$f = new NumberFormatter('hu_HU', NumberFormatter::PERCENT, '#,##0%');
+var_dump($f->format(0.26));
+
+?>
+==DONE==
+--EXPECTF--
+string(%d) "5,50 kr%A"
+string(%d) "5,50 kr%A"
+string(%d) "5,00 kr%A"
+string(5) "23,25"
+string(3) "26%"
+==DONE==
diff --git a/ext/intl/tests/bug67052.phpt b/ext/intl/tests/bug67052.phpt
index 80c7e88017..7f0c4cba51 100644
--- a/ext/intl/tests/bug67052.phpt
+++ b/ext/intl/tests/bug67052.phpt
@@ -17,7 +17,7 @@ setlocale(LC_ALL, $l);
function ut_main()
{
- setlocale(LC_ALL, 'de_DE');
+ setlocale(LC_ALL, 'de_DE.UTF-8');
$fmt = new NumberFormatter( 'sl_SI.UTF-8', NumberFormatter::DECIMAL);
$num = "1.234.567,891";
$res_str = $fmt->parse($num)."\n";
@@ -31,5 +31,5 @@ ut_run();
?>
--EXPECT--
1234567,891
-de_DE
+de_DE.UTF-8
diff --git a/ext/intl/tests/bug69374.phpt b/ext/intl/tests/bug69374.phpt
new file mode 100644
index 0000000000..4d9fffab7a
--- /dev/null
+++ b/ext/intl/tests/bug69374.phpt
@@ -0,0 +1,24 @@
+--TEST--
+IntlDateFormatter::formatObject(): returns wrong utf8 value when $format param is utf8 string pattern.
+--SKIPIF--
+<?php
+if (!extension_loaded('intl')) die('skip intl extension not enabled'); ?>
+<?php if (version_compare(INTL_ICU_VERSION, '50.1.2') < 0) die('skip for ICU >= 51.1.2'); ?>
+--FILE--
+<?php
+$millitimestamp = 1428133423941.0; // 14:43:43 April 04 2015
+$pattern1 = '\'tháng\' MM, y'; // yMM format for Vietnamese
+$pattern2 = 'y년 MMM'; // yMM format for Korean
+$date = IntlCalendar::createInstance('Asia/Ho_Chi_Minh');
+$date->setTime($millitimestamp);
+echo IntlDateFormatter::formatObject($date, $pattern1, 'vi_VN'), "\n";
+echo IntlDateFormatter::formatObject ($date, $pattern2, 'ko_KR'), "\n";
+?>
+==DONE==
+
+--EXPECTF--
+tháng 04, 2015
+2015년 4월
+==DONE==
+
+
diff --git a/ext/intl/tests/bug69398.phpt b/ext/intl/tests/bug69398.phpt
new file mode 100644
index 0000000000..ea7dbd5098
--- /dev/null
+++ b/ext/intl/tests/bug69398.phpt
@@ -0,0 +1,22 @@
+--TEST--
+IntlDateFormatter::formatObject(): returns wrong value when time style is NONE.
+--SKIPIF--
+<?php
+if (!extension_loaded('intl')) die('skip intl extension not enabled'); ?>
+<?php if (version_compare(INTL_ICU_VERSION, '50.1.2') < 0) die('skip for ICU >= 51.1.2'); ?>
+--FILE--
+<?php
+$millitimestamp = 1428133423941.0; // 14:43:43 April 04 2015
+$date = IntlCalendar::createInstance('Asia/Ho_Chi_Minh');
+$date->setTime($millitimestamp);
+echo IntlDateFormatter::formatObject($date, array(IntlDateFormatter::SHORT, IntlDateFormatter::NONE), 'vi_VN'), "\n";
+echo IntlDateFormatter::formatObject ($date, array(IntlDateFormatter::SHORT, IntlDateFormatter::NONE), 'ko_KR'), "\n";
+?>
+==DONE==
+
+--EXPECTF--
+04/04/2015
+15. 4. 4.
+==DONE==
+
+
diff --git a/ext/intl/tests/bug70451.phpt b/ext/intl/tests/bug70451.phpt
new file mode 100644
index 0000000000..75392c8dad
--- /dev/null
+++ b/ext/intl/tests/bug70451.phpt
@@ -0,0 +1,12 @@
+--TEST--
+Bug #70451 IntlChar::charFromName() not consistent with C library or HHVM
+--SKIPIF--
+<?php if( !extension_loaded( 'intl' ) ) print 'skip'; ?>
+--FILE--
+<?php
+var_dump(IntlChar::charFromName("RECYCLING SYMBOL FOR TYPE-1 PLASTICS"));
+var_dump(IntlChar::charFromName("sdfasdfasdfasdf"));
+?>
+--EXPECT--
+int(9843)
+NULL
diff --git a/ext/intl/tests/bug70452.phpt b/ext/intl/tests/bug70452.phpt
new file mode 100644
index 0000000000..ee1cd7053a
--- /dev/null
+++ b/ext/intl/tests/bug70452.phpt
@@ -0,0 +1,21 @@
+--TEST--
+Bug #70452 string IntlChar::charName() can sometimes return bool(false)
+--SKIPIF--
+<?php if( !extension_loaded( 'intl' ) ) print 'skip'; ?>
+--FILE--
+<?php
+// Rely on the default value for the second parameter
+var_dump(IntlChar::charName("A"));
+// Provide a valid option for the second parameter
+var_dump(IntlChar::charName("A", IntlChar::UNICODE_CHAR_NAME));
+// Another valid option, but with no corresponding name for that given option
+// This properly returns an empty string, as expected
+var_dump(IntlChar::charName("A", IntlChar::UNICODE_10_CHAR_NAME));
+// Provide an invalid value for the second parameter
+var_dump(IntlChar::charName("A", 12345));
+?>
+--EXPECT--
+string(22) "LATIN CAPITAL LETTER A"
+string(22) "LATIN CAPITAL LETTER A"
+string(0) ""
+NULL
diff --git a/ext/intl/tests/bug71020.phpt b/ext/intl/tests/bug71020.phpt
new file mode 100644
index 0000000000..368d967efd
--- /dev/null
+++ b/ext/intl/tests/bug71020.phpt
@@ -0,0 +1,15 @@
+--TEST--
+Bug #71020 (Use after free in Collator::sortWithSortKeys)
+--SKIPIF--
+<?php if( !extension_loaded( 'intl' ) ) print 'skip'; ?>
+--FILE--
+<?php
+
+$var_3=new Collator("Whatever");
+for($x=0;$x<0xbb;$x++)
+ $myarray[substr(md5(microtime()),rand(0,26),9) . strval($x)]= substr(md5(microtime()),rand(0,26),9) . strval($x);
+$var_3->sortWithSortKeys($myarray);
+?>
+okey
+--EXPECT--
+okey
diff --git a/ext/intl/tests/bug72061.phpt b/ext/intl/tests/bug72061.phpt
new file mode 100644
index 0000000000..782c32c11c
--- /dev/null
+++ b/ext/intl/tests/bug72061.phpt
@@ -0,0 +1,15 @@
+--TEST--
+Bug #72061: Out-of-bounds reads in zif_grapheme_stripos with negative offset
+--SKIPIF--
+<?php if( !extension_loaded( 'intl' ) ) print 'skip'; ?>
+--FILE--
+<?php
+
+var_dump(grapheme_stripos(str_repeat("ABCD", 16384), "A", -201));
+var_dump(grapheme_strpos(str_repeat("ABCD", 16384), "A", -201));
+?>
+DONE
+--EXPECT--
+int(65336)
+int(65336)
+DONE \ No newline at end of file
diff --git a/ext/intl/tests/bug72241.phpt b/ext/intl/tests/bug72241.phpt
new file mode 100644
index 0000000000..397e1e7834
--- /dev/null
+++ b/ext/intl/tests/bug72241.phpt
@@ -0,0 +1,14 @@
+--TEST--
+Bug #72241: get_icu_value_internal out-of-bounds read
+--SKIPIF--
+<?php if( !extension_loaded( 'intl' ) ) print 'skip'; ?>
+--FILE--
+<?php
+$var1=str_repeat("A", 1000);
+$out = locale_get_primary_language($var1);
+echo strlen($out) . PHP_EOL;
+echo unpack('H*', $out)[1] . PHP_EOL;
+--EXPECT--
+1000
+61616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161
+
diff --git a/ext/intl/tests/calendar_before_after_error.phpt b/ext/intl/tests/calendar_before_after_error.phpt
index 938c7a5fb7..7d57b93a33 100644
--- a/ext/intl/tests/calendar_before_after_error.phpt
+++ b/ext/intl/tests/calendar_before_after_error.phpt
@@ -67,9 +67,9 @@ bool(false)
error: 2, IntlCalendar::before() expects exactly 1 parameter, 0 given
error: 2, IntlCalendar::before(): intlcal_before/after: bad arguments
bool(false)
-error: 1, Argument 1 passed to IntlCalendar::after() must be an instance of IntlCalendar, integer given
+error: 0, Argument 1 passed to IntlCalendar::after() must be an instance of IntlCalendar, integer given
-error: 1, Argument 1 passed to IntlCalendar::before() must be an instance of IntlCalendar, integer given
+error: 0, Argument 1 passed to IntlCalendar::before() must be an instance of IntlCalendar, integer given
error: 2, IntlCalendar::after() expects exactly 1 parameter, 2 given
error: 2, IntlCalendar::after(): intlcal_before/after: bad arguments
diff --git a/ext/intl/tests/calendar_clear_error.phpt b/ext/intl/tests/calendar_clear_error.phpt
index 7e9c52b2a5..7ff2ff0867 100644
--- a/ext/intl/tests/calendar_clear_error.phpt
+++ b/ext/intl/tests/calendar_clear_error.phpt
@@ -18,8 +18,9 @@ var_dump($c->clear(-1));
var_dump(intlcal_clear($c, -1));
var_dump(intlcal_clear(1, 2));
--EXPECTF--
+Warning: IntlCalendar::clear() expects at most 1 parameter, 2 given in %s on line %d
-Warning: IntlCalendar::clear(): intlcal_clear: too many arguments in %s on line %d
+Warning: IntlCalendar::clear(): intlcal_clear: bad arguments in %s on line %d
bool(false)
Warning: IntlCalendar::clear(): intlcal_clear: invalid field in %s on line %d
diff --git a/ext/intl/tests/calendar_equals_error.phpt b/ext/intl/tests/calendar_equals_error.phpt
index 8465541c87..a9f164d38f 100644
--- a/ext/intl/tests/calendar_equals_error.phpt
+++ b/ext/intl/tests/calendar_equals_error.phpt
@@ -49,10 +49,10 @@ try {
error: 2, IntlCalendar::equals() expects exactly 1 parameter, 0 given
error: 2, IntlCalendar::equals(): intlcal_equals: bad arguments
bool(false)
-error: 1, Argument 1 passed to IntlCalendar::equals() must be an instance of IntlCalendar, instance of stdClass given
+error: 0, Argument 1 passed to IntlCalendar::equals() must be an instance of IntlCalendar, instance of stdClass given
-error: 1, Argument 1 passed to IntlCalendar::equals() must be an instance of IntlCalendar, integer given
+error: 0, Argument 1 passed to IntlCalendar::equals() must be an instance of IntlCalendar, integer given
-error: 1, Argument 2 passed to intlcal_equals() must be an instance of IntlCalendar, array given
+error: 0, Argument 2 passed to intlcal_equals() must be an instance of IntlCalendar, array given
-error: 1, Argument 1 passed to intlcal_equals() must be an instance of IntlCalendar, integer given
+error: 0, Argument 1 passed to intlcal_equals() must be an instance of IntlCalendar, integer given
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
index 3d881a781d..5d74a7d72d 100644
--- a/ext/intl/tests/calendar_get_Least_Greatest_Minimum_Maximum_error.phpt
+++ b/ext/intl/tests/calendar_get_Least_Greatest_Minimum_Maximum_error.phpt
@@ -98,11 +98,11 @@ bool(false)
Warning: intlcal_get_minimum(): intlcal_get_minimum: invalid field in %s on line %d
bool(false)
-error: 1, Argument 1 passed to intlcal_get_least_maximum() must be an instance of IntlCalendar, integer given
+error: 0, Argument 1 passed to intlcal_get_least_maximum() must be an instance of IntlCalendar, integer given
-error: 1, Argument 1 passed to intlcal_get_maximum() must be an instance of IntlCalendar, integer given
+error: 0, Argument 1 passed to intlcal_get_maximum() must be an instance of IntlCalendar, integer given
-error: 1, Argument 1 passed to intlcal_get_greatest_minimum() must be an instance of IntlCalendar, integer given
+error: 0, Argument 1 passed to intlcal_get_greatest_minimum() must be an instance of IntlCalendar, integer given
-error: 1, Argument 1 passed to intlcal_get_minimum() must be an instance of IntlCalendar, integer given
+error: 0, Argument 1 passed to intlcal_get_minimum() must be an instance of IntlCalendar, integer given
diff --git a/ext/intl/tests/calendar_get_getActualMaximum_Minumum_error2.phpt b/ext/intl/tests/calendar_get_getActualMaximum_Minumum_error2.phpt
index b29e8ed0cb..88b03f8cdb 100644
--- a/ext/intl/tests/calendar_get_getActualMaximum_Minumum_error2.phpt
+++ b/ext/intl/tests/calendar_get_getActualMaximum_Minumum_error2.phpt
@@ -105,9 +105,9 @@ bool(false)
error: 2, intlcal_get_actual_minimum() expects parameter 2 to be integer, string given
error: 2, intlcal_get_actual_minimum(): intlcal_get_actual_minimum: bad arguments
bool(false)
-error: 1, Argument 1 passed to intlcal_get() must be an instance of IntlCalendar, integer given
+error: 0, Argument 1 passed to intlcal_get() must be an instance of IntlCalendar, integer given
-error: 1, Argument 1 passed to intlcal_get_actual_maximum() must be an instance of IntlCalendar, integer given
+error: 0, Argument 1 passed to intlcal_get_actual_maximum() must be an instance of IntlCalendar, integer given
-error: 1, Argument 1 passed to intlcal_get_actual_minimum() must be an instance of IntlCalendar, integer given
+error: 0, Argument 1 passed to intlcal_get_actual_minimum() must be an instance of IntlCalendar, integer given
diff --git a/ext/intl/tests/calendar_isEquivalentTo_error.phpt b/ext/intl/tests/calendar_isEquivalentTo_error.phpt
index ac19e1dd90..35b8fc189a 100644
--- a/ext/intl/tests/calendar_isEquivalentTo_error.phpt
+++ b/ext/intl/tests/calendar_isEquivalentTo_error.phpt
@@ -50,16 +50,16 @@ try {
}
--EXPECT--
-error: 1, Argument 1 passed to IntlCalendar::isEquivalentTo() must be an instance of IntlCalendar, integer given
+error: 0, Argument 1 passed to IntlCalendar::isEquivalentTo() must be an instance of IntlCalendar, integer given
error: 2, IntlCalendar::isEquivalentTo() expects exactly 1 parameter, 2 given
error: 2, IntlCalendar::isEquivalentTo(): intlcal_is_equivalent_to: bad arguments
bool(false)
-error: 1, Argument 1 passed to IntlCalendar::isEquivalentTo() must be an instance of IntlCalendar, integer given
+error: 0, Argument 1 passed to IntlCalendar::isEquivalentTo() must be an instance of IntlCalendar, integer given
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: 1, Argument 2 passed to intlcal_is_equivalent_to() must be an instance of IntlCalendar, integer given
+error: 0, Argument 2 passed to intlcal_is_equivalent_to() must be an instance of IntlCalendar, integer given
-error: 1, Argument 1 passed to intlcal_is_equivalent_to() must be an instance of IntlCalendar, integer given
+error: 0, Argument 1 passed to intlcal_is_equivalent_to() must be an instance of IntlCalendar, integer given
diff --git a/ext/intl/tests/calendar_isWeekend_error.phpt b/ext/intl/tests/calendar_isWeekend_error.phpt
index 8f723cc3c9..417bcb4c23 100644
--- a/ext/intl/tests/calendar_isWeekend_error.phpt
+++ b/ext/intl/tests/calendar_isWeekend_error.phpt
@@ -21,6 +21,7 @@ var_dump(intlcal_is_weekend($c, "jj"));
var_dump(intlcal_is_weekend(1));
--EXPECTF--
+Warning: IntlCalendar::isWeekend() expects at most 1 parameter, 2 given in %s on line %d
Warning: IntlCalendar::isWeekend(): intlcal_is_weekend: bad arguments in %s on line %d
bool(false)
diff --git a/ext/intl/tests/calendar_setTimeZone_error.phpt b/ext/intl/tests/calendar_setTimeZone_error.phpt
index 410dc86c60..4dee131ef7 100644
--- a/ext/intl/tests/calendar_setTimeZone_error.phpt
+++ b/ext/intl/tests/calendar_setTimeZone_error.phpt
@@ -51,4 +51,4 @@ 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: 1, Argument 1 passed to intlcal_set_time_zone() must be an instance of IntlCalendar, integer given
+error: 0, Argument 1 passed to intlcal_set_time_zone() must be an instance of IntlCalendar, integer given
diff --git a/ext/intl/tests/collator_get_sort_key_variant4.phpt b/ext/intl/tests/collator_get_sort_key_variant4.phpt
index ed2c9bc175..bd7af6a284 100644
--- a/ext/intl/tests/collator_get_sort_key_variant4.phpt
+++ b/ext/intl/tests/collator_get_sort_key_variant4.phpt
@@ -1,5 +1,5 @@
--TEST--
-collator_get_sort_key() icu >= 55.1
+collator_get_sort_key() icu >= 54.1
--SKIPIF--
<?php if( !extension_loaded( 'intl' ) ) print 'skip'; ?>
<?php if (version_compare(INTL_ICU_VERSION, '55.1') >= 0) die('skip for ICU < 55.1'); ?>
diff --git a/ext/intl/tests/collator_get_sort_key_variant5.phpt b/ext/intl/tests/collator_get_sort_key_variant5.phpt
index 52a3af9766..c7717389b7 100644
--- a/ext/intl/tests/collator_get_sort_key_variant5.phpt
+++ b/ext/intl/tests/collator_get_sort_key_variant5.phpt
@@ -2,6 +2,7 @@
collator_get_sort_key() icu >= 55.1
--SKIPIF--
<?php if( !extension_loaded( 'intl' ) ) print 'skip'; ?>
+<?php if (version_compare(INTL_ICU_VERSION, '56.1') >= 0) die('skip for ICU < 56.1'); ?>
<?php if (version_compare(INTL_ICU_VERSION, '55.1') < 0) die('skip for ICU >= 55.1'); ?>
--FILE--
<?php
diff --git a/ext/intl/tests/collator_get_sort_key_variant6.phpt b/ext/intl/tests/collator_get_sort_key_variant6.phpt
new file mode 100644
index 0000000000..d8105d76d4
--- /dev/null
+++ b/ext/intl/tests/collator_get_sort_key_variant6.phpt
@@ -0,0 +1,98 @@
+--TEST--
+collator_get_sort_key() icu >= 56.1
+--SKIPIF--
+<?php if( !extension_loaded( 'intl' ) ) print 'skip'; ?>
+<?php if (version_compare(INTL_ICU_VERSION, '56.1') < 0) die('skip for ICU >= 56.1'); ?>
+--FILE--
+<?php
+
+/*
+ * Get sort keys using various locales
+ */
+function sort_arrays( $locale, $data )
+{
+ $res_str = '';
+
+ $coll = ut_coll_create( $locale );
+
+ foreach($data as $value) {
+ $res_val = ut_coll_get_sort_key( $coll, $value );
+ $res_str .= "source: ".$value."\n".
+ "key: ".bin2hex($res_val)."\n";
+ }
+
+ return $res_str;
+}
+
+
+function ut_main()
+{
+ $res_str = '';
+
+ // Regular strings keys
+ $test_params = array(
+ 'abc', 'abd', 'aaa',
+ 'аа', 'а', 'z',
+ '', null , '3',
+ 'y' , 'i' , 'k'
+ );
+
+ $res_str .= sort_arrays( 'en_US', $test_params );
+
+ // Sort a non-ASCII array using ru_RU locale.
+ $test_params = array(
+ 'абг', 'абв', 'жжж', 'эюя'
+ );
+
+ $res_str .= sort_arrays( 'ru_RU', $test_params );
+
+ // Sort an array using Lithuanian locale.
+ $res_str .= sort_arrays( 'lt_LT', $test_params );
+
+ return $res_str . "\n";
+}
+
+include_once( 'ut_common.inc' );
+ut_run();
+?>
+--EXPECT--
+source: abc
+key: 292b2d01070107
+source: abd
+key: 292b2f01070107
+source: aaa
+key: 29292901070107
+source: аа
+key: 60060601060106
+source: а
+key: 600601050105
+source: z
+key: 5b01050105
+source:
+key: 0101
+source:
+key: 0101
+source: 3
+key: 1801050105
+source: y
+key: 5901050105
+source: i
+key: 3901050105
+source: k
+key: 3d01050105
+source: абг
+key: 26060c1001070107
+source: абв
+key: 26060c0e01070107
+source: жжж
+key: 262c2c2c01070107
+source: эюя
+key: 26eef0f401070107
+source: абг
+key: 60060c1001070107
+source: абв
+key: 60060c0e01070107
+source: жжж
+key: 602c2c2c01070107
+source: эюя
+key: 60eef0f401070107
diff --git a/ext/intl/tests/dateformat_bug68893.phpt b/ext/intl/tests/dateformat_bug68893.phpt
new file mode 100644
index 0000000000..b3faf54342
--- /dev/null
+++ b/ext/intl/tests/dateformat_bug68893.phpt
@@ -0,0 +1,19 @@
+--TEST--
+Bug #68893 Stackoverflow in datefmt_create
+--SKIPIF--
+<?php if( !extension_loaded( 'intl' ) ) print 'skip'; ?>
+--FILE--
+<?php
+
+$f = datefmt_create("en_us", -10000000, 1);
+var_dump($f, intl_get_error_message());
+
+$f = datefmt_create("en_us", 1, -10000000);
+var_dump($f, intl_get_error_message());
+
+?>
+--EXPECT--
+NULL
+string(67) "datefmt_create: invalid date format style: U_ILLEGAL_ARGUMENT_ERROR"
+NULL
+string(67) "datefmt_create: invalid time format style: U_ILLEGAL_ARGUMENT_ERROR"
diff --git a/ext/intl/tests/dateformat_bug71516.phpt b/ext/intl/tests/dateformat_bug71516.phpt
new file mode 100644
index 0000000000..88ba9bf840
--- /dev/null
+++ b/ext/intl/tests/dateformat_bug71516.phpt
@@ -0,0 +1,25 @@
+--TEST--
+Bug #71516 IntlDateFormatter losts locale if pattern is set via constructor
+--SKIPIF--
+<?php
+if (!extension_loaded('intl')) die('skip intl extension not enabled'); ?>
+--FILE--
+<?php
+
+$loc = "ru_RU";
+$goodFormatter = new IntlDateFormatter($loc, IntlDateFormatter::FULL, IntlDateFormatter::FULL, new DateTimeZone("UTC"));
+$badFormatter = new IntlDateFormatter($loc, IntlDateFormatter::FULL, IntlDateFormatter::FULL, new DateTimeZone("UTC"), null, "d MMM");
+$badFormatter2 = new IntlDateFormatter($loc, IntlDateFormatter::FULL, IntlDateFormatter::FULL, new DateTimeZone("UTC"));
+$badFormatter2->setPattern("d MMM");
+
+echo "Formatter without pattern: " . $goodFormatter->getLocale() . PHP_EOL;
+echo "Formatter with pattern: " . $badFormatter->getLocale() . PHP_EOL;
+echo "Formatter with pattern set later: " . $badFormatter2->getLocale() . PHP_EOL;
+
+?>
+==DONE==
+--EXPECT--
+Formatter without pattern: ru
+Formatter with pattern: ru
+Formatter with pattern set later: ru
+==DONE==
diff --git a/ext/intl/tests/formatter_format5.phpt b/ext/intl/tests/formatter_format5.phpt
index cbaf140a0f..0bc4a6679b 100644
--- a/ext/intl/tests/formatter_format5.phpt
+++ b/ext/intl/tests/formatter_format5.phpt
@@ -1,7 +1,8 @@
--TEST--
-numfmt_format() icu >= 54.1
+numfmt_format() icu >= 54.1 && icu < 56.1
--SKIPIF--
<?php if( !extension_loaded( 'intl' ) ) print 'skip'; ?>
+<?php if (version_compare(INTL_ICU_VERSION, '56.1') >= 0) die('skip for ICU < 56.1'); ?>
<?php if (version_compare(INTL_ICU_VERSION, '54.1') < 0) die('skip for ICU >= 54.1'); ?>
--FILE--
<?php
diff --git a/ext/intl/tests/formatter_format6.phpt b/ext/intl/tests/formatter_format6.phpt
new file mode 100644
index 0000000000..80894c332b
--- /dev/null
+++ b/ext/intl/tests/formatter_format6.phpt
@@ -0,0 +1,130 @@
+--TEST--
+numfmt_format() icu >= 56.1
+--SKIPIF--
+<?php if( !extension_loaded( 'intl' ) ) print 'skip'; ?>
+<?php if (version_compare(INTL_ICU_VERSION, '56.1') < 0) die('skip for ICU >= 56.1'); ?>
+--FILE--
+<?php
+
+/*
+ * Format a number using misc locales/patterns.
+ */
+
+/*
+ * TODO: doesn't pass on ICU 3.6 because 'ru' and 'de' locales changed
+ * currency and percent formatting.
+ */
+
+function ut_main()
+{
+ $styles = array(
+ NumberFormatter::PATTERN_DECIMAL => '##.#####################',
+ NumberFormatter::DECIMAL => '',
+ NumberFormatter::CURRENCY => '',
+ NumberFormatter::PERCENT => '',
+ NumberFormatter::SCIENTIFIC => '',
+ NumberFormatter::SPELLOUT => '@@@@@@@',
+ NumberFormatter::ORDINAL => '',
+ NumberFormatter::DURATION => '',
+ NumberFormatter::PATTERN_RULEBASED => '#####.###',
+ 1234999, // bad one
+ );
+
+ $integer = array(
+ NumberFormatter::ORDINAL => '',
+ NumberFormatter::DURATION => '',
+ );
+ $locales = array(
+ 'en_US',
+ 'ru_UA',
+ 'de',
+ 'fr',
+ 'en_UK'
+ );
+
+ $str_res = '';
+ $number = 1234567.891234567890000;
+
+ foreach( $locales as $locale )
+ {
+ $str_res .= "\nLocale is: $locale\n";
+ foreach( $styles as $style => $pattern )
+ {
+ $fmt = ut_nfmt_create( $locale, $style, $pattern );
+
+ if(!$fmt) {
+ $str_res .= "Bad formatter!\n";
+ continue;
+ }
+ $str_res .= dump( isset($integer[$style])?ut_nfmt_format( $fmt, $number, NumberFormatter::TYPE_INT32):ut_nfmt_format( $fmt, $number ) ) . "\n";
+ }
+ }
+ return $str_res;
+}
+
+include_once( 'ut_common.inc' );
+
+// Run the test
+ut_run();
+
+?>
+--EXPECTREGEX--
+Locale is: en_US
+'1234567.89123457'
+'1,234,567.891'
+'\$1,234,567.89'
+'123,456,789%'
+'1.23456789123457E6'
+'one million,? two hundred (and )?thirty-four thousand,? five hundred (and )?sixty-seven point eight nine one two three four five seven'
+'1,234,567(th|ᵗʰ)'
+'342:56:07'
+'#####.###'
+'USD1,234,567.89'
+
+Locale is: ru_UA
+'1234567,89123457'
+'1 234 567,891'
+'1 234 567,89 ?(грн\.|₴)'
+'123 456 789 ?%'
+'1,23456789123457E6'
+'один миллион двести тридцать четыре тысячи пятьсот шестьдесят семь целых восемьдесят девять миллионов сто двадцать три тысячи четыреста пятьдесят семь стомиллионных'
+'1 234 567.?'
+'1 234 567'
+'#####.###'
+'1 234 567,89 UAH'
+
+Locale is: de
+'1234567,89123457'
+'1.234.567,891'
+'(¤ )?1.234.567,89( ¤)?'
+'123\.456\.789 %'
+'1,23456789123457E6'
+'eine Million zwei­hundert­vier­und­dreißig­tausend­fünf­hundert­sieben­und­sechzig Komma acht neun eins zwei drei vier fünf sieben'
+'1.234.567.?'
+'1.234.567'
+'#####.###'
+'1.234.567,89 ¤¤'
+
+Locale is: fr
+'1234567,89123457'
+'1 234 567,891'
+'1 234 567,89 ¤'
+'123 456 789 ?%'
+'1,23456789123457E6'
+'un million deux cent trente-quatre mille cinq cent soixante-sept virgule huit neuf un deux trois quatre cinq sept'
+'1 234 567e'
+'1 234 567'
+'#####.###'
+'1 234 567,89 ¤¤'
+
+Locale is: en_UK
+'1234567.89123457'
+'1,234,567.891'
+'¤1,234,567.89'
+'123,456,789%'
+'1.23456789123457E6'
+'one million,? two hundred (and )?thirty-four thousand,? five hundred (and )?sixty-seven point eight nine one two three four five seven'
+'1,234,567(th|ᵗʰ)'
+'342:56:07'
+'#####.###'
+'¤¤1,234,567.89'
diff --git a/ext/intl/tests/formatter_get_set_text_attribute.phpt b/ext/intl/tests/formatter_get_set_text_attribute.phpt
index 539ff52322..0535da477b 100644
--- a/ext/intl/tests/formatter_get_set_text_attribute.phpt
+++ b/ext/intl/tests/formatter_get_set_text_attribute.phpt
@@ -1,7 +1,8 @@
--TEST--
-numfmt_get/set_text_attribute()
+numfmt_get/set_text_attribute() ICU < 56.1
--SKIPIF--
<?php if( !extension_loaded( 'intl' ) ) print 'skip'; ?>
+<?php if (version_compare(INTL_ICU_VERSION, '56.1') >= 0) die('skip for ICU < 56.1'); ?>
--FILE--
<?php
diff --git a/ext/intl/tests/formatter_get_set_text_attribute_var2.phpt b/ext/intl/tests/formatter_get_set_text_attribute_var2.phpt
new file mode 100644
index 0000000000..f1306094c4
--- /dev/null
+++ b/ext/intl/tests/formatter_get_set_text_attribute_var2.phpt
@@ -0,0 +1,122 @@
+--TEST--
+numfmt_get/set_text_attribute() ICU >= 56.1
+--SKIPIF--
+<?php if( !extension_loaded( 'intl' ) ) print 'skip'; ?>
+<?php if (version_compare(INTL_ICU_VERSION, '56.1') < 0) die('skip for ICU >= 56.1'); ?>
+--FILE--
+<?php
+
+/*
+ * Get/set text attribute.
+ */
+
+
+function ut_main()
+{
+ // Array with data for testing
+ $long_str = str_repeat('blah', 100);
+ $attributes = array(
+ 'POSITIVE_PREFIX' => array( NumberFormatter::POSITIVE_PREFIX, '_+_', 12345.1234 ),
+ 'POSITIVE_SUFFIX' => array( NumberFormatter::POSITIVE_SUFFIX, '_+_', 12345.1234 ),
+ 'NEGATIVE_PREFIX' => array( NumberFormatter::NEGATIVE_PREFIX, '_-_', -12345.1234 ),
+ 'NEGATIVE_SUFFIX' => array( NumberFormatter::NEGATIVE_SUFFIX, '_-_', -12345.1234 ),
+ 'PADDING_CHARACTER' => array( NumberFormatter::PADDING_CHARACTER, '^', 12345.1234 ),
+ 'POSITIVE_PREFIX-2' => array( NumberFormatter::POSITIVE_PREFIX, $long_str, 12345.1234 ),
+// 'CURRENCY_CODE' => array( NumberFormatter::CURRENCY_CODE, '_C_', 12345.1234 )
+// 'DEFAULT_RULESET' => array( NumberFormatter::DEFAULT_RULESET, '_DR_', 12345.1234 ),
+// 'PUBLIC_RULESETS' => array( NumberFormatter::PUBLIC_RULESETS, '_PR_', 12345.1234 )
+ );
+
+ $res_str = '';
+
+ $fmt = ut_nfmt_create( "en_US", NumberFormatter::DECIMAL );
+
+ foreach( $attributes as $attr_name => $data )
+ {
+ list( $attr, $new_val, $test_number ) = $data;
+ $res_str .= "\nAttribute $attr_name\n";
+
+ if( $attr == NumberFormatter::PADDING_CHARACTER )
+ ut_nfmt_set_attribute( $fmt, NumberFormatter::FORMAT_WIDTH, 21 );
+
+ // Get default attribute's value
+ $def_val = ut_nfmt_get_text_attribute( $fmt, $attr );
+ if( $def_val === false )
+ $res_str .= "get_text_attribute() error: " . ut_nfmt_get_error_message( $fmt ) . "\n";
+
+ $res_str .= "Default value: [$def_val]\n";
+ $res_str .= "Formatting number with default value: " . ut_nfmt_format( $fmt, $test_number ) . "\n";
+
+ // Set new attribute's value and see if it works out.
+ $res_val = ut_nfmt_set_text_attribute( $fmt, $attr, $new_val );
+ if( !$res_val )
+ $res_str .= "set_text_attribute() error: " . ut_nfmt_get_error_message( $fmt ) . "\n";
+
+ // Get attribute value back.
+ $new_val_check = ut_nfmt_get_text_attribute( $fmt, $attr );
+ $res_str .= "New value: [$new_val_check]\n";
+ $res_str .= "Formatting number with new value: " . ut_nfmt_format( $fmt, $test_number ) . "\n";
+
+ // Check if the new value has been set.
+ if( $new_val !== $new_val_check )
+ $res_str .= "ERROR: New $attr_name symbol value has not been set correctly.\n";
+
+ // Restore attribute's value to default
+ ut_nfmt_set_text_attribute( $fmt, $attr, $def_val );
+
+ if( $attr == NumberFormatter::PADDING_CHARACTER )
+ ut_nfmt_set_attribute( $fmt, NumberFormatter::FORMAT_WIDTH, 0 );
+ }
+
+ //
+ $fmt = ut_nfmt_create( "uk_UA", NumberFormatter::CURRENCY );
+ $res_str .= sprintf( "\nCurrency ISO-code for locale 'uk_UA' is: %s\n",
+ ut_nfmt_get_text_attribute( $fmt, NumberFormatter::CURRENCY_CODE ) );
+
+ return $res_str;
+}
+
+include_once( 'ut_common.inc' );
+ut_run();
+
+?>
+--EXPECT--
+Attribute POSITIVE_PREFIX
+Default value: []
+Formatting number with default value: 12,345.123
+New value: [_+_]
+Formatting number with new value: _+_12,345.123
+
+Attribute POSITIVE_SUFFIX
+Default value: []
+Formatting number with default value: 12,345.123
+New value: [_+_]
+Formatting number with new value: 12,345.123_+_
+
+Attribute NEGATIVE_PREFIX
+Default value: [-]
+Formatting number with default value: -12,345.123
+New value: [_-_]
+Formatting number with new value: _-_12,345.123
+
+Attribute NEGATIVE_SUFFIX
+Default value: []
+Formatting number with default value: -12,345.123
+New value: [_-_]
+Formatting number with new value: -12,345.123_-_
+
+Attribute PADDING_CHARACTER
+Default value: [ ]
+Formatting number with default value: 12,345.123
+New value: [^]
+Formatting number with new value: ^^^^^^^^^^^12,345.123
+
+Attribute POSITIVE_PREFIX-2
+Default value: []
+Formatting number with default value: 12,345.123
+New value: [blahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblah]
+Formatting number with new value: blahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblah12,345.123
+
+Currency ISO-code for locale 'uk_UA' is: UAH
+
+
diff --git a/ext/intl/tests/grapheme.phpt b/ext/intl/tests/grapheme.phpt
index def9110d0d..251b1d142f 100644
--- a/ext/intl/tests/grapheme.phpt
+++ b/ext/intl/tests/grapheme.phpt
@@ -68,9 +68,13 @@ function ut_main()
array( "abc", "a", 0 ),
array( "abc", "a", 0, 0 ),
array( "abc", "a", 1, "false" ),
+ array( "abc", "a", -1, "false" ),
array( "ababc", "a", 1, 2 ),
array( "ao" . $char_a_ring_nfd . "bc" . $char_o_diaeresis_nfd . "o", "o", 2, 6 ),
+ array( "ao" . $char_a_ring_nfd . "bc" . $char_o_diaeresis_nfd . "o", "o", -1, 6 ),
+ array( "ao" . $char_a_ring_nfd . "bc" . $char_o_diaeresis_nfd . "o", "o", -5, 6 ),
array( $char_o_diaeresis_nfd . $char_a_ring_nfd . "a" . $char_a_ring_nfd . "bc", $char_a_ring_nfd, 2, 3 ),
+ array( $char_o_diaeresis_nfd . $char_a_ring_nfd . "a" . $char_a_ring_nfd . "bc", $char_a_ring_nfd, -4, 3 ),
array( "a" . $char_a_ring_nfd . "bc" . $char_o_diaeresis_nfd . "opq", "op", 5 ),
array( "a" . $char_a_ring_nfd . "bc" . $char_o_diaeresis_nfd . "opq", "opq", 5 ),
@@ -91,6 +95,7 @@ function ut_main()
array( "ababc", "ab", 1, 2 ),
array( "ababc", "abc", 1, 2 ),
array( "ao" . $char_a_ring_nfd . "bc" . $char_o_diaeresis_nfd . "o" . $char_a_ring_nfd . "bc", "o" . $char_a_ring_nfd . "bc", 2, 6 ),
+ array( "ao" . $char_a_ring_nfd . "bc" . $char_o_diaeresis_nfd . "o" . $char_a_ring_nfd . "bc", "o" . $char_a_ring_nfd . "bc", -8, 6 ),
array( $char_o_diaeresis_nfd . $char_a_ring_nfd . "a" . $char_a_ring_nfd . "bc" . $char_a_ring_nfd . "def", $char_a_ring_nfd . "bc" . $char_a_ring_nfd, 2, 3 ),
);
@@ -120,10 +125,12 @@ function ut_main()
$tests = array(
array( "ao" . $char_a_ring_nfd . "bc" . $char_o_diaeresis_nfd . "O", "o", 2, 6 ),
+ array( "ao" . $char_a_ring_nfd . "bc" . $char_o_diaeresis_nfd . "Oo", "o", -6, 6 ),
array( $char_o_diaeresis_nfd . $char_a_ring_nfd . "a" . $char_A_ring_nfd . "bc", $char_a_ring_nfd, 2, 3 ),
array( "a" . $char_a_ring_nfd . "bc" . $char_o_diaeresis_nfd . "O", "o", 5 ),
array( "a" . $char_a_ring_nfd . "bc" . $char_o_diaeresis_nfd, "O", "false" ),
array( "a" . $char_a_ring_nfd . "bc" . $char_O_diaeresis_nfd, $char_o_diaeresis_nfd, 4 ),
+ array( "a" . $char_a_ring_nfd . "bc" . $char_O_diaeresis_nfd, $char_o_diaeresis_nfd, -1, 4 ),
array( $char_o_diaeresis_nfd . "a" . $char_a_ring_nfd . "bc", $char_A_ring_nfd, 2 ),
array( "a" . $char_A_ring_nfd . "bc", $char_a_ring_nfd, 1 ),
array( "Abc", $char_a_ring_nfd, "false" ),
@@ -153,6 +160,7 @@ function ut_main()
array( "aBc", "abC", 0, 0 ),
array( "abc", "aBc", 1, "false" ),
array( "ABabc", "AB", 1, 2 ),
+ array( "ABabc", "AB", -4, 2 ),
array( "abaBc", "aBc", 1, 2 ),
array( "ao" . $char_a_ring_nfd . "bc" . $char_o_diaeresis_nfd . "o" . $char_A_ring_nfd . "bC", "O" . $char_a_ring_nfd . "bC", 2, 6 ),
array( $char_o_diaeresis_nfd . $char_a_ring_nfd . "a" . $char_A_ring_nfd . "bC" . $char_a_ring_nfd . "def", $char_a_ring_nfd . "Bc" . $char_a_ring_nfd, 2, 3 ),
@@ -559,6 +567,7 @@ function ut_main()
array( "abc", 1, 0, 1, "a" ),
array( "abc", 1, 1, 2, "b" ),
array( "abc", 1, 2, 3, "c" ),
+ array( "abc", 1, -2, 2, "b" ),
array( "abc", 0, 2, 2, "" ),
array( "http://news.bbc.co.uk/2/hi/middle_east/7831588.stm", 48, 48 , 50 , "tm" ),
@@ -569,8 +578,11 @@ function ut_main()
array( $char_a_ring_nfd . "bc", 2, 0, 4, $char_a_ring_nfd . "b" ),
array( $char_a_ring_nfd . "bc", 1, 0, 3, $char_a_ring_nfd . "" ),
array( $char_a_ring_nfd . "bcde", 2, 3, 5, "bc" ),
+ array( $char_a_ring_nfd . "bcde", 2, -4, 5, "bc" ),
array( $char_a_ring_nfd . "bcde", 2, 4, 6, "cd" ),
+ array( $char_a_ring_nfd . "bcde", 2, -7, 4, $char_a_ring_nfd . "b" ),
array( $char_a_ring_nfd . "bcde" . $char_a_ring_nfd . "f", 4, 5, 11, "de" . $char_a_ring_nfd . "f" ),
+ array( $char_a_ring_nfd . "bcde" . $char_a_ring_nfd . "f", 4, -6, 11, "de" . $char_a_ring_nfd . "f" ),
array( $char_a_ring_nfd . $char_o_diaeresis_nfd . $char_o_diaeresis_nfd, 3, $char_a_ring_nfd . $char_o_diaeresis_nfd . $char_o_diaeresis_nfd ),
array( $char_a_ring_nfd . $char_o_diaeresis_nfd . $char_o_diaeresis_nfd, 2, $char_a_ring_nfd . $char_o_diaeresis_nfd ),
@@ -794,9 +806,13 @@ find "b" in "abc" - grapheme_strpos = 1 == 1
find "a" in "abc" - grapheme_strpos = 0 == 0
find "a" in "abc" - grapheme_strpos from 0 = 0 == 0
find "a" in "abc" - grapheme_strpos from 1 = false == false
+find "a" in "abc" - grapheme_strpos from -1 = false == false
find "a" in "ababc" - grapheme_strpos from 1 = 2 == 2
find "o" in "aoa%CC%8Abco%CC%88o" - grapheme_strpos from 2 = 6 == 6
+find "o" in "aoa%CC%8Abco%CC%88o" - grapheme_strpos from -1 = 6 == 6
+find "o" in "aoa%CC%8Abco%CC%88o" - grapheme_strpos from -5 = 6 == 6
find "a%CC%8A" in "o%CC%88a%CC%8Aaa%CC%8Abc" - grapheme_strpos from 2 = 3 == 3
+find "a%CC%8A" in "o%CC%88a%CC%8Aaa%CC%8Abc" - grapheme_strpos from -4 = 3 == 3
find "op" in "aa%CC%8Abco%CC%88opq" - grapheme_strpos = 5 == 5
find "opq" in "aa%CC%8Abco%CC%88opq" - grapheme_strpos = 5 == 5
find "abc" in "aa%CC%8Abco%CC%88" - grapheme_strpos = false == false
@@ -816,15 +832,18 @@ find "abc" in "abc" - grapheme_strpos from 1 = false == false
find "ab" in "ababc" - grapheme_strpos from 1 = 2 == 2
find "abc" in "ababc" - grapheme_strpos from 1 = 2 == 2
find "oa%CC%8Abc" in "aoa%CC%8Abco%CC%88oa%CC%8Abc" - grapheme_strpos from 2 = 6 == 6
+find "oa%CC%8Abc" in "aoa%CC%8Abco%CC%88oa%CC%8Abc" - grapheme_strpos from -8 = 6 == 6
find "a%CC%8Abca%CC%8A" in "o%CC%88a%CC%8Aaa%CC%8Abca%CC%8Adef" - grapheme_strpos from 2 = 3 == 3
function grapheme_stripos($haystack, $needle, $offset = 0) {}
find "o" in "aoa%CC%8Abco%CC%88O" - grapheme_stripos from 2 = 6 == 6
+find "o" in "aoa%CC%8Abco%CC%88Oo" - grapheme_stripos from -6 = 6 == 6
find "a%CC%8A" in "o%CC%88a%CC%8AaA%CC%8Abc" - grapheme_stripos from 2 = 3 == 3
find "o" in "aa%CC%8Abco%CC%88O" - grapheme_stripos = 5 == 5
find "O" in "aa%CC%8Abco%CC%88" - grapheme_stripos = false == false
find "o%CC%88" in "aa%CC%8AbcO%CC%88" - grapheme_stripos = 4 == 4
+find "o%CC%88" in "aa%CC%8AbcO%CC%88" - grapheme_stripos from -1 = 4 == 4
find "A%CC%8A" in "o%CC%88aa%CC%8Abc" - grapheme_stripos = 2 == 2
find "a%CC%8A" in "aA%CC%8Abc" - grapheme_stripos = 1 == 1
find "a%CC%8A" in "Abc" - grapheme_stripos = false == false
@@ -853,6 +872,7 @@ find "ab" in "ABc" - grapheme_stripos from 0 = 0 == 0
find "abC" in "aBc" - grapheme_stripos from 0 = 0 == 0
find "aBc" in "abc" - grapheme_stripos from 1 = false == false
find "AB" in "ABabc" - grapheme_stripos from 1 = 2 == 2
+find "AB" in "ABabc" - grapheme_stripos from -4 = 2 == 2
find "aBc" in "abaBc" - grapheme_stripos from 1 = 2 == 2
find "Oa%CC%8AbC" in "aoa%CC%8Abco%CC%88oA%CC%8AbC" - grapheme_stripos from 2 = 6 == 6
find "a%CC%8ABca%CC%8A" in "o%CC%88a%CC%8AaA%CC%8AbCa%CC%8Adef" - grapheme_stripos from 2 = 3 == 3
@@ -1094,6 +1114,7 @@ extract from "abc" "0" graphemes - grapheme_extract starting at byte position 0
extract from "abc" "1" graphemes - grapheme_extract starting at byte position 0 with $next = a == a $next=1 == 1
extract from "abc" "1" graphemes - grapheme_extract starting at byte position 1 with $next = b == b $next=2 == 2
extract from "abc" "1" graphemes - grapheme_extract starting at byte position 2 with $next = c == c $next=3 == 3
+extract from "abc" "1" graphemes - grapheme_extract starting at byte position -2 with $next = b == b $next=2 == 2
extract from "abc" "0" graphemes - grapheme_extract starting at byte position 2 with $next = == $next=2 == 2
extract from "http%3A%2F%2Fnews.bbc.co.uk%2F2%2Fhi%2Fmiddle_east%2F7831588.stm" "48" graphemes - grapheme_extract starting at byte position 48 with $next = tm == tm $next=50 == 50
extract from "a%CC%8Abc" "3" graphemes - grapheme_extract = a%CC%8Abc == a%CC%8Abc
@@ -1103,8 +1124,11 @@ extract from "a%CC%8Abc" "3" graphemes - grapheme_extract starting at byte posit
extract from "a%CC%8Abc" "2" graphemes - grapheme_extract starting at byte position 0 with $next = a%CC%8Ab == a%CC%8Ab $next=4 == 4
extract from "a%CC%8Abc" "1" graphemes - grapheme_extract starting at byte position 0 with $next = a%CC%8A == a%CC%8A $next=3 == 3
extract from "a%CC%8Abcde" "2" graphemes - grapheme_extract starting at byte position 3 with $next = bc == bc $next=5 == 5
+extract from "a%CC%8Abcde" "2" graphemes - grapheme_extract starting at byte position -4 with $next = bc == bc $next=5 == 5
extract from "a%CC%8Abcde" "2" graphemes - grapheme_extract starting at byte position 4 with $next = cd == cd $next=6 == 6
+extract from "a%CC%8Abcde" "2" graphemes - grapheme_extract starting at byte position -7 with $next = a%CC%8Ab == a%CC%8Ab $next=4 == 4
extract from "a%CC%8Abcdea%CC%8Af" "4" graphemes - grapheme_extract starting at byte position 5 with $next = dea%CC%8Af == dea%CC%8Af $next=11 == 11
+extract from "a%CC%8Abcdea%CC%8Af" "4" graphemes - grapheme_extract starting at byte position -6 with $next = dea%CC%8Af == dea%CC%8Af $next=11 == 11
extract from "a%CC%8Ao%CC%88o%CC%88" "3" graphemes - grapheme_extract = a%CC%8Ao%CC%88o%CC%88 == a%CC%8Ao%CC%88o%CC%88
extract from "a%CC%8Ao%CC%88o%CC%88" "2" graphemes - grapheme_extract = a%CC%8Ao%CC%88 == a%CC%8Ao%CC%88
extract from "a%CC%8Ao%CC%88c" "1" graphemes - grapheme_extract = a%CC%8A == a%CC%8A
diff --git a/ext/intl/tests/locale_bug66289.phpt b/ext/intl/tests/locale_bug66289.phpt
new file mode 100644
index 0000000000..6afd821b5a
--- /dev/null
+++ b/ext/intl/tests/locale_bug66289.phpt
@@ -0,0 +1,27 @@
+--TEST--
+Bug #66289 Locale::lookup incorrectly returns en or en_US if locale is empty
+--SKIPIF--
+<?php if( !extension_loaded( 'intl' ) ) print 'skip'; ?>
+--FILE--
+<?php
+
+ini_set("intl.default_locale", "en-US");
+$availableLocales = array('fr_FR', 'de', 'es_ES', 'es_419', 'en_US');
+var_dump(locale_lookup($availableLocales, false, true, 'fr_FR'));
+var_dump(locale_lookup($availableLocales, false, true, null));
+
+$availableLocales = array('fr_FR', 'de', 'es_ES', 'es_419');
+var_dump(locale_lookup($availableLocales, false, true, 'fr_FR'));
+
+ini_set("intl.default_locale", "de-DE");
+$availableLocales = array(Locale::getDefault());
+var_dump(locale_lookup($availableLocales, false, true));
+
+?>
+==DONE==
+--EXPECT--
+string(5) "fr_fr"
+string(5) "en_us"
+string(5) "fr_fr"
+string(5) "de_de"
+==DONE==
diff --git a/ext/intl/tests/msgfmt_bug70484.phpt b/ext/intl/tests/msgfmt_bug70484.phpt
new file mode 100644
index 0000000000..9d0bdc4ee8
--- /dev/null
+++ b/ext/intl/tests/msgfmt_bug70484.phpt
@@ -0,0 +1,97 @@
+--TEST--
+Bug #70484 selectordinal doesn't work with named parameters
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+if (version_compare(INTL_ICU_VERSION, '5.0') < 0)
+ die('skip for ICU 5.0+');
+--FILE--
+<?php
+
+$locale = array("de", "fr", "en", "ru",);
+
+$data = array(42, 42.42, 2147483643, 2147483643.12345, 5);
+
+foreach ($locale as $lc) {
+ echo "$lc string key\n";
+ $m = new MessageFormatter($lc, "{n, selectordinal, =5 {five} zero {#-zero} one {#-one} two {#-two} few {#-few} many {#-many} other {#-other}}");
+ foreach ($data as $i) {
+ var_dump($m->format(array("n" => $i)));
+ if ($m->getErrorCode()) {
+ echo "$lc $i ", $m->getErrorMessage();
+ }
+ }
+ echo "\n";
+
+ echo "$lc numeric key\n";
+ $m = new MessageFormatter($lc, "{0, selectordinal, =5 {five} zero {#-zero} one {#-one} two {#-two} few {#-few} many {#-many} other {#-other}}");
+ foreach ($data as $i) {
+ var_dump($m->format(array($i)));
+ if ($m->getErrorCode()) {
+ echo "$lc $i ", $m->getErrorMessage();
+ }
+ }
+ echo "\n";
+}
+
+?>
+==DONE==
+--EXPECT--
+de string key
+string(8) "42-other"
+string(11) "42,42-other"
+string(19) "2.147.483.643-other"
+string(23) "2.147.483.643,123-other"
+string(4) "five"
+
+de numeric key
+string(8) "42-other"
+string(11) "42,42-other"
+string(19) "2.147.483.643-other"
+string(23) "2.147.483.643,123-other"
+string(4) "five"
+
+fr string key
+string(8) "42-other"
+string(11) "42,42-other"
+string(22) "2 147 483 643-other"
+string(26) "2 147 483 643,123-other"
+string(4) "five"
+
+fr numeric key
+string(8) "42-other"
+string(11) "42,42-other"
+string(22) "2 147 483 643-other"
+string(26) "2 147 483 643,123-other"
+string(4) "five"
+
+en string key
+string(6) "42-two"
+string(11) "42.42-other"
+string(17) "2,147,483,643-few"
+string(23) "2,147,483,643.123-other"
+string(4) "five"
+
+en numeric key
+string(6) "42-two"
+string(11) "42.42-other"
+string(17) "2,147,483,643-few"
+string(23) "2,147,483,643.123-other"
+string(4) "five"
+
+ru string key
+string(8) "42-other"
+string(11) "42,42-other"
+string(22) "2 147 483 643-other"
+string(26) "2 147 483 643,123-other"
+string(4) "five"
+
+ru numeric key
+string(8) "42-other"
+string(11) "42,42-other"
+string(22) "2 147 483 643-other"
+string(26) "2 147 483 643,123-other"
+string(4) "five"
+
+==DONE==
diff --git a/ext/intl/tests/timezone_IDforWindowsID_basic.phpt b/ext/intl/tests/timezone_IDforWindowsID_basic.phpt
new file mode 100644
index 0000000000..4127d8e31c
--- /dev/null
+++ b/ext/intl/tests/timezone_IDforWindowsID_basic.phpt
@@ -0,0 +1,46 @@
+--TEST--
+IntlTimeZone::getIDForWindowsID basic test
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+if (version_compare(INTL_ICU_VERSION, '52') < 0)
+ die('skip for ICU >= 52');
+--FILE--
+<?php
+
+$tzs = array(
+ 'Gnomeregan' => array(NULL),
+ 'India Standard Time' => array(NULL),
+ 'Pacific Standard Time' => array('001', 'CA', 'MX', 'US', 'ZZ'),
+ 'Romance Standard Time' => array('001', 'BE', 'DK', 'ES', 'FR'),
+);
+
+foreach ($tzs as $tz => $regions) {
+ echo "** $tz\n";
+ foreach ($regions as $region) {
+ var_dump(IntlTimeZone::getIDForWindowsID($tz, $region));
+ if (intl_get_error_code() != U_ZERO_ERROR) {
+ echo "Error: ", intl_get_error_message(), "\n";
+ }
+ }
+}
+
+--EXPECT--
+** Gnomeregan
+bool(false)
+Error: intltz_get_windows_id: Unknown windows timezone: U_ILLEGAL_ARGUMENT_ERROR
+** India Standard Time
+string(13) "Asia/Calcutta"
+** Pacific Standard Time
+string(19) "America/Los_Angeles"
+string(17) "America/Vancouver"
+string(15) "America/Tijuana"
+string(19) "America/Los_Angeles"
+string(7) "PST8PDT"
+** Romance Standard Time
+string(12) "Europe/Paris"
+string(15) "Europe/Brussels"
+string(17) "Europe/Copenhagen"
+string(13) "Europe/Madrid"
+string(12) "Europe/Paris"
diff --git a/ext/intl/tests/timezone_getCanonicalID_error.phpt b/ext/intl/tests/timezone_getCanonicalID_error.phpt
index e268e216a8..b29ca67701 100644
--- a/ext/intl/tests/timezone_getCanonicalID_error.phpt
+++ b/ext/intl/tests/timezone_getCanonicalID_error.phpt
@@ -11,7 +11,6 @@ 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--
@@ -28,8 +27,3 @@ 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: Uncaught Error: Cannot pass parameter 2 by reference in %s:%d
-Stack trace:
-#0 {main}
- thrown in %s on line %d
diff --git a/ext/intl/tests/timezone_hasSameRules_error.phpt b/ext/intl/tests/timezone_hasSameRules_error.phpt
index 5fb5bdde7a..0e9b4a8bd6 100644
--- a/ext/intl/tests/timezone_hasSameRules_error.phpt
+++ b/ext/intl/tests/timezone_hasSameRules_error.phpt
@@ -31,9 +31,9 @@ try {
}
--EXPECT--
-int(1)
+int(0)
string(99) "Argument 1 passed to IntlTimeZone::hasSameRules() must be an instance of IntlTimeZone, string given"
-int(1)
+int(0)
string(92) "Argument 1 passed to intltz_has_same_rules() must be an instance of IntlTimeZone, null given"
diff --git a/ext/intl/tests/timezone_windowsID_basic.phpt b/ext/intl/tests/timezone_windowsID_basic.phpt
new file mode 100644
index 0000000000..dd48f016e2
--- /dev/null
+++ b/ext/intl/tests/timezone_windowsID_basic.phpt
@@ -0,0 +1,43 @@
+--TEST--
+IntlTimeZone::getWindowsID basic test
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+if (version_compare(INTL_ICU_VERSION, '52') < 0)
+ die('skip for ICU >= 52');
+--FILE--
+<?php
+
+$tzs = array(
+ 'America/Bogota',
+ 'America/Havana',
+ 'America/Indiana/Knox',
+ 'America/Los_Angeles',
+ 'Azeroth/Kalimdor/Durotar',
+ 'Africa/Casablanca',
+ 'Asia/Singapore',
+ 'Australia/Perth',
+ 'Europe/London',
+ 'Europe/Istanbul',
+);
+
+foreach ($tzs as $tz) {
+ var_dump(IntlTimeZone::getWindowsID($tz));
+ if (intl_get_error_code() != U_ZERO_ERROR) {
+ echo "Error: ", intl_get_error_message(), "\n";
+ }
+}
+
+--EXPECT--
+string(24) "SA Pacific Standard Time"
+string(21) "Eastern Standard Time"
+string(21) "Central Standard Time"
+string(21) "Pacific Standard Time"
+bool(false)
+Error: intltz_get_windows_id: Unknown system timezone: U_ILLEGAL_ARGUMENT_ERROR
+string(21) "Morocco Standard Time"
+string(23) "Singapore Standard Time"
+string(26) "W. Australia Standard Time"
+string(17) "GMT Standard Time"
+string(20) "Turkey Standard Time"
diff --git a/ext/intl/tests/uconverter_getAvailable_wrongparam_001.phpt b/ext/intl/tests/uconverter_getAvailable_wrongparam_001.phpt
new file mode 100644
index 0000000000..4e381289b3
--- /dev/null
+++ b/ext/intl/tests/uconverter_getAvailable_wrongparam_001.phpt
@@ -0,0 +1,8 @@
+--TEST--
+Check the function UConverter::getAvailable with parameter wrong
+--SKIPIF--
+<?php if( !extension_loaded( 'intl' ) ) print 'skip'; ?>
+--FILE--
+<?php UConverter::getAvailable("This is an ascii string"); ?>
+--EXPECTF--
+Warning: UConverter::getAvailable() expects exactly 0 parameters, 1 given in %s on line %d
diff --git a/ext/intl/timezone/timezone_class.cpp b/ext/intl/timezone/timezone_class.cpp
index d1e8e2e0a6..f67e55ae4e 100644
--- a/ext/intl/timezone/timezone_class.cpp
+++ b/ext/intl/timezone/timezone_class.cpp
@@ -439,6 +439,17 @@ ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(ainfo_tz_void, 0, 0, 0)
ZEND_END_ARG_INFO()
+#if U_ICU_VERSION_MAJOR_NUM >= 52
+ZEND_BEGIN_ARG_INFO_EX(ainfo_tz_getWindowsID, 0, ZEND_RETURN_VALUE, 1)
+ ZEND_ARG_INFO(0, timezone)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX(ainfo_tz_getIDForWindowsID, 0, ZEND_RETURN_VALUE, 1)
+ ZEND_ARG_INFO(0, timezone)
+ ZEND_ARG_INFO(0, region)
+ZEND_END_ARG_INFO()
+#endif
+
/* }}} */
/* {{{ TimeZone_class_functions
@@ -475,6 +486,10 @@ static zend_function_entry TimeZone_class_functions[] = {
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)
+#if U_ICU_VERSION_MAJOR_NUM >= 52
+ PHP_ME_MAPPING(getWindowsID, intltz_get_windows_id, ainfo_tz_getWindowsID, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
+ PHP_ME_MAPPING(getIDForWindowsID, intltz_get_id_for_windows_id, ainfo_tz_getIDForWindowsID, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
+#endif
PHP_FE_END
};
/* }}} */
diff --git a/ext/intl/timezone/timezone_methods.cpp b/ext/intl/timezone/timezone_methods.cpp
index c46b448bbe..20c0e02480 100644
--- a/ext/intl/timezone/timezone_methods.cpp
+++ b/ext/intl/timezone/timezone_methods.cpp
@@ -440,7 +440,7 @@ U_CFUNC PHP_FUNCTION(intltz_use_daylight_time)
U_CFUNC PHP_FUNCTION(intltz_get_offset)
{
- UDate date;
+ double date;
zend_bool local;
zval *rawOffsetArg,
*dstOffsetArg;
@@ -458,7 +458,7 @@ U_CFUNC PHP_FUNCTION(intltz_get_offset)
TIMEZONE_METHOD_FETCH_OBJECT;
- to->utimezone->getOffset(date, (UBool) local, rawOffset, dstOffset,
+ to->utimezone->getOffset((UDate) date, (UBool) local, rawOffset, dstOffset,
TIMEZONE_ERROR_CODE(to));
INTL_METHOD_CHECK_STATUS(to, "intltz_get_offset: error obtaining offset");
@@ -647,3 +647,81 @@ U_CFUNC PHP_FUNCTION(intltz_get_error_message)
message = intl_error_get_message(TIMEZONE_ERROR_P(to));
RETURN_STR(message);
}
+
+#if U_ICU_VERSION_MAJOR_NUM >= 52
+/* {{{ proto string IntlTimeZone::getWindowsID(string $timezone)
+ proto string intltz_get_windows_id(string $timezone)
+Translate a system timezone (e.g. "America/Los_Angeles" into a
+Windows Timezone (e.g. "Pacific Standard Time")
+ */
+U_CFUNC PHP_FUNCTION(intltz_get_windows_id)
+{
+ zend_string *id, *winID;
+ UnicodeString uID, uWinID;
+ UErrorCode error;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &id) == FAILURE) {
+ return;
+ }
+
+ error = U_ZERO_ERROR;
+ if (intl_stringFromChar(uID, id->val, id->len, &error) == FAILURE) {
+ intl_error_set(NULL, error,
+ "intltz_get_windows_id: could not convert time zone id to UTF-16", 0);
+ RETURN_FALSE;
+ }
+
+ error = U_ZERO_ERROR;
+ TimeZone::getWindowsID(uID, uWinID, error);
+ INTL_CHECK_STATUS(error, "intltz_get_windows_id: Unable to get timezone from windows ID");
+ if (uWinID.length() == 0) {
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "intltz_get_windows_id: Unknown system timezone", 0);
+ RETURN_FALSE;
+ }
+
+ error = U_ZERO_ERROR;
+ winID = intl_convert_utf16_to_utf8(uWinID.getBuffer(), uWinID.length(), &error);
+ INTL_CHECK_STATUS(error, "intltz_get_windows_id: could not convert time zone id to UTF-8");
+ RETURN_STR(winID);
+}
+/* }}} */
+
+/* {{{ proto string IntlTimeZone::getIDForWindowsID(string $timezone[, string $region = NULL])
+ proto string intltz_get_id_for_windows_id(string $timezone[, string $region = NULL])
+Translate a windows timezone (e.g. "Pacific Time Zone" into a
+System Timezone (e.g. "America/Los_Angeles")
+ */
+U_CFUNC PHP_FUNCTION(intltz_get_id_for_windows_id)
+{
+ zend_string *winID, *region = NULL, *id;
+ UnicodeString uWinID, uID;
+ UErrorCode error;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS(), "S|S", &winID, &region) == FAILURE) {
+ return;
+ }
+
+ error = U_ZERO_ERROR;
+ if (intl_stringFromChar(uWinID, winID->val, winID->len, &error) == FAILURE) {
+ intl_error_set(NULL, error,
+ "intltz_get_id_for_windows_id: could not convert time zone id to UTF-16", 0);
+ RETURN_FALSE;
+ }
+
+ error = U_ZERO_ERROR;
+ TimeZone::getIDForWindowsID(uWinID, region ? region->val : NULL, uID, error);
+ INTL_CHECK_STATUS(error, "intltz_get_id_for_windows_id: Unable to get windows ID for timezone");
+ if (uID.length() == 0) {
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "intltz_get_windows_id: Unknown windows timezone", 0);
+ RETURN_FALSE;
+ }
+
+ error = U_ZERO_ERROR;
+ id = intl_convert_utf16_to_utf8(uID.getBuffer(), uID.length(), &error);
+ INTL_CHECK_STATUS(error, "intltz_get_id_for_windows_id: could not convert time zone id to UTF-8");
+ RETURN_STR(id);
+}
+/* }}} */
+#endif
diff --git a/ext/intl/timezone/timezone_methods.h b/ext/intl/timezone/timezone_methods.h
index 29d72913fd..6e6fa3f472 100644
--- a/ext/intl/timezone/timezone_methods.h
+++ b/ext/intl/timezone/timezone_methods.h
@@ -65,4 +65,9 @@ PHP_FUNCTION(intltz_get_error_code);
PHP_FUNCTION(intltz_get_error_message);
+#if U_ICU_VERSION_MAJOR_NUM >= 52
+PHP_FUNCTION(intltz_get_windows_id);
+PHP_FUNCTION(intltz_get_id_for_windows_id);
+#endif
+
#endif /* #ifndef TIMEZONE_METHODS_H */
diff --git a/ext/intl/transliterator/transliterator_class.c b/ext/intl/transliterator/transliterator_class.c
index 9a4cee97b0..96e52a15fd 100644
--- a/ext/intl/transliterator/transliterator_class.c
+++ b/ext/intl/transliterator/transliterator_class.c
@@ -269,9 +269,15 @@ static zval *Transliterator_read_property( zval *object, zval *member, int type,
static void Transliterator_write_property( zval *object, zval *member, zval *value,
void **cache_slot )
{
+ zend_class_entry *scope;
TRANSLITERATOR_PROPERTY_HANDLER_PROLOG;
- if( ( EG( scope ) != Transliterator_ce_ptr ) &&
+ if (EG(fake_scope)) {
+ scope = EG(fake_scope);
+ } else {
+ scope = zend_get_executed_scope();
+ }
+ if( ( scope != Transliterator_ce_ptr ) &&
( zend_binary_strcmp( "id", sizeof( "id" ) - 1,
Z_STRVAL_P( member ), Z_STRLEN_P( member ) ) == 0 ) )
{
diff --git a/ext/intl/transliterator/transliterator_methods.c b/ext/intl/transliterator/transliterator_methods.c
index e7b0870891..f0e5dcd2e8 100644
--- a/ext/intl/transliterator/transliterator_methods.c
+++ b/ext/intl/transliterator/transliterator_methods.c
@@ -332,7 +332,6 @@ PHP_FUNCTION( transliterator_transliterate )
int res;
if(Z_TYPE_P( arg1 ) != IS_STRING )
{
- SEPARATE_ZVAL( arg1 );
convert_to_string( arg1 );
}
object = &tmp_object;
diff --git a/ext/intl/uchar/tests/basic-functionality.phpt b/ext/intl/uchar/tests/basic-functionality.phpt
index eb8e4fb261..b61e129051 100644
--- a/ext/intl/uchar/tests/basic-functionality.phpt
+++ b/ext/intl/uchar/tests/basic-functionality.phpt
@@ -1,5 +1,7 @@
--TEST--
IntlChar basic functionality
+--SKIPIF--
+<?php if (!extension_loaded('intl')) die("skip requires ext/intl") ?>
--FILE--
<?php
diff --git a/ext/intl/uchar/tests/bug70453.phpt b/ext/intl/uchar/tests/bug70453.phpt
new file mode 100644
index 0000000000..4b3024e241
--- /dev/null
+++ b/ext/intl/uchar/tests/bug70453.phpt
@@ -0,0 +1,18 @@
+--TEST--
+Bug #70453 (IntlChar::foldCase() incorrect arguments and missing constants)
+--SKIPIF--
+<?php if (!extension_loaded('intl')) die("skip requires ext/intl") ?>
+--FILE--
+<?php
+$method = new ReflectionMethod('IntlChar', 'foldCase');
+$param = $method->getParameters()[1];
+var_dump($param->name, $param->isOptional(), $param->isPassedByReference());
+var_dump(IntlChar::foldCase('I', IntlChar::FOLD_CASE_DEFAULT));
+var_dump(IntlChar::foldCase('I', IntlChar::FOLD_CASE_EXCLUDE_SPECIAL_I));
+?>
+--EXPECT--
+string(7) "options"
+bool(true)
+bool(false)
+string(1) "i"
+string(2) "ı"
diff --git a/ext/intl/uchar/tests/bug70454.phpt b/ext/intl/uchar/tests/bug70454.phpt
new file mode 100644
index 0000000000..351bb65243
--- /dev/null
+++ b/ext/intl/uchar/tests/bug70454.phpt
@@ -0,0 +1,18 @@
+--TEST--
+Bug #70454 (IntlChar::forDigit second parameter should be optional)
+--SKIPIF--
+<?php if (!extension_loaded('intl')) die("skip requires ext/intl") ?>
+--FILE--
+<?php
+var_dump(IntlChar::forDigit(0));
+var_dump(IntlChar::forDigit(3));
+var_dump(IntlChar::forDigit(3, 10));
+var_dump(IntlChar::forDigit(10));
+var_dump(IntlChar::forDigit(10, 16));
+?>
+--EXPECT--
+int(48)
+int(51)
+int(51)
+int(0)
+int(97)
diff --git a/ext/intl/uchar/tests/bug70455.phpt b/ext/intl/uchar/tests/bug70455.phpt
new file mode 100644
index 0000000000..00ee8984a0
--- /dev/null
+++ b/ext/intl/uchar/tests/bug70455.phpt
@@ -0,0 +1,13 @@
+--TEST--
+Bug #70455 Missing constant: IntlChar::NO_NUMERIC_VALUE
+--SKIPIF--
+<?php if (!extension_loaded('intl')) die("skip requires ext/intl") ?>
+--FILE--
+<?php
+$value = IntlChar::getNumericValue("x");
+var_dump($value);
+var_dump($value === IntlChar::NO_NUMERIC_VALUE);
+?>
+--EXPECT--
+float(-123456789)
+bool(true)
diff --git a/ext/intl/uchar/uchar.c b/ext/intl/uchar/uchar.c
index 0dbe9c9cf8..266c62821b 100644
--- a/ext/intl/uchar/uchar.c
+++ b/ext/intl/uchar/uchar.c
@@ -32,7 +32,7 @@ static inline int convert_cp(UChar32* pcp, zval *zcp) {
return SUCCESS;
}
-/* {{{ proto string IntlChar::chr(int|string $char)
+/* {{{ proto string IntlChar::chr(int|string $codepoint)
* Converts a numeric codepoint to UTF-8
* Acts as an identify function when given a valid UTF-8 encoded codepoint
*/
@@ -59,7 +59,7 @@ IC_METHOD(chr) {
}
/* }}} */
-/* {{{ proto int IntlChar::ord(int|string $codepoint)
+/* {{{ proto int IntlChar::ord(int|string $character)
* Converts a UTf-8 encoded codepoint to its integer U32 value
* Acts as an identity function when passed a valid integer codepoint
*/
@@ -79,7 +79,7 @@ IC_METHOD(ord) {
}
/* }}} */
-/* {{{ proto bool IntlChar::hasBinaryProperty(int|string $char, int $property) */
+/* {{{ proto bool IntlChar::hasBinaryProperty(int|string $codepoint, int $property) */
ZEND_BEGIN_ARG_INFO_EX(hasBinaryProperty_arginfo, 0, ZEND_RETURN_VALUE, 2)
ZEND_ARG_INFO(0, codepoint)
ZEND_ARG_INFO(0, property)
@@ -98,7 +98,7 @@ IC_METHOD(hasBinaryProperty) {
}
/* }}} */
-/* {{{ proto int IntlChar::getIntPropertyValue(int|string $char, int $property) */
+/* {{{ proto int IntlChar::getIntPropertyValue(int|string $codepoint, int $property) */
ZEND_BEGIN_ARG_INFO_EX(getIntPropertyValue_arginfo, 0, ZEND_RETURN_VALUE, 2)
ZEND_ARG_INFO(0, codepoint)
ZEND_ARG_INFO(0, property)
@@ -147,7 +147,7 @@ IC_METHOD(getIntPropertyMaxValue) {
}
/* }}} */
-/* {{{ proto float IntlChar::getNumericValue(int|string $char) */
+/* {{{ proto float IntlChar::getNumericValue(int|string $codepoint) */
ZEND_BEGIN_ARG_INFO_EX(getNumericValue_arginfo, 0, ZEND_RETURN_VALUE, 1)
ZEND_ARG_INFO(0, codepoint)
ZEND_END_ARG_INFO();
@@ -164,7 +164,7 @@ IC_METHOD(getNumericValue) {
}
/* }}} */
-/* {{{ proto void IntlChar::enumCharTypes(callable $cb) */
+/* {{{ proto void IntlChar::enumCharTypes(callable $callback) */
ZEND_BEGIN_ARG_INFO_EX(enumCharTypes_arginfo, 0, ZEND_RETURN_VALUE, 0)
ZEND_ARG_INFO(0, callback)
ZEND_END_ARG_INFO();
@@ -209,7 +209,7 @@ IC_METHOD(enumCharTypes) {
}
/* }}} */
-/* {{{ proto int IntlChar::getBlockCode(int|string $char) */
+/* {{{ proto int IntlChar::getBlockCode(int|string $codepoint) */
ZEND_BEGIN_ARG_INFO_EX(getBlockCode_arginfo, 0, ZEND_RETURN_VALUE, 1)
ZEND_ARG_INFO(0, codepoint)
ZEND_END_ARG_INFO()
@@ -226,7 +226,7 @@ IC_METHOD(getBlockCode) {
}
/* }}} */
-/* {{{ proto string IntlChar::charName(int|string $char, int $nameChoice = IntlChar::UNICODE_CHAR_NAME) */
+/* {{{ proto string IntlChar::charName(int|string $codepoint, int $nameChoice = IntlChar::UNICODE_CHAR_NAME) */
ZEND_BEGIN_ARG_INFO_EX(charName_arginfo, 0, ZEND_RETURN_VALUE, 1)
ZEND_ARG_INFO(0, codepoint)
ZEND_ARG_INFO(0, nameChoice)
@@ -241,7 +241,7 @@ IC_METHOD(charName) {
if ((zend_parse_parameters(ZEND_NUM_ARGS(), "z|l", &zcp, &nameChoice) == FAILURE) ||
(convert_cp(&cp, zcp) == FAILURE)) {
- return;
+ RETURN_NULL();
}
buffer_len = u_charName(cp, (UCharNameChoice)nameChoice, NULL, 0, &error);
@@ -250,13 +250,13 @@ IC_METHOD(charName) {
buffer_len = u_charName(cp, (UCharNameChoice)nameChoice, ZSTR_VAL(buffer), ZSTR_LEN(buffer) + 1, &error);
if (U_FAILURE(error)) {
zend_string_free(buffer);
- INTL_CHECK_STATUS(error, "Failure getting character name");
+ INTL_CHECK_STATUS_OR_NULL(error, "Failure getting character name");
}
RETURN_NEW_STR(buffer);
}
/* }}} */
-/* {{{ proto int IntlChar::charFromName(string $name, int $nameChoice = IntlChar::UNICODE_CHAR_NAME) */
+/* {{{ proto int IntlChar::charFromName(string $characterName, int $nameChoice = IntlChar::UNICODE_CHAR_NAME) */
ZEND_BEGIN_ARG_INFO_EX(charFromName_arginfo, 0, ZEND_RETURN_VALUE, 1)
ZEND_ARG_INFO(0, characterName)
ZEND_ARG_INFO(0, nameChoice)
@@ -269,11 +269,11 @@ IC_METHOD(charFromName) {
UErrorCode error = U_ZERO_ERROR;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|l", &name, &name_len, &nameChoice) == FAILURE) {
- return;
+ RETURN_NULL();
}
ret = u_charFromName((UCharNameChoice)nameChoice, name, &error);
- INTL_CHECK_STATUS(error, NULL);
+ INTL_CHECK_STATUS_OR_NULL(error, NULL);
RETURN_LONG(ret);
}
/* }}} */
@@ -374,7 +374,7 @@ IC_METHOD(getPropertyEnum) {
}
/* }}} */
-/* {{{ proto string IntlChar::getPropertyValueName(int $prop, int $val[, int $nameChoice = IntlChar::LONG_PROPERTY_NAME) */
+/* {{{ proto string IntlChar::getPropertyValueName(int $property, int $value[, int $nameChoice = IntlChar::LONG_PROPERTY_NAME) */
ZEND_BEGIN_ARG_INFO_EX(getPropertyValueName_arginfo, 0, ZEND_RETURN_VALUE, 2)
ZEND_ARG_INFO(0, property)
ZEND_ARG_INFO(0, value)
@@ -417,9 +417,10 @@ IC_METHOD(getPropertyValueEnum) {
}
/* }}} */
-/* {{{ proto int|string IntlChar::foldCase(int|string $char, int $options = IntlChar::FOLD_CASE_DEFAULT) */
+/* {{{ proto int|string IntlChar::foldCase(int|string $codepoint, int $options = IntlChar::FOLD_CASE_DEFAULT) */
ZEND_BEGIN_ARG_INFO_EX(foldCase_arginfo, 0, ZEND_RETURN_VALUE, 1)
- ZEND_ARG_INFO(0, foldCase)
+ ZEND_ARG_INFO(0, codepoint)
+ ZEND_ARG_INFO(0, options)
ZEND_END_ARG_INFO();
IC_METHOD(foldCase) {
UChar32 cp, ret;
@@ -444,7 +445,7 @@ IC_METHOD(foldCase) {
}
/* }}} */
-/* {{{ proto int IntlChar::digit(int|string $char[, int $radix = 10]) */
+/* {{{ proto int IntlChar::digit(int|string $codepoint[, int $radix = 10]) */
ZEND_BEGIN_ARG_INFO_EX(digit_arginfo, 0, ZEND_RETURN_VALUE, 1)
ZEND_ARG_INFO(0, codepoint)
ZEND_ARG_INFO(0, radix)
@@ -478,7 +479,7 @@ ZEND_END_ARG_INFO();
IC_METHOD(forDigit) {
zend_long digit, radix = 10;
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "ll", &digit, &radix) == FAILURE) {
+ if (zend_parse_parameters(ZEND_NUM_ARGS(), "l|l", &digit, &radix) == FAILURE) {
return;
}
@@ -486,7 +487,7 @@ IC_METHOD(forDigit) {
}
/* }}} */
-/* {{{ proto array IntlChar::charAge(int|string $char) */
+/* {{{ proto array IntlChar::charAge(int|string $codepoint) */
ZEND_BEGIN_ARG_INFO_EX(charAge_arginfo, 0, ZEND_RETURN_VALUE, 1)
ZEND_ARG_INFO(0, codepoint)
ZEND_END_ARG_INFO();
@@ -525,7 +526,7 @@ IC_METHOD(getUnicodeVersion) {
}
/* }}} */
-/* {{{ proto string IntlChar::getFC_NFKC_Closure(int|string $char) */
+/* {{{ proto string IntlChar::getFC_NFKC_Closure(int|string $codepoint) */
ZEND_BEGIN_ARG_INFO_EX(getFC_NFKC_Closure_arginfo, 0, ZEND_RETURN_VALUE, 1)
ZEND_ARG_INFO(0, codepoint)
ZEND_END_ARG_INFO();
@@ -562,7 +563,7 @@ IC_METHOD(getFC_NFKC_Closure) {
}
/* }}} */
-/* {{{ proto bool IntlChar::<name>(int|string $char) */
+/* {{{ proto bool IntlChar::<name>(int|string $codepoint) */
#define IC_BOOL_METHOD_CHAR(name) \
ZEND_BEGIN_ARG_INFO_EX(name##_arginfo, 0, ZEND_RETURN_VALUE, 1) \
ZEND_ARG_INFO(0, codepoint) \
@@ -604,7 +605,7 @@ IC_BOOL_METHOD_CHAR(isJavaIDPart)
#undef IC_BOOL_METHOD_CHAR
/* }}} */
-/* {{{ proto int IntlChar::<name>(int|string $char) */
+/* {{{ proto int IntlChar::<name>(int|string $codepoint) */
#define IC_INT_METHOD_CHAR(name) \
ZEND_BEGIN_ARG_INFO_EX(name##_arginfo, 0, ZEND_RETURN_VALUE, 1) \
ZEND_ARG_INFO(0, codepoint) \
@@ -622,7 +623,7 @@ IC_INT_METHOD_CHAR(charDigitValue)
#undef IC_INT_METHOD_CHAR
/* }}} */
-/* {{{ proto int|string IntlChar::<name>(int|string $char)
+/* {{{ proto int|string IntlChar::<name>(int|string $codepoint)
* Returns a utf-8 character if codepoint was passed as a utf-8 sequence
* Returns an int otherwise
*/
@@ -734,6 +735,9 @@ int php_uchar_minit(INIT_FUNC_ARGS) {
zend_declare_class_constant_string(ce, "UNICODE_VERSION", sizeof("UNICODE_VERISON")-1, U_UNICODE_VERSION);
IC_CONSTL("CODEPOINT_MIN", UCHAR_MIN_VALUE)
IC_CONSTL("CODEPOINT_MAX", UCHAR_MAX_VALUE)
+ IC_CONSTL("FOLD_CASE_DEFAULT", U_FOLD_CASE_DEFAULT)
+ IC_CONSTL("FOLD_CASE_EXCLUDE_SPECIAL_I", U_FOLD_CASE_EXCLUDE_SPECIAL_I)
+ zend_declare_class_constant_double(ce, "NO_NUMERIC_VALUE", sizeof("NO_NUMERIC_VALUE")-1, U_NO_NUMERIC_VALUE);
/* All enums used by the uchar APIs. There are a LOT of them,
* so they're separated out into include files,