summaryrefslogtreecommitdiff
path: root/ext/intl
diff options
context:
space:
mode:
Diffstat (limited to 'ext/intl')
-rw-r--r--ext/intl/ERROR.CONVENTIONS115
-rw-r--r--ext/intl/breakiterator/breakiterator_class.cpp397
-rw-r--r--ext/intl/breakiterator/breakiterator_class.h71
-rw-r--r--ext/intl/breakiterator/breakiterator_iterators.cpp346
-rw-r--r--ext/intl/breakiterator/breakiterator_iterators.h42
-rw-r--r--ext/intl/breakiterator/breakiterator_methods.cpp452
-rw-r--r--ext/intl/breakiterator/breakiterator_methods.h64
-rw-r--r--ext/intl/breakiterator/codepointiterator_internal.cpp291
-rw-r--r--ext/intl/breakiterator/codepointiterator_internal.h98
-rw-r--r--ext/intl/breakiterator/codepointiterator_methods.cpp44
-rw-r--r--ext/intl/breakiterator/codepointiterator_methods.h24
-rw-r--r--ext/intl/breakiterator/rulebasedbreakiterator_methods.cpp221
-rw-r--r--ext/intl/breakiterator/rulebasedbreakiterator_methods.h32
-rw-r--r--ext/intl/calendar/calendar_class.cpp550
-rw-r--r--ext/intl/calendar/calendar_class.h70
-rw-r--r--ext/intl/calendar/calendar_methods.cpp1328
-rw-r--r--ext/intl/calendar/calendar_methods.h112
-rw-r--r--ext/intl/calendar/gregoriancalendar_methods.cpp256
-rw-r--r--ext/intl/calendar/gregoriancalendar_methods.h32
-rw-r--r--ext/intl/collator/collator_create.c2
-rw-r--r--ext/intl/collator/collator_sort.c1
-rw-r--r--ext/intl/common/common_date.cpp250
-rw-r--r--ext/intl/common/common_date.h40
-rw-r--r--ext/intl/common/common_enum.cpp354
-rw-r--r--ext/intl/common/common_enum.h77
-rw-r--r--ext/intl/common/common_error.c2
-rw-r--r--ext/intl/config.m425
-rw-r--r--ext/intl/config.w3232
-rw-r--r--ext/intl/converter/converter.c1173
-rw-r--r--ext/intl/converter/converter.h28
-rw-r--r--ext/intl/dateformat/dateformat.c154
-rw-r--r--ext/intl/dateformat/dateformat_attr.c164
-rw-r--r--ext/intl/dateformat/dateformat_attr.h4
-rw-r--r--ext/intl/dateformat/dateformat_attrcpp.cpp261
-rw-r--r--ext/intl/dateformat/dateformat_attrcpp.h35
-rw-r--r--ext/intl/dateformat/dateformat_class.c28
-rw-r--r--ext/intl/dateformat/dateformat_class.h12
-rw-r--r--ext/intl/dateformat/dateformat_create.cpp193
-rw-r--r--ext/intl/dateformat/dateformat_create.h25
-rw-r--r--ext/intl/dateformat/dateformat_format.c179
-rw-r--r--ext/intl/dateformat/dateformat_format_object.cpp230
-rw-r--r--ext/intl/dateformat/dateformat_format_object.h19
-rw-r--r--ext/intl/dateformat/dateformat_helpers.cpp106
-rw-r--r--ext/intl/dateformat/dateformat_helpers.h39
-rw-r--r--ext/intl/formatter/formatter_main.c2
-rw-r--r--ext/intl/grapheme/grapheme.h1
-rw-r--r--ext/intl/intl_convertcpp.cpp89
-rw-r--r--ext/intl/intl_convertcpp.h32
-rw-r--r--ext/intl/intl_cppshims.h34
-rw-r--r--ext/intl/intl_error.c101
-rw-r--r--ext/intl/intl_error.h8
-rw-r--r--ext/intl/locale/locale_methods.c21
-rw-r--r--ext/intl/msgformat/msgformat.c2
-rw-r--r--ext/intl/msgformat/msgformat_attr.c6
-rw-r--r--ext/intl/msgformat/msgformat_data.c24
-rw-r--r--ext/intl/msgformat/msgformat_data.h2
-rw-r--r--ext/intl/msgformat/msgformat_format.c49
-rw-r--r--ext/intl/msgformat/msgformat_helpers.cpp629
-rw-r--r--ext/intl/msgformat/msgformat_helpers.h6
-rw-r--r--ext/intl/msgformat/msgformat_parse.c2
-rw-r--r--ext/intl/php_intl.c358
-rw-r--r--ext/intl/php_intl.h10
-rw-r--r--ext/intl/resourcebundle/resourcebundle_class.c15
-rw-r--r--ext/intl/tests/badargs.phpt5
-rw-r--r--ext/intl/tests/breakiter___construct.phpt14
-rw-r--r--ext/intl/tests/breakiter___construct_error.phpt38
-rw-r--r--ext/intl/tests/breakiter_clone_basic.phpt27
-rw-r--r--ext/intl/tests/breakiter_createCodePointInstance_basic.phpt43
-rw-r--r--ext/intl/tests/breakiter_createCodePointInstance_error.phpt18
-rw-r--r--ext/intl/tests/breakiter_current_basic.phpt28
-rw-r--r--ext/intl/tests/breakiter_factories_basic.phpt46
-rw-r--r--ext/intl/tests/breakiter_factories_error.phpt43
-rw-r--r--ext/intl/tests/breakiter_first_basic.phpt22
-rw-r--r--ext/intl/tests/breakiter_first_last_previous_current_error.phpt39
-rw-r--r--ext/intl/tests/breakiter_following_basic.phpt24
-rw-r--r--ext/intl/tests/breakiter_following_preceding_isBoundary_error.phpt51
-rw-r--r--ext/intl/tests/breakiter_getLocale_basic.phpt21
-rw-r--r--ext/intl/tests/breakiter_getLocale_error.phpt33
-rw-r--r--ext/intl/tests/breakiter_getPartsIterator_basic.phpt37
-rw-r--r--ext/intl/tests/breakiter_getPartsIterator_error.phpt33
-rw-r--r--ext/intl/tests/breakiter_getPartsIterator_var1.phpt60
-rw-r--r--ext/intl/tests/breakiter_getText_basic.phpt17
-rw-r--r--ext/intl/tests/breakiter_getText_error.phpt19
-rw-r--r--ext/intl/tests/breakiter_isBoundary_basic.phpt28
-rw-r--r--ext/intl/tests/breakiter_last_basic.phpt20
-rw-r--r--ext/intl/tests/breakiter_next_basic.phpt30
-rw-r--r--ext/intl/tests/breakiter_next_error.phpt27
-rw-r--r--ext/intl/tests/breakiter_preceding_basic.phpt24
-rw-r--r--ext/intl/tests/breakiter_previous_basic.phpt22
-rw-r--r--ext/intl/tests/breakiter_setText_basic.phpt36
-rw-r--r--ext/intl/tests/breakiter_setText_error.phpt44
-rw-r--r--ext/intl/tests/bug50590.phpt2
-rw-r--r--ext/intl/tests/bug58756_MessageFormatter.phpt34
-rw-r--r--ext/intl/tests/bug62017.phpt2
-rw-r--r--ext/intl/tests/bug62081.phpt6
-rw-r--r--ext/intl/tests/bug62915.phpt24
-rw-r--r--ext/intl/tests/calendar_add_basic.phpt33
-rw-r--r--ext/intl/tests/calendar_add_error.phpt41
-rw-r--r--ext/intl/tests/calendar_before_after_error.phpt57
-rw-r--r--ext/intl/tests/calendar_clear_basic.phpt40
-rw-r--r--ext/intl/tests/calendar_clear_error.phpt31
-rw-r--r--ext/intl/tests/calendar_clear_variation1.phpt33
-rw-r--r--ext/intl/tests/calendar_createInstance_basic.phpt42
-rw-r--r--ext/intl/tests/calendar_createInstance_error.phpt38
-rw-r--r--ext/intl/tests/calendar_createInstance_variation1.phpt84
-rw-r--r--ext/intl/tests/calendar_equals_before_after_basic.phpt59
-rw-r--r--ext/intl/tests/calendar_equals_error.phpt46
-rw-r--r--ext/intl/tests/calendar_fieldDifference_basic.phpt35
-rw-r--r--ext/intl/tests/calendar_fieldDifference_error.phpt42
-rw-r--r--ext/intl/tests/calendar_fromDateTime_basic.phpt52
-rw-r--r--ext/intl/tests/calendar_fromDateTime_error.phpt59
-rw-r--r--ext/intl/tests/calendar_getAvailableLocales_basic.phpt23
-rw-r--r--ext/intl/tests/calendar_getAvailableLocales_error.phpt24
-rw-r--r--ext/intl/tests/calendar_getDayOfWeekType_basic.phpt34
-rw-r--r--ext/intl/tests/calendar_getDayOfWeekType_error.phpt44
-rw-r--r--ext/intl/tests/calendar_getErrorCode_error.phpt26
-rw-r--r--ext/intl/tests/calendar_getErrorCode_getErrorMessage_basic.phpt43
-rw-r--r--ext/intl/tests/calendar_getErrorMessage_error.phpt26
-rw-r--r--ext/intl/tests/calendar_getFirstDayOfWeek_basic.phpt20
-rw-r--r--ext/intl/tests/calendar_getFirstDayOfWeek_error.phpt32
-rw-r--r--ext/intl/tests/calendar_getKeywordValuesForLocale_basic.phpt36
-rw-r--r--ext/intl/tests/calendar_getKeywordValuesForLocale_error.phpt26
-rw-r--r--ext/intl/tests/calendar_getLocale_basic.phpt22
-rw-r--r--ext/intl/tests/calendar_getLocale_error.phpt42
-rw-r--r--ext/intl/tests/calendar_getMinimalDaysInFirstWeek_basic.phpt22
-rw-r--r--ext/intl/tests/calendar_getMinimalDaysInFirstWeek_error.phpt32
-rw-r--r--ext/intl/tests/calendar_getNow_basic.phpt23
-rw-r--r--ext/intl/tests/calendar_getNow_error.phpt24
-rw-r--r--ext/intl/tests/calendar_getSkipped_RepeatedWallTimeOption_error.phpt47
-rw-r--r--ext/intl/tests/calendar_getTimeZone_basic.phpt34
-rw-r--r--ext/intl/tests/calendar_getTimeZone_error.phpt32
-rw-r--r--ext/intl/tests/calendar_getTime_basic.phpt29
-rw-r--r--ext/intl/tests/calendar_getTime_error.phpt31
-rw-r--r--ext/intl/tests/calendar_getType_basic.phpt23
-rw-r--r--ext/intl/tests/calendar_getType_error.phpt32
-rw-r--r--ext/intl/tests/calendar_getWeekendTransition_basic.phpt24
-rw-r--r--ext/intl/tests/calendar_getWeekendTransition_error.phpt44
-rw-r--r--ext/intl/tests/calendar_getXMaximum_basic.phpt34
-rw-r--r--ext/intl/tests/calendar_getXMinimum_basic.phpt34
-rw-r--r--ext/intl/tests/calendar_get_Least_Greatest_Minimum_Maximum_error.phpt100
-rw-r--r--ext/intl/tests/calendar_get_basic.phpt23
-rw-r--r--ext/intl/tests/calendar_get_getActualMaximum_Minumum_error.phpt84
-rw-r--r--ext/intl/tests/calendar_get_getActualMaximum_Minumum_error2.phpt71
-rw-r--r--ext/intl/tests/calendar_get_setRepeatedWallTimeOption_basic.phpt49
-rw-r--r--ext/intl/tests/calendar_get_setSkippedWallTimeOption_basic.phpt67
-rw-r--r--ext/intl/tests/calendar_inDaylightTime_basic.phpt24
-rw-r--r--ext/intl/tests/calendar_inDaylightTime_error.phpt32
-rw-r--r--ext/intl/tests/calendar_isEquivalentTo_basic.phpt40
-rw-r--r--ext/intl/tests/calendar_isEquivalentTo_error.phpt50
-rw-r--r--ext/intl/tests/calendar_isLenient_error.phpt32
-rw-r--r--ext/intl/tests/calendar_isSet_basic.phpt24
-rw-r--r--ext/intl/tests/calendar_isSet_error.phpt42
-rw-r--r--ext/intl/tests/calendar_isWeekend_basic.phpt26
-rw-r--r--ext/intl/tests/calendar_isWeekend_error.phpt38
-rw-r--r--ext/intl/tests/calendar_is_set_lenient_basic.phpt28
-rw-r--r--ext/intl/tests/calendar_roll_basic.phpt34
-rw-r--r--ext/intl/tests/calendar_roll_error.phpt37
-rw-r--r--ext/intl/tests/calendar_roll_variation1.phpt32
-rw-r--r--ext/intl/tests/calendar_setFirstDayOfWeek_basic.phpt28
-rw-r--r--ext/intl/tests/calendar_setFirstDayOfWeek_error.phpt40
-rw-r--r--ext/intl/tests/calendar_setLenient_error.phpt44
-rw-r--r--ext/intl/tests/calendar_setSkipped_RepeatedWallTimeOption_error.phpt82
-rw-r--r--ext/intl/tests/calendar_setTimeZone_basic.phpt39
-rw-r--r--ext/intl/tests/calendar_setTimeZone_error.phpt41
-rw-r--r--ext/intl/tests/calendar_setTimeZone_error2.phpt29
-rw-r--r--ext/intl/tests/calendar_setTimeZone_variation1.phpt30
-rw-r--r--ext/intl/tests/calendar_setTimeZone_variation2.phpt30
-rw-r--r--ext/intl/tests/calendar_setTime_basic.phpt33
-rw-r--r--ext/intl/tests/calendar_setTime_error.phpt37
-rw-r--r--ext/intl/tests/calendar_set_basic.phpt27
-rw-r--r--ext/intl/tests/calendar_set_error.phpt41
-rw-r--r--ext/intl/tests/calendar_set_variation1.phpt41
-rw-r--r--ext/intl/tests/calendar_toDateTime_basic.phpt23
-rw-r--r--ext/intl/tests/calendar_toDateTime_error.phpt41
-rw-r--r--ext/intl/tests/cpbi_clone_equality.phpt33
-rw-r--r--ext/intl/tests/cpbi_getLastCodePoint_basic.phpt82
-rw-r--r--ext/intl/tests/cpbi_getLastCodePoint_error.phpt19
-rw-r--r--ext/intl/tests/cpbi_parts_iterator.phpt40
-rw-r--r--ext/intl/tests/dateformat___construct_bad_tz_cal.phpt32
-rw-r--r--ext/intl/tests/dateformat_calendars.phpt2
-rw-r--r--ext/intl/tests/dateformat_create_cal_arg.phpt53
-rw-r--r--ext/intl/tests/dateformat_format.phpt14
-rw-r--r--ext/intl/tests/dateformat_formatObject_calendar.phpt41
-rw-r--r--ext/intl/tests/dateformat_formatObject_datetime.phpt34
-rw-r--r--ext/intl/tests/dateformat_formatObject_error.phpt74
-rw-r--r--ext/intl/tests/dateformat_format_parse.phpt2
-rw-r--r--ext/intl/tests/dateformat_getCalendarObject_error.phpt43
-rw-r--r--ext/intl/tests/dateformat_getTimeZone_error.phpt43
-rw-r--r--ext/intl/tests/dateformat_get_set_calendar.phpt95
-rw-r--r--ext/intl/tests/dateformat_get_set_timezone.phpt62
-rw-r--r--ext/intl/tests/dateformat_get_timezone_id.phpt15
-rw-r--r--ext/intl/tests/dateformat_setTimeZoneID_deprecation.phpt22
-rw-r--r--ext/intl/tests/dateformat_setTimeZone_error.phpt53
-rw-r--r--ext/intl/tests/dateformat_set_timezone_id2.phpt22
-rw-r--r--ext/intl/tests/dateformat_timezone_arg_variations.phpt45
-rw-r--r--ext/intl/tests/gregoriancalendar___construct_basic.phpt51
-rw-r--r--ext/intl/tests/gregoriancalendar___construct_error.phpt35
-rw-r--r--ext/intl/tests/gregoriancalendar___construct_variant1.phpt30
-rw-r--r--ext/intl/tests/gregoriancalendar_getGregorianChange_error.phpt30
-rw-r--r--ext/intl/tests/gregoriancalendar_get_setGregorianChange_basic.phpt32
-rw-r--r--ext/intl/tests/gregoriancalendar_isLeapYear_basic.phpt28
-rw-r--r--ext/intl/tests/gregoriancalendar_isLeapYear_error.phpt48
-rw-r--r--ext/intl/tests/gregoriancalendar_setGregorianChange_error.phpt42
-rw-r--r--ext/intl/tests/ini_use_exceptions_basic.phpt21
-rw-r--r--ext/intl/tests/msgfmt_format_datetime.phpt28
-rw-r--r--ext/intl/tests/msgfmt_format_error1.phpt19
-rw-r--r--ext/intl/tests/msgfmt_format_error2.phpt23
-rw-r--r--ext/intl/tests/msgfmt_format_error3.phpt23
-rw-r--r--ext/intl/tests/msgfmt_format_error4.phpt28
-rw-r--r--ext/intl/tests/msgfmt_format_error5.phpt26
-rw-r--r--ext/intl/tests/msgfmt_format_error6.phpt23
-rw-r--r--ext/intl/tests/msgfmt_format_intlcalendar.phpt30
-rw-r--r--ext/intl/tests/msgfmt_format_mixed_params.phpt25
-rw-r--r--ext/intl/tests/msgfmt_format_simple_types_numeric_strings.phpt58
-rw-r--r--ext/intl/tests/msgfmt_format_subpatterns.phpt75
-rw-r--r--ext/intl/tests/msgfmt_format_subpatterns_named.phpt75
-rw-r--r--ext/intl/tests/msgfmt_get_error.phpt29
-rw-r--r--ext/intl/tests/msgfmt_millisecond_dates.phpt29
-rw-r--r--ext/intl/tests/msgfmt_setPattern_cache.phpt26
-rw-r--r--ext/intl/tests/rbbiter___construct_basic.phpt31
-rw-r--r--ext/intl/tests/rbbiter_getBinaryRules_basic.phpt39
-rw-r--r--ext/intl/tests/rbbiter_getRuleStatusVec_basic.phpt59
-rw-r--r--ext/intl/tests/rbbiter_getRuleStatus_basic.phpt46
-rw-r--r--ext/intl/tests/rbbiter_getRules_basic.phpt32
-rw-r--r--ext/intl/tests/timezone_clone_basic.phpt51
-rw-r--r--ext/intl/tests/timezone_clone_error.phpt32
-rw-r--r--ext/intl/tests/timezone_countEquivalentIDs_basic.phpt20
-rw-r--r--ext/intl/tests/timezone_countEquivalentIDs_error.phpt35
-rw-r--r--ext/intl/tests/timezone_createDefault_basic.phpt31
-rw-r--r--ext/intl/tests/timezone_createDefault_error.phpt19
-rw-r--r--ext/intl/tests/timezone_createEnumeration_basic.phpt26
-rw-r--r--ext/intl/tests/timezone_createEnumeration_error.phpt23
-rw-r--r--ext/intl/tests/timezone_createEnumeration_variation1.phpt24
-rw-r--r--ext/intl/tests/timezone_createEnumeration_variation2.phpt24
-rw-r--r--ext/intl/tests/timezone_createTimeZoneIDEnumeration_basic.phpt34
-rw-r--r--ext/intl/tests/timezone_createTimeZoneIDEnumeration_error.phpt42
-rw-r--r--ext/intl/tests/timezone_createTimeZoneIDEnumeration_variant1.phpt32
-rw-r--r--ext/intl/tests/timezone_createTimeZoneIDEnumeration_variant2.phpt52
-rw-r--r--ext/intl/tests/timezone_createTimeZone_basic.phpt33
-rw-r--r--ext/intl/tests/timezone_createTimeZone_error.phpt34
-rw-r--r--ext/intl/tests/timezone_equals_basic.phpt33
-rw-r--r--ext/intl/tests/timezone_equals_error.phpt43
-rw-r--r--ext/intl/tests/timezone_fromDateTimeZone_basic.phpt41
-rw-r--r--ext/intl/tests/timezone_fromDateTimeZone_error.phpt50
-rw-r--r--ext/intl/tests/timezone_getCanonicalID_basic.phpt19
-rw-r--r--ext/intl/tests/timezone_getCanonicalID_error.phpt32
-rw-r--r--ext/intl/tests/timezone_getCanonicalID_variant1.phpt24
-rw-r--r--ext/intl/tests/timezone_getDSTSavings_basic.phpt21
-rw-r--r--ext/intl/tests/timezone_getDSTSavings_error.phpt23
-rw-r--r--ext/intl/tests/timezone_getDisplayName_basic.phpt24
-rw-r--r--ext/intl/tests/timezone_getDisplayName_error.phpt45
-rw-r--r--ext/intl/tests/timezone_getDisplayName_variant1.phpt26
-rw-r--r--ext/intl/tests/timezone_getDisplayName_variant2-49+.phpt38
-rw-r--r--ext/intl/tests/timezone_getDisplayName_variant2.phpt40
-rw-r--r--ext/intl/tests/timezone_getDisplayName_variant3-49+.phpt28
-rw-r--r--ext/intl/tests/timezone_getDisplayName_variant3.phpt28
-rw-r--r--ext/intl/tests/timezone_getEquivalentID_basic.phpt19
-rw-r--r--ext/intl/tests/timezone_getEquivalentID_error.phpt34
-rw-r--r--ext/intl/tests/timezone_getErrorCodeMessage_basic.phpt31
-rw-r--r--ext/intl/tests/timezone_getErrorCode_error.phpt23
-rw-r--r--ext/intl/tests/timezone_getErrorMessage_error.phpt23
-rw-r--r--ext/intl/tests/timezone_getGMT_basic.phpt31
-rw-r--r--ext/intl/tests/timezone_getGMT_error.phpt19
-rw-r--r--ext/intl/tests/timezone_getID_error.phpt23
-rw-r--r--ext/intl/tests/timezone_getOffset_basic.phpt33
-rw-r--r--ext/intl/tests/timezone_getOffset_error.phpt33
-rw-r--r--ext/intl/tests/timezone_getRawOffset_basic.phpt21
-rw-r--r--ext/intl/tests/timezone_getRawOffset_error.phpt23
-rw-r--r--ext/intl/tests/timezone_getRegion_basic.phpt21
-rw-r--r--ext/intl/tests/timezone_getRegion_error.phpt42
-rw-r--r--ext/intl/tests/timezone_getTZDataVersion_error.phpt18
-rw-r--r--ext/intl/tests/timezone_getTZData_basic.phpt19
-rw-r--r--ext/intl/tests/timezone_getUnknown_basic.phpt35
-rw-r--r--ext/intl/tests/timezone_getUnknown_error.phpt29
-rw-r--r--ext/intl/tests/timezone_hasSameRules_basic.phpt35
-rw-r--r--ext/intl/tests/timezone_hasSameRules_error.phpt37
-rw-r--r--ext/intl/tests/timezone_toDateTimeZone_basic.phpt38
-rw-r--r--ext/intl/tests/timezone_toDateTimeZone_error.phpt38
-rw-r--r--ext/intl/tests/timezone_useDaylightTime_basic.phpt25
-rw-r--r--ext/intl/tests/timezone_useDaylightTime_error.phpt22
-rw-r--r--ext/intl/tests/uconverter___construct_error.phpt14
-rw-r--r--ext/intl/tests/uconverter_enum.phpt21
-rw-r--r--ext/intl/tests/uconverter_func_basic.phpt17
-rw-r--r--ext/intl/tests/uconverter_func_subst.phpt31
-rw-r--r--ext/intl/tests/uconverter_oop_algo.phpt18
-rw-r--r--ext/intl/tests/uconverter_oop_basic.phpt21
-rw-r--r--ext/intl/tests/uconverter_oop_callback.phpt52
-rw-r--r--ext/intl/tests/uconverter_oop_callback_return.phpt40
-rw-r--r--ext/intl/tests/uconverter_oop_subst.phpt24
-rw-r--r--ext/intl/timezone/timezone_class.cpp540
-rw-r--r--ext/intl/timezone/timezone_class.h72
-rw-r--r--ext/intl/timezone/timezone_methods.cpp659
-rw-r--r--ext/intl/timezone/timezone_methods.h68
-rw-r--r--ext/intl/transliterator/transliterator.c79
-rw-r--r--ext/intl/transliterator/transliterator_class.c10
-rw-r--r--ext/intl/transliterator/transliterator_methods.c2
296 files changed, 17744 insertions, 770 deletions
diff --git a/ext/intl/ERROR.CONVENTIONS b/ext/intl/ERROR.CONVENTIONS
new file mode 100644
index 0000000000..6f9079c56d
--- /dev/null
+++ b/ext/intl/ERROR.CONVENTIONS
@@ -0,0 +1,115 @@
+The intl extension has particular conventions regarding error reporting.
+These conventions are enumerated in this document.
+
+:: The last error is always stored globally.
+
+The global error code can be obtained in userland with intl_get_error_code().
+This is a U_* error code defined by ICU, but it does not have necessarily to be
+returned obtained after a call to an ICU function. That is to say, the internal
+PHP wrapper functions can set these error codes when appropriate. For instance,
+in response to bad arguments (e.g. zend_parse_parameters() failure), the PHP
+wrapper function should set the global error code to U_ILLEGAL_ARGUMENT_ERROR).
+
+The error code (an integer) can be converter to the corresponding enum name
+string in userland with intl_error_name().
+
+The associated message can be obtained with intl_get_error_message(). This is a
+message set by the PHP wrapping code, not by ICU. The message should include the
+name of the function that failed in order to make debugging easier (though if
+you activate warnings with intl.error_level or exceptions with
+intl.use_exceptions you get more fine-grained information about where the
+error ocurred).
+
+The internal PHP code can set the global last error with:
+void intl_error_set_code(intl_error* err, UErrorCode err_code TSRMLS_DC);
+void intl_error_set_custom_msg(intl_error* err, char* msg, int copyMsg TSRMLS_DC);
+void intl_error_set(intl_error* err, UErrorCode code, char* msg, int copyMsg TSRMLS_DC);
+
+and by passing NULL as the first parameter. The last function is a combination
+of the first two. If the message is not a static buffer, copyMsg should be 1.
+This makes the message string be copied and freed when no longer needed. There's
+no way to pass ownership of the string without it being copied.
+
+
+:: The last is ALSO stored in the object whose method call triggered the error,
+ unless the error is due to bad arguments, in which case only the global error
+ should be set
+
+Objects store an intl_error structed in their private data. For instance:
+typedef struct {
+ zend_object zo;
+ intl_error err;
+ Calendar* ucal;
+} Calendar_object;
+
+The global error and the object error can be SIMULTANEOUSLY set with these
+functions:
+void intl_errors_set_custom_msg(intl_error* err, char* msg, int copyMsg TSRMLS_DC);
+void intl_errors_set_code(intl_error* err, UErrorCode err_code TSRMLS_DC);
+void intl_errors_set(intl_error* err, UErrorCode code, char* msg, int copyMsg TSRMLS_DC);
+
+by passing a pointer to the object's intl_error structed as the first parameter.
+Node the extra 's' in the functions' names ('errors', not 'error').
+
+Static methods should only set the global error.
+
+
+:: Intl classes that can be instantiated should provide ::getErrorCode() and
+ getErrorMessage() methods
+
+These methods are used to retrieve the error codes stored in the object's
+private intl_error structured and mirror the global intl_get_error_code() and
+intl_get_error_message().
+
+
+:: Intl methods and functions should return FALSE on error (even argument
+ parsing errors), not NULL. Constructors and factory methods are the
+ exception; these should return NULL, not FALSE.
+
+Not that constructors in Intl generally (always?) don't throws exceptions.
+They instead destroy the object to that the result of new IntlClass() can
+be NULL. This may be surprising.
+
+
+:: Intl functions and methods should reset the global error before doing
+ anything else (even parse the arguments); instance methods should also reset
+ the object's private error
+
+Errors should be lost after a function call. This is different from the way
+ICU operates, where functions return immediately if an error is set.
+
+Error resetting can be done with:
+void intl_error_reset(NULL TSRMLS_DC); /* reset global error */
+void intl_errors_reset(intl_error* err TSRMLS_DC ); /* reset global and object error */
+
+In practice, intl_errors_reset() is not used because most classes have also
+plain functions mapped to the same internal functions as their instance methods.
+Fetching of the object is done with zend_parse_method_parameters() instead of
+directly using getThis(). Therefore, no reference to object is obtained until
+the arguments are fully parsed. Without a reference to the object, there's no
+way to reset the object's internal error code. Instead, resetting of the
+object's internal error code is done upon fetching the object from its zval.
+
+Example:
+U_CFUNC PHP_FUNCTION(breakiter_set_text)
+{
+ /* ... variable declations ... */
+ BREAKITER_METHOD_INIT_VARS; /* macro also resets global error */
+ object = getThis();
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s",
+ &text, &text_len) == FAILURE) {
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "breakiter_set_text: bad arguments", 0 TSRMLS_CC);
+ RETURN_FALSE;
+ }
+
+ /* ... */
+
+ BREAKITER_METHOD_FETCH_OBJECT; /* macro also resets object's error */
+
+ /* ... */
+}
+
+Implementations of ::getErrorCode() and ::getErrorMessage() should not reset the
+object's error code.
diff --git a/ext/intl/breakiterator/breakiterator_class.cpp b/ext/intl/breakiterator/breakiterator_class.cpp
new file mode 100644
index 0000000000..7bf271a344
--- /dev/null
+++ b/ext/intl/breakiterator/breakiterator_class.cpp
@@ -0,0 +1,397 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Gustavo Lopes <cataphract@php.net> |
+ +----------------------------------------------------------------------+
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <unicode/brkiter.h>
+#include <unicode/rbbi.h>
+#include "codepointiterator_internal.h"
+
+#include "breakiterator_iterators.h"
+
+#include <typeinfo>
+
+extern "C" {
+#define USE_BREAKITERATOR_POINTER 1
+#include "breakiterator_class.h"
+#include "breakiterator_methods.h"
+#include "rulebasedbreakiterator_methods.h"
+#include "codepointiterator_methods.h"
+#include <zend_exceptions.h>
+#include <zend_interfaces.h>
+#include <assert.h>
+}
+
+using PHP::CodePointBreakIterator;
+
+/* {{{ Global variables */
+zend_class_entry *BreakIterator_ce_ptr;
+zend_class_entry *RuleBasedBreakIterator_ce_ptr;
+zend_class_entry *CodePointBreakIterator_ce_ptr;
+zend_object_handlers BreakIterator_handlers;
+/* }}} */
+
+U_CFUNC void breakiterator_object_create(zval *object,
+ BreakIterator *biter TSRMLS_DC)
+{
+ UClassID classId = biter->getDynamicClassID();
+ zend_class_entry *ce;
+
+ if (classId == RuleBasedBreakIterator::getStaticClassID()) {
+ ce = RuleBasedBreakIterator_ce_ptr;
+ } else if (classId == CodePointBreakIterator::getStaticClassID()) {
+ ce = CodePointBreakIterator_ce_ptr;
+ } else {
+ ce = BreakIterator_ce_ptr;
+ }
+
+ object_init_ex(object, ce);
+ breakiterator_object_construct(object, biter TSRMLS_CC);
+}
+
+U_CFUNC void breakiterator_object_construct(zval *object,
+ BreakIterator *biter TSRMLS_DC)
+{
+ BreakIterator_object *bio;
+
+ BREAKITER_METHOD_FETCH_OBJECT_NO_CHECK; //populate to from object
+ assert(bio->biter == NULL);
+ bio->biter = biter;
+}
+
+/* {{{ compare handler for BreakIterator */
+static int BreakIterator_compare_objects(zval *object1,
+ zval *object2 TSRMLS_DC)
+{
+ BreakIterator_object *bio1,
+ *bio2;
+
+ bio1 = (BreakIterator_object*)zend_object_store_get_object(object1 TSRMLS_CC);
+ bio2 = (BreakIterator_object*)zend_object_store_get_object(object2 TSRMLS_CC);
+
+ if (bio1->biter == NULL || bio2->biter == NULL) {
+ return bio1->biter == bio2->biter ? 0 : 1;
+ }
+
+ return *bio1->biter == *bio2->biter ? 0 : 1;
+}
+/* }}} */
+
+/* {{{ clone handler for BreakIterator */
+static zend_object_value BreakIterator_clone_obj(zval *object TSRMLS_DC)
+{
+ BreakIterator_object *bio_orig,
+ *bio_new;
+ zend_object_value ret_val;
+
+ bio_orig = (BreakIterator_object*)zend_object_store_get_object(object TSRMLS_CC);
+ intl_errors_reset(INTL_DATA_ERROR_P(bio_orig) TSRMLS_CC);
+
+ ret_val = BreakIterator_ce_ptr->create_object(Z_OBJCE_P(object) TSRMLS_CC);
+ bio_new = (BreakIterator_object*)zend_object_store_get_object_by_handle(
+ ret_val.handle TSRMLS_CC);
+
+ zend_objects_clone_members(&bio_new->zo, ret_val,
+ &bio_orig->zo, Z_OBJ_HANDLE_P(object) TSRMLS_CC);
+
+ if (bio_orig->biter != NULL) {
+ BreakIterator *new_biter;
+
+ new_biter = bio_orig->biter->clone();
+ if (!new_biter) {
+ char *err_msg;
+ intl_errors_set_code(BREAKITER_ERROR_P(bio_orig),
+ U_MEMORY_ALLOCATION_ERROR TSRMLS_CC);
+ intl_errors_set_custom_msg(BREAKITER_ERROR_P(bio_orig),
+ "Could not clone BreakIterator", 0 TSRMLS_CC);
+ err_msg = intl_error_get_message(BREAKITER_ERROR_P(bio_orig) TSRMLS_CC);
+ zend_throw_exception(NULL, err_msg, 0 TSRMLS_CC);
+ efree(err_msg);
+ } else {
+ bio_new->biter = new_biter;
+ bio_new->text = bio_orig->text;
+ if (bio_new->text) {
+ zval_add_ref(&bio_new->text);
+ }
+ }
+ } else {
+ zend_throw_exception(NULL, "Cannot clone unconstructed BreakIterator", 0 TSRMLS_CC);
+ }
+
+ return ret_val;
+}
+/* }}} */
+
+/* {{{ get_debug_info handler for BreakIterator */
+static HashTable *BreakIterator_get_debug_info(zval *object, int *is_temp TSRMLS_DC)
+{
+ zval zv = zval_used_for_init;
+ BreakIterator_object *bio;
+ const BreakIterator *biter;
+
+ *is_temp = 1;
+
+ array_init_size(&zv, 8);
+
+ bio = (BreakIterator_object*)zend_object_store_get_object(object TSRMLS_CC);
+ biter = bio->biter;
+
+ if (biter == NULL) {
+ add_assoc_bool_ex(&zv, "valid", sizeof("valid"), 0);
+ return Z_ARRVAL(zv);
+ }
+ add_assoc_bool_ex(&zv, "valid", sizeof("valid"), 1);
+
+ if (bio->text == NULL) {
+ add_assoc_null_ex(&zv, "text", sizeof("text"));
+ } else {
+ zval_add_ref(&bio->text);
+ add_assoc_zval_ex(&zv, "text", sizeof("text"), bio->text);
+ }
+
+ add_assoc_string_ex(&zv, "type", sizeof("type"),
+ const_cast<char*>(typeid(*biter).name()), 1);
+
+ return Z_ARRVAL(zv);
+}
+/* }}} */
+
+/* {{{ void breakiterator_object_init(BreakIterator_object* to)
+ * Initialize internals of BreakIterator_object not specific to zend standard objects.
+ */
+static void breakiterator_object_init(BreakIterator_object *bio TSRMLS_DC)
+{
+ intl_error_init(BREAKITER_ERROR_P(bio) TSRMLS_CC);
+ bio->biter = NULL;
+ bio->text = NULL;
+}
+/* }}} */
+
+/* {{{ BreakIterator_objects_dtor */
+static void BreakIterator_objects_dtor(void *object,
+ zend_object_handle handle TSRMLS_DC)
+{
+ zend_objects_destroy_object((zend_object*)object, handle TSRMLS_CC);
+}
+/* }}} */
+
+/* {{{ BreakIterator_objects_free */
+static void BreakIterator_objects_free(zend_object *object TSRMLS_DC)
+{
+ BreakIterator_object* bio = (BreakIterator_object*) object;
+
+ if (bio->text) {
+ zval_ptr_dtor(&bio->text);
+ }
+ if (bio->biter) {
+ delete bio->biter;
+ bio->biter = NULL;
+ }
+ intl_error_reset(BREAKITER_ERROR_P(bio) TSRMLS_CC);
+
+ zend_object_std_dtor(&bio->zo TSRMLS_CC);
+
+ efree(bio);
+}
+/* }}} */
+
+/* {{{ BreakIterator_object_create */
+static zend_object_value BreakIterator_object_create(zend_class_entry *ce TSRMLS_DC)
+{
+ zend_object_value retval;
+ BreakIterator_object* intern;
+
+ intern = (BreakIterator_object*)ecalloc(1, sizeof(BreakIterator_object));
+
+ zend_object_std_init(&intern->zo, ce TSRMLS_CC);
+#if PHP_VERSION_ID < 50399
+ zend_hash_copy(intern->zo.properties, &(ce->default_properties),
+ (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval*));
+#else
+ object_properties_init((zend_object*) intern, ce);
+#endif
+ breakiterator_object_init(intern TSRMLS_CC);
+
+ retval.handle = zend_objects_store_put(
+ intern,
+ BreakIterator_objects_dtor,
+ (zend_objects_free_object_storage_t) BreakIterator_objects_free,
+ NULL TSRMLS_CC);
+
+ retval.handlers = &BreakIterator_handlers;
+
+ return retval;
+}
+/* }}} */
+
+/* {{{ BreakIterator/RuleBasedBreakIterator methods arguments info */
+
+ZEND_BEGIN_ARG_INFO_EX(ainfo_biter_void, 0, 0, 0)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX(ainfo_biter_locale, 0, 0, 0)
+ ZEND_ARG_INFO(0, "locale")
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX(ainfo_biter_setText, 0, 0, 1)
+ ZEND_ARG_INFO(0, "text")
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX(ainfo_biter_next, 0, 0, 0)
+ ZEND_ARG_INFO(0, "offset")
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX(ainfo_biter_offset, 0, 0, 1)
+ ZEND_ARG_INFO(0, "offset")
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX(ainfo_biter_get_locale, 0, 0, 1)
+ ZEND_ARG_INFO(0, "locale_type")
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX(ainfo_biter_getPartsIterator, 0, 0, 0)
+ ZEND_ARG_INFO(0, "key_type")
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX(ainfo_rbbi___construct, 0, 0, 1)
+ ZEND_ARG_INFO(0, "rules")
+ ZEND_ARG_INFO(0, "areCompiled")
+ZEND_END_ARG_INFO()
+
+/* }}} */
+
+/* {{{ BreakIterator_class_functions
+ * Every 'BreakIterator' class method has an entry in this table
+ */
+static const zend_function_entry BreakIterator_class_functions[] = {
+ PHP_ME(BreakIterator, __construct, ainfo_biter_void, ZEND_ACC_PRIVATE)
+ PHP_ME_MAPPING(createWordInstance, breakiter_create_word_instance, ainfo_biter_locale, ZEND_ACC_STATIC | ZEND_ACC_PUBLIC)
+ PHP_ME_MAPPING(createLineInstance, breakiter_create_line_instance, ainfo_biter_locale, ZEND_ACC_STATIC | ZEND_ACC_PUBLIC)
+ PHP_ME_MAPPING(createCharacterInstance, breakiter_create_character_instance, ainfo_biter_locale, ZEND_ACC_STATIC | ZEND_ACC_PUBLIC)
+ PHP_ME_MAPPING(createSentenceInstance, breakiter_create_sentence_instance, ainfo_biter_locale, ZEND_ACC_STATIC | ZEND_ACC_PUBLIC)
+ PHP_ME_MAPPING(createTitleInstance, breakiter_create_title_instance, ainfo_biter_locale, ZEND_ACC_STATIC | ZEND_ACC_PUBLIC)
+ PHP_ME_MAPPING(createCodePointInstance, breakiter_create_code_point_instance, ainfo_biter_void, ZEND_ACC_STATIC | ZEND_ACC_PUBLIC)
+ PHP_ME_MAPPING(getText, breakiter_get_text, ainfo_biter_void, ZEND_ACC_PUBLIC)
+ PHP_ME_MAPPING(setText, breakiter_set_text, ainfo_biter_setText, ZEND_ACC_PUBLIC)
+ PHP_ME_MAPPING(first, breakiter_first, ainfo_biter_void, ZEND_ACC_PUBLIC)
+ PHP_ME_MAPPING(last, breakiter_last, ainfo_biter_void, ZEND_ACC_PUBLIC)
+ PHP_ME_MAPPING(previous, breakiter_previous, ainfo_biter_void, ZEND_ACC_PUBLIC)
+ PHP_ME_MAPPING(next, breakiter_next, ainfo_biter_next, ZEND_ACC_PUBLIC)
+ PHP_ME_MAPPING(current, breakiter_current, ainfo_biter_void, ZEND_ACC_PUBLIC)
+ PHP_ME_MAPPING(following, breakiter_following, ainfo_biter_offset, ZEND_ACC_PUBLIC)
+ PHP_ME_MAPPING(preceding, breakiter_preceding, ainfo_biter_offset, ZEND_ACC_PUBLIC)
+ PHP_ME_MAPPING(isBoundary, breakiter_is_boundary, ainfo_biter_offset, ZEND_ACC_PUBLIC)
+ PHP_ME_MAPPING(getLocale, breakiter_get_locale, ainfo_biter_get_locale, ZEND_ACC_PUBLIC)
+ PHP_ME_MAPPING(getPartsIterator, breakiter_get_parts_iterator, ainfo_biter_getPartsIterator, ZEND_ACC_PUBLIC)
+
+ PHP_ME_MAPPING(getErrorCode, breakiter_get_error_code, ainfo_biter_void, ZEND_ACC_PUBLIC)
+ PHP_ME_MAPPING(getErrorMessage, breakiter_get_error_message, ainfo_biter_void, ZEND_ACC_PUBLIC)
+ PHP_FE_END
+};
+/* }}} */
+
+/* {{{ RuleBasedBreakIterator_class_functions
+ */
+static const zend_function_entry RuleBasedBreakIterator_class_functions[] = {
+ PHP_ME(IntlRuleBasedBreakIterator, __construct, ainfo_rbbi___construct, ZEND_ACC_PUBLIC)
+ PHP_ME_MAPPING(getRules, rbbi_get_rules, ainfo_biter_void, ZEND_ACC_PUBLIC)
+ PHP_ME_MAPPING(getRuleStatus, rbbi_get_rule_status, ainfo_biter_void, ZEND_ACC_PUBLIC)
+ PHP_ME_MAPPING(getRuleStatusVec, rbbi_get_rule_status_vec, ainfo_biter_void, ZEND_ACC_PUBLIC)
+#if U_ICU_VERSION_MAJOR_NUM * 10 + U_ICU_VERSION_MINOR_NUM >= 48
+ PHP_ME_MAPPING(getBinaryRules, rbbi_get_binary_rules, ainfo_biter_void, ZEND_ACC_PUBLIC)
+#endif
+ PHP_FE_END
+};
+/* }}} */
+
+/* {{{ CodePointBreakIterator_class_functions
+ */
+static const zend_function_entry CodePointBreakIterator_class_functions[] = {
+ PHP_ME_MAPPING(getLastCodePoint, cpbi_get_last_code_point, ainfo_biter_void, ZEND_ACC_PUBLIC)
+ PHP_FE_END
+};
+/* }}} */
+
+
+/* {{{ breakiterator_register_BreakIterator_class
+ * Initialize 'BreakIterator' class
+ */
+U_CFUNC void breakiterator_register_BreakIterator_class(TSRMLS_D)
+{
+ zend_class_entry ce;
+
+ /* Create and register 'BreakIterator' class. */
+ INIT_CLASS_ENTRY(ce, "IntlBreakIterator", BreakIterator_class_functions);
+ ce.create_object = BreakIterator_object_create;
+ ce.get_iterator = _breakiterator_get_iterator;
+ BreakIterator_ce_ptr = zend_register_internal_class(&ce TSRMLS_CC);
+
+ memcpy(&BreakIterator_handlers, zend_get_std_object_handlers(),
+ sizeof BreakIterator_handlers);
+ BreakIterator_handlers.compare_objects = BreakIterator_compare_objects;
+ BreakIterator_handlers.clone_obj = BreakIterator_clone_obj;
+ BreakIterator_handlers.get_debug_info = BreakIterator_get_debug_info;
+
+ zend_class_implements(BreakIterator_ce_ptr TSRMLS_CC, 1,
+ zend_ce_traversable);
+
+ zend_declare_class_constant_long(BreakIterator_ce_ptr,
+ "DONE", sizeof("DONE") - 1, BreakIterator::DONE TSRMLS_CC );
+
+ /* Declare constants that are defined in the C header */
+#define BREAKITER_DECL_LONG_CONST(name) \
+ zend_declare_class_constant_long(BreakIterator_ce_ptr, #name, \
+ sizeof(#name) - 1, UBRK_ ## name TSRMLS_CC)
+
+ BREAKITER_DECL_LONG_CONST(WORD_NONE);
+ BREAKITER_DECL_LONG_CONST(WORD_NONE_LIMIT);
+ BREAKITER_DECL_LONG_CONST(WORD_NUMBER);
+ BREAKITER_DECL_LONG_CONST(WORD_NUMBER_LIMIT);
+ BREAKITER_DECL_LONG_CONST(WORD_LETTER);
+ BREAKITER_DECL_LONG_CONST(WORD_LETTER_LIMIT);
+ BREAKITER_DECL_LONG_CONST(WORD_KANA);
+ BREAKITER_DECL_LONG_CONST(WORD_KANA_LIMIT);
+ BREAKITER_DECL_LONG_CONST(WORD_IDEO);
+ BREAKITER_DECL_LONG_CONST(WORD_IDEO_LIMIT);
+
+ BREAKITER_DECL_LONG_CONST(LINE_SOFT);
+ BREAKITER_DECL_LONG_CONST(LINE_SOFT_LIMIT);
+ BREAKITER_DECL_LONG_CONST(LINE_HARD);
+ BREAKITER_DECL_LONG_CONST(LINE_HARD_LIMIT);
+
+ BREAKITER_DECL_LONG_CONST(SENTENCE_TERM);
+ BREAKITER_DECL_LONG_CONST(SENTENCE_TERM_LIMIT);
+ BREAKITER_DECL_LONG_CONST(SENTENCE_SEP);
+ BREAKITER_DECL_LONG_CONST(SENTENCE_SEP_LIMIT);
+
+#undef BREAKITER_DECL_LONG_CONST
+
+
+ /* Create and register 'RuleBasedBreakIterator' class. */
+ INIT_CLASS_ENTRY(ce, "IntlRuleBasedBreakIterator",
+ RuleBasedBreakIterator_class_functions);
+ RuleBasedBreakIterator_ce_ptr = zend_register_internal_class_ex(&ce,
+ BreakIterator_ce_ptr, NULL TSRMLS_CC);
+
+ /* Create and register 'CodePointBreakIterator' class. */
+ INIT_CLASS_ENTRY(ce, "IntlCodePointBreakIterator",
+ CodePointBreakIterator_class_functions);
+ CodePointBreakIterator_ce_ptr = zend_register_internal_class_ex(&ce,
+ BreakIterator_ce_ptr, NULL TSRMLS_CC);
+}
+/* }}} */
diff --git a/ext/intl/breakiterator/breakiterator_class.h b/ext/intl/breakiterator/breakiterator_class.h
new file mode 100644
index 0000000000..cc5d51256f
--- /dev/null
+++ b/ext/intl/breakiterator/breakiterator_class.h
@@ -0,0 +1,71 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Gustavo Lopes <cataphract@php.net> |
+ +----------------------------------------------------------------------+
+ */
+
+#ifndef BREAKITERATOR_CLASS_H
+#define BREAKITERATOR_CLASS_H
+
+//redefinition of inline in PHP headers causes problems, so include this before
+#include <math.h>
+
+#include <php.h>
+#include "../intl_error.h"
+#include "../intl_data.h"
+
+#ifndef USE_BREAKITERATOR_POINTER
+typedef void BreakIterator;
+#endif
+
+typedef struct {
+ zend_object zo;
+
+ // error handling
+ intl_error err;
+
+ // ICU break iterator
+ BreakIterator* biter;
+
+ // current text
+ zval *text;
+} BreakIterator_object;
+
+#define BREAKITER_ERROR(bio) (bio)->err
+#define BREAKITER_ERROR_P(bio) &(BREAKITER_ERROR(bio))
+
+#define BREAKITER_ERROR_CODE(bio) INTL_ERROR_CODE(BREAKITER_ERROR(bio))
+#define BREAKITER_ERROR_CODE_P(bio) &(INTL_ERROR_CODE(BREAKITER_ERROR(bio)))
+
+#define BREAKITER_METHOD_INIT_VARS INTL_METHOD_INIT_VARS(BreakIterator, bio)
+#define BREAKITER_METHOD_FETCH_OBJECT_NO_CHECK INTL_METHOD_FETCH_OBJECT(BreakIterator, bio)
+#define BREAKITER_METHOD_FETCH_OBJECT \
+ BREAKITER_METHOD_FETCH_OBJECT_NO_CHECK; \
+ if (bio->biter == NULL) \
+ { \
+ intl_errors_set(&bio->err, U_ILLEGAL_ARGUMENT_ERROR, "Found unconstructed BreakIterator", 0 TSRMLS_CC); \
+ RETURN_FALSE; \
+ }
+
+void breakiterator_object_create(zval *object, BreakIterator *break_iter TSRMLS_DC);
+
+void breakiterator_object_construct(zval *object, BreakIterator *break_iter TSRMLS_DC);
+
+void breakiterator_register_BreakIterator_class(TSRMLS_D);
+
+extern zend_class_entry *BreakIterator_ce_ptr,
+ *RuleBasedBreakIterator_ce_ptr;
+
+extern zend_object_handlers BreakIterator_handlers;
+
+#endif /* #ifndef BREAKITERATOR_CLASS_H */
diff --git a/ext/intl/breakiterator/breakiterator_iterators.cpp b/ext/intl/breakiterator/breakiterator_iterators.cpp
new file mode 100644
index 0000000000..d88ad8a712
--- /dev/null
+++ b/ext/intl/breakiterator/breakiterator_iterators.cpp
@@ -0,0 +1,346 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Gustavo Lopes <cataphract@php.net> |
+ +----------------------------------------------------------------------+
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <unicode/brkiter.h>
+
+#include "breakiterator_iterators.h"
+#include "../common/common_enum.h"
+
+extern "C" {
+#define USE_BREAKITERATOR_POINTER
+#include "breakiterator_class.h"
+#include "../intl_convert.h"
+#include "../locale/locale.h"
+#include <zend_exceptions.h>
+}
+
+static zend_class_entry *IntlPartsIterator_ce_ptr;
+static zend_object_handlers IntlPartsIterator_handlers;
+
+/* BreakIterator's iterator */
+
+inline BreakIterator *_breakiter_prolog(zend_object_iterator *iter TSRMLS_DC)
+{
+ BreakIterator_object *bio;
+ bio = (BreakIterator_object*)zend_object_store_get_object(
+ (const zval*)iter->data TSRMLS_CC);
+ intl_errors_reset(BREAKITER_ERROR_P(bio) TSRMLS_CC);
+ if (bio->biter == NULL) {
+ intl_errors_set(BREAKITER_ERROR_P(bio), U_INVALID_STATE_ERROR,
+ "The BreakIterator object backing the PHP iterator is not "
+ "properly constructed", 0 TSRMLS_CC);
+ }
+ return bio->biter;
+}
+
+static void _breakiterator_destroy_it(zend_object_iterator *iter TSRMLS_DC)
+{
+ zval_ptr_dtor((zval**)&iter->data);
+}
+
+static void _breakiterator_move_forward(zend_object_iterator *iter TSRMLS_DC)
+{
+ BreakIterator *biter = _breakiter_prolog(iter TSRMLS_CC);
+ zoi_with_current *zoi_iter = (zoi_with_current*)iter;
+
+ iter->funcs->invalidate_current(iter TSRMLS_CC);
+
+ if (biter == NULL) {
+ return;
+ }
+
+ int32_t pos = biter->next();
+ if (pos != BreakIterator::DONE) {
+ MAKE_STD_ZVAL(zoi_iter->current);
+ ZVAL_LONG(zoi_iter->current, (long)pos);
+ } //else we've reached the end of the enum, nothing more is required
+}
+
+static void _breakiterator_rewind(zend_object_iterator *iter TSRMLS_DC)
+{
+ BreakIterator *biter = _breakiter_prolog(iter TSRMLS_CC);
+ zoi_with_current *zoi_iter = (zoi_with_current*)iter;
+
+ int32_t pos = biter->first();
+ MAKE_STD_ZVAL(zoi_iter->current);
+ ZVAL_LONG(zoi_iter->current, (long)pos);
+}
+
+static zend_object_iterator_funcs breakiterator_iterator_funcs = {
+ zoi_with_current_dtor,
+ zoi_with_current_valid,
+ zoi_with_current_get_current_data,
+ NULL,
+ _breakiterator_move_forward,
+ _breakiterator_rewind,
+ zoi_with_current_invalidate_current
+};
+
+U_CFUNC zend_object_iterator *_breakiterator_get_iterator(
+ zend_class_entry *ce, zval *object, int by_ref TSRMLS_DC)
+{
+ BreakIterator_object *bio;
+ if (by_ref) {
+ zend_throw_exception(NULL,
+ "Iteration by reference is not supported", 0 TSRMLS_CC);
+ return NULL;
+ }
+
+ bio = (BreakIterator_object*)zend_object_store_get_object(object TSRMLS_CC);
+ BreakIterator *biter = bio->biter;
+
+ if (biter == NULL) {
+ zend_throw_exception(NULL,
+ "The BreakIterator is not properly constructed", 0 TSRMLS_CC);
+ return NULL;
+ }
+
+ zoi_with_current *zoi_iter =
+ static_cast<zoi_with_current*>(emalloc(sizeof *zoi_iter));
+ zoi_iter->zoi.data = static_cast<void*>(object);
+ zoi_iter->zoi.funcs = &breakiterator_iterator_funcs;
+ zoi_iter->zoi.index = 0;
+ zoi_iter->destroy_it = _breakiterator_destroy_it;
+ zoi_iter->wrapping_obj = NULL; /* not used; object is in zoi.data */
+ zoi_iter->current = NULL;
+
+ zval_add_ref(&object);
+
+ return reinterpret_cast<zend_object_iterator *>(zoi_iter);
+}
+
+/* BreakIterator parts iterator */
+
+typedef struct zoi_break_iter_parts {
+ zoi_with_current zoi_cur;
+ parts_iter_key_type key_type;
+ BreakIterator_object *bio; /* so we don't have to fetch it all the time */
+} zoi_break_iter_parts;
+
+static void _breakiterator_parts_destroy_it(zend_object_iterator *iter TSRMLS_DC)
+{
+ zval_ptr_dtor(reinterpret_cast<zval**>(&iter->data));
+}
+
+static int _breakiterator_parts_get_current_key(zend_object_iterator *iter,
+ char **str_key,
+ uint *str_key_len,
+ ulong *int_key TSRMLS_DC)
+{
+ /* the actual work is done in move_forward and rewind */
+ *int_key = iter->index;
+ return HASH_KEY_IS_LONG;
+}
+
+static void _breakiterator_parts_move_forward(zend_object_iterator *iter TSRMLS_DC)
+{
+ zoi_break_iter_parts *zoi_bit = (zoi_break_iter_parts*)iter;
+ BreakIterator_object *bio = zoi_bit->bio;
+
+ iter->funcs->invalidate_current(iter TSRMLS_CC);
+
+ int32_t cur,
+ next;
+
+ cur = bio->biter->current();
+ if (cur == BreakIterator::DONE) {
+ return;
+ }
+ next = bio->biter->next();
+ if (next == BreakIterator::DONE) {
+ return;
+ }
+
+ if (zoi_bit->key_type == PARTS_ITERATOR_KEY_LEFT) {
+ iter->index = cur;
+ } else if (zoi_bit->key_type == PARTS_ITERATOR_KEY_RIGHT) {
+ iter->index = next;
+ }
+ /* else zoi_bit->key_type == PARTS_ITERATOR_KEY_SEQUENTIAL
+ * No need to do anything, the engine increments ->index */
+
+ const char *s = Z_STRVAL_P(bio->text);
+ int32_t slen = Z_STRLEN_P(bio->text),
+ len;
+ char *res;
+
+ if (next == BreakIterator::DONE) {
+ next = slen;
+ }
+ assert(next <= slen && next >= cur);
+ len = next - cur;
+ res = static_cast<char*>(emalloc(len + 1));
+
+ memcpy(res, &s[cur], len);
+ res[len] = '\0';
+
+ MAKE_STD_ZVAL(zoi_bit->zoi_cur.current);
+ ZVAL_STRINGL(zoi_bit->zoi_cur.current, res, len, 0);
+}
+
+static void _breakiterator_parts_rewind(zend_object_iterator *iter TSRMLS_DC)
+{
+ zoi_break_iter_parts *zoi_bit = (zoi_break_iter_parts*)iter;
+ BreakIterator_object *bio = zoi_bit->bio;
+
+ if (zoi_bit->zoi_cur.current) {
+ iter->funcs->invalidate_current(iter TSRMLS_CC);
+ }
+
+ bio->biter->first();
+
+ iter->funcs->move_forward(iter TSRMLS_CC);
+}
+
+static zend_object_iterator_funcs breakiterator_parts_it_funcs = {
+ zoi_with_current_dtor,
+ zoi_with_current_valid,
+ zoi_with_current_get_current_data,
+ _breakiterator_parts_get_current_key,
+ _breakiterator_parts_move_forward,
+ _breakiterator_parts_rewind,
+ zoi_with_current_invalidate_current
+};
+
+void IntlIterator_from_BreakIterator_parts(zval *break_iter_zv,
+ zval *object,
+ parts_iter_key_type key_type TSRMLS_DC)
+{
+ IntlIterator_object *ii;
+
+ zval_add_ref(&break_iter_zv);
+
+ object_init_ex(object, IntlPartsIterator_ce_ptr);
+ ii = (IntlIterator_object*)zend_object_store_get_object(object TSRMLS_CC);
+
+ ii->iterator = (zend_object_iterator*)emalloc(sizeof(zoi_break_iter_parts));
+ ii->iterator->data = break_iter_zv;
+ ii->iterator->funcs = &breakiterator_parts_it_funcs;
+ ii->iterator->index = 0;
+ ((zoi_with_current*)ii->iterator)->destroy_it = _breakiterator_parts_destroy_it;
+ ((zoi_with_current*)ii->iterator)->wrapping_obj = object;
+ ((zoi_with_current*)ii->iterator)->current = NULL;
+
+ ((zoi_break_iter_parts*)ii->iterator)->bio = (BreakIterator_object*)
+ zend_object_store_get_object(break_iter_zv TSRMLS_CC);
+ assert(((zoi_break_iter_parts*)ii->iterator)->bio->biter != NULL);
+ ((zoi_break_iter_parts*)ii->iterator)->key_type = key_type;
+}
+
+U_CFUNC zend_object_value IntlPartsIterator_object_create(zend_class_entry *ce TSRMLS_DC)
+{
+ zend_object_value retval;
+
+ retval = IntlIterator_ce_ptr->create_object(ce TSRMLS_CC);
+ retval.handlers = &IntlPartsIterator_handlers;
+
+ return retval;
+}
+
+U_CFUNC zend_function *IntlPartsIterator_get_method(zval **object_ptr,
+ char *method, int method_len, const zend_literal *key TSRMLS_DC)
+{
+ zend_literal local_literal = {0};
+ zend_function *ret;
+ ALLOCA_FLAG(use_heap)
+
+ if (key == NULL) {
+ Z_STRVAL(local_literal.constant) = static_cast<char*>(
+ do_alloca(method_len + 1, use_heap));
+ zend_str_tolower_copy(Z_STRVAL(local_literal.constant),
+ method, method_len);
+ local_literal.hash_value = zend_hash_func(
+ Z_STRVAL(local_literal.constant), method_len + 1);
+ key = &local_literal;
+ }
+
+ if ((key->hash_value & 0xFFFFFFFF) == 0xA2B486A1 /* hash of getrulestatus\0 */
+ && method_len == sizeof("getrulestatus") - 1
+ && memcmp("getrulestatus", Z_STRVAL(key->constant), method_len) == 0) {
+ IntlIterator_object *obj = (IntlIterator_object*)
+ zend_object_store_get_object(*object_ptr TSRMLS_CC);
+ if (obj->iterator && obj->iterator->data) {
+ zval *break_iter_zv = static_cast<zval*>(obj->iterator->data);
+ *object_ptr = break_iter_zv;
+ ret = Z_OBJ_HANDLER_P(break_iter_zv, get_method)(object_ptr,
+ method, method_len, key TSRMLS_CC);
+ goto end;
+ }
+ }
+
+ ret = std_object_handlers.get_method(object_ptr,
+ method, method_len, key TSRMLS_CC);
+
+end:
+ if (key == &local_literal) {
+ free_alloca(Z_STRVAL(local_literal.constant), use_heap);
+ }
+
+ return ret;
+}
+
+U_CFUNC PHP_METHOD(IntlPartsIterator, getBreakIterator)
+{
+ INTLITERATOR_METHOD_INIT_VARS;
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "IntlPartsIterator::getBreakIterator: bad arguments", 0 TSRMLS_CC);
+ return;
+ }
+
+ INTLITERATOR_METHOD_FETCH_OBJECT;
+
+ zval *biter_zval = static_cast<zval*>(ii->iterator->data);
+ RETURN_ZVAL(biter_zval, 1, 0);
+}
+
+ZEND_BEGIN_ARG_INFO_EX(ainfo_parts_it_void, 0, 0, 0)
+ZEND_END_ARG_INFO()
+
+static const zend_function_entry IntlPartsIterator_class_functions[] = {
+ PHP_ME(IntlPartsIterator, getBreakIterator, ainfo_parts_it_void, ZEND_ACC_PUBLIC)
+ PHP_FE_END
+};
+
+U_CFUNC void breakiterator_register_IntlPartsIterator_class(TSRMLS_D)
+{
+ zend_class_entry ce;
+
+ /* Create and register 'BreakIterator' class. */
+ INIT_CLASS_ENTRY(ce, "IntlPartsIterator", IntlPartsIterator_class_functions);
+ IntlPartsIterator_ce_ptr = zend_register_internal_class_ex(&ce,
+ IntlIterator_ce_ptr, NULL TSRMLS_CC);
+ IntlPartsIterator_ce_ptr->create_object = IntlPartsIterator_object_create;
+
+ memcpy(&IntlPartsIterator_handlers, &IntlIterator_handlers,
+ sizeof IntlPartsIterator_handlers);
+ IntlPartsIterator_handlers.get_method = IntlPartsIterator_get_method;
+
+#define PARTSITER_DECL_LONG_CONST(name) \
+ zend_declare_class_constant_long(IntlPartsIterator_ce_ptr, #name, \
+ sizeof(#name) - 1, PARTS_ITERATOR_ ## name TSRMLS_CC)
+
+ PARTSITER_DECL_LONG_CONST(KEY_SEQUENTIAL);
+ PARTSITER_DECL_LONG_CONST(KEY_LEFT);
+ PARTSITER_DECL_LONG_CONST(KEY_RIGHT);
+
+#undef PARTSITER_DECL_LONG_CONST
+} \ No newline at end of file
diff --git a/ext/intl/breakiterator/breakiterator_iterators.h b/ext/intl/breakiterator/breakiterator_iterators.h
new file mode 100644
index 0000000000..7162072414
--- /dev/null
+++ b/ext/intl/breakiterator/breakiterator_iterators.h
@@ -0,0 +1,42 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Gustavo Lopes <cataphract@php.net> |
+ +----------------------------------------------------------------------+
+*/
+#ifndef INTL_BREAKITERATOR_ITERATORS_H
+#define INTL_BREAKITERATOR_ITERATORS_H
+
+#include <unicode/umachine.h>
+
+U_CDECL_BEGIN
+#include <math.h>
+#include <php.h>
+U_CDECL_END
+
+typedef enum {
+ PARTS_ITERATOR_KEY_SEQUENTIAL,
+ PARTS_ITERATOR_KEY_LEFT,
+ PARTS_ITERATOR_KEY_RIGHT,
+} parts_iter_key_type;
+
+#ifdef __cplusplus
+void IntlIterator_from_BreakIterator_parts(zval *break_iter_zv,
+ zval *object,
+ parts_iter_key_type key_type TSRMLS_DC);
+#endif
+
+U_CFUNC zend_object_iterator *_breakiterator_get_iterator(
+ zend_class_entry *ce, zval *object, int by_ref TSRMLS_DC);
+U_CFUNC void breakiterator_register_IntlPartsIterator_class(TSRMLS_D);
+
+#endif \ No newline at end of file
diff --git a/ext/intl/breakiterator/breakiterator_methods.cpp b/ext/intl/breakiterator/breakiterator_methods.cpp
new file mode 100644
index 0000000000..6a61f8cb93
--- /dev/null
+++ b/ext/intl/breakiterator/breakiterator_methods.cpp
@@ -0,0 +1,452 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Gustavo Lopes <cataphract@php.net> |
+ +----------------------------------------------------------------------+
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <unicode/brkiter.h>
+#include "codepointiterator_internal.h"
+
+#include "breakiterator_iterators.h"
+
+extern "C" {
+#include "../php_intl.h"
+#define USE_BREAKITERATOR_POINTER 1
+#include "breakiterator_class.h"
+#include "../locale/locale.h"
+#include <zend_exceptions.h>
+}
+
+using PHP::CodePointBreakIterator;
+
+U_CFUNC PHP_METHOD(BreakIterator, __construct)
+{
+ zend_throw_exception( NULL,
+ "An object of this type cannot be created with the new operator",
+ 0 TSRMLS_CC );
+}
+
+static void _breakiter_factory(const char *func_name,
+ BreakIterator *(*func)(const Locale&, UErrorCode&),
+ INTERNAL_FUNCTION_PARAMETERS)
+{
+ BreakIterator *biter;
+ const char *locale_str = NULL;
+ int dummy;
+ char *msg;
+ UErrorCode status = UErrorCode();
+ intl_error_reset(NULL TSRMLS_CC);
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s!",
+ &locale_str, &dummy) == FAILURE) {
+ spprintf(&msg, NULL, "%s: bad arguments", func_name);
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, msg, 1 TSRMLS_CC);
+ efree(msg);
+ RETURN_NULL();
+ }
+
+ if (locale_str == NULL) {
+ locale_str = intl_locale_get_default(TSRMLS_C);
+ }
+
+ biter = func(Locale::createFromName(locale_str), status);
+ intl_error_set_code(NULL, status TSRMLS_CC);
+ if (U_FAILURE(status)) {
+ spprintf(&msg, NULL, "%s: error creating BreakIterator",
+ func_name);
+ intl_error_set_custom_msg(NULL, msg, 1 TSRMLS_CC);
+ efree(msg);
+ RETURN_NULL();
+ }
+
+ breakiterator_object_create(return_value, biter TSRMLS_CC);
+}
+
+U_CFUNC PHP_FUNCTION(breakiter_create_word_instance)
+{
+ _breakiter_factory("breakiter_create_word_instance",
+ &BreakIterator::createWordInstance,
+ INTERNAL_FUNCTION_PARAM_PASSTHRU);
+}
+
+U_CFUNC PHP_FUNCTION(breakiter_create_line_instance)
+{
+ _breakiter_factory("breakiter_create_line_instance",
+ &BreakIterator::createLineInstance,
+ INTERNAL_FUNCTION_PARAM_PASSTHRU);
+}
+
+U_CFUNC PHP_FUNCTION(breakiter_create_character_instance)
+{
+ _breakiter_factory("breakiter_create_character_instance",
+ &BreakIterator::createCharacterInstance,
+ INTERNAL_FUNCTION_PARAM_PASSTHRU);
+}
+
+U_CFUNC PHP_FUNCTION(breakiter_create_sentence_instance)
+{
+ _breakiter_factory("breakiter_create_sentence_instance",
+ &BreakIterator::createSentenceInstance,
+ INTERNAL_FUNCTION_PARAM_PASSTHRU);
+}
+
+U_CFUNC PHP_FUNCTION(breakiter_create_title_instance)
+{
+ _breakiter_factory("breakiter_create_title_instance",
+ &BreakIterator::createTitleInstance,
+ INTERNAL_FUNCTION_PARAM_PASSTHRU);
+}
+
+U_CFUNC PHP_FUNCTION(breakiter_create_code_point_instance)
+{
+ UErrorCode status = UErrorCode();
+ intl_error_reset(NULL TSRMLS_CC);
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "breakiter_create_code_point_instance: bad arguments", 0 TSRMLS_CC);
+ RETURN_NULL();
+ }
+
+ CodePointBreakIterator *cpbi = new CodePointBreakIterator();
+ breakiterator_object_create(return_value, cpbi TSRMLS_CC);
+}
+
+U_CFUNC PHP_FUNCTION(breakiter_get_text)
+{
+ BREAKITER_METHOD_INIT_VARS;
+ object = getThis();
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "breakiter_get_text: bad arguments", 0 TSRMLS_CC);
+ RETURN_FALSE;
+ }
+
+ BREAKITER_METHOD_FETCH_OBJECT;
+
+ if (bio->text == NULL) {
+ RETURN_NULL();
+ } else {
+ RETURN_ZVAL(bio->text, 1, 0);
+ }
+}
+
+U_CFUNC PHP_FUNCTION(breakiter_set_text)
+{
+ char *text;
+ int text_len;
+ UText *ut = NULL;
+ zval **textzv;
+ BREAKITER_METHOD_INIT_VARS;
+ object = getThis();
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s",
+ &text, &text_len) == FAILURE) {
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "breakiter_set_text: bad arguments", 0 TSRMLS_CC);
+ RETURN_FALSE;
+ }
+
+ int res = zend_get_parameters_ex(1, &textzv);
+ assert(res == SUCCESS);
+
+ BREAKITER_METHOD_FETCH_OBJECT;
+
+ /* assert it's safe to use text and text_len because zpp changes the
+ * arguments in the stack */
+ assert(text == Z_STRVAL_PP(textzv));
+
+ ut = utext_openUTF8(ut, text, text_len, BREAKITER_ERROR_CODE_P(bio));
+ INTL_CTOR_CHECK_STATUS(bio, "breakiter_set_text: error opening UText");
+
+ bio->biter->setText(ut, BREAKITER_ERROR_CODE(bio));
+ utext_close(ut); /* ICU shallow clones the UText */
+ INTL_CTOR_CHECK_STATUS(bio, "breakiter_set_text: error calling "
+ "BreakIterator::setText()");
+
+ /* When ICU clones the UText, it does not copy the buffer, so we have to
+ * keep the string buffer around by holding a reference to its zval. This
+ * also allows a faste implementation of getText() */
+ if (bio->text != NULL) {
+ zval_ptr_dtor(&bio->text);
+ }
+ bio->text = *textzv;
+ zval_add_ref(&bio->text);
+
+ RETURN_TRUE;
+}
+
+static void _breakiter_no_args_ret_int32(
+ const char *func_name,
+ int32_t (BreakIterator::*func)(),
+ INTERNAL_FUNCTION_PARAMETERS)
+{
+ char *msg;
+ BREAKITER_METHOD_INIT_VARS;
+ object = getThis();
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ spprintf(&msg, NULL, "%s: bad arguments", func_name);
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, msg, 1 TSRMLS_CC);
+ efree(msg);
+ RETURN_FALSE;
+ }
+
+ BREAKITER_METHOD_FETCH_OBJECT;
+
+ int32_t res = (bio->biter->*func)();
+
+ RETURN_LONG((long)res);
+}
+
+static void _breakiter_int32_ret_int32(
+ const char *func_name,
+ int32_t (BreakIterator::*func)(int32_t),
+ INTERNAL_FUNCTION_PARAMETERS)
+{
+ char *msg;
+ long arg;
+ BREAKITER_METHOD_INIT_VARS;
+ object = getThis();
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &arg) == FAILURE) {
+ spprintf(&msg, NULL, "%s: bad arguments", func_name);
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, msg, 1 TSRMLS_CC);
+ efree(msg);
+ RETURN_FALSE;
+ }
+
+ BREAKITER_METHOD_FETCH_OBJECT;
+
+ if (arg < INT32_MIN || arg > INT32_MAX) {
+ spprintf(&msg, NULL, "%s: offset argument is outside bounds of "
+ "a 32-bit wide integer", func_name);
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, msg, 1 TSRMLS_CC);
+ efree(msg);
+ RETURN_FALSE;
+ }
+
+ int32_t res = (bio->biter->*func)((int32_t)arg);
+
+ RETURN_LONG((long)res);
+}
+
+U_CFUNC PHP_FUNCTION(breakiter_first)
+{
+ _breakiter_no_args_ret_int32("breakiter_first",
+ &BreakIterator::first,
+ INTERNAL_FUNCTION_PARAM_PASSTHRU);
+}
+
+U_CFUNC PHP_FUNCTION(breakiter_last)
+{
+ _breakiter_no_args_ret_int32("breakiter_last",
+ &BreakIterator::last,
+ INTERNAL_FUNCTION_PARAM_PASSTHRU);
+}
+
+U_CFUNC PHP_FUNCTION(breakiter_previous)
+{
+ _breakiter_no_args_ret_int32("breakiter_previous",
+ &BreakIterator::previous,
+ INTERNAL_FUNCTION_PARAM_PASSTHRU);
+}
+
+U_CFUNC PHP_FUNCTION(breakiter_next)
+{
+ bool no_arg_version = false;
+
+ if (ZEND_NUM_ARGS() == 0) {
+ no_arg_version = true;
+ } else if (ZEND_NUM_ARGS() == 1) {
+ zval **arg;
+ int res = zend_get_parameters_ex(1, &arg);
+ assert(res == SUCCESS);
+ if (Z_TYPE_PP(arg) == IS_NULL) {
+ no_arg_version = true;
+ ht = 0; /* pretend we don't have any argument */
+ } else {
+ no_arg_version = false;
+ }
+ }
+
+ if (no_arg_version) {
+ _breakiter_no_args_ret_int32("breakiter_next",
+ &BreakIterator::next,
+ INTERNAL_FUNCTION_PARAM_PASSTHRU);
+ } else {
+ _breakiter_int32_ret_int32("breakiter_next",
+ &BreakIterator::next,
+ INTERNAL_FUNCTION_PARAM_PASSTHRU);
+ }
+}
+
+U_CFUNC PHP_FUNCTION(breakiter_current)
+{
+ BREAKITER_METHOD_INIT_VARS;
+ object = getThis();
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "breakiter_current: bad arguments", 0 TSRMLS_CC);
+ RETURN_FALSE;
+ }
+
+ BREAKITER_METHOD_FETCH_OBJECT;
+
+ int32_t res = bio->biter->current();
+
+ RETURN_LONG((long)res);
+}
+
+U_CFUNC PHP_FUNCTION(breakiter_following)
+{
+ _breakiter_int32_ret_int32("breakiter_following",
+ &BreakIterator::following,
+ INTERNAL_FUNCTION_PARAM_PASSTHRU);
+}
+
+U_CFUNC PHP_FUNCTION(breakiter_preceding)
+{
+ _breakiter_int32_ret_int32("breakiter_preceding",
+ &BreakIterator::preceding,
+ INTERNAL_FUNCTION_PARAM_PASSTHRU);
+}
+
+U_CFUNC PHP_FUNCTION(breakiter_is_boundary)
+{
+ long offset;
+ BREAKITER_METHOD_INIT_VARS;
+ object = getThis();
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l",
+ &offset) == FAILURE) {
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "breakiter_is_boundary: bad arguments", 0 TSRMLS_CC);
+ RETURN_FALSE;
+ }
+
+ if (offset < INT32_MIN || offset > INT32_MAX) {
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "breakiter_is_boundary: offset argument is outside bounds of "
+ "a 32-bit wide integer", 0 TSRMLS_CC);
+ RETURN_FALSE;
+ }
+
+ BREAKITER_METHOD_FETCH_OBJECT;
+
+ UBool res = bio->biter->isBoundary((int32_t)offset);
+
+ RETURN_BOOL((long)res);
+}
+
+U_CFUNC PHP_FUNCTION(breakiter_get_locale)
+{
+ long locale_type;
+ BREAKITER_METHOD_INIT_VARS;
+ object = getThis();
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &locale_type) == FAILURE) {
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "breakiter_get_locale: bad arguments", 0 TSRMLS_CC);
+ RETURN_FALSE;
+ }
+
+ if (locale_type != ULOC_ACTUAL_LOCALE && locale_type != ULOC_VALID_LOCALE) {
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "breakiter_get_locale: invalid locale type", 0 TSRMLS_CC);
+ RETURN_FALSE;
+ }
+
+ BREAKITER_METHOD_FETCH_OBJECT;
+
+ Locale locale = bio->biter->getLocale((ULocDataLocaleType)locale_type,
+ BREAKITER_ERROR_CODE(bio));
+ INTL_METHOD_CHECK_STATUS(bio,
+ "breakiter_get_locale: Call to ICU method has failed");
+
+ RETURN_STRING(locale.getName(), 1);
+}
+
+U_CFUNC PHP_FUNCTION(breakiter_get_parts_iterator)
+{
+ long key_type = 0;
+ BREAKITER_METHOD_INIT_VARS;
+ object = getThis();
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &key_type) == FAILURE) {
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "breakiter_get_parts_iterator: bad arguments", 0 TSRMLS_CC);
+ RETURN_FALSE;
+ }
+
+ if (key_type != PARTS_ITERATOR_KEY_SEQUENTIAL
+ && key_type != PARTS_ITERATOR_KEY_LEFT
+ && key_type != PARTS_ITERATOR_KEY_RIGHT) {
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "breakiter_get_parts_iterator: bad key type", 0 TSRMLS_CC);
+ RETURN_FALSE;
+ }
+
+ BREAKITER_METHOD_FETCH_OBJECT;
+
+ IntlIterator_from_BreakIterator_parts(
+ object, return_value, (parts_iter_key_type)key_type TSRMLS_CC);
+}
+
+U_CFUNC PHP_FUNCTION(breakiter_get_error_code)
+{
+ BREAKITER_METHOD_INIT_VARS;
+ object = getThis();
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "breakiter_get_error_code: bad arguments", 0 TSRMLS_CC);
+ RETURN_FALSE;
+ }
+
+ /* Fetch the object (without resetting its last error code ). */
+ bio = (BreakIterator_object*)zend_object_store_get_object(object TSRMLS_CC);
+ if (bio == NULL)
+ RETURN_FALSE;
+
+ RETURN_LONG((long)BREAKITER_ERROR_CODE(bio));
+}
+
+U_CFUNC PHP_FUNCTION(breakiter_get_error_message)
+{
+ const char* message = NULL;
+ BREAKITER_METHOD_INIT_VARS;
+ object = getThis();
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "breakiter_get_error_message: bad arguments", 0 TSRMLS_CC );
+ RETURN_FALSE;
+ }
+
+
+ /* Fetch the object (without resetting its last error code ). */
+ bio = (BreakIterator_object*)zend_object_store_get_object(object TSRMLS_CC);
+ if (bio == NULL)
+ RETURN_FALSE;
+
+ /* Return last error message. */
+ message = intl_error_get_message(BREAKITER_ERROR_P(bio) TSRMLS_CC);
+ RETURN_STRING(message, 0);
+}
diff --git a/ext/intl/breakiterator/breakiterator_methods.h b/ext/intl/breakiterator/breakiterator_methods.h
new file mode 100644
index 0000000000..a479ac92e8
--- /dev/null
+++ b/ext/intl/breakiterator/breakiterator_methods.h
@@ -0,0 +1,64 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Gustavo Lopes <cataphract@php.net> |
+ +----------------------------------------------------------------------+
+ */
+
+#ifndef BREAKITERATOR_METHODS_H
+#define BREAKITERATOR_METHODS_H
+
+#include <php.h>
+
+PHP_METHOD(BreakIterator, __construct);
+
+PHP_FUNCTION(breakiter_create_word_instance);
+
+PHP_FUNCTION(breakiter_create_line_instance);
+
+PHP_FUNCTION(breakiter_create_character_instance);
+
+PHP_FUNCTION(breakiter_create_sentence_instance);
+
+PHP_FUNCTION(breakiter_create_title_instance);
+
+PHP_FUNCTION(breakiter_create_code_point_instance);
+
+PHP_FUNCTION(breakiter_get_text);
+
+PHP_FUNCTION(breakiter_set_text);
+
+PHP_FUNCTION(breakiter_first);
+
+PHP_FUNCTION(breakiter_last);
+
+PHP_FUNCTION(breakiter_previous);
+
+PHP_FUNCTION(breakiter_next);
+
+PHP_FUNCTION(breakiter_current);
+
+PHP_FUNCTION(breakiter_following);
+
+PHP_FUNCTION(breakiter_preceding);
+
+PHP_FUNCTION(breakiter_is_boundary);
+
+PHP_FUNCTION(breakiter_get_locale);
+
+PHP_FUNCTION(breakiter_get_parts_iterator);
+
+PHP_FUNCTION(breakiter_get_error_code);
+
+PHP_FUNCTION(breakiter_get_error_message);
+
+#endif \ No newline at end of file
diff --git a/ext/intl/breakiterator/codepointiterator_internal.cpp b/ext/intl/breakiterator/codepointiterator_internal.cpp
new file mode 100644
index 0000000000..bf9239d531
--- /dev/null
+++ b/ext/intl/breakiterator/codepointiterator_internal.cpp
@@ -0,0 +1,291 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Gustavo Lopes <cataphract@php.net> |
+ +----------------------------------------------------------------------+
+ */
+
+#include "codepointiterator_internal.h"
+#include <unicode/uchriter.h>
+#include <typeinfo>
+
+//copied from cmemory.h, which is not public
+typedef union {
+ long t1;
+ double t2;
+ void *t3;
+} UAlignedMemory;
+
+#define U_POINTER_MASK_LSB(ptr, mask) (((ptrdiff_t)(char *)(ptr)) & (mask))
+#define U_ALIGNMENT_OFFSET(ptr) U_POINTER_MASK_LSB(ptr, sizeof(UAlignedMemory) - 1)
+#define U_ALIGNMENT_OFFSET_UP(ptr) (sizeof(UAlignedMemory) - U_ALIGNMENT_OFFSET(ptr))
+
+using namespace PHP;
+
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(CodePointBreakIterator);
+
+CodePointBreakIterator::CodePointBreakIterator()
+: BreakIterator(), fCharIter(NULL), lastCodePoint(U_SENTINEL)
+{
+ UErrorCode uec = UErrorCode();
+ this->fText = utext_openUChars(NULL, NULL, 0, &uec);
+}
+
+CodePointBreakIterator::CodePointBreakIterator(const PHP::CodePointBreakIterator &other)
+: BreakIterator(other), fText(NULL), fCharIter(NULL), lastCodePoint(U_SENTINEL)
+{
+ *this = other;
+}
+
+CodePointBreakIterator& CodePointBreakIterator::operator=(const CodePointBreakIterator& that)
+{
+ UErrorCode uec = UErrorCode();
+ UText *ut_clone = NULL;
+
+ if (this == &that) {
+ return *this;
+ }
+
+ this->fText = utext_clone(this->fText, that.fText, FALSE, TRUE, &uec);
+
+ //don't bother copying the character iterator, getText() is deprecated
+ clearCurrentCharIter();
+
+ this->lastCodePoint = that.lastCodePoint;
+ return *this;
+}
+
+CodePointBreakIterator::~CodePointBreakIterator()
+{
+ if (this->fText) {
+ utext_close(this->fText);
+ }
+ clearCurrentCharIter();
+}
+
+UBool CodePointBreakIterator::operator==(const BreakIterator& that) const
+{
+ if (typeid(*this) != typeid(that)) {
+ return FALSE;
+ }
+
+ const CodePointBreakIterator& that2 =
+ static_cast<const CodePointBreakIterator&>(that);
+
+ if (!utext_equals(this->fText, that2.fText)) {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+CodePointBreakIterator* CodePointBreakIterator::clone(void) const
+{
+ return new CodePointBreakIterator(*this);
+}
+
+CharacterIterator& CodePointBreakIterator::getText(void) const
+{
+ if (this->fCharIter == NULL) {
+ //this method is deprecated anyway; setup bogus iterator
+ static const UChar c = 0;
+ this->fCharIter = new UCharCharacterIterator(&c, 0);
+ }
+
+ return *this->fCharIter;
+}
+
+UText *CodePointBreakIterator::getUText(UText *fillIn, UErrorCode &status) const
+{
+ return utext_clone(fillIn, this->fText, FALSE, TRUE, &status);
+}
+
+void CodePointBreakIterator::setText(const UnicodeString &text)
+{
+ UErrorCode uec = UErrorCode();
+
+ //this closes the previous utext, if any
+ this->fText = utext_openConstUnicodeString(this->fText, &text, &uec);
+
+ clearCurrentCharIter();
+}
+
+void CodePointBreakIterator::setText(UText *text, UErrorCode &status)
+{
+ if (U_FAILURE(status)) {
+ return;
+ }
+
+ this->fText = utext_clone(this->fText, text, FALSE, TRUE, &status);
+
+ clearCurrentCharIter();
+}
+
+void CodePointBreakIterator::adoptText(CharacterIterator* it)
+{
+ UErrorCode uec = UErrorCode();
+ clearCurrentCharIter();
+
+ this->fCharIter = it;
+ this->fText = utext_openCharacterIterator(this->fText, it, &uec);
+}
+
+int32_t CodePointBreakIterator::first(void)
+{
+ UTEXT_SETNATIVEINDEX(this->fText, 0);
+ this->lastCodePoint = U_SENTINEL;
+
+ return 0;
+}
+
+int32_t CodePointBreakIterator::last(void)
+{
+ int32_t pos = (int32_t)utext_nativeLength(this->fText);
+ UTEXT_SETNATIVEINDEX(this->fText, pos);
+ this->lastCodePoint = U_SENTINEL;
+
+ return pos;
+}
+
+int32_t CodePointBreakIterator::previous(void)
+{
+ this->lastCodePoint = UTEXT_PREVIOUS32(this->fText);
+ if (this->lastCodePoint == U_SENTINEL) {
+ return BreakIterator::DONE;
+ }
+
+ return (int32_t)UTEXT_GETNATIVEINDEX(this->fText);
+}
+
+int32_t CodePointBreakIterator::next(void)
+{
+ this->lastCodePoint = UTEXT_NEXT32(this->fText);
+ if (this->lastCodePoint == U_SENTINEL) {
+ return BreakIterator::DONE;
+ }
+
+ return (int32_t)UTEXT_GETNATIVEINDEX(this->fText);
+}
+
+int32_t CodePointBreakIterator::current(void) const
+{
+ return (int32_t)UTEXT_GETNATIVEINDEX(this->fText);
+}
+
+int32_t CodePointBreakIterator::following(int32_t offset)
+{
+ this->lastCodePoint = utext_next32From(this->fText, offset);
+ if (this->lastCodePoint == U_SENTINEL) {
+ return BreakIterator::DONE;
+ }
+
+ return (int32_t)UTEXT_GETNATIVEINDEX(this->fText);
+}
+
+int32_t CodePointBreakIterator::preceding(int32_t offset)
+{
+ this->lastCodePoint = utext_previous32From(this->fText, offset);
+ if (this->lastCodePoint == U_SENTINEL) {
+ return BreakIterator::DONE;
+ }
+
+ return (int32_t)UTEXT_GETNATIVEINDEX(this->fText);
+}
+
+UBool CodePointBreakIterator::isBoundary(int32_t offset)
+{
+ //this function has side effects, and it's supposed to
+ utext_setNativeIndex(this->fText, offset);
+ return (offset == utext_getNativeIndex(this->fText));
+}
+
+int32_t CodePointBreakIterator::next(int32_t n)
+{
+ UBool res = utext_moveIndex32(this->fText, n);
+
+#ifndef UTEXT_CURRENT32
+#define UTEXT_CURRENT32 utext_current32
+#endif
+
+ if (res) {
+ this->lastCodePoint = UTEXT_CURRENT32(this->fText);
+ return (int32_t)UTEXT_GETNATIVEINDEX(this->fText);
+ } else {
+ this->lastCodePoint = U_SENTINEL;
+ return BreakIterator::DONE;
+ }
+}
+
+CodePointBreakIterator *CodePointBreakIterator::createBufferClone(
+ void *stackBuffer, int32_t &bufferSize, UErrorCode &status)
+{
+ //see implementation of RuleBasedBreakIterator::createBufferClone()
+ if (U_FAILURE(status)) {
+ return NULL;
+ }
+
+ if (bufferSize <= 0) {
+ bufferSize = sizeof(CodePointBreakIterator) + U_ALIGNMENT_OFFSET_UP(0);
+ return NULL;
+ }
+
+ char *buf = (char*)stackBuffer;
+ uint32_t s = bufferSize;
+
+ if (stackBuffer == NULL) {
+ s = 0;
+ }
+
+ if (U_ALIGNMENT_OFFSET(stackBuffer) != 0) {
+ uint32_t offsetUp = (uint32_t)U_ALIGNMENT_OFFSET_UP(buf);
+ s -= offsetUp;
+ buf += offsetUp;
+ }
+
+ if (s < sizeof(CodePointBreakIterator)) {
+ CodePointBreakIterator *clonedBI = new CodePointBreakIterator(*this);
+ if (clonedBI == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ } else {
+ status = U_SAFECLONE_ALLOCATED_WARNING;
+ }
+
+ return clonedBI;
+ }
+
+ return new(buf) CodePointBreakIterator(*this);
+}
+
+CodePointBreakIterator &CodePointBreakIterator::refreshInputText(UText *input, UErrorCode &status)
+{
+ //see implementation of RuleBasedBreakIterator::createBufferClone()
+ if (U_FAILURE(status)) {
+ return *this;
+ }
+ if (input == NULL) {
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ return *this;
+ }
+
+ int64_t pos = utext_getNativeIndex(this->fText);
+ this->fText = utext_clone(this->fText, input, FALSE, TRUE, &status);
+ if (U_FAILURE(status)) {
+ return *this;
+ }
+
+ utext_setNativeIndex(this->fText, pos);
+ if (utext_getNativeIndex(fText) != pos) {
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ }
+
+ return *this;
+}
diff --git a/ext/intl/breakiterator/codepointiterator_internal.h b/ext/intl/breakiterator/codepointiterator_internal.h
new file mode 100644
index 0000000000..988b91c200
--- /dev/null
+++ b/ext/intl/breakiterator/codepointiterator_internal.h
@@ -0,0 +1,98 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Gustavo Lopes <cataphract@php.net> |
+ +----------------------------------------------------------------------+
+ */
+
+#ifndef CODEPOINTITERATOR_INTERNAL_H
+#define CODEPOINTITERATOR_INTERNAL_H
+
+#include <unicode/brkiter.h>
+
+using U_ICU_NAMESPACE::BreakIterator;
+
+namespace PHP {
+
+ class CodePointBreakIterator : public BreakIterator {
+
+ public:
+ static UClassID getStaticClassID();
+
+ CodePointBreakIterator();
+
+ CodePointBreakIterator(const CodePointBreakIterator &other);
+
+ CodePointBreakIterator& operator=(const CodePointBreakIterator& that);
+
+ virtual ~CodePointBreakIterator();
+
+ virtual UBool operator==(const BreakIterator& that) const;
+
+ virtual CodePointBreakIterator* clone(void) const;
+
+ virtual UClassID getDynamicClassID(void) const;
+
+ virtual CharacterIterator& getText(void) const;
+
+ virtual UText *getUText(UText *fillIn, UErrorCode &status) const;
+
+ virtual void setText(const UnicodeString &text);
+
+ virtual void setText(UText *text, UErrorCode &status);
+
+ virtual void adoptText(CharacterIterator* it);
+
+ virtual int32_t first(void);
+
+ virtual int32_t last(void);
+
+ virtual int32_t previous(void);
+
+ virtual int32_t next(void);
+
+ virtual int32_t current(void) const;
+
+ virtual int32_t following(int32_t offset);
+
+ virtual int32_t preceding(int32_t offset);
+
+ virtual UBool isBoundary(int32_t offset);
+
+ virtual int32_t next(int32_t n);
+
+ virtual CodePointBreakIterator *createBufferClone(void *stackBuffer,
+ int32_t &BufferSize,
+ UErrorCode &status);
+
+ virtual CodePointBreakIterator &refreshInputText(UText *input, UErrorCode &status);
+
+ inline UChar32 getLastCodePoint()
+ {
+ return this->lastCodePoint;
+ }
+
+ private:
+ UText *fText;
+ UChar32 lastCodePoint;
+ mutable CharacterIterator *fCharIter;
+
+ inline void clearCurrentCharIter()
+ {
+ delete this->fCharIter;
+ this->fCharIter = NULL;
+ this->lastCodePoint = U_SENTINEL;
+ }
+ };
+}
+
+#endif \ No newline at end of file
diff --git a/ext/intl/breakiterator/codepointiterator_methods.cpp b/ext/intl/breakiterator/codepointiterator_methods.cpp
new file mode 100644
index 0000000000..ae7e526ead
--- /dev/null
+++ b/ext/intl/breakiterator/codepointiterator_methods.cpp
@@ -0,0 +1,44 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Gustavo Lopes <cataphract@php.net> |
+ +----------------------------------------------------------------------+
+ */
+
+#include "codepointiterator_internal.h"
+
+extern "C" {
+#define USE_BREAKITERATOR_POINTER 1
+#include "breakiterator_class.h"
+}
+
+using PHP::CodePointBreakIterator;
+
+static inline CodePointBreakIterator *fetch_cpbi(BreakIterator_object *bio) {
+ return (CodePointBreakIterator*)bio->biter;
+}
+
+U_CFUNC PHP_FUNCTION(cpbi_get_last_code_point)
+{
+ BREAKITER_METHOD_INIT_VARS;
+ object = getThis();
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "cpbi_get_last_code_point: bad arguments", 0 TSRMLS_CC);
+ RETURN_FALSE;
+ }
+
+ BREAKITER_METHOD_FETCH_OBJECT;
+
+ RETURN_LONG(fetch_cpbi(bio)->getLastCodePoint());
+} \ No newline at end of file
diff --git a/ext/intl/breakiterator/codepointiterator_methods.h b/ext/intl/breakiterator/codepointiterator_methods.h
new file mode 100644
index 0000000000..d34e5b61e2
--- /dev/null
+++ b/ext/intl/breakiterator/codepointiterator_methods.h
@@ -0,0 +1,24 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Gustavo Lopes <cataphract@php.net> |
+ +----------------------------------------------------------------------+
+ */
+
+#ifndef CODEPOINTITERATOR_METHODS_H
+#define CODEPOINTITERATOR_METHODS_H
+
+#include <php.h>
+
+PHP_FUNCTION(cpbi_get_last_code_point);
+
+#endif \ No newline at end of file
diff --git a/ext/intl/breakiterator/rulebasedbreakiterator_methods.cpp b/ext/intl/breakiterator/rulebasedbreakiterator_methods.cpp
new file mode 100644
index 0000000000..454e5249fd
--- /dev/null
+++ b/ext/intl/breakiterator/rulebasedbreakiterator_methods.cpp
@@ -0,0 +1,221 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Gustavo Lopes <cataphract@php.net> |
+ +----------------------------------------------------------------------+
+ */
+
+#include <unicode/rbbi.h>
+
+extern "C" {
+#define USE_BREAKITERATOR_POINTER 1
+#include "breakiterator_class.h"
+#include <zend_exceptions.h>
+#include <limits.h>
+}
+
+#include "../intl_convertcpp.h"
+
+static inline RuleBasedBreakIterator *fetch_rbbi(BreakIterator_object *bio) {
+ return (RuleBasedBreakIterator*)bio->biter;
+}
+
+static void _php_intlrbbi_constructor_body(INTERNAL_FUNCTION_PARAMETERS)
+{
+ zval *object = getThis();
+ char *rules;
+ int rules_len;
+ zend_bool compiled = 0;
+ UErrorCode status = U_ZERO_ERROR;
+ intl_error_reset(NULL TSRMLS_CC);
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|b",
+ &rules, &rules_len, &compiled) == FAILURE) {
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "rbbi_create_instance: bad arguments", 0 TSRMLS_CC);
+ RETURN_NULL();
+ }
+
+ // instantiation of ICU object
+ RuleBasedBreakIterator *rbbi;
+
+ if (!compiled) {
+ UnicodeString rulesStr;
+ UParseError parseError = UParseError();
+ if (intl_stringFromChar(rulesStr, rules, rules_len, &status)
+ == FAILURE) {
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "rbbi_create_instance: rules were not a valid UTF-8 string",
+ 0 TSRMLS_CC);
+ RETURN_NULL();
+ }
+
+ rbbi = new RuleBasedBreakIterator(rulesStr, parseError, status);
+ intl_error_set_code(NULL, status TSRMLS_CC);
+ if (U_FAILURE(status)) {
+ char *msg;
+ smart_str parse_error_str;
+ parse_error_str = intl_parse_error_to_string(&parseError);
+ spprintf(&msg, 0, "rbbi_create_instance: unable to create "
+ "RuleBasedBreakIterator from rules (%s)", parse_error_str.c);
+ smart_str_free(&parse_error_str);
+ intl_error_set_custom_msg(NULL, msg, 1 TSRMLS_CC);
+ efree(msg);
+ delete rbbi;
+ RETURN_NULL();
+ }
+ } else { // compiled
+#if U_ICU_VERSION_MAJOR_NUM * 10 + U_ICU_VERSION_MINOR_NUM >= 48
+ rbbi = new RuleBasedBreakIterator((uint8_t*)rules, rules_len, status);
+ if (U_FAILURE(status)) {
+ intl_error_set(NULL, status, "rbbi_create_instance: unable to "
+ "create instance from compiled rules", 0 TSRMLS_CC);
+ delete rbbi;
+ RETURN_NULL();
+ }
+#else
+ intl_error_set(NULL, U_UNSUPPORTED_ERROR, "rbbi_create_instance: "
+ "compiled rules require ICU >= 4.8", 0 TSRMLS_CC);
+ RETURN_NULL();
+#endif
+ }
+
+ breakiterator_object_create(return_value, rbbi TSRMLS_CC);
+}
+
+U_CFUNC PHP_METHOD(IntlRuleBasedBreakIterator, __construct)
+{
+ zval orig_this = *getThis();
+
+ return_value = getThis();
+ //changes this to IS_NULL (without first destroying) if there's an error
+ _php_intlrbbi_constructor_body(INTERNAL_FUNCTION_PARAM_PASSTHRU);
+
+ if (Z_TYPE_P(return_value) == IS_NULL) {
+ zend_object_store_ctor_failed(&orig_this TSRMLS_CC);
+ zval_dtor(&orig_this);
+ }
+}
+
+U_CFUNC PHP_FUNCTION(rbbi_get_rules)
+{
+ BREAKITER_METHOD_INIT_VARS;
+ object = getThis();
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "rbbi_get_rules: bad arguments", 0 TSRMLS_CC);
+ RETURN_FALSE;
+ }
+
+ BREAKITER_METHOD_FETCH_OBJECT;
+
+ const UnicodeString rules = fetch_rbbi(bio)->getRules();
+
+ Z_TYPE_P(return_value) = IS_STRING;
+ if (intl_charFromString(rules, &Z_STRVAL_P(return_value),
+ &Z_STRLEN_P(return_value), BREAKITER_ERROR_CODE_P(bio)) == FAILURE)
+ {
+ intl_errors_set(BREAKITER_ERROR_P(bio), BREAKITER_ERROR_CODE(bio),
+ "rbbi_hash_code: Error converting result to UTF-8 string",
+ 0 TSRMLS_CC);
+ RETURN_FALSE;
+ }
+}
+
+U_CFUNC PHP_FUNCTION(rbbi_get_rule_status)
+{
+ BREAKITER_METHOD_INIT_VARS;
+ object = getThis();
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "rbbi_get_rule_status: bad arguments", 0 TSRMLS_CC);
+ RETURN_FALSE;
+ }
+
+ BREAKITER_METHOD_FETCH_OBJECT;
+
+ RETURN_LONG(fetch_rbbi(bio)->getRuleStatus());
+}
+
+U_CFUNC PHP_FUNCTION(rbbi_get_rule_status_vec)
+{
+ BREAKITER_METHOD_INIT_VARS;
+ object = getThis();
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "rbbi_get_rule_status_vec: bad arguments", 0 TSRMLS_CC);
+ RETURN_FALSE;
+ }
+
+ BREAKITER_METHOD_FETCH_OBJECT;
+
+ int32_t num_rules = fetch_rbbi(bio)->getRuleStatusVec(NULL, 0,
+ BREAKITER_ERROR_CODE(bio));
+ if (BREAKITER_ERROR_CODE(bio) == U_BUFFER_OVERFLOW_ERROR) {
+ BREAKITER_ERROR_CODE(bio) = U_ZERO_ERROR;
+ } else {
+ // should not happen
+ INTL_METHOD_CHECK_STATUS(bio, "rbbi_get_rule_status_vec: failed "
+ " determining the number of status values");
+ }
+ int32_t *rules = new int32_t[num_rules];
+ num_rules = fetch_rbbi(bio)->getRuleStatusVec(rules, num_rules,
+ BREAKITER_ERROR_CODE(bio));
+ if (U_FAILURE(BREAKITER_ERROR_CODE(bio))) {
+ delete[] rules;
+ intl_errors_set(BREAKITER_ERROR_P(bio), BREAKITER_ERROR_CODE(bio),
+ "rbbi_get_rule_status_vec: failed obtaining the status values",
+ 0 TSRMLS_CC);
+ RETURN_FALSE;
+ }
+
+ array_init_size(return_value, num_rules);
+ for (int32_t i = 0; i < num_rules; i++) {
+ add_next_index_long(return_value, rules[i]);
+ }
+ delete[] rules;
+}
+
+#if U_ICU_VERSION_MAJOR_NUM * 10 + U_ICU_VERSION_MINOR_NUM >= 48
+U_CFUNC PHP_FUNCTION(rbbi_get_binary_rules)
+{
+ BREAKITER_METHOD_INIT_VARS;
+ object = getThis();
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "rbbi_get_binary_rules: bad arguments", 0 TSRMLS_CC);
+ RETURN_FALSE;
+ }
+
+ BREAKITER_METHOD_FETCH_OBJECT;
+
+ uint32_t rules_len;
+ const uint8_t *rules = fetch_rbbi(bio)->getBinaryRules(rules_len);
+
+ if (rules_len > INT_MAX - 1) {
+ intl_errors_set(BREAKITER_ERROR_P(bio), BREAKITER_ERROR_CODE(bio),
+ "rbbi_get_binary_rules: the rules are too large",
+ 0 TSRMLS_CC);
+ RETURN_FALSE;
+ }
+
+ char *ret_rules = static_cast<char*>(emalloc(rules_len + 1));
+ memcpy(ret_rules, rules, rules_len);
+ ret_rules[rules_len] = '\0';
+
+ RETURN_STRINGL(ret_rules, rules_len, 0);
+}
+#endif
diff --git a/ext/intl/breakiterator/rulebasedbreakiterator_methods.h b/ext/intl/breakiterator/rulebasedbreakiterator_methods.h
new file mode 100644
index 0000000000..edea4ea2a6
--- /dev/null
+++ b/ext/intl/breakiterator/rulebasedbreakiterator_methods.h
@@ -0,0 +1,32 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Gustavo Lopes <cataphract@php.net> |
+ +----------------------------------------------------------------------+
+ */
+
+#ifndef RULEBASEDBREAKITERATOR_METHODS_H
+#define RULEBASEDBREAKITERATOR_METHODS_H
+
+#include <php.h>
+
+PHP_METHOD(IntlRuleBasedBreakIterator, __construct);
+
+PHP_FUNCTION(rbbi_get_rules);
+
+PHP_FUNCTION(rbbi_get_rule_status);
+
+PHP_FUNCTION(rbbi_get_rule_status_vec);
+
+PHP_FUNCTION(rbbi_get_binary_rules);
+
+#endif \ No newline at end of file
diff --git a/ext/intl/calendar/calendar_class.cpp b/ext/intl/calendar/calendar_class.cpp
new file mode 100644
index 0000000000..beb65f718f
--- /dev/null
+++ b/ext/intl/calendar/calendar_class.cpp
@@ -0,0 +1,550 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Gustavo Lopes <cataphract@php.net> |
+ +----------------------------------------------------------------------+
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "../intl_cppshims.h"
+
+#include <unicode/calendar.h>
+#include <unicode/gregocal.h>
+
+extern "C" {
+#define USE_TIMEZONE_POINTER 1
+#include "../timezone/timezone_class.h"
+#define USE_CALENDAR_POINTER 1
+#include "calendar_class.h"
+#include "calendar_methods.h"
+#include "gregoriancalendar_methods.h"
+#include <zend_exceptions.h>
+#include <assert.h>
+}
+
+/* {{{ Global variables */
+zend_class_entry *Calendar_ce_ptr;
+zend_class_entry *GregorianCalendar_ce_ptr;
+zend_object_handlers Calendar_handlers;
+/* }}} */
+
+U_CFUNC void calendar_object_create(zval *object,
+ Calendar *calendar TSRMLS_DC)
+{
+ UClassID classId = calendar->getDynamicClassID();
+ zend_class_entry *ce;
+
+ //if (dynamic_cast<GregorianCalendar*>(calendar) != NULL) {
+ if (classId == GregorianCalendar::getStaticClassID()) {
+ ce = GregorianCalendar_ce_ptr;
+ } else {
+ ce = Calendar_ce_ptr;
+ }
+
+ object_init_ex(object, ce);
+ calendar_object_construct(object, calendar TSRMLS_CC);
+}
+
+U_CFUNC Calendar *calendar_fetch_native_calendar(zval *object TSRMLS_DC)
+{
+ Calendar_object *co = (Calendar_object*)
+ zend_object_store_get_object(object TSRMLS_CC);
+
+ return co->ucal;
+}
+
+U_CFUNC void calendar_object_construct(zval *object,
+ Calendar *calendar TSRMLS_DC)
+{
+ Calendar_object *co;
+
+ CALENDAR_METHOD_FETCH_OBJECT_NO_CHECK; //populate to from object
+ assert(co->ucal == NULL);
+ co->ucal = (Calendar*)calendar;
+}
+
+/* {{{ clone handler for Calendar */
+static zend_object_value Calendar_clone_obj(zval *object TSRMLS_DC)
+{
+ Calendar_object *co_orig,
+ *co_new;
+ zend_object_value ret_val;
+ intl_error_reset(NULL TSRMLS_CC);
+
+ co_orig = (Calendar_object*)zend_object_store_get_object(object TSRMLS_CC);
+ intl_error_reset(INTL_DATA_ERROR_P(co_orig) TSRMLS_CC);
+
+ ret_val = Calendar_ce_ptr->create_object(Z_OBJCE_P(object) TSRMLS_CC);
+ co_new = (Calendar_object*)zend_object_store_get_object_by_handle(ret_val.handle TSRMLS_CC);
+
+ zend_objects_clone_members(&co_new->zo, ret_val,
+ &co_orig->zo, Z_OBJ_HANDLE_P(object) TSRMLS_CC);
+
+ if (co_orig->ucal != NULL) {
+ Calendar *newCalendar;
+
+ newCalendar = co_orig->ucal->clone();
+ if (!newCalendar) {
+ char *err_msg;
+ intl_errors_set_code(CALENDAR_ERROR_P(co_orig),
+ U_MEMORY_ALLOCATION_ERROR TSRMLS_CC);
+ intl_errors_set_custom_msg(CALENDAR_ERROR_P(co_orig),
+ "Could not clone IntlCalendar", 0 TSRMLS_CC);
+ err_msg = intl_error_get_message(CALENDAR_ERROR_P(co_orig) TSRMLS_CC);
+ zend_throw_exception(NULL, err_msg, 0 TSRMLS_CC);
+ efree(err_msg);
+ } else {
+ co_new->ucal = newCalendar;
+ }
+ } else {
+ zend_throw_exception(NULL, "Cannot clone unconstructed IntlCalendar", 0 TSRMLS_CC);
+ }
+
+ return ret_val;
+}
+/* }}} */
+
+static const struct {
+ UCalendarDateFields field;
+ const char *name;
+} debug_info_fields[] = {
+ {UCAL_ERA, "era"},
+ {UCAL_YEAR, "year"},
+ {UCAL_MONTH, "month"},
+ {UCAL_WEEK_OF_YEAR, "week of year"},
+ {UCAL_WEEK_OF_MONTH, "week of month"},
+ {UCAL_DAY_OF_YEAR, "day of year"},
+ {UCAL_DAY_OF_MONTH, "day of month"},
+ {UCAL_DAY_OF_WEEK, "day of week"},
+ {UCAL_DAY_OF_WEEK_IN_MONTH, "day of week in month"},
+ {UCAL_AM_PM, "AM/PM"},
+ {UCAL_HOUR, "hour"},
+ {UCAL_HOUR_OF_DAY, "hour of day"},
+ {UCAL_MINUTE, "minute"},
+ {UCAL_SECOND, "second"},
+ {UCAL_MILLISECOND, "millisecond"},
+ {UCAL_ZONE_OFFSET, "zone offset"},
+ {UCAL_DST_OFFSET, "DST offset"},
+ {UCAL_YEAR_WOY, "year for week of year"},
+ {UCAL_DOW_LOCAL, "localized day of week"},
+ {UCAL_EXTENDED_YEAR, "extended year"},
+ {UCAL_JULIAN_DAY, "julian day"},
+ {UCAL_MILLISECONDS_IN_DAY, "milliseconds in day"},
+ {UCAL_IS_LEAP_MONTH, "is leap month"},
+};
+
+/* {{{ get_debug_info handler for Calendar */
+static HashTable *Calendar_get_debug_info(zval *object, int *is_temp TSRMLS_DC)
+{
+ zval zv = zval_used_for_init,
+ *zfields;
+ Calendar_object *co;
+ const Calendar *cal;
+
+ *is_temp = 1;
+
+ array_init_size(&zv, 8);
+
+ co = (Calendar_object*)zend_object_store_get_object(object TSRMLS_CC);
+ cal = co->ucal;
+
+ if (cal == NULL) {
+ add_assoc_bool_ex(&zv, "valid", sizeof("valid"), 0);
+ return Z_ARRVAL(zv);
+ }
+
+ add_assoc_bool_ex(&zv, "valid", sizeof("valid"), 1);
+
+ add_assoc_string_ex(&zv, "type", sizeof("type"),
+ const_cast<char*>(cal->getType()), 1);
+
+ {
+ zval ztz = zval_used_for_init,
+ *ztz_debug;
+ int is_tmp;
+ HashTable *debug_info;
+
+ timezone_object_construct(&cal->getTimeZone(), &ztz , 0 TSRMLS_CC);
+ debug_info = Z_OBJ_HANDLER(ztz, get_debug_info)(&ztz, &is_tmp TSRMLS_CC);
+ assert(is_tmp == 1);
+
+ ALLOC_INIT_ZVAL(ztz_debug);
+ Z_TYPE_P(ztz_debug) = IS_ARRAY;
+ Z_ARRVAL_P(ztz_debug) = debug_info;
+ add_assoc_zval_ex(&zv, "timeZone", sizeof("timeZone"), ztz_debug);
+ }
+
+ {
+ UErrorCode uec = U_ZERO_ERROR;
+ Locale locale = cal->getLocale(ULOC_VALID_LOCALE, uec);
+ if (U_SUCCESS(uec)) {
+ add_assoc_string_ex(&zv, "locale", sizeof("locale"),
+ const_cast<char*>(locale.getName()), 1);
+ } else {
+ add_assoc_string_ex(&zv, "locale", sizeof("locale"),
+ const_cast<char*>(u_errorName(uec)), 1);
+ }
+ }
+
+ ALLOC_INIT_ZVAL(zfields);
+ array_init_size(zfields, UCAL_FIELD_COUNT);
+
+ for (int i = 0;
+ i < sizeof(debug_info_fields) / sizeof(*debug_info_fields);
+ i++) {
+ UErrorCode uec = U_ZERO_ERROR;
+ const char *name = debug_info_fields[i].name;
+ int32_t res = cal->get(debug_info_fields[i].field, uec);
+ if (U_SUCCESS(uec)) {
+ add_assoc_long(zfields, name, (long)res);
+ } else {
+ add_assoc_string(zfields, name, const_cast<char*>(u_errorName(uec)), 1);
+ }
+ }
+
+ add_assoc_zval_ex(&zv, "fields", sizeof("fields"), zfields);
+
+ return Z_ARRVAL(zv);
+}
+/* }}} */
+
+/* {{{ void calendar_object_init(Calendar_object* to)
+ * Initialize internals of Calendar_object not specific to zend standard objects.
+ */
+static void calendar_object_init(Calendar_object *co TSRMLS_DC)
+{
+ intl_error_init(CALENDAR_ERROR_P(co) TSRMLS_CC);
+ co->ucal = NULL;
+}
+/* }}} */
+
+/* {{{ Calendar_objects_dtor */
+static void Calendar_objects_dtor(void *object,
+ zend_object_handle handle TSRMLS_DC)
+{
+ zend_objects_destroy_object((zend_object*)object, handle TSRMLS_CC);
+}
+/* }}} */
+
+/* {{{ Calendar_objects_free */
+static void Calendar_objects_free(zend_object *object TSRMLS_DC)
+{
+ Calendar_object* co = (Calendar_object*) object;
+
+ if (co->ucal) {
+ delete co->ucal;
+ co->ucal = NULL;
+ }
+ intl_error_reset(CALENDAR_ERROR_P(co) TSRMLS_CC);
+
+ zend_object_std_dtor(&co->zo TSRMLS_CC);
+
+ efree(co);
+}
+/* }}} */
+
+/* {{{ Calendar_object_create */
+static zend_object_value Calendar_object_create(zend_class_entry *ce TSRMLS_DC)
+{
+ zend_object_value retval;
+ Calendar_object* intern;
+
+ intern = (Calendar_object*)ecalloc(1, sizeof(Calendar_object));
+
+ zend_object_std_init(&intern->zo, ce TSRMLS_CC);
+#if PHP_VERSION_ID < 50399
+ zend_hash_copy(intern->zo.properties, &(ce->default_properties),
+ (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval*));
+#else
+ object_properties_init((zend_object*) intern, ce);
+#endif
+ calendar_object_init(intern TSRMLS_CC);
+
+ retval.handle = zend_objects_store_put(
+ intern,
+ Calendar_objects_dtor,
+ (zend_objects_free_object_storage_t) Calendar_objects_free,
+ NULL TSRMLS_CC);
+
+ retval.handlers = &Calendar_handlers;
+
+ return retval;
+}
+/* }}} */
+
+/* {{{ Calendar methods arguments info */
+
+ZEND_BEGIN_ARG_INFO_EX(ainfo_cal_void, 0, 0, 0)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX(ainfo_cal_field, 0, 0, 1)
+ ZEND_ARG_INFO(0, field)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX(ainfo_cal_dow, 0, 0, 1)
+ ZEND_ARG_INFO(0, dayOfWeek)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX(ainfo_cal_other_cal, 0, 0, 1)
+ ZEND_ARG_OBJ_INFO(0, calendar, IntlCalendar, 0)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX(ainfo_cal_date, 0, 0, 1)
+ ZEND_ARG_INFO(0, date)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX(ainfo_cal_date_optional, 0, 0, 0)
+ ZEND_ARG_INFO(0, date)
+ZEND_END_ARG_INFO()
+
+
+ZEND_BEGIN_ARG_INFO_EX(ainfo_cal_createInstance, 0, 0, 0)
+ ZEND_ARG_INFO(0, timeZone)
+ ZEND_ARG_INFO(0, locale)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX(ainfo_cal_get_keyword_values_for_locale, 0, 0, 3)
+ ZEND_ARG_INFO(0, key)
+ ZEND_ARG_INFO(0, locale)
+ ZEND_ARG_INFO(0, commonlyUsed)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX(ainfo_cal_add, 0, 0, 2)
+ ZEND_ARG_INFO(0, field)
+ ZEND_ARG_INFO(0, amount)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX(ainfo_cal_setTimeZone, 0, 0, 1)
+ ZEND_ARG_INFO(0, timeZone)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX(ainfo_cal_set, 0, 0, 2)
+ ZEND_ARG_INFO(0, fieldOrYear)
+ ZEND_ARG_INFO(0, valueOrMonth)
+ ZEND_ARG_INFO(0, dayOfMonth)
+ ZEND_ARG_INFO(0, hour)
+ ZEND_ARG_INFO(0, minute)
+ ZEND_ARG_INFO(0, second)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX(ainfo_cal_roll, 0, 0, 2)
+ ZEND_ARG_INFO(0, field)
+ ZEND_ARG_INFO(0, amountOrUpOrDown)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX(ainfo_cal_clear, 0, 0, 0)
+ ZEND_ARG_INFO(0, field)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX(ainfo_cal_field_difference, 0, 0, 2)
+ ZEND_ARG_INFO(0, when)
+ ZEND_ARG_INFO(0, field)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX(ainfo_cal_get_locale, 0, 0, 1)
+ ZEND_ARG_INFO(0, localeType)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX(ainfo_cal_setLenient, 0, 0, 1)
+ ZEND_ARG_INFO(0, isLenient)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX(ainfo_cal_from_date_time, 0, 0, 1)
+ ZEND_ARG_INFO(0, dateTime)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX(ainfo_cal_wall_time_option, 0, 0, 1)
+ ZEND_ARG_INFO(0, wallTimeOption)
+ZEND_END_ARG_INFO()
+
+/* Gregorian Calendar */
+ZEND_BEGIN_ARG_INFO_EX(ainfo_gregcal___construct, 0, 0, 0)
+ ZEND_ARG_INFO(0, timeZoneOrYear)
+ ZEND_ARG_INFO(0, localeOrMonth)
+ ZEND_ARG_INFO(0, dayOfMonth)
+ ZEND_ARG_INFO(0, hour)
+ ZEND_ARG_INFO(0, minute)
+ ZEND_ARG_INFO(0, second)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX(ainfo_gregcal_isLeapYear, 0, 0, 1)
+ ZEND_ARG_INFO(0, year)
+ZEND_END_ARG_INFO()
+
+/* }}} */
+
+/* {{{ Calendar_class_functions
+ * Every 'IntlCalendar' class method has an entry in this table
+ */
+static const zend_function_entry Calendar_class_functions[] = {
+ PHP_ME(IntlCalendar, __construct, ainfo_cal_void, ZEND_ACC_PRIVATE)
+ PHP_ME_MAPPING(createInstance, intlcal_create_instance, ainfo_cal_createInstance, ZEND_ACC_STATIC | ZEND_ACC_PUBLIC)
+#if U_ICU_VERSION_MAJOR_NUM * 10 + U_ICU_VERSION_MINOR_NUM >= 42
+ PHP_ME_MAPPING(getKeywordValuesForLocale, intlcal_get_keyword_values_for_locale, ainfo_cal_get_keyword_values_for_locale, ZEND_ACC_STATIC | ZEND_ACC_PUBLIC)
+#endif
+ PHP_ME_MAPPING(getNow, intlcal_get_now, ainfo_cal_void, ZEND_ACC_STATIC | ZEND_ACC_PUBLIC)
+ PHP_ME_MAPPING(getAvailableLocales, intlcal_get_available_locales, ainfo_cal_void, ZEND_ACC_STATIC | ZEND_ACC_PUBLIC)
+ PHP_ME_MAPPING(get, intlcal_get, ainfo_cal_field, ZEND_ACC_PUBLIC)
+ PHP_ME_MAPPING(getTime, intlcal_get_time, ainfo_cal_void, ZEND_ACC_PUBLIC)
+ PHP_ME_MAPPING(setTime, intlcal_set_time, ainfo_cal_date, ZEND_ACC_PUBLIC)
+ PHP_ME_MAPPING(add, intlcal_add, ainfo_cal_add, ZEND_ACC_PUBLIC)
+ PHP_ME_MAPPING(setTimeZone, intlcal_set_time_zone, ainfo_cal_setTimeZone, ZEND_ACC_PUBLIC)
+ PHP_ME_MAPPING(after, intlcal_after, ainfo_cal_other_cal, ZEND_ACC_PUBLIC)
+ PHP_ME_MAPPING(before, intlcal_before, ainfo_cal_other_cal, ZEND_ACC_PUBLIC)
+ PHP_ME_MAPPING(set, intlcal_set, ainfo_cal_set, ZEND_ACC_PUBLIC)
+ PHP_ME_MAPPING(roll, intlcal_roll, ainfo_cal_roll, ZEND_ACC_PUBLIC)
+ PHP_ME_MAPPING(clear, intlcal_clear, ainfo_cal_clear, ZEND_ACC_PUBLIC)
+ PHP_ME_MAPPING(fieldDifference, intlcal_field_difference, ainfo_cal_field_difference, ZEND_ACC_PUBLIC)
+ PHP_ME_MAPPING(getActualMaximum, intlcal_get_actual_maximum, ainfo_cal_field, ZEND_ACC_PUBLIC)
+ PHP_ME_MAPPING(getActualMinimum, intlcal_get_actual_minimum, ainfo_cal_field, ZEND_ACC_PUBLIC)
+#if U_ICU_VERSION_MAJOR_NUM * 10 + U_ICU_VERSION_MINOR_NUM >= 44
+ PHP_ME_MAPPING(getDayOfWeekType, intlcal_get_day_of_week_type, ainfo_cal_dow, ZEND_ACC_PUBLIC)
+#endif
+ PHP_ME_MAPPING(getFirstDayOfWeek, intlcal_get_first_day_of_week, ainfo_cal_void, ZEND_ACC_PUBLIC)
+ PHP_ME_MAPPING(getGreatestMinimum, intlcal_get_greatest_minimum, ainfo_cal_field, ZEND_ACC_PUBLIC)
+ PHP_ME_MAPPING(getLeastMaximum, intlcal_get_least_maximum, ainfo_cal_field, ZEND_ACC_PUBLIC)
+ PHP_ME_MAPPING(getLocale, intlcal_get_locale, ainfo_cal_get_locale, ZEND_ACC_PUBLIC)
+ PHP_ME_MAPPING(getMaximum, intlcal_get_maximum, ainfo_cal_field, ZEND_ACC_PUBLIC)
+ PHP_ME_MAPPING(getMinimalDaysInFirstWeek, intlcal_get_minimal_days_in_first_week, ainfo_cal_void, ZEND_ACC_PUBLIC)
+ PHP_ME_MAPPING(getMinimum, intlcal_get_minimum, ainfo_cal_field, ZEND_ACC_PUBLIC)
+ PHP_ME_MAPPING(getTimeZone, intlcal_get_time_zone, ainfo_cal_void, ZEND_ACC_PUBLIC)
+ PHP_ME_MAPPING(getType, intlcal_get_type, ainfo_cal_void, ZEND_ACC_PUBLIC)
+#if U_ICU_VERSION_MAJOR_NUM * 10 + U_ICU_VERSION_MINOR_NUM >= 44
+ PHP_ME_MAPPING(getWeekendTransition,intlcal_get_weekend_transition, ainfo_cal_dow, ZEND_ACC_PUBLIC)
+#endif
+ PHP_ME_MAPPING(inDaylightTime, intlcal_in_daylight_time, ainfo_cal_void, ZEND_ACC_PUBLIC)
+ PHP_ME_MAPPING(isEquivalentTo, intlcal_is_equivalent_to, ainfo_cal_other_cal, ZEND_ACC_PUBLIC)
+ PHP_ME_MAPPING(isLenient, intlcal_is_lenient, ainfo_cal_void, ZEND_ACC_PUBLIC)
+ PHP_ME_MAPPING(isSet, intlcal_is_set, ainfo_cal_field, ZEND_ACC_PUBLIC)
+#if U_ICU_VERSION_MAJOR_NUM * 10 + U_ICU_VERSION_MINOR_NUM >= 44
+ PHP_ME_MAPPING(isWeekend, intlcal_is_weekend, ainfo_cal_date_optional, ZEND_ACC_PUBLIC)
+#endif
+ PHP_ME_MAPPING(setFirstDayOfWeek, intlcal_set_first_day_of_week, ainfo_cal_dow, ZEND_ACC_PUBLIC)
+ PHP_ME_MAPPING(setLenient, intlcal_set_lenient, ainfo_cal_setLenient, ZEND_ACC_PUBLIC)
+ PHP_ME_MAPPING(equals, intlcal_equals, ainfo_cal_other_cal, ZEND_ACC_PUBLIC)
+#if U_ICU_VERSION_MAJOR_NUM >= 49
+ PHP_ME_MAPPING(getRepeatedWallTimeOption,intlcal_get_repeated_wall_time_option,ainfo_cal_void, ZEND_ACC_PUBLIC)
+ PHP_ME_MAPPING(getSkippedWallTimeOption,intlcal_get_skipped_wall_time_option,ainfo_cal_void, ZEND_ACC_PUBLIC)
+ PHP_ME_MAPPING(setRepeatedWallTimeOption,intlcal_set_repeated_wall_time_option,ainfo_cal_wall_time_option,ZEND_ACC_PUBLIC)
+ PHP_ME_MAPPING(setSkippedWallTimeOption,intlcal_set_skipped_wall_time_option,ainfo_cal_wall_time_option,ZEND_ACC_PUBLIC)
+#endif
+ PHP_ME_MAPPING(fromDateTime, intlcal_from_date_time, ainfo_cal_from_date_time, ZEND_ACC_STATIC | ZEND_ACC_PUBLIC)
+ PHP_ME_MAPPING(toDateTime, intlcal_to_date_time, ainfo_cal_void, ZEND_ACC_PUBLIC)
+ PHP_ME_MAPPING(getErrorCode, intlcal_get_error_code, ainfo_cal_void, ZEND_ACC_PUBLIC)
+ PHP_ME_MAPPING(getErrorMessage, intlcal_get_error_message, ainfo_cal_void, ZEND_ACC_PUBLIC)
+ PHP_FE_END
+};
+/* }}} */
+
+/* {{{ GregorianCalendar_class_functions
+ */
+static const zend_function_entry GregorianCalendar_class_functions[] = {
+ PHP_ME(IntlGregorianCalendar, __construct, ainfo_gregcal___construct, ZEND_ACC_PUBLIC)
+ PHP_ME_MAPPING(setGregorianChange, intlgregcal_set_gregorian_change, ainfo_cal_date, ZEND_ACC_PUBLIC)
+ PHP_ME_MAPPING(getGregorianChange, intlgregcal_get_gregorian_change, ainfo_cal_void, ZEND_ACC_PUBLIC)
+ PHP_ME_MAPPING(isLeapYear, intlgregcal_is_leap_year, ainfo_gregcal_isLeapYear, ZEND_ACC_PUBLIC)
+ PHP_FE_END
+};
+/* }}} */
+
+
+/* {{{ calendar_register_IntlCalendar_class
+ * Initialize 'IntlCalendar' class
+ */
+void calendar_register_IntlCalendar_class(TSRMLS_D)
+{
+ zend_class_entry ce;
+
+ /* Create and register 'IntlCalendar' class. */
+ INIT_CLASS_ENTRY(ce, "IntlCalendar", Calendar_class_functions);
+ ce.create_object = Calendar_object_create;
+ Calendar_ce_ptr = zend_register_internal_class(&ce TSRMLS_CC);
+ if (!Calendar_ce_ptr) {
+ //can't happen now without bigger problems before
+ php_error_docref0(NULL TSRMLS_CC, E_ERROR,
+ "IntlCalendar: class registration has failed.");
+ return;
+ }
+ memcpy( &Calendar_handlers, zend_get_std_object_handlers(),
+ sizeof Calendar_handlers);
+ Calendar_handlers.clone_obj = Calendar_clone_obj;
+ Calendar_handlers.get_debug_info = Calendar_get_debug_info;
+
+ /* Create and register 'IntlGregorianCalendar' class. */
+ INIT_CLASS_ENTRY(ce, "IntlGregorianCalendar", GregorianCalendar_class_functions);
+ GregorianCalendar_ce_ptr = zend_register_internal_class_ex(&ce,
+ Calendar_ce_ptr, NULL TSRMLS_CC);
+ if (!GregorianCalendar_ce_ptr) {
+ //can't happen know without bigger problems before
+ php_error_docref0(NULL TSRMLS_CC, E_ERROR,
+ "IntlGregorianCalendar: class registration has failed.");
+ return;
+ }
+
+ /* Declare 'IntlCalendar' class constants */
+#define CALENDAR_DECL_LONG_CONST(name, val) \
+ zend_declare_class_constant_long(Calendar_ce_ptr, name, sizeof(name) - 1, \
+ val TSRMLS_CC)
+
+ CALENDAR_DECL_LONG_CONST("FIELD_ERA", UCAL_ERA);
+ CALENDAR_DECL_LONG_CONST("FIELD_YEAR", UCAL_YEAR);
+ CALENDAR_DECL_LONG_CONST("FIELD_MONTH", UCAL_MONTH);
+ CALENDAR_DECL_LONG_CONST("FIELD_WEEK_OF_YEAR", UCAL_WEEK_OF_YEAR);
+ CALENDAR_DECL_LONG_CONST("FIELD_WEEK_OF_MONTH", UCAL_WEEK_OF_MONTH);
+ CALENDAR_DECL_LONG_CONST("FIELD_DATE", UCAL_DATE);
+ CALENDAR_DECL_LONG_CONST("FIELD_DAY_OF_YEAR", UCAL_DAY_OF_YEAR);
+ CALENDAR_DECL_LONG_CONST("FIELD_DAY_OF_WEEK", UCAL_DAY_OF_WEEK);
+ CALENDAR_DECL_LONG_CONST("FIELD_DAY_OF_WEEK_IN_MONTH", UCAL_DAY_OF_WEEK_IN_MONTH);
+ CALENDAR_DECL_LONG_CONST("FIELD_AM_PM", UCAL_AM_PM);
+ CALENDAR_DECL_LONG_CONST("FIELD_HOUR", UCAL_HOUR);
+ CALENDAR_DECL_LONG_CONST("FIELD_HOUR_OF_DAY", UCAL_HOUR_OF_DAY);
+ CALENDAR_DECL_LONG_CONST("FIELD_HOUR", UCAL_HOUR);
+ CALENDAR_DECL_LONG_CONST("FIELD_HOUR_OF_DAY", UCAL_HOUR_OF_DAY);
+ CALENDAR_DECL_LONG_CONST("FIELD_MINUTE", UCAL_MINUTE);
+ CALENDAR_DECL_LONG_CONST("FIELD_SECOND", UCAL_SECOND);
+ CALENDAR_DECL_LONG_CONST("FIELD_MILLISECOND", UCAL_MILLISECOND);
+ CALENDAR_DECL_LONG_CONST("FIELD_ZONE_OFFSET", UCAL_ZONE_OFFSET);
+ CALENDAR_DECL_LONG_CONST("FIELD_DST_OFFSET", UCAL_DST_OFFSET);
+ CALENDAR_DECL_LONG_CONST("FIELD_YEAR_WOY", UCAL_YEAR_WOY);
+ CALENDAR_DECL_LONG_CONST("FIELD_DOW_LOCAL", UCAL_DOW_LOCAL);
+ CALENDAR_DECL_LONG_CONST("FIELD_EXTENDED_YEAR", UCAL_EXTENDED_YEAR);
+ CALENDAR_DECL_LONG_CONST("FIELD_JULIAN_DAY", UCAL_JULIAN_DAY);
+ CALENDAR_DECL_LONG_CONST("FIELD_MILLISECONDS_IN_DAY", UCAL_MILLISECONDS_IN_DAY);
+ CALENDAR_DECL_LONG_CONST("FIELD_IS_LEAP_MONTH", UCAL_IS_LEAP_MONTH);
+ CALENDAR_DECL_LONG_CONST("FIELD_FIELD_COUNT ", UCAL_FIELD_COUNT);
+ CALENDAR_DECL_LONG_CONST("FIELD_DAY_OF_MONTH", UCAL_DAY_OF_MONTH);
+
+ CALENDAR_DECL_LONG_CONST("DOW_SUNDAY", UCAL_SUNDAY);
+ CALENDAR_DECL_LONG_CONST("DOW_MONDAY", UCAL_MONDAY);
+ CALENDAR_DECL_LONG_CONST("DOW_TUESDAY", UCAL_TUESDAY);
+ CALENDAR_DECL_LONG_CONST("DOW_WEDNESDAY", UCAL_WEDNESDAY);
+ CALENDAR_DECL_LONG_CONST("DOW_THURSDAY", UCAL_THURSDAY);
+ CALENDAR_DECL_LONG_CONST("DOW_FRIDAY", UCAL_FRIDAY);
+ CALENDAR_DECL_LONG_CONST("DOW_SATURDAY", UCAL_SATURDAY);
+
+#if U_ICU_VERSION_MAJOR_NUM * 10 + U_ICU_VERSION_MINOR_NUM >= 44
+ CALENDAR_DECL_LONG_CONST("DOW_TYPE_WEEKDAY", UCAL_WEEKDAY);
+ CALENDAR_DECL_LONG_CONST("DOW_TYPE_WEEKEND", UCAL_WEEKEND);
+ CALENDAR_DECL_LONG_CONST("DOW_TYPE_WEEKEND_OFFSET", UCAL_WEEKEND_ONSET);
+ CALENDAR_DECL_LONG_CONST("DOW_TYPE_WEEKEND_CEASE", UCAL_WEEKEND_CEASE);
+#endif
+
+#if U_ICU_VERSION_MAJOR_NUM >= 49
+ CALENDAR_DECL_LONG_CONST("WALLTIME_FIRST", UCAL_WALLTIME_FIRST);
+ CALENDAR_DECL_LONG_CONST("WALLTIME_LAST", UCAL_WALLTIME_LAST);
+ CALENDAR_DECL_LONG_CONST("WALLTIME_NEXT_VALID", UCAL_WALLTIME_NEXT_VALID);
+#endif
+}
+/* }}} */
diff --git a/ext/intl/calendar/calendar_class.h b/ext/intl/calendar/calendar_class.h
new file mode 100644
index 0000000000..140389b639
--- /dev/null
+++ b/ext/intl/calendar/calendar_class.h
@@ -0,0 +1,70 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Gustavo Lopes <cataphract@php.net> |
+ +----------------------------------------------------------------------+
+ */
+
+#ifndef CALENDAR_CLASS_H
+#define CALENDAR_CLASS_H
+
+//redefinition of inline in PHP headers causes problems, so include this before
+#include <math.h>
+
+#include <php.h>
+#include "intl_error.h"
+#include "intl_data.h"
+
+#ifndef USE_CALENDAR_POINTER
+typedef void Calendar;
+#endif
+
+typedef struct {
+ zend_object zo;
+
+ // error handling
+ intl_error err;
+
+ // ICU calendar
+ Calendar* ucal;
+} Calendar_object;
+
+#define CALENDAR_ERROR(co) (co)->err
+#define CALENDAR_ERROR_P(co) &(CALENDAR_ERROR(co))
+
+#define CALENDAR_ERROR_CODE(co) INTL_ERROR_CODE(CALENDAR_ERROR(co))
+#define CALENDAR_ERROR_CODE_P(co) &(INTL_ERROR_CODE(CALENDAR_ERROR(co)))
+
+#define CALENDAR_METHOD_INIT_VARS INTL_METHOD_INIT_VARS(Calendar, co)
+#define CALENDAR_METHOD_FETCH_OBJECT_NO_CHECK INTL_METHOD_FETCH_OBJECT(Calendar, co)
+#define CALENDAR_METHOD_FETCH_OBJECT \
+ CALENDAR_METHOD_FETCH_OBJECT_NO_CHECK; \
+ if (co->ucal == NULL) \
+ { \
+ intl_errors_set(&co->err, U_ILLEGAL_ARGUMENT_ERROR, "Found unconstructed IntlCalendar", 0 TSRMLS_CC); \
+ RETURN_FALSE; \
+ }
+
+void calendar_object_create(zval *object, Calendar *calendar TSRMLS_DC);
+
+Calendar *calendar_fetch_native_calendar(zval *object TSRMLS_DC);
+
+void calendar_object_construct(zval *object, Calendar *calendar TSRMLS_DC);
+
+void calendar_register_IntlCalendar_class(TSRMLS_D);
+
+extern zend_class_entry *Calendar_ce_ptr,
+ *GregorianCalendar_ce_ptr;
+
+extern zend_object_handlers Calendar_handlers;
+
+#endif /* #ifndef CALENDAR_CLASS_H */
diff --git a/ext/intl/calendar/calendar_methods.cpp b/ext/intl/calendar/calendar_methods.cpp
new file mode 100644
index 0000000000..2d33bd1952
--- /dev/null
+++ b/ext/intl/calendar/calendar_methods.cpp
@@ -0,0 +1,1328 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Gustavo Lopes <cataphract@php.net> |
+ +----------------------------------------------------------------------+
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "../intl_cppshims.h"
+
+#include <unicode/locid.h>
+#include <unicode/calendar.h>
+#include <unicode/ustring.h>
+
+#include "../intl_convertcpp.h"
+#include "../common/common_date.h"
+
+extern "C" {
+#include "../php_intl.h"
+#define USE_TIMEZONE_POINTER 1
+#include "../timezone/timezone_class.h"
+#define USE_CALENDAR_POINTER 1
+#include "calendar_class.h"
+#include "../intl_convert.h"
+#include <zend_exceptions.h>
+#include <zend_interfaces.h>
+#include <ext/date/php_date.h>
+}
+#include "../common/common_enum.h"
+
+U_CFUNC PHP_METHOD(IntlCalendar, __construct)
+{
+ zend_throw_exception( NULL,
+ "An object of this type cannot be created with the new operator",
+ 0 TSRMLS_CC );
+}
+
+U_CFUNC PHP_FUNCTION(intlcal_create_instance)
+{
+ zval **zv_timezone = NULL;
+ const char *locale_str = NULL;
+ int dummy;
+ TimeZone *timeZone;
+ UErrorCode status = U_ZERO_ERROR;
+ intl_error_reset(NULL TSRMLS_CC);
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|Zs!",
+ &zv_timezone, &locale_str, &dummy) == FAILURE) {
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "intlcal_create_calendar: bad arguments", 0 TSRMLS_CC);
+ RETURN_NULL();
+ }
+
+ timeZone = timezone_process_timezone_argument(zv_timezone, NULL,
+ "intlcal_create_instance" TSRMLS_CC);
+ if (timeZone == NULL) {
+ RETURN_NULL();
+ }
+
+ if (!locale_str) {
+ locale_str = intl_locale_get_default(TSRMLS_C);
+ }
+
+ Calendar *cal = Calendar::createInstance(timeZone,
+ Locale::createFromName(locale_str), status);
+ if (cal == NULL) {
+ delete timeZone;
+ intl_error_set(NULL, status, "Error creating ICU Calendar object", 0 TSRMLS_CC);
+ RETURN_NULL();
+ }
+
+ calendar_object_create(return_value, cal TSRMLS_CC);
+}
+
+#if U_ICU_VERSION_MAJOR_NUM * 10 + U_ICU_VERSION_MINOR_NUM >= 42
+class BugStringCharEnumeration : public StringEnumeration
+{
+public:
+ BugStringCharEnumeration(UEnumeration* _uenum) : uenum(_uenum) {}
+
+ ~BugStringCharEnumeration()
+ {
+ uenum_close(uenum);
+ }
+
+ int32_t count(UErrorCode& status) const {
+ return uenum_count(uenum, &status);
+ }
+
+ virtual const UnicodeString* snext(UErrorCode& status)
+ {
+ int32_t length;
+ const UChar* str = uenum_unext(uenum, &length, &status);
+ if (str == 0 || U_FAILURE(status)) {
+ return 0;
+ }
+ return &unistr.setTo(str, length);
+ }
+
+ virtual const char* next(int32_t *resultLength, UErrorCode &status)
+ {
+ int32_t length = -1;
+ const char* str = uenum_next(uenum, &length, &status);
+ if (str == 0 || U_FAILURE(status)) {
+ return 0;
+ }
+ if (resultLength) {
+ //the bug is that uenum_next doesn't set the length
+ *resultLength = (length == -1) ? strlen(str) : length;
+ }
+
+ return str;
+ }
+
+ void reset(UErrorCode& status)
+ {
+ uenum_reset(uenum, &status);
+ }
+
+ virtual UClassID getDynamicClassID() const;
+
+ static UClassID U_EXPORT2 getStaticClassID();
+
+private:
+ UEnumeration *uenum;
+};
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(BugStringCharEnumeration)
+
+U_CFUNC PHP_FUNCTION(intlcal_get_keyword_values_for_locale)
+{
+ UErrorCode status = U_ZERO_ERROR;
+ char *key,
+ *locale;
+ int key_len,
+ locale_len;
+ zend_bool commonly_used;
+ intl_error_reset(NULL TSRMLS_CC);
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ssb",
+ &key, &key_len, &locale, &locale_len, &commonly_used) == FAILURE) {
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "intlcal_get_keyword_values_for_locale: bad arguments", 0 TSRMLS_CC);
+ RETURN_FALSE;
+ }
+
+ //does not work; see ICU bug 9194
+#if 0
+ StringEnumeration *se = Calendar::getKeywordValuesForLocale(key,
+ Locale::createFromName(locale), (UBool)commonly_used,
+ status);
+ if (se == NULL) {
+ intl_error_set(NULL, status, "intlcal_get_keyword_values_for_locale: "
+ "error calling underlying method", 0 TSRMLS_CC);
+ RETURN_FALSE;
+ }
+#else
+ UEnumeration *uenum = ucal_getKeywordValuesForLocale(
+ key, locale, !!commonly_used, &status);
+ if (U_FAILURE(status)) {
+ uenum_close(uenum);
+ intl_error_set(NULL, status, "intlcal_get_keyword_values_for_locale: "
+ "error calling underlying method", 0 TSRMLS_CC);
+ RETURN_FALSE;
+ }
+
+ StringEnumeration *se = new BugStringCharEnumeration(uenum);
+#endif
+
+ IntlIterator_from_StringEnumeration(se, return_value TSRMLS_CC);
+}
+#endif //ICU 4.2 only
+
+U_CFUNC PHP_FUNCTION(intlcal_get_now)
+{
+ UErrorCode status = U_ZERO_ERROR;
+ intl_error_reset(NULL TSRMLS_CC);
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "intlcal_get_now: bad arguments", 0 TSRMLS_CC);
+ RETURN_FALSE;
+ }
+
+ RETURN_DOUBLE((double)Calendar::getNow());
+}
+
+U_CFUNC PHP_FUNCTION(intlcal_get_available_locales)
+{
+ intl_error_reset(NULL TSRMLS_CC);
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "intlcal_get_available_locales: bad arguments", 0 TSRMLS_CC);
+ RETURN_FALSE;
+ }
+
+ int32_t count;
+ const Locale *availLocales = Calendar::getAvailableLocales(count);
+ array_init(return_value);
+ for (int i = 0; i < count; i++) {
+ Locale locale = availLocales[i];
+ add_next_index_string(return_value, locale.getName(), 1);
+ }
+}
+
+static void _php_intlcal_field_uec_ret_in32t_method(
+ int32_t (Calendar::*func)(UCalendarDateFields, UErrorCode&) const,
+ const char *method_name,
+ INTERNAL_FUNCTION_PARAMETERS)
+{
+ long field;
+ char *message;
+ CALENDAR_METHOD_INIT_VARS;
+
+ if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(),
+ "Ol", &object, Calendar_ce_ptr, &field) == FAILURE) {
+ spprintf(&message, 0, "%s: bad arguments", method_name);
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, message, 1 TSRMLS_CC);
+ efree(message);
+ RETURN_FALSE;
+ }
+
+ if (field < 0 || field >= UCAL_FIELD_COUNT) {
+ spprintf(&message, 0, "%s: invalid field", method_name);
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, message, 1 TSRMLS_CC);
+ efree(message);
+ RETURN_FALSE;
+ }
+
+ CALENDAR_METHOD_FETCH_OBJECT;
+
+ int32_t result = (co->ucal->*func)(
+ (UCalendarDateFields)field, CALENDAR_ERROR_CODE(co));
+ INTL_METHOD_CHECK_STATUS(co, "Call to ICU method has failed");
+
+ RETURN_LONG((long)result);
+}
+
+U_CFUNC PHP_FUNCTION(intlcal_get)
+{
+ _php_intlcal_field_uec_ret_in32t_method(&Calendar::get,
+ "intlcal_get", INTERNAL_FUNCTION_PARAM_PASSTHRU);
+}
+
+U_CFUNC PHP_FUNCTION(intlcal_get_time)
+{
+ CALENDAR_METHOD_INIT_VARS;
+
+ if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O",
+ &object, Calendar_ce_ptr) == FAILURE) {
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "intlcal_get_time: bad arguments", 0 TSRMLS_CC);
+ RETURN_FALSE;
+ }
+
+ CALENDAR_METHOD_FETCH_OBJECT;
+
+ UDate result = co->ucal->getTime(CALENDAR_ERROR_CODE(co));
+ INTL_METHOD_CHECK_STATUS(co,
+ "intlcal_get_time: error calling ICU Calendar::getTime");
+
+ RETURN_DOUBLE((double)result);
+}
+
+U_CFUNC PHP_FUNCTION(intlcal_set_time)
+{
+ double time_arg;
+ CALENDAR_METHOD_INIT_VARS;
+
+ if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Od",
+ &object, Calendar_ce_ptr, &time_arg) == FAILURE) {
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "intlcal_set_time: bad arguments", 0 TSRMLS_CC);
+ RETURN_FALSE;
+ }
+
+ CALENDAR_METHOD_FETCH_OBJECT;
+
+ co->ucal->setTime((UDate)time_arg, CALENDAR_ERROR_CODE(co));
+ INTL_METHOD_CHECK_STATUS(co, "Call to underlying method failed");
+
+ RETURN_TRUE;
+}
+
+U_CFUNC PHP_FUNCTION(intlcal_add)
+{
+ long field,
+ amount;
+ CALENDAR_METHOD_INIT_VARS;
+
+ if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(),
+ "Oll", &object, Calendar_ce_ptr, &field, &amount) == FAILURE) {
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "intlcal_add: bad arguments", 0 TSRMLS_CC);
+ RETURN_FALSE;
+ }
+
+ if (field < 0 || field >= UCAL_FIELD_COUNT) {
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "intlcal_add: invalid field", 0 TSRMLS_CC);
+ RETURN_FALSE;
+ }
+ if (amount < INT32_MIN || amount > INT32_MAX) {
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "intlcal_add: amount out of bounds", 0 TSRMLS_CC);
+ RETURN_FALSE;
+ }
+
+ CALENDAR_METHOD_FETCH_OBJECT;
+
+ co->ucal->add((UCalendarDateFields)field, (int32_t)amount, CALENDAR_ERROR_CODE(co));
+ INTL_METHOD_CHECK_STATUS(co, "intlcal_add: Call to underlying method failed");
+
+ RETURN_TRUE;
+}
+
+U_CFUNC PHP_FUNCTION(intlcal_set_time_zone)
+{
+ zval *zv_timezone;
+ TimeZone *timeZone;
+ CALENDAR_METHOD_INIT_VARS;
+
+ if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(),
+ "Oz!", &object, Calendar_ce_ptr, &zv_timezone) == FAILURE) {
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "intlcal_set_time_zone: bad arguments", 0 TSRMLS_CC);
+ RETURN_FALSE;
+ }
+
+ CALENDAR_METHOD_FETCH_OBJECT;
+
+ if (zv_timezone == NULL) {
+ RETURN_TRUE; /* the method does nothing if passed null */
+ }
+
+ timeZone = timezone_process_timezone_argument(&zv_timezone,
+ CALENDAR_ERROR_P(co), "intlcal_set_time_zone" TSRMLS_CC);
+ if (timeZone == NULL) {
+ RETURN_FALSE;
+ }
+
+ co->ucal->adoptTimeZone(timeZone);
+
+ RETURN_TRUE;
+}
+
+
+static void _php_intlcal_before_after(
+ UBool (Calendar::*func)(const Calendar&, UErrorCode&) const,
+ INTERNAL_FUNCTION_PARAMETERS)
+{
+ zval *when_object;
+ Calendar_object *when_co;
+ CALENDAR_METHOD_INIT_VARS;
+
+ if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(),
+ "OO", &object, Calendar_ce_ptr, &when_object, Calendar_ce_ptr)
+ == FAILURE) {
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "intlcal_before/after: bad arguments", 0 TSRMLS_CC);
+ RETURN_FALSE;
+ }
+
+ CALENDAR_METHOD_FETCH_OBJECT;
+
+ when_co = static_cast<Calendar_object*>(
+ zend_object_store_get_object(when_object TSRMLS_CC));
+ if (when_co->ucal == NULL) {
+ intl_errors_set(&co->err, U_ILLEGAL_ARGUMENT_ERROR,
+ "intlcal_before/after: Other IntlCalendar was unconstructed", 0 TSRMLS_CC);
+ RETURN_FALSE;
+ }
+
+ UBool res = (co->ucal->*func)(*when_co->ucal, CALENDAR_ERROR_CODE(co));
+ INTL_METHOD_CHECK_STATUS(co, "intlcal_before/after: Error calling ICU method");
+
+ RETURN_BOOL((int)res);
+}
+
+U_CFUNC PHP_FUNCTION(intlcal_after)
+{
+ _php_intlcal_before_after(&Calendar::after, INTERNAL_FUNCTION_PARAM_PASSTHRU);
+}
+
+U_CFUNC PHP_FUNCTION(intlcal_before)
+{
+ _php_intlcal_before_after(&Calendar::before, INTERNAL_FUNCTION_PARAM_PASSTHRU);
+}
+
+U_CFUNC PHP_FUNCTION(intlcal_set)
+{
+ long arg1, arg2, arg3, arg4, arg5, arg6;
+ zval **args_a[7] = {0},
+ ***args = &args_a[0];
+ int i;
+ int variant; /* number of args of the set() overload */
+ CALENDAR_METHOD_INIT_VARS;
+
+ /* must come before zpp because zpp would convert the args in the stack to 0 */
+ if (ZEND_NUM_ARGS() > (getThis() ? 6 : 7) ||
+ zend_get_parameters_array_ex(ZEND_NUM_ARGS(), args) == FAILURE) {
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "intlcal_set: too many arguments", 0 TSRMLS_CC);
+ RETURN_FALSE;
+ }
+ if (!getThis()) {
+ args++;
+ }
+ variant = ZEND_NUM_ARGS() - (getThis() ? 0 : 1);
+ while (variant > 2 && Z_TYPE_PP(args[variant - 1]) == IS_NULL) {
+ variant--;
+ }
+
+ if (variant == 4 ||
+ zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(),
+ "Oll|llll", &object, Calendar_ce_ptr, &arg1, &arg2, &arg3, &arg4,
+ &arg5, &arg6) == FAILURE) {
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "intlcal_set: bad arguments", 0 TSRMLS_CC);
+ RETURN_FALSE;
+ }
+
+ for (i = 0; i < variant; i++) {
+ if (Z_LVAL_PP(args[i]) < INT32_MIN || Z_LVAL_PP(args[i]) > INT32_MAX) {
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "intlcal_set: at least one of the arguments has an absolute "
+ "value that is too large", 0 TSRMLS_CC);
+ RETURN_FALSE;
+ }
+ }
+
+ if (variant == 2 && (arg1 < 0 || arg1 >= UCAL_FIELD_COUNT)) {
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "intlcal_set: invalid field", 0 TSRMLS_CC);
+ RETURN_FALSE;
+ }
+
+ CALENDAR_METHOD_FETCH_OBJECT;
+
+ if (variant == 2) {
+ co->ucal->set((UCalendarDateFields)arg1, (int32_t)arg2);
+ } else if (variant == 3) {
+ co->ucal->set((int32_t)arg1, (int32_t)arg2, (int32_t)arg3);
+ } else if (variant == 5) {
+ co->ucal->set((int32_t)arg1, (int32_t)arg2, (int32_t)arg3, (int32_t)arg4, (int32_t)arg5);
+ } else if (variant == 6) {
+ co->ucal->set((int32_t)arg1, (int32_t)arg2, (int32_t)arg3, (int32_t)arg4, (int32_t)arg5, (int32_t)arg6);
+ }
+
+ RETURN_TRUE;
+}
+
+U_CFUNC PHP_FUNCTION(intlcal_roll)
+{
+ long field,
+ value;
+ zval **args_a[3] = {0},
+ ***args = &args_a[0];
+ zend_bool bool_variant_val = (zend_bool)-1;
+ CALENDAR_METHOD_INIT_VARS;
+
+ if (ZEND_NUM_ARGS() > (getThis() ? 2 :3) ||
+ zend_get_parameters_array_ex(ZEND_NUM_ARGS(), args) == FAILURE) {
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "intlcal_set: too many arguments", 0 TSRMLS_CC);
+ RETURN_FALSE;
+ }
+ if (!getThis()) {
+ args++;
+ }
+ if (args[1] != NULL && Z_TYPE_PP(args[1]) == IS_BOOL) {
+ if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(),
+ "Olb", &object, Calendar_ce_ptr, &field, &bool_variant_val)
+ == FAILURE) {
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "intlcal_roll: bad arguments", 0 TSRMLS_CC);
+ RETURN_FALSE;
+ }
+ bool_variant_val = Z_BVAL_PP(args[1]);
+ } else if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(),
+ "Oll", &object, Calendar_ce_ptr, &field, &value) == FAILURE) {
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "intlcal_roll: bad arguments", 0 TSRMLS_CC);
+ RETURN_FALSE;
+ }
+
+ if (field < 0 || field >= UCAL_FIELD_COUNT) {
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "intlcal_roll: invalid field", 0 TSRMLS_CC);
+ RETURN_FALSE;
+ }
+ if (bool_variant_val == (zend_bool)-1 &&
+ (value < INT32_MIN || value > INT32_MAX)) {
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "intlcal_roll: value out of bounds", 0 TSRMLS_CC);
+ RETURN_FALSE;
+ }
+
+ CALENDAR_METHOD_FETCH_OBJECT;
+
+ if (bool_variant_val != (zend_bool)-1) {
+ co->ucal->roll((UCalendarDateFields)field, (UBool)bool_variant_val,
+ CALENDAR_ERROR_CODE(co));
+ } else {
+ co->ucal->roll((UCalendarDateFields)field, (int32_t)value,
+ CALENDAR_ERROR_CODE(co));
+ }
+ INTL_METHOD_CHECK_STATUS(co, "intlcal_roll: Error calling ICU Calendar::roll");
+
+ RETURN_TRUE;
+}
+
+U_CFUNC PHP_FUNCTION(intlcal_clear)
+{
+ zval **args_a[2] = {0},
+ ***args = &args_a[0];
+ long field;
+ int variant;
+ CALENDAR_METHOD_INIT_VARS;
+
+ if (ZEND_NUM_ARGS() > (getThis() ? 1 : 2) ||
+ zend_get_parameters_array_ex(ZEND_NUM_ARGS(), args) == FAILURE) {
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "intlcal_clear: too many arguments", 0 TSRMLS_CC);
+ RETURN_FALSE;
+ }
+ if (!getThis()) {
+ args++;
+ }
+ if (args[0] == NULL || Z_TYPE_PP(args[0]) == IS_NULL) {
+ zval *dummy; /* we know it's null */
+ if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC,
+ getThis(), "O|z", &object, Calendar_ce_ptr, &dummy) == FAILURE) {
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "intlcal_clear: bad arguments", 0 TSRMLS_CC);
+ RETURN_FALSE;
+ }
+ variant = 0;
+ } else if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC,
+ getThis(), "Ol", &object, Calendar_ce_ptr, &field) == FAILURE) {
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "intlcal_clear: bad arguments", 0 TSRMLS_CC);
+ RETURN_FALSE;
+ } else if (field < 0 || field >= UCAL_FIELD_COUNT) {
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "intlcal_clear: invalid field", 0 TSRMLS_CC);
+ RETURN_FALSE;
+ } else {
+ variant = 1;
+ }
+
+ CALENDAR_METHOD_FETCH_OBJECT;
+
+ if (variant == 0) {
+ co->ucal->clear();
+ } else {
+ co->ucal->clear((UCalendarDateFields)field);
+ }
+
+ RETURN_TRUE;
+}
+
+U_CFUNC PHP_FUNCTION(intlcal_field_difference)
+{
+ long field;
+ double when;
+ CALENDAR_METHOD_INIT_VARS;
+
+ if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(),
+ "Odl", &object, Calendar_ce_ptr, &when, &field) == FAILURE) {
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "intlcal_field_difference: bad arguments", 0 TSRMLS_CC);
+ RETURN_FALSE;
+ }
+
+ if (field < 0 || field >= UCAL_FIELD_COUNT) {
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "intlcal_field_difference: invalid field", 0 TSRMLS_CC);
+ RETURN_FALSE;
+ }
+
+ CALENDAR_METHOD_FETCH_OBJECT;
+
+ int32_t result = co->ucal->fieldDifference((UDate)when,
+ (UCalendarDateFields)field, CALENDAR_ERROR_CODE(co));
+ INTL_METHOD_CHECK_STATUS(co,
+ "intlcal_field_difference: Call to ICU method has failed");
+
+ RETURN_LONG((long)result);
+}
+
+U_CFUNC PHP_FUNCTION(intlcal_get_actual_maximum)
+{
+ _php_intlcal_field_uec_ret_in32t_method(&Calendar::getActualMaximum,
+ "intlcal_get_actual_maximum", INTERNAL_FUNCTION_PARAM_PASSTHRU);
+}
+
+U_CFUNC PHP_FUNCTION(intlcal_get_actual_minimum)
+{
+ _php_intlcal_field_uec_ret_in32t_method(&Calendar::getActualMinimum,
+ "intlcal_get_actual_minimum", INTERNAL_FUNCTION_PARAM_PASSTHRU);
+}
+
+#if U_ICU_VERSION_MAJOR_NUM * 10 + U_ICU_VERSION_MINOR_NUM >= 44
+U_CFUNC PHP_FUNCTION(intlcal_get_day_of_week_type)
+{
+ long dow;
+ CALENDAR_METHOD_INIT_VARS;
+
+ if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(),
+ "Ol", &object, Calendar_ce_ptr, &dow) == FAILURE) {
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "intlcal_get_day_of_week_type: bad arguments", 0 TSRMLS_CC);
+ RETURN_FALSE;
+ }
+
+ if (dow < UCAL_SUNDAY || dow > UCAL_SATURDAY) {
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "intlcal_get_day_of_week_type: invalid day of week", 0 TSRMLS_CC);
+ RETURN_FALSE;
+ }
+
+ CALENDAR_METHOD_FETCH_OBJECT;
+
+ int32_t result = co->ucal->getDayOfWeekType(
+ (UCalendarDaysOfWeek)dow, CALENDAR_ERROR_CODE(co));
+ INTL_METHOD_CHECK_STATUS(co,
+ "intlcal_get_day_of_week_type: Call to ICU method has failed");
+
+ RETURN_LONG((long)result);
+}
+#endif
+
+U_CFUNC PHP_FUNCTION(intlcal_get_first_day_of_week)
+{
+ CALENDAR_METHOD_INIT_VARS;
+
+ if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(),
+ "O", &object, Calendar_ce_ptr) == FAILURE) {
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "intlcal_get_first_day_of_week: bad arguments", 0 TSRMLS_CC);
+ RETURN_FALSE;
+ }
+
+ CALENDAR_METHOD_FETCH_OBJECT;
+
+ int32_t result = co->ucal->getFirstDayOfWeek(CALENDAR_ERROR_CODE(co));
+ INTL_METHOD_CHECK_STATUS(co,
+ "intlcal_get_first_day_of_week: Call to ICU method has failed");
+
+ RETURN_LONG((long)result);
+}
+
+static void _php_intlcal_field_ret_in32t_method(
+ int32_t (Calendar::*func)(UCalendarDateFields) const,
+ const char *method_name,
+ INTERNAL_FUNCTION_PARAMETERS)
+{
+ long field;
+ char *message;
+ CALENDAR_METHOD_INIT_VARS;
+
+ if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(),
+ "Ol", &object, Calendar_ce_ptr, &field) == FAILURE) {
+ spprintf(&message, 0, "%s: bad arguments", method_name);
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, message, 1 TSRMLS_CC);
+ efree(message);
+ RETURN_FALSE;
+ }
+
+ if (field < 0 || field >= UCAL_FIELD_COUNT) {
+ spprintf(&message, 0, "%s: invalid field", method_name);
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, message, 1 TSRMLS_CC);
+ efree(message);
+ RETURN_FALSE;
+ }
+
+ CALENDAR_METHOD_FETCH_OBJECT;
+
+ int32_t result = (co->ucal->*func)((UCalendarDateFields)field);
+ INTL_METHOD_CHECK_STATUS(co, "Call to ICU method has failed");
+
+ RETURN_LONG((long)result);
+}
+
+U_CFUNC PHP_FUNCTION(intlcal_get_greatest_minimum)
+{
+ _php_intlcal_field_ret_in32t_method(&Calendar::getGreatestMinimum,
+ "intlcal_get_greatest_minimum", INTERNAL_FUNCTION_PARAM_PASSTHRU);
+}
+
+U_CFUNC PHP_FUNCTION(intlcal_get_least_maximum)
+{
+ _php_intlcal_field_ret_in32t_method(&Calendar::getLeastMaximum,
+ "intlcal_get_least_maximum", INTERNAL_FUNCTION_PARAM_PASSTHRU);
+}
+
+U_CFUNC PHP_FUNCTION(intlcal_get_locale)
+{
+ long locale_type;
+ CALENDAR_METHOD_INIT_VARS;
+
+ if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(),
+ "Ol", &object, Calendar_ce_ptr, &locale_type) == FAILURE) {
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "intlcal_get_locale: bad arguments", 0 TSRMLS_CC);
+ RETURN_FALSE;
+ }
+
+ if (locale_type != ULOC_ACTUAL_LOCALE && locale_type != ULOC_VALID_LOCALE) {
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "intlcal_get_locale: invalid locale type", 0 TSRMLS_CC);
+ RETURN_FALSE;
+ }
+
+ CALENDAR_METHOD_FETCH_OBJECT;
+
+ Locale locale = co->ucal->getLocale((ULocDataLocaleType)locale_type,
+ CALENDAR_ERROR_CODE(co));
+ INTL_METHOD_CHECK_STATUS(co,
+ "intlcal_get_locale: Call to ICU method has failed");
+
+ RETURN_STRING(locale.getName(), 1);
+}
+
+U_CFUNC PHP_FUNCTION(intlcal_get_maximum)
+{
+ _php_intlcal_field_ret_in32t_method(&Calendar::getMaximum,
+ "intlcal_get_maximum", INTERNAL_FUNCTION_PARAM_PASSTHRU);
+}
+
+U_CFUNC PHP_FUNCTION(intlcal_get_minimal_days_in_first_week)
+{
+ CALENDAR_METHOD_INIT_VARS;
+
+ if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(),
+ "O", &object, Calendar_ce_ptr) == FAILURE) {
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "intlcal_get_minimal_days_in_first_week: bad arguments", 0 TSRMLS_CC);
+ RETURN_FALSE;
+ }
+
+ CALENDAR_METHOD_FETCH_OBJECT;
+
+ uint8_t result = co->ucal->getMinimalDaysInFirstWeek();
+ INTL_METHOD_CHECK_STATUS(co,
+ "intlcal_get_first_day_of_week: Call to ICU method has failed");
+
+ RETURN_LONG((long)result);
+}
+
+U_CFUNC PHP_FUNCTION(intlcal_get_minimum)
+{
+ _php_intlcal_field_ret_in32t_method(&Calendar::getMinimum,
+ "intlcal_get_minimum", INTERNAL_FUNCTION_PARAM_PASSTHRU);
+}
+
+U_CFUNC PHP_FUNCTION(intlcal_get_time_zone)
+{
+ CALENDAR_METHOD_INIT_VARS;
+
+ if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(),
+ "O", &object, Calendar_ce_ptr) == FAILURE) {
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "intlcal_get_time_zone: bad arguments", 0 TSRMLS_CC);
+ RETURN_FALSE;
+ }
+
+ CALENDAR_METHOD_FETCH_OBJECT;
+
+ TimeZone *tz = co->ucal->getTimeZone().clone();
+ if (tz == NULL) {
+ intl_errors_set(CALENDAR_ERROR_P(co), U_MEMORY_ALLOCATION_ERROR,
+ "intlcal_get_time_zone: could not clone TimeZone", 0 TSRMLS_CC);
+ RETURN_FALSE;
+ }
+
+ timezone_object_construct(tz, return_value, 1 TSRMLS_CC);
+}
+
+U_CFUNC PHP_FUNCTION(intlcal_get_type)
+{
+ CALENDAR_METHOD_INIT_VARS;
+
+ if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(),
+ "O", &object, Calendar_ce_ptr) == FAILURE) {
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "intlcal_get_type: bad arguments", 0 TSRMLS_CC);
+ RETURN_FALSE;
+ }
+
+ CALENDAR_METHOD_FETCH_OBJECT;
+
+ RETURN_STRING(co->ucal->getType(), 1);
+}
+
+#if U_ICU_VERSION_MAJOR_NUM * 10 + U_ICU_VERSION_MINOR_NUM >= 44
+U_CFUNC PHP_FUNCTION(intlcal_get_weekend_transition)
+{
+ long dow;
+ CALENDAR_METHOD_INIT_VARS;
+
+ if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(),
+ "Ol", &object, Calendar_ce_ptr, &dow) == FAILURE) {
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "intlcal_get_weekend_transition: bad arguments", 0 TSRMLS_CC);
+ RETURN_FALSE;
+ }
+
+ if (dow < UCAL_SUNDAY || dow > UCAL_SATURDAY) {
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "intlcal_get_weekend_transition: invalid day of week", 0 TSRMLS_CC);
+ RETURN_FALSE;
+ }
+
+ CALENDAR_METHOD_FETCH_OBJECT;
+
+ int32_t res = co->ucal->getWeekendTransition((UCalendarDaysOfWeek)dow,
+ CALENDAR_ERROR_CODE(co));
+ INTL_METHOD_CHECK_STATUS(co, "intlcal_get_weekend_transition: "
+ "Error calling ICU method");
+
+ RETURN_LONG((long)res);
+}
+#endif
+
+U_CFUNC PHP_FUNCTION(intlcal_in_daylight_time)
+{
+ CALENDAR_METHOD_INIT_VARS;
+
+ if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(),
+ "O", &object, Calendar_ce_ptr) == FAILURE) {
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "intlcal_in_daylight_time: bad arguments", 0 TSRMLS_CC);
+ RETURN_FALSE;
+ }
+
+ CALENDAR_METHOD_FETCH_OBJECT;
+
+ UBool ret = co->ucal->inDaylightTime(CALENDAR_ERROR_CODE(co));
+ INTL_METHOD_CHECK_STATUS(co, "intlcal_in_daylight_time: "
+ "Error calling ICU method");
+
+ RETURN_BOOL((int)ret);
+}
+
+U_CFUNC PHP_FUNCTION(intlcal_is_equivalent_to)
+{
+ zval *other_object;
+ Calendar_object *other_co;
+ CALENDAR_METHOD_INIT_VARS;
+
+ if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(),
+ "OO", &object, Calendar_ce_ptr, &other_object, Calendar_ce_ptr)
+ == FAILURE) {
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "intlcal_is_equivalent_to: bad arguments", 0 TSRMLS_CC);
+ RETURN_FALSE;
+ }
+
+ other_co = (Calendar_object*)zend_object_store_get_object(other_object TSRMLS_CC);
+ if (other_co->ucal == NULL) {
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, "intlcal_is_equivalent_to:"
+ " Other IntlCalendar is unconstructed", 0 TSRMLS_CC);
+ RETURN_FALSE;
+ }
+
+ CALENDAR_METHOD_FETCH_OBJECT;
+
+ RETURN_BOOL((int)co->ucal->isEquivalentTo(*other_co->ucal));
+}
+
+U_CFUNC PHP_FUNCTION(intlcal_is_lenient)
+{
+ CALENDAR_METHOD_INIT_VARS;
+
+ if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(),
+ "O", &object, Calendar_ce_ptr) == FAILURE) {
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "intlcal_is_lenient: bad arguments", 0 TSRMLS_CC);
+ RETURN_FALSE;
+ }
+
+ CALENDAR_METHOD_FETCH_OBJECT;
+
+ RETURN_BOOL((int)co->ucal->isLenient());
+}
+
+U_CFUNC PHP_FUNCTION(intlcal_is_set)
+{
+ long field;
+ CALENDAR_METHOD_INIT_VARS;
+
+ if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(),
+ "Ol", &object, Calendar_ce_ptr, &field) == FAILURE) {
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "intlcal_is_set: bad arguments", 0 TSRMLS_CC);
+ RETURN_FALSE;
+ }
+
+ if (field < 0 || field >= UCAL_FIELD_COUNT) {
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "intlcal_is_set: invalid field", 0 TSRMLS_CC);
+ RETURN_FALSE;
+ }
+
+ CALENDAR_METHOD_FETCH_OBJECT;
+
+ RETURN_BOOL((int)co->ucal->isSet((UCalendarDateFields)field));
+}
+
+#if U_ICU_VERSION_MAJOR_NUM * 10 + U_ICU_VERSION_MINOR_NUM >= 44
+U_CFUNC PHP_FUNCTION(intlcal_is_weekend)
+{
+ double date;
+ zval *rawDate = NULL;
+ CALENDAR_METHOD_INIT_VARS;
+
+ if (zend_parse_method_parameters_ex(ZEND_PARSE_PARAMS_QUIET,
+ ZEND_NUM_ARGS() TSRMLS_CC, getThis(),
+ "O|z!", &object, Calendar_ce_ptr, &rawDate) == FAILURE
+ || (rawDate != NULL &&
+ zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(),
+ "O|d", &object, Calendar_ce_ptr, &date) == FAILURE)) {
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "intlcal_is_weekend: bad arguments", 0 TSRMLS_CC);
+ RETURN_FALSE;
+ }
+
+ CALENDAR_METHOD_FETCH_OBJECT;
+
+ if (rawDate == NULL) {
+ RETURN_BOOL((int)co->ucal->isWeekend());
+ } else {
+ UBool ret = co->ucal->isWeekend((UDate)date, CALENDAR_ERROR_CODE(co));
+ INTL_METHOD_CHECK_STATUS(co, "intlcal_is_weekend: "
+ "Error calling ICU method");
+ RETURN_BOOL((int)ret);
+ }
+}
+#endif
+
+
+U_CFUNC PHP_FUNCTION(intlcal_set_first_day_of_week)
+{
+ long dow;
+ CALENDAR_METHOD_INIT_VARS;
+
+ if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(),
+ "Ol", &object, Calendar_ce_ptr, &dow) == FAILURE) {
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "intlcal_set_first_day_of_week: bad arguments", 0 TSRMLS_CC);
+ RETURN_FALSE;
+ }
+
+ if (dow < UCAL_SUNDAY || dow > UCAL_SATURDAY) {
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "intlcal_set_first_day_of_week: invalid day of week", 0 TSRMLS_CC);
+ RETURN_FALSE;
+ }
+
+ CALENDAR_METHOD_FETCH_OBJECT;
+
+ co->ucal->setFirstDayOfWeek((UCalendarDaysOfWeek)dow);
+
+ RETURN_TRUE;
+}
+
+U_CFUNC PHP_FUNCTION(intlcal_set_lenient)
+{
+ zend_bool is_lenient;
+ CALENDAR_METHOD_INIT_VARS;
+
+ if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(),
+ "Ob", &object, Calendar_ce_ptr, &is_lenient) == FAILURE) {
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "intlcal_set_lenient: bad arguments", 0 TSRMLS_CC);
+ RETURN_FALSE;
+ }
+
+ CALENDAR_METHOD_FETCH_OBJECT;
+
+ co->ucal->setLenient((UBool) is_lenient);
+
+ RETURN_TRUE;
+}
+
+U_CFUNC PHP_FUNCTION(intlcal_equals)
+{
+ zval *other_object;
+ Calendar_object *other_co;
+ CALENDAR_METHOD_INIT_VARS;
+
+ if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(),
+ "OO", &object, Calendar_ce_ptr, &other_object, Calendar_ce_ptr)
+ == FAILURE) {
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "intlcal_equals: bad arguments", 0 TSRMLS_CC);
+ RETURN_FALSE;
+ }
+
+ CALENDAR_METHOD_FETCH_OBJECT;
+ other_co = (Calendar_object *) zend_object_store_get_object(other_object TSRMLS_CC);
+ if (other_co->ucal == NULL) {
+ intl_errors_set(&co->err, U_ILLEGAL_ARGUMENT_ERROR,
+ "intlcal_equals: The second IntlCalendar is unconstructed", 0 TSRMLS_CC);
+ RETURN_FALSE;
+ }
+
+ UBool result = co->ucal->equals(*other_co->ucal, CALENDAR_ERROR_CODE(co));
+ INTL_METHOD_CHECK_STATUS(co, "intlcal_equals: error calling ICU Calendar::equals");
+
+ RETURN_BOOL((int)result);
+}
+
+#if U_ICU_VERSION_MAJOR_NUM >= 49
+
+U_CFUNC PHP_FUNCTION(intlcal_get_repeated_wall_time_option)
+{
+ CALENDAR_METHOD_INIT_VARS;
+
+ if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(),
+ "O", &object, Calendar_ce_ptr) == FAILURE) {
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "intlcal_get_repeated_wall_time_option: bad arguments", 0 TSRMLS_CC);
+ RETURN_FALSE;
+ }
+
+ CALENDAR_METHOD_FETCH_OBJECT;
+
+ RETURN_LONG(co->ucal->getRepeatedWallTimeOption());
+}
+
+U_CFUNC PHP_FUNCTION(intlcal_get_skipped_wall_time_option)
+{
+ CALENDAR_METHOD_INIT_VARS;
+
+ if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(),
+ "O", &object, Calendar_ce_ptr) == FAILURE) {
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "intlcal_get_skipped_wall_time_option: bad arguments", 0 TSRMLS_CC);
+ RETURN_FALSE;
+ }
+
+ CALENDAR_METHOD_FETCH_OBJECT;
+
+ RETURN_LONG(co->ucal->getSkippedWallTimeOption());
+}
+
+U_CFUNC PHP_FUNCTION(intlcal_set_repeated_wall_time_option)
+{
+ long option;
+ CALENDAR_METHOD_INIT_VARS;
+
+ if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(),
+ "Ol", &object, Calendar_ce_ptr, &option) == FAILURE) {
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "intlcal_set_repeated_wall_time_option: bad arguments", 0 TSRMLS_CC);
+ RETURN_FALSE;
+ }
+
+ if (option != UCAL_WALLTIME_FIRST && option != UCAL_WALLTIME_LAST) {
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "intlcal_set_repeated_wall_time_option: invalid option", 0 TSRMLS_CC);
+ RETURN_FALSE;
+ }
+
+ CALENDAR_METHOD_FETCH_OBJECT;
+
+ co->ucal->setRepeatedWallTimeOption((UCalendarWallTimeOption)option);
+
+ RETURN_TRUE;
+}
+
+U_CFUNC PHP_FUNCTION(intlcal_set_skipped_wall_time_option)
+{
+ long option;
+ CALENDAR_METHOD_INIT_VARS;
+
+ if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(),
+ "Ol", &object, Calendar_ce_ptr, &option) == FAILURE) {
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "intlcal_set_skipped_wall_time_option: bad arguments", 0 TSRMLS_CC);
+ RETURN_FALSE;
+ }
+
+ if (option != UCAL_WALLTIME_FIRST && option != UCAL_WALLTIME_LAST
+ && option != UCAL_WALLTIME_NEXT_VALID) {
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "intlcal_set_skipped_wall_time_option: invalid option", 0 TSRMLS_CC);
+ RETURN_FALSE;
+ }
+
+ CALENDAR_METHOD_FETCH_OBJECT;
+
+ co->ucal->setSkippedWallTimeOption((UCalendarWallTimeOption)option);
+
+ RETURN_TRUE;
+}
+
+#endif
+
+U_CFUNC PHP_FUNCTION(intlcal_from_date_time)
+{
+ zval **zv_arg,
+ *zv_datetime = NULL,
+ *zv_timestamp = NULL;
+ php_date_obj *datetime;
+ char *locale_str = NULL;
+ int locale_str_len;
+ TimeZone *timeZone;
+ UErrorCode status = U_ZERO_ERROR;
+ Calendar *cal;
+ intl_error_reset(NULL TSRMLS_CC);
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z|s!",
+ &zv_arg, &locale_str, &locale_str_len) == FAILURE) {
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "intlcal_from_date_time: bad arguments", 0 TSRMLS_CC);
+ RETURN_NULL();
+ }
+
+ if (!(Z_TYPE_PP(zv_arg) == IS_OBJECT && instanceof_function(
+ Z_OBJCE_PP(zv_arg), php_date_get_date_ce() TSRMLS_CC))) {
+ ALLOC_INIT_ZVAL(zv_datetime);
+ object_init_ex(zv_datetime, php_date_get_date_ce());
+ zend_call_method_with_1_params(&zv_datetime, NULL, NULL, "__construct",
+ NULL, *zv_arg);
+ if (EG(exception)) {
+ zend_object_store_ctor_failed(zv_datetime TSRMLS_CC);
+ goto error;
+ }
+ } else {
+ zv_datetime = *zv_arg;
+ }
+
+ datetime = (php_date_obj*)zend_object_store_get_object(zv_datetime TSRMLS_CC);
+ if (!datetime->time) {
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "intlcal_from_date_time: DateTime object is unconstructed",
+ 0 TSRMLS_CC);
+ goto error;
+ }
+
+ zend_call_method_with_0_params(&zv_datetime, php_date_get_date_ce(),
+ NULL, "gettimestamp", &zv_timestamp);
+ if (!zv_timestamp || Z_TYPE_P(zv_timestamp) != IS_LONG) {
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "intlcal_from_date_time: bad DateTime; call to "
+ "DateTime::getTimestamp() failed", 0 TSRMLS_CC);
+ goto error;
+ }
+
+ if (!datetime->time->is_localtime) {
+ timeZone = TimeZone::getGMT()->clone();
+ } else {
+ timeZone = timezone_convert_datetimezone(datetime->time->zone_type,
+ datetime, 1, NULL, "intlcal_from_date_time" TSRMLS_CC);
+ if (timeZone == NULL) {
+ goto error;
+ }
+ }
+
+ if (!locale_str) {
+ locale_str = const_cast<char*>(intl_locale_get_default(TSRMLS_C));
+ }
+
+ cal = Calendar::createInstance(timeZone,
+ Locale::createFromName(locale_str), status);
+ if (cal == NULL) {
+ delete timeZone;
+ intl_error_set(NULL, status, "intlcal_from_date_time: "
+ "error creating ICU Calendar object", 0 TSRMLS_CC);
+ goto error;
+ }
+ cal->setTime(((UDate)Z_LVAL_P(zv_timestamp)) * 1000., status);
+ if (U_FAILURE(status)) {
+ /* time zone was adopted by cal; should not be deleted here */
+ delete cal;
+ intl_error_set(NULL, status, "intlcal_from_date_time: "
+ "error creating ICU Calendar::setTime()", 0 TSRMLS_CC);
+ goto error;
+ }
+
+ calendar_object_create(return_value, cal TSRMLS_CC);
+
+error:
+ if (zv_datetime != *zv_arg) {
+ zval_ptr_dtor(&zv_datetime);
+ }
+ if (zv_timestamp) {
+ zval_ptr_dtor(&zv_timestamp);
+ }
+}
+
+U_CFUNC PHP_FUNCTION(intlcal_to_date_time)
+{
+ zval *retval = NULL;
+ CALENDAR_METHOD_INIT_VARS;
+
+ if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O",
+ &object, Calendar_ce_ptr) == FAILURE) {
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "intlcal_to_date_time: bad arguments", 0 TSRMLS_CC);
+ RETURN_FALSE;
+ }
+
+ CALENDAR_METHOD_FETCH_OBJECT;
+
+ /* There are no exported functions in ext/date to this
+ * in a more native fashion */
+ double date = co->ucal->getTime(CALENDAR_ERROR_CODE(co)) / 1000.;
+ int64_t ts;
+ char ts_str[sizeof("@-9223372036854775808")];
+ int ts_str_len;
+ zval ts_zval = zval_used_for_init;
+
+ INTL_METHOD_CHECK_STATUS(co, "Call to ICU method has failed");
+
+ if (date > (double)U_INT64_MAX || date < (double)U_INT64_MIN) {
+ intl_errors_set(CALENDAR_ERROR_P(co), U_ILLEGAL_ARGUMENT_ERROR,
+ "intlcal_to_date_time: The calendar date is out of the "
+ "range for a 64-bit integer", 0 TSRMLS_CC);
+ RETURN_FALSE;
+ }
+
+ ts = (int64_t)date;
+
+ ts_str_len = slprintf(ts_str, sizeof(ts_str), "@%I64d", ts);
+ ZVAL_STRINGL(&ts_zval, ts_str, ts_str_len, 0);
+
+ /* Now get the time zone */
+ const TimeZone& tz = co->ucal->getTimeZone();
+ zval *timezone_zval = timezone_convert_to_datetimezone(
+ &tz, CALENDAR_ERROR_P(co), "intlcal_to_date_time" TSRMLS_CC);
+ if (timezone_zval == NULL) {
+ RETURN_FALSE;
+ }
+
+ /* resources allocated from now on */
+
+ /* Finally, instantiate object and call constructor */
+ object_init_ex(return_value, php_date_get_date_ce());
+ zend_call_method_with_2_params(&return_value, NULL, NULL, "__construct",
+ NULL, &ts_zval, timezone_zval);
+ if (EG(exception)) {
+ intl_errors_set(CALENDAR_ERROR_P(co), U_ILLEGAL_ARGUMENT_ERROR,
+ "intlcal_to_date_time: DateTime constructor has thrown exception",
+ 1 TSRMLS_CC);
+ zend_object_store_ctor_failed(return_value TSRMLS_CC);
+ zval_ptr_dtor(&return_value);
+
+ RETVAL_FALSE;
+ goto error;
+ }
+
+ /* due to bug #40743, we have to set the time zone again */
+ zend_call_method_with_1_params(&return_value, NULL, NULL, "settimezone",
+ &retval, timezone_zval);
+ if (retval == NULL || Z_TYPE_P(retval) == IS_BOOL) {
+ intl_errors_set(CALENDAR_ERROR_P(co), U_ILLEGAL_ARGUMENT_ERROR,
+ "intlcal_to_date_time: call to DateTime::setTimeZone has failed",
+ 1 TSRMLS_CC);
+ zval_ptr_dtor(&return_value);
+ RETVAL_FALSE;
+ goto error;
+ }
+
+error:
+ zval_ptr_dtor(&timezone_zval);
+ if (retval != NULL) {
+ zval_ptr_dtor(&retval);
+ }
+}
+
+U_CFUNC PHP_FUNCTION(intlcal_get_error_code)
+{
+ CALENDAR_METHOD_INIT_VARS;
+
+ if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O",
+ &object, Calendar_ce_ptr) == FAILURE) {
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "intlcal_get_error_code: bad arguments", 0 TSRMLS_CC);
+ RETURN_FALSE;
+ }
+
+ /* Fetch the object (without resetting its last error code ). */
+ co = (Calendar_object*)zend_object_store_get_object(object TSRMLS_CC);
+ if (co == NULL)
+ RETURN_FALSE;
+
+ RETURN_LONG((long)CALENDAR_ERROR_CODE(co));
+}
+
+U_CFUNC PHP_FUNCTION(intlcal_get_error_message)
+{
+ const char* message = NULL;
+ CALENDAR_METHOD_INIT_VARS;
+
+ if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O",
+ &object, Calendar_ce_ptr) == FAILURE) {
+ intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "intlcal_get_error_message: bad arguments", 0 TSRMLS_CC );
+ RETURN_FALSE;
+ }
+
+
+ /* Fetch the object (without resetting its last error code ). */
+ co = (Calendar_object*)zend_object_store_get_object(object TSRMLS_CC);
+ if (co == NULL)
+ RETURN_FALSE;
+
+ /* Return last error message. */
+ message = intl_error_get_message(CALENDAR_ERROR_P(co) TSRMLS_CC);
+ RETURN_STRING(message, 0);
+}
diff --git a/ext/intl/calendar/calendar_methods.h b/ext/intl/calendar/calendar_methods.h
new file mode 100644
index 0000000000..2be13e4920
--- /dev/null
+++ b/ext/intl/calendar/calendar_methods.h
@@ -0,0 +1,112 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Gustavo Lopes <cataphract@netcabo.pt> |
+ +----------------------------------------------------------------------+
+ */
+
+#ifndef CALENDAR_METHODS_H
+#define CALENDAR_METHODS_H
+
+#include <php.h>
+
+PHP_METHOD(IntlCalendar, __construct);
+
+PHP_FUNCTION(intlcal_create_instance);
+
+PHP_FUNCTION(intlcal_get_keyword_values_for_locale);
+
+PHP_FUNCTION(intlcal_get_now);
+
+PHP_FUNCTION(intlcal_get_available_locales);
+
+PHP_FUNCTION(intlcal_get);
+
+PHP_FUNCTION(intlcal_get_time);
+
+PHP_FUNCTION(intlcal_set_time);
+
+PHP_FUNCTION(intlcal_add);
+
+PHP_FUNCTION(intlcal_set_time_zone);
+
+PHP_FUNCTION(intlcal_after);
+
+PHP_FUNCTION(intlcal_before);
+
+PHP_FUNCTION(intlcal_set);
+
+PHP_FUNCTION(intlcal_roll);
+
+PHP_FUNCTION(intlcal_clear);
+
+PHP_FUNCTION(intlcal_field_difference);
+
+PHP_FUNCTION(intlcal_get_actual_maximum);
+
+PHP_FUNCTION(intlcal_get_actual_minimum);
+
+PHP_FUNCTION(intlcal_get_day_of_week_type);
+
+PHP_FUNCTION(intlcal_get_first_day_of_week);
+
+PHP_FUNCTION(intlcal_get_greatest_minimum);
+
+PHP_FUNCTION(intlcal_get_least_maximum);
+
+PHP_FUNCTION(intlcal_get_locale);
+
+PHP_FUNCTION(intlcal_get_maximum);
+
+PHP_FUNCTION(intlcal_get_minimal_days_in_first_week);
+
+PHP_FUNCTION(intlcal_get_minimum);
+
+PHP_FUNCTION(intlcal_get_time_zone);
+
+PHP_FUNCTION(intlcal_get_type);
+
+PHP_FUNCTION(intlcal_get_weekend_transition);
+
+PHP_FUNCTION(intlcal_in_daylight_time);
+
+PHP_FUNCTION(intlcal_is_equivalent_to);
+
+PHP_FUNCTION(intlcal_is_lenient);
+
+PHP_FUNCTION(intlcal_is_set);
+
+PHP_FUNCTION(intlcal_is_weekend);
+
+PHP_FUNCTION(intlcal_set_first_day_of_week);
+
+PHP_FUNCTION(intlcal_set_lenient);
+
+PHP_FUNCTION(intlcal_equals);
+
+PHP_FUNCTION(intlcal_get_repeated_wall_time_option);
+
+PHP_FUNCTION(intlcal_get_skipped_wall_time_option);
+
+PHP_FUNCTION(intlcal_set_repeated_wall_time_option);
+
+PHP_FUNCTION(intlcal_set_skipped_wall_time_option);
+
+PHP_FUNCTION(intlcal_from_date_time);
+
+PHP_FUNCTION(intlcal_to_date_time);
+
+PHP_FUNCTION(intlcal_get_error_code);
+
+PHP_FUNCTION(intlcal_get_error_message);
+
+#endif /* #ifndef CALENDAR_METHODS_H */
diff --git a/ext/intl/calendar/gregoriancalendar_methods.cpp b/ext/intl/calendar/gregoriancalendar_methods.cpp
new file mode 100644
index 0000000000..3c05253de1
--- /dev/null
+++ b/ext/intl/calendar/gregoriancalendar_methods.cpp
@@ -0,0 +1,256 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Gustavo Lopes <cataphract@php.net> |
+ +----------------------------------------------------------------------+
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "../intl_cppshims.h"
+
+#include <unicode/locid.h>
+#include <unicode/calendar.h>
+#include <unicode/gregocal.h>
+extern "C" {
+#include "../php_intl.h"
+#define USE_TIMEZONE_POINTER 1
+#include "../timezone/timezone_class.h"
+#define USE_CALENDAR_POINTER 1
+#include "calendar_class.h"
+#include <ext/date/php_date.h>
+}
+
+static inline GregorianCalendar *fetch_greg(Calendar_object *co) {
+ return (GregorianCalendar*)co->ucal;
+}
+
+static void _php_intlgregcal_constructor_body(INTERNAL_FUNCTION_PARAMETERS)
+{
+ zval *object = getThis();
+ zval **tz_object = NULL;
+ zval **args_a[6] = {0},
+ ***args = &args_a[0];
+ char *locale = NULL;
+ int locale_len;
+ long largs[6];
+ UErrorCode status = U_ZERO_ERROR;
+ int variant;
+ intl_error_reset(NULL TSRMLS_CC);
+
+ // parameter number validation / variant determination
+ if (ZEND_NUM_ARGS() > 6 ||
+ zend_get_parameters_array_ex(ZEND_NUM_ARGS(), args) == FAILURE) {
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "intlgregcal_create_instance: too many arguments", 0 TSRMLS_CC);
+ RETURN_NULL();
+ }
+ for (variant = ZEND_NUM_ARGS();
+ variant > 0 && Z_TYPE_PP(args[variant - 1]) == IS_NULL;
+ variant--) {}
+ if (variant == 4) {
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "intlgregcal_create_instance: no variant with 4 arguments "
+ "(excluding trailing NULLs)", 0 TSRMLS_CC);
+ RETURN_NULL();
+ }
+
+ // argument parsing
+ if (variant <= 2) {
+ if (zend_parse_parameters(MIN(ZEND_NUM_ARGS(), 2) TSRMLS_CC,
+ "|Z!s!", &tz_object, &locale, &locale_len) == FAILURE) {
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "intlgregcal_create_instance: bad arguments", 0 TSRMLS_CC);
+ RETURN_NULL();
+ }
+ }
+ if (variant > 2 && zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,
+ "lll|lll", &largs[0], &largs[1], &largs[2], &largs[3], &largs[4],
+ &largs[5]) == FAILURE) {
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "intlgregcal_create_instance: bad arguments", 0 TSRMLS_CC);
+ RETURN_NULL();
+ }
+
+ // instantion of ICU object
+ GregorianCalendar *gcal;
+
+ if (variant <= 2) {
+ // From timezone and locale (0 to 2 arguments)
+ TimeZone *tz = timezone_process_timezone_argument(tz_object, NULL,
+ "intlgregcal_create_instance" TSRMLS_CC);
+ if (tz == NULL) {
+ RETURN_NULL();
+ }
+ if (!locale) {
+ locale = const_cast<char*>(intl_locale_get_default(TSRMLS_C));
+ }
+
+ gcal = new GregorianCalendar(tz, Locale::createFromName(locale),
+ status);
+ if (U_FAILURE(status)) {
+ intl_error_set(NULL, status, "intlgregcal_create_instance: error "
+ "creating ICU GregorianCalendar from time zone and locale", 0 TSRMLS_CC);
+ if (gcal) {
+ delete gcal;
+ }
+ delete tz;
+ RETURN_NULL();
+ }
+ } else {
+ // From date/time (3, 5 or 6 arguments)
+ for (int i = 0; i < variant; i++) {
+ if (largs[i] < INT32_MIN || largs[i] > INT32_MAX) {
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "intlgregcal_create_instance: at least one of the arguments"
+ " has an absolute value that is too large", 0 TSRMLS_CC);
+ RETURN_NULL();
+ }
+ }
+
+ if (variant == 3) {
+ gcal = new GregorianCalendar((int32_t)largs[0], (int32_t)largs[1],
+ (int32_t)largs[2], status);
+ } else if (variant == 5) {
+ gcal = new GregorianCalendar((int32_t)largs[0], (int32_t)largs[1],
+ (int32_t)largs[2], (int32_t)largs[3], (int32_t)largs[4], status);
+ } else if (variant == 6) {
+ gcal = new GregorianCalendar((int32_t)largs[0], (int32_t)largs[1],
+ (int32_t)largs[2], (int32_t)largs[3], (int32_t)largs[4], (int32_t)largs[5],
+ status);
+ }
+ if (U_FAILURE(status)) {
+ intl_error_set(NULL, status, "intlgregcal_create_instance: error "
+ "creating ICU GregorianCalendar from date", 0 TSRMLS_CC);
+ if (gcal) {
+ delete gcal;
+ }
+ RETURN_NULL();
+ }
+
+ timelib_tzinfo *tzinfo = get_timezone_info(TSRMLS_C);
+#if U_ICU_VERSION_MAJOR_NUM * 10 + U_ICU_VERSION_MINOR_NUM >= 42
+ UnicodeString tzstr = UnicodeString::fromUTF8(StringPiece(tzinfo->name));
+#else
+ UnicodeString tzstr = UnicodeString(tzinfo->name,
+ strlen(tzinfo->name), US_INV);
+#endif
+ if (tzstr.isBogus()) {
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "intlgregcal_create_instance: could not create UTF-8 string "
+ "from PHP's default timezone name (see date_default_timezone_get())",
+ 0 TSRMLS_CC);
+ delete gcal;
+ RETURN_NULL();
+ }
+
+ TimeZone *tz = TimeZone::createTimeZone(tzstr);
+ gcal->adoptTimeZone(tz);
+ }
+
+ Calendar_object *co = (Calendar_object*)zend_object_store_get_object(
+ return_value TSRMLS_CC);
+ co->ucal = gcal;
+}
+
+U_CFUNC PHP_FUNCTION(intlgregcal_create_instance)
+{
+ zval orig;
+ intl_error_reset(NULL TSRMLS_CC);
+
+ object_init_ex(return_value, GregorianCalendar_ce_ptr);
+ orig = *return_value;
+
+ _php_intlgregcal_constructor_body(INTERNAL_FUNCTION_PARAM_PASSTHRU);
+
+ if (Z_TYPE_P(return_value) == IS_NULL) {
+ zend_object_store_ctor_failed(&orig TSRMLS_CC);
+ zval_dtor(&orig);
+ }
+}
+
+U_CFUNC PHP_METHOD(IntlGregorianCalendar, __construct)
+{
+ zval orig_this = *getThis();
+ intl_error_reset(NULL TSRMLS_CC);
+
+ return_value = getThis();
+ //changes this to IS_NULL (without first destroying) if there's an error
+ _php_intlgregcal_constructor_body(INTERNAL_FUNCTION_PARAM_PASSTHRU);
+
+ if (Z_TYPE_P(return_value) == IS_NULL) {
+ zend_object_store_ctor_failed(&orig_this TSRMLS_CC);
+ zval_dtor(&orig_this);
+ }
+}
+
+U_CFUNC PHP_FUNCTION(intlgregcal_set_gregorian_change)
+{
+ double date;
+ CALENDAR_METHOD_INIT_VARS;
+
+ if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(),
+ "Od", &object, GregorianCalendar_ce_ptr, &date) == FAILURE) {
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "intlgregcal_set_gregorian_change: bad arguments", 0 TSRMLS_CC);
+ RETURN_FALSE;
+ }
+
+ CALENDAR_METHOD_FETCH_OBJECT;
+
+ fetch_greg(co)->setGregorianChange(date, CALENDAR_ERROR_CODE(co));
+ INTL_METHOD_CHECK_STATUS(co, "intlgregcal_set_gregorian_change: error "
+ "calling ICU method");
+
+ RETURN_TRUE;
+}
+
+U_CFUNC PHP_FUNCTION(intlgregcal_get_gregorian_change)
+{
+ CALENDAR_METHOD_INIT_VARS;
+
+ if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(),
+ "O", &object, GregorianCalendar_ce_ptr) == FAILURE) {
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "intlgregcal_get_gregorian_change: bad arguments", 0 TSRMLS_CC);
+ RETURN_FALSE;
+ }
+
+ CALENDAR_METHOD_FETCH_OBJECT;
+
+ RETURN_DOUBLE((double)fetch_greg(co)->getGregorianChange());
+}
+
+U_CFUNC PHP_FUNCTION(intlgregcal_is_leap_year)
+{
+ long year;
+ CALENDAR_METHOD_INIT_VARS;
+
+ if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(),
+ "Ol", &object, GregorianCalendar_ce_ptr, &year) == FAILURE) {
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "intlgregcal_is_leap_year: bad arguments", 0 TSRMLS_CC);
+ RETURN_FALSE;
+ }
+
+ if (year < INT32_MIN || year > INT32_MAX) {
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "intlgregcal_is_leap_year: year out of bounds", 0 TSRMLS_CC);
+ RETURN_FALSE;
+ }
+
+ CALENDAR_METHOD_FETCH_OBJECT;
+
+ RETURN_BOOL((int)fetch_greg(co)->isLeapYear((int32_t)year));
+}
diff --git a/ext/intl/calendar/gregoriancalendar_methods.h b/ext/intl/calendar/gregoriancalendar_methods.h
new file mode 100644
index 0000000000..f911752cc7
--- /dev/null
+++ b/ext/intl/calendar/gregoriancalendar_methods.h
@@ -0,0 +1,32 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Gustavo Lopes <cataphract@php.net> |
+ +----------------------------------------------------------------------+
+ */
+
+#ifndef GREORIANCALENDAR_METHODS_H
+#define GREORIANCALENDAR_METHODS_H
+
+#include <php.h>
+
+PHP_FUNCTION(intlgregcal_create_instance);
+
+PHP_METHOD(IntlGregorianCalendar, __construct);
+
+PHP_FUNCTION(intlgregcal_set_gregorian_change);
+
+PHP_FUNCTION(intlgregcal_get_gregorian_change);
+
+PHP_FUNCTION(intlgregcal_is_leap_year);
+
+#endif
diff --git a/ext/intl/collator/collator_create.c b/ext/intl/collator/collator_create.c
index b2a9968af4..b2a8c7f6ba 100644
--- a/ext/intl/collator/collator_create.c
+++ b/ext/intl/collator/collator_create.c
@@ -48,7 +48,7 @@ static void collator_ctor(INTERNAL_FUNCTION_PARAMETERS)
COLLATOR_METHOD_FETCH_OBJECT;
if(locale_len == 0) {
- locale = INTL_G(default_locale);
+ locale = intl_locale_get_default(TSRMLS_C);
}
/* Open ICU collator. */
diff --git a/ext/intl/collator/collator_sort.c b/ext/intl/collator/collator_sort.c
index 0785111c96..04a24f013e 100644
--- a/ext/intl/collator/collator_sort.c
+++ b/ext/intl/collator/collator_sort.c
@@ -78,6 +78,7 @@ static int collator_regular_compare_function(zval *result, zval *op1, zval *op2
intl_errors_set_custom_msg( COLLATOR_ERROR_P( co ),
"Object not initialized", 0 TSRMLS_CC );
php_error_docref(NULL TSRMLS_CC, E_RECOVERABLE_ERROR, "Object not initialized");
+
}
/* Compare the strings using ICU. */
diff --git a/ext/intl/common/common_date.cpp b/ext/intl/common/common_date.cpp
new file mode 100644
index 0000000000..ee998818d9
--- /dev/null
+++ b/ext/intl/common/common_date.cpp
@@ -0,0 +1,250 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Gustavo Lopes <cataphract@php.net> |
+ +----------------------------------------------------------------------+
+*/
+
+#include "../intl_cppshims.h"
+
+#include <unicode/calendar.h>
+
+extern "C" {
+#include "../php_intl.h"
+#define USE_CALENDAR_POINTER 1
+#include "../calendar/calendar_class.h"
+#include <ext/date/php_date.h>
+}
+
+#ifndef INFINITY
+#define INFINITY (DBL_MAX+DBL_MAX)
+#endif
+
+#ifndef NAN
+#define NAN (INFINITY-INFINITY)
+#endif
+
+/* {{{ timezone_convert_datetimezone
+ * The timezone in DateTime and DateTimeZone is not unified. */
+U_CFUNC TimeZone *timezone_convert_datetimezone(int type,
+ void *object,
+ int is_datetime,
+ intl_error *outside_error,
+ const char *func TSRMLS_DC)
+{
+ char *id = NULL,
+ offset_id[] = "GMT+00:00";
+ int id_len = 0;
+ char *message;
+ TimeZone *timeZone;
+
+ switch (type) {
+ case TIMELIB_ZONETYPE_ID:
+ id = is_datetime
+ ? ((php_date_obj*)object)->time->tz_info->name
+ : ((php_timezone_obj*)object)->tzi.tz->name;
+ id_len = strlen(id);
+ break;
+ case TIMELIB_ZONETYPE_OFFSET: {
+ int offset_mins = is_datetime
+ ? -((php_date_obj*)object)->time->z
+ : -(int)((php_timezone_obj*)object)->tzi.utc_offset,
+ hours = offset_mins / 60,
+ minutes = offset_mins - hours * 60;
+ minutes *= minutes > 0 ? 1 : -1;
+
+ if (offset_mins <= -24 * 60 || offset_mins >= 24 * 60) {
+ spprintf(&message, 0, "%s: object has an time zone offset "
+ "that's too large", func);
+ intl_errors_set(outside_error, U_ILLEGAL_ARGUMENT_ERROR,
+ message, 1 TSRMLS_CC);
+ efree(message);
+ return NULL;
+ }
+
+ id = offset_id;
+ id_len = slprintf(id, sizeof(offset_id), "GMT%+03d:%02d",
+ hours, minutes);
+ break;
+ }
+ case TIMELIB_ZONETYPE_ABBR:
+ id = is_datetime
+ ? ((php_date_obj*)object)->time->tz_abbr
+ : ((php_timezone_obj*)object)->tzi.z.abbr;
+ id_len = strlen(id);
+ break;
+ }
+
+ UnicodeString s = UnicodeString(id, id_len, US_INV);
+ timeZone = TimeZone::createTimeZone(s);
+#if U_ICU_VERSION_MAJOR_NUM >= 49
+ if (*timeZone == TimeZone::getUnknown()) {
+#else
+ UnicodeString resultingId;
+ timeZone->getID(resultingId);
+ if (resultingId == UnicodeString("Etc/Unknown", -1, US_INV)
+ || resultingId == UnicodeString("GMT", -1, US_INV)) {
+#endif
+ spprintf(&message, 0, "%s: time zone id '%s' "
+ "extracted from ext/date DateTimeZone not recognized", func, id);
+ intl_errors_set(outside_error, U_ILLEGAL_ARGUMENT_ERROR,
+ message, 1 TSRMLS_CC);
+ efree(message);
+ delete timeZone;
+ return NULL;
+ }
+ return timeZone;
+}
+/* }}} */
+
+U_CFUNC int intl_datetime_decompose(zval *z, double *millis, TimeZone **tz,
+ intl_error *err, const char *func TSRMLS_DC)
+{
+ zval retval;
+ zval *zfuncname;
+ char *message;
+
+ if (err && U_FAILURE(err->code)) {
+ return FAILURE;
+ }
+
+ if (millis) {
+ *millis = NAN;
+ }
+ if (tz) {
+ *tz = NULL;
+ }
+
+ if (millis) {
+ INIT_ZVAL(retval);
+ MAKE_STD_ZVAL(zfuncname);
+ ZVAL_STRING(zfuncname, "getTimestamp", 1);
+ if (call_user_function(NULL, &(z), zfuncname, &retval, 0, NULL TSRMLS_CC)
+ != SUCCESS || Z_TYPE(retval) != IS_LONG) {
+ spprintf(&message, 0, "%s: error calling ::getTimeStamp() on the "
+ "object", func);
+ intl_errors_set(err, U_INTERNAL_PROGRAM_ERROR,
+ message, 1 TSRMLS_CC);
+ efree(message);
+ zval_ptr_dtor(&zfuncname);
+ return FAILURE;
+ }
+
+ *millis = U_MILLIS_PER_SECOND * (double)Z_LVAL(retval);
+ zval_ptr_dtor(&zfuncname);
+ }
+
+ if (tz) {
+ php_date_obj *datetime;
+ datetime = (php_date_obj*)zend_object_store_get_object(z TSRMLS_CC);
+ if (!datetime->time) {
+ spprintf(&message, 0, "%s: the DateTime object is not properly "
+ "initialized", func);
+ intl_errors_set(err, U_ILLEGAL_ARGUMENT_ERROR,
+ message, 1 TSRMLS_CC);
+ efree(message);
+ return FAILURE;
+ }
+ if (!datetime->time->is_localtime) {
+ *tz = TimeZone::getGMT()->clone();
+ } else {
+ *tz = timezone_convert_datetimezone(datetime->time->zone_type,
+ datetime, 1, NULL, func TSRMLS_CC);
+ if (*tz == NULL) {
+ spprintf(&message, 0, "%s: could not convert DateTime's "
+ "time zone", func);
+ intl_errors_set(err, U_ILLEGAL_ARGUMENT_ERROR,
+ message, 1 TSRMLS_CC);
+ efree(message);
+ return FAILURE;
+ }
+ }
+ }
+
+ return SUCCESS;
+}
+
+U_CFUNC double intl_zval_to_millis(zval *z, intl_error *err, const char *func TSRMLS_DC)
+{
+ double rv = NAN;
+ long lv;
+ int type;
+ char *message;
+
+ if (err && U_FAILURE(err->code)) {
+ return NAN;
+ }
+
+ switch (Z_TYPE_P(z)) {
+ case IS_STRING:
+ type = is_numeric_string(Z_STRVAL_P(z), Z_STRLEN_P(z), &lv, &rv, 0);
+ if (type == IS_DOUBLE) {
+ rv *= U_MILLIS_PER_SECOND;
+ } else if (type == IS_LONG) {
+ rv = U_MILLIS_PER_SECOND * (double)lv;
+ } else {
+ spprintf(&message, 0, "%s: string '%s' is not numeric, "
+ "which would be required for it to be a valid date", func,
+ Z_STRVAL_P(z));
+ intl_errors_set(err, U_ILLEGAL_ARGUMENT_ERROR,
+ message, 1 TSRMLS_CC);
+ efree(message);
+ }
+ break;
+ case IS_LONG:
+ rv = U_MILLIS_PER_SECOND * (double)Z_LVAL_P(z);
+ break;
+ case IS_DOUBLE:
+ rv = U_MILLIS_PER_SECOND * Z_DVAL_P(z);
+ break;
+ case IS_OBJECT:
+ if (instanceof_function(Z_OBJCE_P(z), php_date_get_date_ce() TSRMLS_CC)) {
+ intl_datetime_decompose(z, &rv, NULL, err, func TSRMLS_CC);
+ } else if (instanceof_function(Z_OBJCE_P(z), Calendar_ce_ptr TSRMLS_CC)) {
+ Calendar_object *co = (Calendar_object *)
+ zend_object_store_get_object(z TSRMLS_CC );
+ if (co->ucal == NULL) {
+ spprintf(&message, 0, "%s: IntlCalendar object is not properly "
+ "constructed", func);
+ intl_errors_set(err, U_ILLEGAL_ARGUMENT_ERROR,
+ message, 1 TSRMLS_CC);
+ efree(message);
+ } else {
+ UErrorCode status = UErrorCode();
+ rv = (double)co->ucal->getTime(status);
+ if (U_FAILURE(status)) {
+ spprintf(&message, 0, "%s: call to internal "
+ "Calendar::getTime() has failed", func);
+ intl_errors_set(err, status, message, 1 TSRMLS_CC);
+ efree(message);
+ }
+ }
+ } else {
+ /* TODO: try with cast(), get() to obtain a number */
+ spprintf(&message, 0, "%s: invalid object type for date/time "
+ "(only IntlCalendar and DateTime permitted)", func);
+ intl_errors_set(err, U_ILLEGAL_ARGUMENT_ERROR,
+ message, 1 TSRMLS_CC);
+ efree(message);
+ }
+ break;
+ default:
+ spprintf(&message, 0, "%s: invalid PHP type for date", func);
+ intl_errors_set(err, U_ILLEGAL_ARGUMENT_ERROR,
+ message, 1 TSRMLS_CC);
+ efree(message);
+ break;
+ }
+
+ return rv;
+}
+
diff --git a/ext/intl/common/common_date.h b/ext/intl/common/common_date.h
new file mode 100644
index 0000000000..d2396cbf5a
--- /dev/null
+++ b/ext/intl/common/common_date.h
@@ -0,0 +1,40 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Gustavo Lopes <cataphract@php.net> |
+ +----------------------------------------------------------------------+
+*/
+
+#ifndef COMMON_DATE_H
+#define COMMON_DATE_H
+
+#include <unicode/umachine.h>
+
+U_CDECL_BEGIN
+#include <php.h>
+#include "../intl_error.h"
+U_CDECL_END
+
+#ifdef __cplusplus
+
+#include <unicode/timezone.h>
+
+U_CFUNC TimeZone *timezone_convert_datetimezone(int type, void *object, int is_datetime, intl_error *outside_error, const char *func TSRMLS_DC);
+U_CFUNC int intl_datetime_decompose(zval *z, double *millis, TimeZone **tz,
+ intl_error *err, const char *func TSRMLS_DC);
+
+#endif
+
+U_CFUNC double intl_zval_to_millis(zval *z, intl_error *err, const char *func TSRMLS_DC);
+
+#endif /* COMMON_DATE_H */
+
diff --git a/ext/intl/common/common_enum.cpp b/ext/intl/common/common_enum.cpp
new file mode 100644
index 0000000000..da47a437a6
--- /dev/null
+++ b/ext/intl/common/common_enum.cpp
@@ -0,0 +1,354 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Gustavo Lopes <cataphract@php.net> |
+ +----------------------------------------------------------------------+
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "../intl_cppshims.h"
+
+// Fix build on Windows/old versions of ICU
+#include <stdio.h>
+
+#include "common_enum.h"
+
+extern "C" {
+#include <zend_interfaces.h>
+#include <zend_exceptions.h>
+}
+
+zend_class_entry *IntlIterator_ce_ptr;
+zend_object_handlers IntlIterator_handlers;
+
+void zoi_with_current_dtor(zend_object_iterator *iter TSRMLS_DC)
+{
+ zoi_with_current *zoiwc = (zoi_with_current*)iter;
+
+ if (zoiwc->wrapping_obj) {
+ /* we have to copy the pointer because zoiwc->wrapping_obj may be
+ * changed midway the execution of zval_ptr_dtor() */
+ zval *zwo = zoiwc->wrapping_obj;
+
+ /* object is still here, we can rely on it to call this again and
+ * destroy this object */
+ zval_ptr_dtor(&zwo);
+ } else {
+ /* Object not here anymore (we've been called by the object free handler)
+ * Note that the iterator wrapper objects (that also depend on this
+ * structure) call this function earlier, in the destruction phase, which
+ * precedes the object free phase. Therefore there's no risk on this
+ * function being called by the iterator wrapper destructor function and
+ * not finding the memory of this iterator allocated anymore. */
+ iter->funcs->invalidate_current(iter TSRMLS_CC);
+ zoiwc->destroy_it(iter TSRMLS_CC);
+ efree(iter);
+ }
+}
+
+U_CFUNC int zoi_with_current_valid(zend_object_iterator *iter TSRMLS_DC)
+{
+ return ((zoi_with_current*)iter)->current != NULL ? SUCCESS : FAILURE;
+}
+
+U_CFUNC void zoi_with_current_get_current_data(zend_object_iterator *iter, zval ***data TSRMLS_DC)
+{
+ *data = &((zoi_with_current*)iter)->current;
+}
+
+U_CFUNC void zoi_with_current_invalidate_current(zend_object_iterator *iter TSRMLS_DC)
+{
+ zoi_with_current *zoi_iter = (zoi_with_current*)iter;
+ if (zoi_iter->current) {
+ zval_ptr_dtor(&zoi_iter->current);
+ zoi_iter->current = NULL; //valid would return FAILURE now
+ }
+}
+
+static void string_enum_current_move_forward(zend_object_iterator *iter TSRMLS_DC)
+{
+ zoi_with_current *zoi_iter = (zoi_with_current*)iter;
+ INTLITERATOR_METHOD_INIT_VARS;
+
+ iter->funcs->invalidate_current(iter TSRMLS_CC);
+
+ object = zoi_iter->wrapping_obj;
+ INTLITERATOR_METHOD_FETCH_OBJECT_NO_CHECK;
+
+ int32_t result_length;
+ const char *result = ((StringEnumeration*)iter->data)->next(
+ &result_length, INTLITERATOR_ERROR_CODE(ii));
+
+ intl_error_set_code(NULL, INTLITERATOR_ERROR_CODE(ii) TSRMLS_CC);
+ if (U_FAILURE(INTLITERATOR_ERROR_CODE(ii))) {
+ intl_errors_set_custom_msg(INTL_DATA_ERROR_P(ii),
+ "Error fetching next iteration element", 0 TSRMLS_CC);
+ } else if (result) {
+ MAKE_STD_ZVAL(zoi_iter->current);
+ ZVAL_STRINGL(zoi_iter->current, result, result_length, 1);
+ } //else we've reached the end of the enum, nothing more is required
+}
+
+static void string_enum_rewind(zend_object_iterator *iter TSRMLS_DC)
+{
+ zoi_with_current *zoi_iter = (zoi_with_current*)iter;
+ INTLITERATOR_METHOD_INIT_VARS;
+
+ if (zoi_iter->current) {
+ iter->funcs->invalidate_current(iter TSRMLS_CC);
+ }
+
+ object = zoi_iter->wrapping_obj;
+ INTLITERATOR_METHOD_FETCH_OBJECT_NO_CHECK;
+
+ ((StringEnumeration*)iter->data)->reset(INTLITERATOR_ERROR_CODE(ii));
+
+ intl_error_set_code(NULL, INTLITERATOR_ERROR_CODE(ii) TSRMLS_CC);
+ if (U_FAILURE(INTLITERATOR_ERROR_CODE(ii))) {
+ intl_errors_set_custom_msg(INTL_DATA_ERROR_P(ii),
+ "Error resetting enumeration", 0 TSRMLS_CC);
+ } else {
+ iter->funcs->move_forward(iter TSRMLS_CC);
+ }
+}
+
+static void string_enum_destroy_it(zend_object_iterator *iter TSRMLS_DC)
+{
+ delete (StringEnumeration*)iter->data;
+}
+
+static zend_object_iterator_funcs string_enum_object_iterator_funcs = {
+ zoi_with_current_dtor,
+ zoi_with_current_valid,
+ zoi_with_current_get_current_data,
+ NULL,
+ string_enum_current_move_forward,
+ string_enum_rewind,
+ zoi_with_current_invalidate_current
+};
+
+U_CFUNC void IntlIterator_from_StringEnumeration(StringEnumeration *se, zval *object TSRMLS_DC)
+{
+ IntlIterator_object *ii;
+ object_init_ex(object, IntlIterator_ce_ptr);
+ ii = (IntlIterator_object*)zend_object_store_get_object(object TSRMLS_CC);
+ ii->iterator = (zend_object_iterator*)emalloc(sizeof(zoi_with_current));
+ ii->iterator->data = (void*)se;
+ ii->iterator->funcs = &string_enum_object_iterator_funcs;
+ ii->iterator->index = 0;
+ ((zoi_with_current*)ii->iterator)->destroy_it = string_enum_destroy_it;
+ ((zoi_with_current*)ii->iterator)->wrapping_obj = object;
+ ((zoi_with_current*)ii->iterator)->current = NULL;
+}
+
+static void IntlIterator_objects_free(zend_object *object TSRMLS_DC)
+{
+ IntlIterator_object *ii = (IntlIterator_object*) object;
+
+ if (ii->iterator) {
+ zval **wrapping_objp = &((zoi_with_current*)ii->iterator)->wrapping_obj;
+ *wrapping_objp = NULL;
+ ii->iterator->funcs->dtor(ii->iterator TSRMLS_CC);
+ }
+ intl_error_reset(INTLITERATOR_ERROR_P(ii) TSRMLS_CC);
+
+ zend_object_std_dtor(&ii->zo TSRMLS_CC);
+
+ efree(ii);
+}
+
+static zend_object_iterator *IntlIterator_get_iterator(
+ zend_class_entry *ce, zval *object, int by_ref TSRMLS_DC)
+{
+ if (by_ref) {
+ zend_throw_exception(NULL,
+ "Iteration by reference is not supported", 0 TSRMLS_CC);
+ return NULL;
+ }
+
+ IntlIterator_object *ii = (IntlIterator_object*)
+ zend_object_store_get_object(object TSRMLS_CC);
+
+ if (ii->iterator == NULL) {
+ zend_throw_exception(NULL,
+ "The IntlIterator is not properly constructed", 0 TSRMLS_CC);
+ return NULL;
+ }
+
+ zval_add_ref(&object);
+
+ return ii->iterator;
+}
+
+static zend_object_value IntlIterator_object_create(zend_class_entry *ce TSRMLS_DC)
+{
+ zend_object_value retval;
+ IntlIterator_object *intern;
+
+ intern = (IntlIterator_object*)ecalloc(1, sizeof(IntlIterator_object));
+
+ zend_object_std_init(&intern->zo, ce TSRMLS_CC);
+#if PHP_VERSION_ID < 50399
+ zend_hash_copy(intern->zo.properties, &(ce->default_properties),
+ (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval*));
+#else
+ object_properties_init((zend_object*) intern, ce);
+#endif
+ intl_error_init(INTLITERATOR_ERROR_P(intern) TSRMLS_CC);
+ intern->iterator = NULL;
+
+ retval.handle = zend_objects_store_put(
+ intern,
+ (zend_objects_store_dtor_t)zend_objects_destroy_object,
+ (zend_objects_free_object_storage_t)IntlIterator_objects_free,
+ NULL TSRMLS_CC);
+
+ retval.handlers = &IntlIterator_handlers;
+
+ return retval;
+}
+
+static PHP_METHOD(IntlIterator, current)
+{
+ zval **data;
+ INTLITERATOR_METHOD_INIT_VARS;
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "IntlIterator::current: bad arguments", 0 TSRMLS_CC);
+ return;
+ }
+
+ INTLITERATOR_METHOD_FETCH_OBJECT;
+ ii->iterator->funcs->get_current_data(ii->iterator, &data TSRMLS_CC);
+ if (data && *data) {
+ RETURN_ZVAL(*data, 1, 0);
+ }
+}
+
+static PHP_METHOD(IntlIterator, key)
+{
+ INTLITERATOR_METHOD_INIT_VARS;
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "IntlIterator::key: bad arguments", 0 TSRMLS_CC);
+ return;
+ }
+
+ INTLITERATOR_METHOD_FETCH_OBJECT;
+
+ if (ii->iterator->funcs->get_current_key) {
+ char *str_key;
+ uint str_key_len;
+ ulong int_key;
+
+ switch (ii->iterator->funcs->get_current_key(
+ ii->iterator, &str_key, &str_key_len, &int_key TSRMLS_CC)) {
+ case HASH_KEY_IS_LONG:
+ RETURN_LONG(int_key);
+ break;
+ case HASH_KEY_IS_STRING:
+ RETURN_STRINGL(str_key, str_key_len-1, 0);
+ break;
+ }
+ } else {
+ RETURN_LONG(ii->iterator->index);
+ }
+}
+
+static PHP_METHOD(IntlIterator, next)
+{
+ INTLITERATOR_METHOD_INIT_VARS;
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "IntlIterator::next: bad arguments", 0 TSRMLS_CC);
+ return;
+ }
+
+ INTLITERATOR_METHOD_FETCH_OBJECT;
+ ii->iterator->funcs->move_forward(ii->iterator TSRMLS_CC);
+ /* foreach also advances the index after the last iteration,
+ * so I see no problem in incrementing the index here unconditionally */
+ ii->iterator->index++;
+}
+
+static PHP_METHOD(IntlIterator, rewind)
+{
+ INTLITERATOR_METHOD_INIT_VARS;
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "IntlIterator::rewind: bad arguments", 0 TSRMLS_CC);
+ return;
+ }
+
+ INTLITERATOR_METHOD_FETCH_OBJECT;
+ if (ii->iterator->funcs->rewind) {
+ ii->iterator->funcs->rewind(ii->iterator TSRMLS_CC);
+ } else {
+ intl_errors_set(INTLITERATOR_ERROR_P(ii), U_UNSUPPORTED_ERROR,
+ "IntlIterator::rewind: rewind not supported", 0 TSRMLS_CC);
+ }
+}
+
+static PHP_METHOD(IntlIterator, valid)
+{
+ INTLITERATOR_METHOD_INIT_VARS;
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "IntlIterator::valid: bad arguments", 0 TSRMLS_CC);
+ return;
+ }
+
+ INTLITERATOR_METHOD_FETCH_OBJECT;
+ RETURN_BOOL(ii->iterator->funcs->valid(ii->iterator TSRMLS_CC) == SUCCESS);
+}
+
+ZEND_BEGIN_ARG_INFO_EX(ainfo_se_void, 0, 0, 0)
+ZEND_END_ARG_INFO()
+
+static zend_function_entry IntlIterator_class_functions[] = {
+ PHP_ME(IntlIterator, current, ainfo_se_void, ZEND_ACC_PUBLIC)
+ PHP_ME(IntlIterator, key, ainfo_se_void, ZEND_ACC_PUBLIC)
+ PHP_ME(IntlIterator, next, ainfo_se_void, ZEND_ACC_PUBLIC)
+ PHP_ME(IntlIterator, rewind, ainfo_se_void, ZEND_ACC_PUBLIC)
+ PHP_ME(IntlIterator, valid, ainfo_se_void, ZEND_ACC_PUBLIC)
+ PHP_FE_END
+};
+
+
+/* {{{ intl_register_IntlIterator_class
+ * Initialize 'IntlIterator' class
+ */
+U_CFUNC void intl_register_IntlIterator_class(TSRMLS_D)
+{
+ zend_class_entry ce;
+
+ /* Create and register 'IntlIterator' class. */
+ INIT_CLASS_ENTRY(ce, "IntlIterator", IntlIterator_class_functions);
+ ce.create_object = IntlIterator_object_create;
+ IntlIterator_ce_ptr = zend_register_internal_class(&ce TSRMLS_CC);
+ IntlIterator_ce_ptr->get_iterator = IntlIterator_get_iterator;
+ zend_class_implements(IntlIterator_ce_ptr TSRMLS_CC, 1,
+ zend_ce_iterator);
+
+ memcpy(&IntlIterator_handlers, zend_get_std_object_handlers(),
+ sizeof IntlIterator_handlers);
+ IntlIterator_handlers.clone_obj = NULL;
+
+}
diff --git a/ext/intl/common/common_enum.h b/ext/intl/common/common_enum.h
new file mode 100644
index 0000000000..4c6abdb8f5
--- /dev/null
+++ b/ext/intl/common/common_enum.h
@@ -0,0 +1,77 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Vadim Savchuk <vsavchuk@productengine.com> |
+ | Dmitry Lakhtyuk <dlakhtyuk@productengine.com> |
+ +----------------------------------------------------------------------+
+ */
+
+#ifndef INTL_COMMON_ENUM_H
+#define INTL_COMMON_ENUM_H
+
+#include <unicode/umachine.h>
+#ifdef __cplusplus
+#include <unicode/strenum.h>
+extern "C" {
+#include <math.h>
+#endif
+#include <php.h>
+#include "../intl_error.h"
+#include "../intl_data.h"
+#ifdef __cplusplus
+}
+#endif
+
+#define INTLITERATOR_ERROR(ii) (ii)->err
+#define INTLITERATOR_ERROR_P(ii) &(INTLITERATOR_ERROR(ii))
+
+#define INTLITERATOR_ERROR_CODE(ii) INTL_ERROR_CODE(INTLITERATOR_ERROR(ii))
+#define INTLITERATOR_ERROR_CODE_P(ii) &(INTL_ERROR_CODE(INTLITERATOR_ERROR(ii)))
+
+#define INTLITERATOR_METHOD_INIT_VARS INTL_METHOD_INIT_VARS(IntlIterator, ii)
+#define INTLITERATOR_METHOD_FETCH_OBJECT_NO_CHECK INTL_METHOD_FETCH_OBJECT(IntlIterator, ii)
+#define INTLITERATOR_METHOD_FETCH_OBJECT\
+ object = getThis(); \
+ INTLITERATOR_METHOD_FETCH_OBJECT_NO_CHECK; \
+ if (ii->iterator == NULL) { \
+ intl_errors_set(&ii->err, U_ILLEGAL_ARGUMENT_ERROR, "Found unconstructed IntlIterator", 0 TSRMLS_CC); \
+ RETURN_FALSE; \
+ }
+
+typedef struct {
+ zend_object zo;
+ intl_error err;
+ zend_object_iterator *iterator;
+} IntlIterator_object;
+
+typedef struct {
+ zend_object_iterator zoi;
+ zval *current;
+ zval *wrapping_obj;
+ void (*destroy_it)(zend_object_iterator *iterator TSRMLS_DC);
+} zoi_with_current;
+
+extern zend_class_entry *IntlIterator_ce_ptr;
+extern zend_object_handlers IntlIterator_handlers;
+
+U_CFUNC void zoi_with_current_dtor(zend_object_iterator *iter TSRMLS_DC);
+U_CFUNC int zoi_with_current_valid(zend_object_iterator *iter TSRMLS_DC);
+U_CFUNC void zoi_with_current_get_current_data(zend_object_iterator *iter, zval ***data TSRMLS_DC);
+U_CFUNC void zoi_with_current_invalidate_current(zend_object_iterator *iter TSRMLS_DC);
+
+#ifdef __cplusplus
+U_CFUNC void IntlIterator_from_StringEnumeration(StringEnumeration *se, zval *object TSRMLS_DC);
+#endif
+
+U_CFUNC void intl_register_IntlIterator_class(TSRMLS_D);
+
+#endif // INTL_COMMON_ENUM_H
diff --git a/ext/intl/common/common_error.c b/ext/intl/common/common_error.c
index 282172224c..a0ee7c145f 100644
--- a/ext/intl/common/common_error.c
+++ b/ext/intl/common/common_error.c
@@ -240,9 +240,7 @@ void intl_expose_icu_error_codes( INIT_FUNC_ARGS )
INTL_EXPOSE_CONST( U_IDNA_ACE_PREFIX_ERROR );
INTL_EXPOSE_CONST( U_IDNA_VERIFICATION_ERROR );
INTL_EXPOSE_CONST( U_IDNA_LABEL_TOO_LONG_ERROR );
-#if U_ICU_VERSION_MAJOR_NUM > 3 || U_ICU_VERSION_MAJOR_NUM == 3 && U_ICU_VERSION_MINOR_NUM >= 6
INTL_EXPOSE_CONST( U_IDNA_ZERO_LENGTH_LABEL_ERROR );
-#endif
#if U_ICU_VERSION_MAJOR_NUM > 3 || U_ICU_VERSION_MAJOR_NUM == 3 && U_ICU_VERSION_MINOR_NUM >= 8
INTL_EXPOSE_CONST( U_IDNA_DOMAIN_NAME_TOO_LONG_ERROR );
#endif
diff --git a/ext/intl/config.m4 b/ext/intl/config.m4
index 0477c7f59d..4630a302ef 100644
--- a/ext/intl/config.m4
+++ b/ext/intl/config.m4
@@ -20,6 +20,7 @@ if test "$PHP_INTL" != "no"; then
PHP_NEW_EXTENSION(intl, php_intl.c \
intl_error.c \
intl_convert.c \
+ intl_convertcpp.cpp \
collator/collator.c \
collator/collator_class.c \
collator/collator_sort.c \
@@ -31,6 +32,9 @@ if test "$PHP_INTL" != "no"; then
collator/collator_is_numeric.c \
collator/collator_error.c \
common/common_error.c \
+ common/common_enum.cpp \
+ common/common_date.cpp \
+ converter/converter.c \
formatter/formatter.c \
formatter/formatter_main.c \
formatter/formatter_class.c \
@@ -49,7 +53,11 @@ if test "$PHP_INTL" != "no"; then
dateformat/dateformat_attr.c \
dateformat/dateformat_data.c \
dateformat/dateformat_format.c \
+ dateformat/dateformat_format_object.cpp \
dateformat/dateformat_parse.c \
+ dateformat/dateformat_create.cpp \
+ dateformat/dateformat_attrcpp.cpp \
+ dateformat/dateformat_helpers.cpp \
msgformat/msgformat.c \
msgformat/msgformat_attr.c \
msgformat/msgformat_class.c \
@@ -65,9 +73,21 @@ if test "$PHP_INTL" != "no"; then
transliterator/transliterator.c \
transliterator/transliterator_class.c \
transliterator/transliterator_methods.c \
+ timezone/timezone_class.cpp \
+ timezone/timezone_methods.cpp \
+ calendar/calendar_class.cpp \
+ calendar/calendar_methods.cpp \
+ calendar/gregoriancalendar_methods.cpp \
+ breakiterator/breakiterator_class.cpp \
+ breakiterator/breakiterator_iterators.cpp \
+ breakiterator/breakiterator_methods.cpp \
+ breakiterator/rulebasedbreakiterator_methods.cpp \
+ breakiterator/codepointiterator_internal.cpp \
+ breakiterator/codepointiterator_methods.cpp \
idn/idn.c \
- $icu_spoof_src, $ext_shared,,$ICU_INCS)
+ $icu_spoof_src, $ext_shared,,$ICU_INCS -Wno-write-strings)
PHP_ADD_BUILD_DIR($ext_builddir/collator)
+ PHP_ADD_BUILD_DIR($ext_builddir/converter)
PHP_ADD_BUILD_DIR($ext_builddir/common)
PHP_ADD_BUILD_DIR($ext_builddir/formatter)
PHP_ADD_BUILD_DIR($ext_builddir/normalizer)
@@ -77,6 +97,9 @@ if test "$PHP_INTL" != "no"; then
PHP_ADD_BUILD_DIR($ext_builddir/grapheme)
PHP_ADD_BUILD_DIR($ext_builddir/resourcebundle)
PHP_ADD_BUILD_DIR($ext_builddir/transliterator)
+ PHP_ADD_BUILD_DIR($ext_builddir/timezone)
+ PHP_ADD_BUILD_DIR($ext_builddir/calendar)
PHP_ADD_BUILD_DIR($ext_builddir/idn)
PHP_ADD_BUILD_DIR($ext_builddir/spoofchecker)
+ PHP_ADD_BUILD_DIR($ext_builddir/breakiterator)
fi
diff --git a/ext/intl/config.w32 b/ext/intl/config.w32
index 437fedb7d3..bb1dca8124 100644
--- a/ext/intl/config.w32
+++ b/ext/intl/config.w32
@@ -7,7 +7,7 @@ if (PHP_INTL != "no") {
if (CHECK_LIB("icuuc.lib", "intl", PHP_INTL) &&
CHECK_HEADER_ADD_INCLUDE("unicode/utf.h", "CFLAGS_INTL")) {
// always build as shared - zend_strtod.c/ICU type conflict
- EXTENSION("intl", "php_intl.c intl_convert.c intl_error.c ", true,
+ EXTENSION("intl", "php_intl.c intl_convert.c intl_convertcpp.cpp intl_error.c ", true,
"/I \"" + configure_module_dirname + "\"");
ADD_SOURCES(configure_module_dirname + "/collator", "\
collator.c \
@@ -23,6 +23,11 @@ if (PHP_INTL != "no") {
", "intl");
ADD_SOURCES(configure_module_dirname + "/common", "\
common_error.c \
+ common_enum.cpp \
+ common_date.cpp \
+ ", "intl");
+ ADD_SOURCES(configure_module_dirname + "/converter", "\
+ converter.c \
", "intl");
ADD_SOURCES(configure_module_dirname + "/formatter", "\
formatter.c \
@@ -60,8 +65,12 @@ if (PHP_INTL != "no") {
dateformat_class.c \
dateformat_attr.c \
dateformat_format.c \
+ dateformat_format_object.cpp \
dateformat_parse.c \
dateformat_data.c \
+ dateformat_attrcpp.cpp \
+ dateformat_helpers.cpp \
+ dateformat_create.cpp \
", "intl");
ADD_SOURCES(configure_module_dirname + "/idn", "\
idn.c",
@@ -87,6 +96,27 @@ if (PHP_INTL != "no") {
transliterator_class.c \
transliterator_methods.c",
"intl");
+
+ ADD_SOURCES(configure_module_dirname + "/timezone", "\
+ timezone_class.cpp \
+ timezone_methods.cpp",
+ "intl");
+
+ ADD_SOURCES(configure_module_dirname + "/calendar", "\
+ calendar_methods.cpp \
+ gregoriancalendar_methods.cpp \
+ calendar_class.cpp",
+ "intl");
+
+ ADD_SOURCES(configure_module_dirname + "/breakiterator", "\
+ breakiterator_class.cpp \
+ breakiterator_methods.cpp \
+ breakiterator_iterators.cpp \
+ rulebasedbreakiterator_methods.cpp \
+ codepointiterator_internal.cpp \
+ codepointiterator_methods.cpp ",
+ "intl");
+
ADD_FLAG("LIBS_INTL", "icudt.lib icuin.lib icuio.lib icule.lib iculx.lib");
AC_DEFINE("HAVE_INTL", 1, "Internationalization support enabled");
} else {
diff --git a/ext/intl/converter/converter.c b/ext/intl/converter/converter.c
new file mode 100644
index 0000000000..5f2d1e7fa7
--- /dev/null
+++ b/ext/intl/converter/converter.c
@@ -0,0 +1,1173 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Sara Golemon <pollita@php.net> |
+ +----------------------------------------------------------------------+
+ */
+
+#include "converter.h"
+#include "zend_exceptions.h"
+
+#include <unicode/utypes.h>
+#include <unicode/ucnv.h>
+#include <unicode/ustring.h>
+
+#include "../intl_error.h"
+
+typedef struct _php_converter_object {
+ zend_object obj;
+#ifdef ZTS
+ void ***tsrm_ls;
+#endif
+ UConverter *src, *dest;
+ zend_fcall_info to_cb, from_cb;
+ zend_fcall_info_cache to_cache, from_cache;
+ intl_error error;
+} php_converter_object;
+
+static zend_class_entry *php_converter_ce;
+static zend_object_handlers php_converter_object_handlers;
+
+#define CONV_GET(pzv) ((php_converter_object*)zend_objects_get_address((pzv) TSRMLS_CC))
+#define THROW_UFAILURE(obj, fname, error) php_converter_throw_failure(obj, error TSRMLS_CC, \
+ fname "() returned error %ld: %s", (long)error, u_errorName(error))
+
+/* {{{ php_converter_throw_failure */
+static inline void php_converter_throw_failure(php_converter_object *objval, UErrorCode error TSRMLS_DC, const char *format, ...) {
+ intl_error *err = objval ? &(objval->error) : NULL;
+ char message[1024];
+ va_list vargs;
+
+ va_start(vargs, format);
+ vsnprintf(message, sizeof(message), format, vargs);
+ va_end(vargs);
+
+ intl_errors_set(err, error, message, 1 TSRMLS_CC);
+}
+/* }}} */
+
+/* {{{ php_converter_default_callback */
+static void php_converter_default_callback(zval *return_value, zval *zobj, long reason, zval *error TSRMLS_DC) {
+ /* Basic functionality so children can call parent::toUCallback() */
+ switch (reason) {
+ case UCNV_UNASSIGNED:
+ case UCNV_ILLEGAL:
+ case UCNV_IRREGULAR:
+ {
+ php_converter_object *objval = (php_converter_object*)CONV_GET(zobj);
+ char chars[127];
+ int8_t chars_len = sizeof(chars);
+ UErrorCode error = U_ZERO_ERROR;
+
+ /* Yes, this is fairly wasteful at first glance,
+ * but considering that the alternative is to store
+ * what's sent into setSubstChars() and the fact
+ * that this is an extremely unlikely codepath
+ * I'd rather take the CPU hit here, than waste time
+ * storing a value I'm unlikely to use.
+ */
+ ucnv_getSubstChars(objval->src, chars, &chars_len, &error);
+ if (U_FAILURE(error)) {
+ THROW_UFAILURE(objval, "ucnv_getSubstChars", error);
+ chars[0] = 0x1A;
+ chars[1] = 0;
+ chars_len = 1;
+ }
+ RETVAL_STRINGL(chars, chars_len, 1);
+ }
+ }
+ zval_dtor(error);
+ ZVAL_LONG(error, U_ZERO_ERROR);
+}
+/* }}} */
+
+/* {{{ proto void UConverter::toUCallback(long $reason,
+ string $source, string $codeUnits,
+ long &$error) */
+ZEND_BEGIN_ARG_INFO_EX(php_converter_toUCallback_arginfo, 0, ZEND_RETURN_VALUE, 4)
+ ZEND_ARG_INFO(0, reason)
+ ZEND_ARG_INFO(0, source)
+ ZEND_ARG_INFO(0, codeUnits)
+ ZEND_ARG_INFO(1, error)
+ZEND_END_ARG_INFO();
+static PHP_METHOD(UConverter, toUCallback) {
+ long reason;
+ zval *source, *codeUnits, *error;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "lzzz",
+ &reason, &source, &codeUnits, &error) == FAILURE) {
+ return;
+ }
+
+ php_converter_default_callback(return_value, getThis(), reason, error TSRMLS_CC);
+}
+/* }}} */
+
+/* {{{ proto void UConverter::fromUCallback(long $reason,
+ Array $source, long $codePoint,
+ long &$error) */
+ZEND_BEGIN_ARG_INFO_EX(php_converter_fromUCallback_arginfo, 0, ZEND_RETURN_VALUE, 4)
+ ZEND_ARG_INFO(0, reason)
+ ZEND_ARG_INFO(0, source)
+ ZEND_ARG_INFO(0, codePoint)
+ ZEND_ARG_INFO(1, error)
+ZEND_END_ARG_INFO();
+static PHP_METHOD(UConverter, fromUCallback) {
+ long reason;
+ zval *source, *codePoint, *error;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "lzzz",
+ &reason, &source, &codePoint, &error) == FAILURE) {
+ return;
+ }
+
+ php_converter_default_callback(return_value, getThis(), reason, error TSRMLS_CC);
+}
+/* }}} */
+
+/* {{{ php_converter_check_limits */
+static inline zend_bool php_converter_check_limits(php_converter_object *objval, long available, long needed TSRMLS_DC) {
+ if (available < needed) {
+ php_converter_throw_failure(objval, U_BUFFER_OVERFLOW_ERROR TSRMLS_CC, "Buffer overrun %ld bytes needed, %ld available", needed, available);
+ return 0;
+ }
+ return 1;
+}
+/* }}} */
+
+#define TARGET_CHECK(cnvargs, needed) php_converter_check_limits(objval, cnvargs->targetLimit - cnvargs->target, needed TSRMLS_CC)
+
+/* {{{ php_converter_append_toUnicode_target */
+static void php_converter_append_toUnicode_target(zval *val, UConverterToUnicodeArgs *args, php_converter_object *objval TSRMLS_DC) {
+ switch (Z_TYPE_P(val)) {
+ case IS_NULL:
+ /* Code unit is being skipped */
+ return;
+ case IS_LONG:
+ {
+ long lval = Z_LVAL_P(val);
+ if ((lval < 0) || (lval > 0x10FFFF)) {
+ php_converter_throw_failure(objval, U_ILLEGAL_ARGUMENT_ERROR TSRMLS_CC, "Invalid codepoint U+%04lx", lval);
+ return;
+ }
+ if (lval > 0xFFFF) {
+ /* Supplemental planes U+010000 - U+10FFFF */
+ if (TARGET_CHECK(args, 2)) {
+ /* TODO: Find the ICU call which does this properly */
+ *(args->target++) = (UChar)(((lval - 0x10000) >> 10) | 0xD800);
+ *(args->target++) = (UChar)(((lval - 0x10000) & 0x3FF) | 0xDC00);
+ }
+ return;
+ }
+ /* Non-suggogate BMP codepoint */
+ if (TARGET_CHECK(args, 1)) {
+ *(args->target++) = (UChar)lval;
+ }
+ return;
+ }
+ case IS_STRING:
+ {
+ const char *strval = Z_STRVAL_P(val);
+ int i = 0, strlen = Z_STRLEN_P(val);
+
+ while((i != strlen) && TARGET_CHECK(args, 1)) {
+ UChar c;
+ U8_NEXT(strval, i, strlen, c);
+ *(args->target++) = c;
+ }
+ return;
+ }
+ case IS_ARRAY:
+ {
+ HashTable *ht = Z_ARRVAL_P(val);
+ HashPosition pos;
+ zval **tmpzval;
+
+ for(zend_hash_internal_pointer_reset_ex(ht, &pos);
+ zend_hash_get_current_data_ex(ht, (void**)&tmpzval, &pos) == SUCCESS;
+ zend_hash_move_forward_ex(ht, &pos)) {
+ php_converter_append_toUnicode_target(*tmpzval, args, objval TSRMLS_CC);
+ }
+ return;
+ }
+ default:
+ php_converter_throw_failure(objval, U_ILLEGAL_ARGUMENT_ERROR TSRMLS_CC,
+ "toUCallback() specified illegal type for substitution character");
+ }
+}
+/* }}} */
+
+/* {{{ php_converter_to_u_callback */
+static void php_converter_to_u_callback(const void *context,
+ UConverterToUnicodeArgs *args,
+ const char *codeUnits, int32_t length,
+ UConverterCallbackReason reason,
+ UErrorCode *pErrorCode) {
+ php_converter_object *objval = (php_converter_object*)context;
+ zval *zreason, *zsource, *zcodeunits, *zerror, *retval = NULL;
+ zval **zargs[4];
+#ifdef ZTS
+ TSRMLS_D = objval->tsrm_ls;
+#endif
+
+ MAKE_STD_ZVAL(zreason);
+ ZVAL_LONG(zreason, reason);
+ zargs[0] = &zreason;
+
+ MAKE_STD_ZVAL(zsource);
+ ZVAL_STRINGL(zsource, args->source, args->sourceLimit - args->source, 1);
+ zargs[1] = &zsource;
+
+ MAKE_STD_ZVAL(zcodeunits);
+ ZVAL_STRINGL(zcodeunits, codeUnits, length, 1);
+ zargs[2] = &zcodeunits;
+
+ MAKE_STD_ZVAL(zerror);
+ ZVAL_LONG(zerror, *pErrorCode);
+ zargs[3] = &zerror;
+
+ objval->to_cb.param_count = 4;
+ objval->to_cb.params = zargs;
+ objval->to_cb.retval_ptr_ptr = &retval;
+ objval->to_cb.no_separation = 0;
+ if (zend_call_function(&(objval->to_cb), &(objval->to_cache) TSRMLS_CC) == FAILURE) {
+ /* Unlikely */
+ php_converter_throw_failure(objval, U_INTERNAL_PROGRAM_ERROR TSRMLS_CC, "Unexpected failure calling toUCallback()");
+ } else if (retval) {
+ php_converter_append_toUnicode_target(retval, args, objval TSRMLS_CC);
+ zval_ptr_dtor(&retval);
+ }
+
+ if (Z_TYPE_P(zerror) == IS_LONG) {
+ *pErrorCode = Z_LVAL_P(zerror);
+ }
+
+ zval_ptr_dtor(&zreason);
+ zval_ptr_dtor(&zsource);
+ zval_ptr_dtor(&zcodeunits);
+ zval_ptr_dtor(&zerror);
+}
+/* }}} */
+
+/* {{{ php_converter_append_fromUnicode_target */
+static void php_converter_append_fromUnicode_target(zval *val, UConverterFromUnicodeArgs *args, php_converter_object *objval TSRMLS_DC) {
+ switch (Z_TYPE_P(val)) {
+ case IS_NULL:
+ /* Ignore */
+ return;
+ case IS_LONG:
+ if (TARGET_CHECK(args, 1)) {
+ *(args->target++) = Z_LVAL_P(val);
+ }
+ return;
+ case IS_STRING:
+ {
+ int vallen = Z_STRLEN_P(val);
+ if (TARGET_CHECK(args, vallen)) {
+ memcpy(args->target, Z_STRVAL_P(val), vallen);
+ args->target += vallen;
+ }
+ return;
+ }
+ case IS_ARRAY:
+ {
+ HashTable *ht = Z_ARRVAL_P(val);
+ HashPosition pos;
+ zval **tmpzval;
+ for(zend_hash_internal_pointer_reset_ex(ht, &pos);
+ zend_hash_get_current_data_ex(ht, (void**)&tmpzval, &pos) == SUCCESS;
+ zend_hash_move_forward_ex(ht, &pos)) {
+ php_converter_append_fromUnicode_target(*tmpzval, args, objval TSRMLS_CC);
+ }
+ return;
+ }
+ default:
+ php_converter_throw_failure(objval, U_ILLEGAL_ARGUMENT_ERROR TSRMLS_CC, "fromUCallback() specified illegal type for substitution character");
+ }
+}
+/* }}} */
+
+/* {{{ php_converter_from_u_callback */
+static void php_converter_from_u_callback(const void *context,
+ UConverterFromUnicodeArgs *args,
+ const UChar *codeUnits, int32_t length, UChar32 codePoint,
+ UConverterCallbackReason reason,
+ UErrorCode *pErrorCode) {
+ php_converter_object *objval = (php_converter_object*)context;
+ zval *zreason, *zsource, *zcodepoint, *zerror, *retval = NULL;
+ zval **zargs[4];
+ int i;
+#ifdef ZTS
+ TSRMLS_D = objval->tsrm_ls;
+#endif
+
+ MAKE_STD_ZVAL(zreason);
+ ZVAL_LONG(zreason, reason);
+ zargs[0] = &zreason;
+
+ MAKE_STD_ZVAL(zsource);
+ array_init(zsource);
+ i = 0;
+ while (i < length) {
+ UChar32 c;
+ U16_NEXT(codeUnits, i, length, c);
+ add_next_index_long(zsource, c);
+ }
+ zargs[1] = &zsource;
+
+ MAKE_STD_ZVAL(zcodepoint);
+ ZVAL_LONG(zcodepoint, codePoint);
+ zargs[2] = &zcodepoint;
+
+ MAKE_STD_ZVAL(zerror);
+ ZVAL_LONG(zerror, *pErrorCode);
+ zargs[3] = &zerror;
+
+ objval->from_cb.param_count = 4;
+ objval->from_cb.params = zargs;
+ objval->from_cb.retval_ptr_ptr = &retval;
+ objval->from_cb.no_separation = 0;
+ if (zend_call_function(&(objval->from_cb), &(objval->from_cache) TSRMLS_CC) == FAILURE) {
+ /* Unlikely */
+ php_converter_throw_failure(objval, U_INTERNAL_PROGRAM_ERROR TSRMLS_CC, "Unexpected failure calling fromUCallback()");
+ } else if (retval) {
+ php_converter_append_fromUnicode_target(retval, args, objval TSRMLS_CC);
+ zval_ptr_dtor(&retval);
+ }
+
+ if (Z_TYPE_P(zerror) == IS_LONG) {
+ *pErrorCode = Z_LVAL_P(zerror);
+ }
+
+ zval_ptr_dtor(&zreason);
+ zval_ptr_dtor(&zsource);
+ zval_ptr_dtor(&zcodepoint);
+ zval_ptr_dtor(&zerror);
+}
+/* }}} */
+
+/* {{{ php_converter_set_callbacks */
+static inline zend_bool php_converter_set_callbacks(php_converter_object *objval, UConverter *cnv TSRMLS_DC) {
+ zend_bool ret = 1;
+ UErrorCode error = U_ZERO_ERROR;
+
+ if (objval->obj.ce == php_converter_ce) {
+ /* Short-circuit having to go through method calls and data marshalling
+ * when we're using default behavior
+ */
+ return 1;
+ }
+
+ ucnv_setToUCallBack(cnv, (UConverterToUCallback)php_converter_to_u_callback, (const void*)objval,
+ NULL, NULL, &error);
+ if (U_FAILURE(error)) {
+ THROW_UFAILURE(objval, "ucnv_setToUCallBack", error);
+ ret = 0;
+ }
+
+ error = U_ZERO_ERROR;
+ ucnv_setFromUCallBack(cnv, (UConverterFromUCallback)php_converter_from_u_callback, (const void*)objval,
+ NULL, NULL, &error);
+ if (U_FAILURE(error)) {
+ THROW_UFAILURE(objval, "ucnv_setFromUCallBack", error);
+ ret = 0;
+ }
+ return ret;
+}
+/* }}} */
+
+/* {{{ php_converter_set_encoding */
+static zend_bool php_converter_set_encoding(php_converter_object *objval,
+ UConverter **pcnv,
+ const char *enc, int enc_len
+ TSRMLS_DC) {
+ UErrorCode error = U_ZERO_ERROR;
+ UConverter *cnv = ucnv_open(enc, &error);
+
+ if (error == U_AMBIGUOUS_ALIAS_WARNING) {
+ UErrorCode getname_error = U_ZERO_ERROR;
+ const char *actual_encoding = ucnv_getName(cnv, &getname_error);
+ if (U_FAILURE(getname_error)) {
+ /* Should never happen */
+ actual_encoding = "(unknown)";
+ }
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Ambiguous encoding specified, using %s", actual_encoding);
+ } else if (U_FAILURE(error)) {
+ if (objval) {
+ THROW_UFAILURE(objval, "ucnv_open", error);
+ } else {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error setting encoding: %d - %s", (int)error, u_errorName(error));
+ }
+ return 0;
+ }
+
+ if (objval && !php_converter_set_callbacks(objval, cnv TSRMLS_CC)) {
+ return 0;
+ }
+
+ if (*pcnv) {
+ ucnv_close(*pcnv);
+ }
+ *pcnv = cnv;
+ return 1;
+}
+/* }}} */
+
+/* {{{ php_converter_do_set_encoding */
+ZEND_BEGIN_ARG_INFO_EX(php_converter_set_encoding_arginfo, 0, ZEND_RETURN_VALUE, 1)
+ ZEND_ARG_INFO(0, encoding)
+ZEND_END_ARG_INFO();
+static void php_converter_do_set_encoding(UConverter *cnv, INTERNAL_FUNCTION_PARAMETERS) {
+ php_converter_object *objval = CONV_GET(getThis());
+ char *enc;
+ int enc_len;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &enc, &enc_len) == FAILURE) {
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, "Bad arguments, "
+ "expected one string argument", 0 TSRMLS_CC);
+ RETURN_FALSE;
+ }
+ intl_errors_reset(&objval->error TSRMLS_CC);
+
+ RETURN_BOOL(php_converter_set_encoding(objval, &(objval->src), enc, enc_len TSRMLS_CC));
+}
+/* }}} */
+
+/* {{{ proto bool UConverter::setSourceEncoding(string encoding) */
+static PHP_METHOD(UConverter, setSourceEncoding) {
+ php_converter_object *objval = CONV_GET(getThis());
+ php_converter_do_set_encoding(objval->src, INTERNAL_FUNCTION_PARAM_PASSTHRU);
+}
+/* }}} */
+
+/* {{{ proto bool UConverter::setDestinationEncoding(string encoding) */
+static PHP_METHOD(UConverter, setDestinationEncoding) {
+ php_converter_object *objval = CONV_GET(getThis());
+ php_converter_do_set_encoding(objval->dest, INTERNAL_FUNCTION_PARAM_PASSTHRU);
+}
+/* }}} */
+
+/* {{{ php_converter_do_get_encoding */
+ZEND_BEGIN_ARG_INFO_EX(php_converter_get_encoding_arginfo, 0, ZEND_RETURN_VALUE, 0)
+ZEND_END_ARG_INFO();
+static void php_converter_do_get_encoding(php_converter_object *objval, UConverter *cnv, INTERNAL_FUNCTION_PARAMETERS) {
+ const char *name;
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, "Expected no arguments", 0 TSRMLS_CC);
+ RETURN_FALSE;
+ }
+
+ intl_errors_reset(&objval->error TSRMLS_CC);
+
+ if (!cnv) {
+ RETURN_NULL();
+ }
+
+ name = ucnv_getName(cnv, &objval->error.code);
+ if (U_FAILURE(objval->error.code)) {
+ THROW_UFAILURE(objval, "ucnv_getName()", objval->error.code);
+ RETURN_FALSE;
+ }
+
+ RETURN_STRING(name, 1);
+}
+/* }}} */
+
+/* {{{ proto string UConverter::getSourceEncoding() */
+static PHP_METHOD(UConverter, getSourceEncoding) {
+ php_converter_object *objval = CONV_GET(getThis());
+ php_converter_do_get_encoding(objval, objval->src, INTERNAL_FUNCTION_PARAM_PASSTHRU);
+}
+/* }}} */
+
+/* {{{ proto string UConverter::getDestinationEncoding() */
+static PHP_METHOD(UConverter, getDestinationEncoding) {
+ php_converter_object *objval = CONV_GET(getThis());
+ php_converter_do_get_encoding(objval, objval->dest, INTERNAL_FUNCTION_PARAM_PASSTHRU);
+}
+/* }}} */
+
+/* {{{ php_converter_do_get_type */
+ZEND_BEGIN_ARG_INFO_EX(php_converter_get_type_arginfo, 0, ZEND_RETURN_VALUE, 0)
+ZEND_END_ARG_INFO();
+static void php_converter_do_get_type(php_converter_object *objval, UConverter *cnv, INTERNAL_FUNCTION_PARAMETERS) {
+ UConverterType t;
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, "Expected no arguments", 0 TSRMLS_CC);
+ RETURN_FALSE;
+ }
+ intl_errors_reset(&objval->error TSRMLS_CC);
+
+ if (!cnv) {
+ RETURN_NULL();
+ }
+
+ t = ucnv_getType(cnv);
+ if (U_FAILURE(objval->error.code)) {
+ THROW_UFAILURE(objval, "ucnv_getType", objval->error.code);
+ RETURN_FALSE;
+ }
+
+ RETURN_LONG(t);
+}
+/* }}} */
+
+/* {{{ proto long UConverter::getSourceType() */
+static PHP_METHOD(UConverter, getSourceType) {
+ php_converter_object *objval = CONV_GET(getThis());
+ php_converter_do_get_type(objval, objval->src, INTERNAL_FUNCTION_PARAM_PASSTHRU);
+}
+/* }}} */
+
+/* {{{ proto long UConverter::getDestinationType() */
+static PHP_METHOD(UConverter, getDestinationType) {
+ php_converter_object *objval = CONV_GET(getThis());
+ php_converter_do_get_type(objval, objval->dest, INTERNAL_FUNCTION_PARAM_PASSTHRU);
+}
+/* }}} */
+
+/* {{{ php_converter_resolve_callback */
+static void php_converter_resolve_callback(zval *zobj,
+ php_converter_object *objval,
+ const char *callback_name,
+ zend_fcall_info *finfo,
+ zend_fcall_info_cache *fcache TSRMLS_DC) {
+ char *errstr = NULL;
+ zval caller;
+
+ array_init(&caller);
+ Z_ADDREF_P(zobj);
+ add_index_zval(&caller, 0, zobj);
+ add_index_string(&caller, 1, callback_name, 1);
+ if (zend_fcall_info_init(&caller, 0, finfo, fcache, NULL, &errstr TSRMLS_CC) == FAILURE) {
+ php_converter_throw_failure(objval, U_INTERNAL_PROGRAM_ERROR TSRMLS_CC, "Error setting converter callback: %s", errstr);
+ }
+ zval_dtor(&caller);
+ if (errstr) {
+ efree(errstr);
+ }
+}
+/* }}} */
+
+/* {{{ proto void UConverter::__construct([string dest = 'utf-8',[string src = 'utf-8']]) */
+ZEND_BEGIN_ARG_INFO_EX(php_converter_arginfo, 0, ZEND_RETURN_VALUE, 0)
+ ZEND_ARG_INFO(0, destination_encoding)
+ ZEND_ARG_INFO(0, source_encoding)
+ZEND_END_ARG_INFO();
+
+static PHP_METHOD(UConverter, __construct) {
+ php_converter_object *objval = CONV_GET(getThis());
+ char *src = "utf-8";
+ int src_len = sizeof("utf-8") - 1;
+ char *dest = src;
+ int dest_len = src_len;
+
+ intl_error_reset(NULL TSRMLS_CC);
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s!s!",
+ &dest, &dest_len, &src, &src_len) == FAILURE) {
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "UConverter::__construct(): bad arguments", 0 TSRMLS_CC);
+ return;
+ }
+
+ php_converter_set_encoding(objval, &(objval->src), src, src_len TSRMLS_CC);
+ php_converter_set_encoding(objval, &(objval->dest), dest, dest_len TSRMLS_CC);
+ php_converter_resolve_callback(getThis(), objval, "toUCallback", &(objval->to_cb), &(objval->to_cache) TSRMLS_CC);
+ php_converter_resolve_callback(getThis(), objval, "fromUCallback", &(objval->from_cb), &(objval->from_cache) TSRMLS_CC);
+}
+/* }}} */
+
+/* {{{ proto bool UConverter::setSubstChars(string $chars) */
+ZEND_BEGIN_ARG_INFO_EX(php_converter_setSubstChars_arginfo, 0, ZEND_RETURN_VALUE, 1)
+ ZEND_ARG_INFO(0, chars)
+ZEND_END_ARG_INFO();
+
+static PHP_METHOD(UConverter, setSubstChars) {
+ php_converter_object *objval = CONV_GET(getThis());
+ char *chars;
+ int chars_len, ret = 1;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &chars, &chars_len) == FAILURE) {
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "UConverter::setSubstChars(): bad arguments", 0 TSRMLS_CC);
+ RETURN_FALSE;
+ }
+ intl_errors_reset(&objval->error TSRMLS_CC);
+
+ if (objval->src) {
+ UErrorCode error = U_ZERO_ERROR;
+ ucnv_setSubstChars(objval->src, chars, chars_len, &error);
+ if (U_FAILURE(error)) {
+ THROW_UFAILURE(objval, "ucnv_setSubstChars", error);
+ ret = 0;
+ }
+ } else {
+ php_converter_throw_failure(objval, U_INVALID_STATE_ERROR TSRMLS_CC, "Source Converter has not been initialized yet");
+ ret = 0;
+ }
+
+ if (objval->dest) {
+ UErrorCode error = U_ZERO_ERROR;
+ ucnv_setSubstChars(objval->dest, chars, chars_len, &error);
+ if (U_FAILURE(error)) {
+ THROW_UFAILURE(objval, "ucnv_setSubstChars", error);
+ ret = 0;
+ }
+ } else {
+ php_converter_throw_failure(objval, U_INVALID_STATE_ERROR TSRMLS_CC, "Destination Converter has not been initialized yet");
+ ret = 0;
+ }
+
+ RETURN_BOOL(ret);
+}
+/* }}} */
+
+/* {{{ proto string UConverter::getSubstChars() */
+ZEND_BEGIN_ARG_INFO_EX(php_converter_getSubstChars_arginfo, 0, ZEND_RETURN_VALUE, 0)
+ZEND_END_ARG_INFO();
+
+static PHP_METHOD(UConverter, getSubstChars) {
+ php_converter_object *objval = CONV_GET(getThis());
+ char chars[127];
+ int8_t chars_len = sizeof(chars);
+ UErrorCode error = U_ZERO_ERROR;
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "UConverter::getSubstChars(): expected no arguments", 0 TSRMLS_CC);
+ RETURN_FALSE;
+ }
+ intl_errors_reset(&objval->error TSRMLS_CC);
+
+ if (!objval->src) {
+ RETURN_NULL();
+ }
+
+ /* src and dest get the same subst chars set,
+ * so it doesn't really matter which one we read from
+ */
+ ucnv_getSubstChars(objval->src, chars, &chars_len, &error);
+ if (U_FAILURE(error)) {
+ THROW_UFAILURE(objval, "ucnv_getSubstChars", error);
+ RETURN_FALSE;
+ }
+
+ RETURN_STRINGL(chars, chars_len, 1);
+}
+/* }}} */
+
+/* {{{ php_converter_do_convert */
+static zend_bool php_converter_do_convert(UConverter *dest_cnv, char **pdest, int32_t *pdest_len,
+ UConverter *src_cnv, const char *src, int32_t src_len,
+ php_converter_object *objval
+ TSRMLS_DC) {
+ UErrorCode error = U_ZERO_ERROR;
+ int32_t dest_len,
+ temp_len;
+ char *dest;
+ UChar *temp;
+
+ if (!src_cnv || !dest_cnv) {
+ php_converter_throw_failure(objval, U_INVALID_STATE_ERROR TSRMLS_CC,
+ "Internal converters not initialized");
+ return 0;
+ }
+
+ /* Get necessary buffer size first */
+ temp_len = 1 + ucnv_toUChars(src_cnv, NULL, 0, src, src_len, &error);
+ if (U_FAILURE(error) && error != U_BUFFER_OVERFLOW_ERROR) {
+ THROW_UFAILURE(objval, "ucnv_toUChars", error);
+ return 0;
+ }
+ temp = safe_emalloc(sizeof(UChar), temp_len, sizeof(UChar));
+
+ /* Convert to intermediate UChar* array */
+ error = U_ZERO_ERROR;
+ temp_len = ucnv_toUChars(src_cnv, temp, temp_len, src, src_len, &error);
+ if (U_FAILURE(error)) {
+ THROW_UFAILURE(objval, "ucnv_toUChars", error);
+ efree(temp);
+ return 0;
+ }
+ temp[temp_len] = 0;
+
+ /* Get necessary output buffer size */
+ dest_len = 1 + ucnv_fromUChars(dest_cnv, NULL, 0, temp, temp_len, &error);
+ if (U_FAILURE(error) && error != U_BUFFER_OVERFLOW_ERROR) {
+ THROW_UFAILURE(objval, "ucnv_fromUChars", error);
+ efree(temp);
+ return 0;
+ }
+ dest = safe_emalloc(sizeof(char), dest_len, sizeof(char));
+
+ /* Convert to final encoding */
+ error = U_ZERO_ERROR;
+ dest_len = ucnv_fromUChars(dest_cnv, dest, dest_len, temp, temp_len, &error);
+ efree(temp);
+ if (U_FAILURE(error)) {
+ THROW_UFAILURE(objval, "ucnv_fromUChars", error);
+ efree(dest);
+ return 0;
+ }
+
+ *pdest = dest;
+ if (pdest_len) {
+ *pdest_len = dest_len;
+ }
+
+ return 1;
+}
+/* }}} */
+
+/* {{{ proto string UConverter::reasonText(long reason) */
+#define UCNV_REASON_CASE(v) case (UCNV_ ## v) : RETURN_STRINGL( "REASON_" #v , sizeof( "REASON_" #v ) - 1, 1);
+ZEND_BEGIN_ARG_INFO_EX(php_converter_reasontext_arginfo, 0, ZEND_RETURN_VALUE, 0)
+ ZEND_ARG_INFO(0, reason)
+ZEND_END_ARG_INFO();
+static PHP_METHOD(UConverter, reasonText) {
+ long reason;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &reason) == FAILURE) {
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "UConverter::reasonText(): bad arguments", 0 TSRMLS_CC);
+ RETURN_FALSE;
+ }
+ intl_error_reset(NULL TSRMLS_CC);
+
+ switch (reason) {
+ UCNV_REASON_CASE(UNASSIGNED)
+ UCNV_REASON_CASE(ILLEGAL)
+ UCNV_REASON_CASE(IRREGULAR)
+ UCNV_REASON_CASE(RESET)
+ UCNV_REASON_CASE(CLOSE)
+ UCNV_REASON_CASE(CLONE)
+ default:
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown UConverterCallbackReason: %ld", reason);
+ RETURN_FALSE;
+ }
+}
+/* }}} */
+
+/* {{{ proto string UConverter::convert(string str[, bool reverse]) */
+ZEND_BEGIN_ARG_INFO_EX(php_converter_convert_arginfo, 0, ZEND_RETURN_VALUE, 1)
+ ZEND_ARG_INFO(0, str)
+ ZEND_ARG_INFO(0, reverse)
+ZEND_END_ARG_INFO();
+
+static PHP_METHOD(UConverter, convert) {
+ php_converter_object *objval = CONV_GET(getThis());
+ char *str, *dest;
+ int str_len, dest_len;
+ zend_bool reverse = 0;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|b",
+ &str, &str_len, &reverse) == FAILURE) {
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "UConverter::convert(): bad arguments", 0 TSRMLS_CC);
+ RETURN_FALSE;
+ }
+ intl_errors_reset(&objval->error TSRMLS_CC);
+
+ if (php_converter_do_convert(reverse ? objval->src : objval->dest,
+ &dest, &dest_len,
+ reverse ? objval->dest : objval->src,
+ str, str_len,
+ objval TSRMLS_CC)) {
+ RETURN_STRINGL(dest, dest_len, 0);
+ } else {
+ RETURN_FALSE;
+ }
+}
+/* }}} */
+
+/* {{{ proto string UConverter::transcode(string $str, string $toEncoding, string $fromEncoding[, Array $options = array()]) */
+ZEND_BEGIN_ARG_INFO_EX(php_converter_transcode_arginfo, 0, ZEND_RETURN_VALUE, 3)
+ ZEND_ARG_INFO(0, str)
+ ZEND_ARG_INFO(0, toEncoding)
+ ZEND_ARG_INFO(0, fromEncoding)
+ ZEND_ARG_ARRAY_INFO(0, options, 1)
+ZEND_END_ARG_INFO();
+
+static PHP_METHOD(UConverter, transcode) {
+ char *str, *src, *dest;
+ int str_len, src_len, dest_len;
+ zval *options = NULL;
+ UConverter *src_cnv = NULL, *dest_cnv = NULL;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sss|a!",
+ &str, &str_len, &dest, &dest_len, &src, &src_len, &options) == FAILURE) {
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "UConverter::transcode(): bad arguments", 0 TSRMLS_CC);
+ RETURN_FALSE;
+ }
+ intl_error_reset(NULL TSRMLS_CC);
+
+ if (php_converter_set_encoding(NULL, &src_cnv, src, src_len TSRMLS_CC) &&
+ php_converter_set_encoding(NULL, &dest_cnv, dest, dest_len TSRMLS_CC)) {
+ char *out = NULL;
+ int out_len = 0;
+ UErrorCode error = U_ZERO_ERROR;
+
+ if (options && zend_hash_num_elements(Z_ARRVAL_P(options))) {
+ zval **tmpzval;
+
+ if (U_SUCCESS(error) &&
+ zend_hash_find(Z_ARRVAL_P(options), "from_subst", sizeof("from_subst"), (void**)&tmpzval) == SUCCESS &&
+ Z_TYPE_PP(tmpzval) == IS_STRING) {
+ error = U_ZERO_ERROR;
+ ucnv_setSubstChars(src_cnv, Z_STRVAL_PP(tmpzval), Z_STRLEN_PP(tmpzval) & 0x7F, &error);
+ }
+ if (U_SUCCESS(error) &&
+ zend_hash_find(Z_ARRVAL_P(options), "to_subst", sizeof("to_subst"), (void**)&tmpzval) == SUCCESS &&
+ Z_TYPE_PP(tmpzval) == IS_STRING) {
+ error = U_ZERO_ERROR;
+ ucnv_setSubstChars(dest_cnv, Z_STRVAL_PP(tmpzval), Z_STRLEN_PP(tmpzval) & 0x7F, &error);
+ }
+ }
+
+ if (U_SUCCESS(error) &&
+ php_converter_do_convert(dest_cnv, &out, &out_len, src_cnv, str, str_len, NULL TSRMLS_CC)) {
+ RETVAL_STRINGL(out, out_len, 0);
+ }
+
+ if (U_FAILURE(error)) {
+ THROW_UFAILURE(NULL, "transcode", error);
+ RETVAL_FALSE;
+ }
+ } else {
+ RETVAL_FALSE;
+ }
+
+ if (src_cnv) {
+ ucnv_close(src_cnv);
+ }
+ if (dest_cnv) {
+ ucnv_close(dest_cnv);
+ }
+}
+/* }}} */
+
+/* {{{ proto int UConverter::getErrorCode() */
+ZEND_BEGIN_ARG_INFO_EX(php_converter_geterrorcode_arginfo, 0, ZEND_RETURN_VALUE, 0)
+ZEND_END_ARG_INFO();
+static PHP_METHOD(UConverter, getErrorCode) {
+ php_converter_object *objval = CONV_GET(getThis());
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "UConverter::getErrorCode(): expected no arguments", 0 TSRMLS_CC);
+ RETURN_FALSE;
+ }
+
+ RETURN_LONG(intl_error_get_code(&(objval->error) TSRMLS_CC));
+}
+/* }}} */
+
+/* {{{ proto string UConverter::getErrorMessage() */
+ZEND_BEGIN_ARG_INFO_EX(php_converter_geterrormsg_arginfo, 0, ZEND_RETURN_VALUE, 0)
+ZEND_END_ARG_INFO();
+static PHP_METHOD(UConverter, getErrorMessage) {
+ php_converter_object *objval = CONV_GET(getThis());
+ char *message = intl_error_get_message(&(objval->error) TSRMLS_CC);
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "UConverter::getErrorMessage(): expected no arguments", 0 TSRMLS_CC);
+ RETURN_FALSE;
+ }
+
+ if (message) {
+ RETURN_STRING(message, 1);
+ } else {
+ RETURN_NULL();
+ }
+}
+/* }}} */
+
+/* {{{ proto array UConverter::getAvailable() */
+ZEND_BEGIN_ARG_INFO_EX(php_converter_getavailable_arginfo, 0, ZEND_RETURN_VALUE, 0)
+ZEND_END_ARG_INFO();
+static PHP_METHOD(UConverter, getAvailable) {
+ int32_t i,
+ count = ucnv_countAvailable();
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "UConverter::getErrorMessage(): expected no arguments", 0 TSRMLS_CC);
+ RETURN_FALSE;
+ }
+ intl_error_reset(NULL TSRMLS_CC);
+
+ array_init(return_value);
+ for(i = 0; i < count; i++) {
+ const char *name = ucnv_getAvailableName(i);
+ add_next_index_string(return_value, name, 1);
+ }
+}
+/* }}} */
+
+/* {{{ proto array UConverter::getAliases(string name) */
+ZEND_BEGIN_ARG_INFO_EX(php_converter_getaliases_arginfo, 0, ZEND_RETURN_VALUE, 0)
+ ZEND_ARG_INFO(0, name)
+ZEND_END_ARG_INFO();
+static PHP_METHOD(UConverter, getAliases) {
+ char *name;
+ int name_len;
+ UErrorCode error = U_ZERO_ERROR;
+ uint16_t i, count;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &name, &name_len) == FAILURE) {
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "UConverter::getAliases(): bad arguments", 0 TSRMLS_CC);
+ RETURN_FALSE;
+ }
+ intl_error_reset(NULL TSRMLS_CC);
+
+ count = ucnv_countAliases(name, &error);
+ if (U_FAILURE(error)) {
+ THROW_UFAILURE(NULL, "ucnv_countAliases", error);
+ RETURN_FALSE;
+ }
+
+ array_init(return_value);
+ for(i = 0; i < count; i++) {
+ const char *alias;
+
+ error = U_ZERO_ERROR;
+ alias = ucnv_getAlias(name, i, &error);
+ if (U_FAILURE(error)) {
+ THROW_UFAILURE(NULL, "ucnv_getAlias", error);
+ zval_dtor(return_value);
+ RETURN_NULL();
+ }
+ add_next_index_string(return_value, alias, 1);
+ }
+}
+/* }}} */
+
+/* {{{ proto array UConverter::getStandards() */
+ZEND_BEGIN_ARG_INFO_EX(php_converter_getstandards_arginfo, 0, ZEND_RETURN_VALUE, 0)
+ZEND_END_ARG_INFO();
+static PHP_METHOD(UConverter, getStandards) {
+ uint16_t i, count;
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "UConverter::getStandards(): expected no arguments", 0 TSRMLS_CC);
+ RETURN_FALSE;
+ }
+ intl_error_reset(NULL TSRMLS_CC);
+
+ array_init(return_value);
+ count = ucnv_countStandards();
+ for(i = 0; i < count; i++) {
+ UErrorCode error = U_ZERO_ERROR;
+ const char *name = ucnv_getStandard(i, &error);
+ if (U_FAILURE(error)) {
+ THROW_UFAILURE(NULL, "ucnv_getStandard", error);
+ zval_dtor(return_value);
+ RETURN_NULL();
+ }
+ add_next_index_string(return_value, name, 1);
+ }
+}
+/* }}} */
+
+static zend_function_entry php_converter_methods[] = {
+ PHP_ME(UConverter, __construct, php_converter_arginfo, ZEND_ACC_PUBLIC | ZEND_ACC_CTOR)
+
+ /* Encoding selection */
+ PHP_ME(UConverter, setSourceEncoding, php_converter_set_encoding_arginfo, ZEND_ACC_PUBLIC)
+ PHP_ME(UConverter, setDestinationEncoding, php_converter_set_encoding_arginfo, ZEND_ACC_PUBLIC)
+ PHP_ME(UConverter, getSourceEncoding, php_converter_get_encoding_arginfo, ZEND_ACC_PUBLIC)
+ PHP_ME(UConverter, getDestinationEncoding, php_converter_get_encoding_arginfo, ZEND_ACC_PUBLIC)
+
+ /* Introspection for algorithmic converters */
+ PHP_ME(UConverter, getSourceType, php_converter_get_type_arginfo, ZEND_ACC_PUBLIC)
+ PHP_ME(UConverter, getDestinationType, php_converter_get_type_arginfo, ZEND_ACC_PUBLIC)
+
+ /* Basic codeunit error handling */
+ PHP_ME(UConverter, getSubstChars, php_converter_getSubstChars_arginfo, ZEND_ACC_PUBLIC)
+ PHP_ME(UConverter, setSubstChars, php_converter_setSubstChars_arginfo, ZEND_ACC_PUBLIC)
+
+ /* Default callback handlers */
+ PHP_ME(UConverter, toUCallback, php_converter_toUCallback_arginfo, ZEND_ACC_PUBLIC)
+ PHP_ME(UConverter, fromUCallback, php_converter_fromUCallback_arginfo, ZEND_ACC_PUBLIC)
+
+ /* Core conversion workhorses */
+ PHP_ME(UConverter, convert, php_converter_convert_arginfo, ZEND_ACC_PUBLIC)
+ PHP_ME(UConverter, transcode, php_converter_transcode_arginfo, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
+
+ /* Error inspection */
+ PHP_ME(UConverter, getErrorCode, php_converter_geterrorcode_arginfo, ZEND_ACC_PUBLIC)
+ PHP_ME(UConverter, getErrorMessage, php_converter_geterrormsg_arginfo, ZEND_ACC_PUBLIC)
+
+ /* Ennumeration and lookup */
+ PHP_ME(UConverter, reasonText, php_converter_reasontext_arginfo, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
+ PHP_ME(UConverter, getAvailable, php_converter_getavailable_arginfo, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
+ PHP_ME(UConverter, getAliases, php_converter_getaliases_arginfo, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
+ PHP_ME(UConverter, getStandards, php_converter_getstandards_arginfo, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
+ { NULL, NULL, NULL }
+};
+
+/* {{{ Converter create/clone/destroy */
+static void php_converter_free_object(php_converter_object *objval TSRMLS_DC) {
+ if (objval->src) {
+ ucnv_close(objval->src);
+ }
+
+ if (objval->dest) {
+ ucnv_close(objval->dest);
+ }
+
+ intl_error_reset(&(objval->error) TSRMLS_CC);
+ zend_object_std_dtor(&(objval->obj) TSRMLS_CC);
+
+ efree(objval);
+}
+
+static zend_object_value php_converter_object_ctor(zend_class_entry *ce, php_converter_object **pobjval TSRMLS_DC) {
+ php_converter_object *objval;
+ zend_object_value retval;
+
+ objval = ecalloc(1, sizeof(php_converter_object));
+ objval->obj.ce = ce;
+
+#ifdef ZTS
+ objval->tsrm_ls = TSRMLS_C;
+#endif
+ intl_error_init(&(objval->error) TSRMLS_CC);
+
+ retval.handle = zend_objects_store_put(objval, NULL, (zend_objects_free_object_storage_t)php_converter_free_object, NULL TSRMLS_CC);
+ retval.handlers = &php_converter_object_handlers;
+ *pobjval = objval;
+
+ return retval;
+}
+
+static zend_object_value php_converter_create_object(zend_class_entry *ce TSRMLS_DC) {
+ php_converter_object *objval = NULL;
+ zend_object_value retval = php_converter_object_ctor(ce, &objval TSRMLS_CC);
+
+ object_properties_init(&(objval->obj), ce);
+
+ return retval;
+}
+
+static zend_object_value php_converter_clone_object(zval *object TSRMLS_DC) {
+ php_converter_object *objval, *oldobj = (php_converter_object*)zend_objects_get_address(object TSRMLS_CC);
+ zend_object_value retval = php_converter_object_ctor(Z_OBJCE_P(object), &objval TSRMLS_CC);
+ UErrorCode error = U_ZERO_ERROR;
+
+ intl_errors_reset(&oldobj->error TSRMLS_CC);
+
+ objval->src = ucnv_safeClone(oldobj->src, NULL, NULL, &error);
+ if (U_SUCCESS(error)) {
+ error = U_ZERO_ERROR;
+ objval->dest = ucnv_safeClone(oldobj->dest, NULL, NULL, &error);
+ }
+ if (U_FAILURE(error)) {
+ char *err_msg;
+ THROW_UFAILURE(oldobj, "ucnv_safeClone", error);
+
+ err_msg = intl_error_get_message(&oldobj->error TSRMLS_CC);
+ zend_throw_exception(NULL, err_msg, 0 TSRMLS_CC);
+ efree(err_msg);
+
+ return retval;
+ }
+
+ /* Update contexts for converter error handlers */
+ php_converter_set_callbacks(objval, objval->src TSRMLS_CC);
+ php_converter_set_callbacks(objval, objval->dest TSRMLS_CC);
+
+ zend_objects_clone_members(&(objval->obj), retval, &(oldobj->obj), Z_OBJ_HANDLE_P(object) TSRMLS_CC);
+
+ /* Newly cloned object deliberately does not inherit error state from original object */
+
+ return retval;
+}
+/* }}} */
+
+#define CONV_REASON_CONST(v) zend_declare_class_constant_long(php_converter_ce, "REASON_" #v, sizeof("REASON_" #v) - 1, UCNV_ ## v TSRMLS_CC)
+#define CONV_TYPE_CONST(v) zend_declare_class_constant_long(php_converter_ce, #v , sizeof(#v) - 1, UCNV_ ## v TSRMLS_CC)
+
+/* {{{ php_converter_minit */
+int php_converter_minit(INIT_FUNC_ARGS) {
+ zend_class_entry ce;
+
+ INIT_CLASS_ENTRY(ce, "UConverter", php_converter_methods);
+ php_converter_ce = zend_register_internal_class(&ce TSRMLS_CC);
+ php_converter_ce->create_object = php_converter_create_object;
+ memcpy(&php_converter_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
+ php_converter_object_handlers.clone_obj = php_converter_clone_object;
+
+ /* enum UConverterCallbackReason */
+ CONV_REASON_CONST(UNASSIGNED);
+ CONV_REASON_CONST(ILLEGAL);
+ CONV_REASON_CONST(IRREGULAR);
+ CONV_REASON_CONST(RESET);
+ CONV_REASON_CONST(CLOSE);
+ CONV_REASON_CONST(CLONE);
+
+ /* enum UConverterType */
+ CONV_TYPE_CONST(UNSUPPORTED_CONVERTER);
+ CONV_TYPE_CONST(SBCS);
+ CONV_TYPE_CONST(DBCS);
+ CONV_TYPE_CONST(MBCS);
+ CONV_TYPE_CONST(LATIN_1);
+ CONV_TYPE_CONST(UTF8);
+ CONV_TYPE_CONST(UTF16_BigEndian);
+ CONV_TYPE_CONST(UTF16_LittleEndian);
+ CONV_TYPE_CONST(UTF32_BigEndian);
+ CONV_TYPE_CONST(UTF32_LittleEndian);
+ CONV_TYPE_CONST(EBCDIC_STATEFUL);
+ CONV_TYPE_CONST(ISO_2022);
+ CONV_TYPE_CONST(LMBCS_1);
+ CONV_TYPE_CONST(LMBCS_2);
+ CONV_TYPE_CONST(LMBCS_3);
+ CONV_TYPE_CONST(LMBCS_4);
+ CONV_TYPE_CONST(LMBCS_5);
+ CONV_TYPE_CONST(LMBCS_6);
+ CONV_TYPE_CONST(LMBCS_8);
+ CONV_TYPE_CONST(LMBCS_11);
+ CONV_TYPE_CONST(LMBCS_16);
+ CONV_TYPE_CONST(LMBCS_17);
+ CONV_TYPE_CONST(LMBCS_18);
+ CONV_TYPE_CONST(LMBCS_19);
+ CONV_TYPE_CONST(LMBCS_LAST);
+ CONV_TYPE_CONST(HZ);
+ CONV_TYPE_CONST(SCSU);
+ CONV_TYPE_CONST(ISCII);
+ CONV_TYPE_CONST(US_ASCII);
+ CONV_TYPE_CONST(UTF7);
+ CONV_TYPE_CONST(BOCU1);
+ CONV_TYPE_CONST(UTF16);
+ CONV_TYPE_CONST(UTF32);
+ CONV_TYPE_CONST(CESU8);
+ CONV_TYPE_CONST(IMAP_MAILBOX);
+
+ return SUCCESS;
+}
+/* }}} */
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: noet sw=4 ts=4 fdm=marker
+ * vim<600: noet sw=4 ts=4
+ */
diff --git a/ext/intl/converter/converter.h b/ext/intl/converter/converter.h
new file mode 100644
index 0000000000..bd316fcf98
--- /dev/null
+++ b/ext/intl/converter/converter.h
@@ -0,0 +1,28 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Sara Golemon <pollita@php.net> |
+ +----------------------------------------------------------------------+
+*/
+
+#ifndef PHP_INTL_CONVERTER_H
+#define PHP_INTL_CONVERTER_H
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "php.h"
+
+int php_converter_minit(INIT_FUNC_ARGS);
+
+#endif /* PHP_INTL_CONVERTER_H */
diff --git a/ext/intl/dateformat/dateformat.c b/ext/intl/dateformat/dateformat.c
index 8aded18bd6..fb83eeef05 100644
--- a/ext/intl/dateformat/dateformat.c
+++ b/ext/intl/dateformat/dateformat.c
@@ -17,12 +17,9 @@
#include "config.h"
#endif
-#include <unicode/ustring.h>
#include <unicode/udat.h>
-#include <unicode/ucal.h>
#include "php_intl.h"
-#include "intl_convert.h"
#include "dateformat_class.h"
#include "dateformat.h"
@@ -67,157 +64,6 @@ void dateformat_register_constants( INIT_FUNC_ARGS )
}
/* }}} */
-/* {{{ */
-static void datefmt_ctor(INTERNAL_FUNCTION_PARAMETERS)
-{
- char* locale;
- int locale_len = 0;
- zval* object;
- long date_type = 0;
- long time_type = 0;
- long calendar = UCAL_GREGORIAN;
- char* timezone_str = NULL;
- int timezone_str_len = 0;
- char* pattern_str = NULL;
- int pattern_str_len = 0;
- UChar* svalue = NULL; /* UTF-16 pattern_str */
- int slength = 0;
- UChar* timezone_utf16 = NULL; /* UTF-16 timezone_str */
- int timezone_utf16_len = 0;
- UCalendar ucal_obj = NULL;
- IntlDateFormatter_object* dfo;
-
- intl_error_reset( NULL TSRMLS_CC );
- object = return_value;
- /* Parse parameters. */
- if( zend_parse_parameters( ZEND_NUM_ARGS() TSRMLS_CC, "sll|sls",
- &locale, &locale_len, &date_type, &time_type, &timezone_str, &timezone_str_len, &calendar,&pattern_str, &pattern_str_len ) == FAILURE )
- {
- intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR, "datefmt_create: unable to parse input parameters", 0 TSRMLS_CC );
- zval_dtor(return_value);
- RETURN_NULL();
- }
-
- INTL_CHECK_LOCALE_LEN_OBJ(locale_len, return_value);
-
- if (calendar != UCAL_TRADITIONAL && calendar != UCAL_GREGORIAN) {
- intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, "datefmt_create: "
- "invalid value for calendar type; it must be one of "
- "IntlDateFormatter::TRADITIONAL (locale's default calendar) "
- "or IntlDateFormatter::GREGORIAN", 0 TSRMLS_CC);
- goto error;
- }
-
- DATE_FORMAT_METHOD_FETCH_OBJECT_NO_CHECK;
-
- if (DATE_FORMAT_OBJECT(dfo) != NULL) {
- intl_errors_set(INTL_DATA_ERROR_P(dfo), U_ILLEGAL_ARGUMENT_ERROR,
- "datefmt_create: cannot call constructor twice", 0 TSRMLS_CC);
- return;
- }
-
- /* Convert pattern (if specified) to UTF-16. */
- if( pattern_str && pattern_str_len>0 ){
- intl_convert_utf8_to_utf16(&svalue, &slength,
- pattern_str, pattern_str_len, &INTL_DATA_ERROR_CODE(dfo));
- if (U_FAILURE(INTL_DATA_ERROR_CODE(dfo))) {
- /* object construction -> only set global error */
- intl_error_set(NULL, INTL_DATA_ERROR_CODE(dfo), "datefmt_create: "
- "error converting pattern to UTF-16", 0 TSRMLS_CC);
- goto error;
- }
- }
-
- /* resources allocated from now on */
-
- /* Convert pattern (if specified) to UTF-16. */
- if( timezone_str && timezone_str_len >0 ){
- intl_convert_utf8_to_utf16(&timezone_utf16, &timezone_utf16_len,
- timezone_str, timezone_str_len, &INTL_DATA_ERROR_CODE(dfo));
- if (U_FAILURE(INTL_DATA_ERROR_CODE(dfo))) {
- intl_error_set(NULL, INTL_DATA_ERROR_CODE(dfo), "datefmt_create: "
- "error converting timezone_str to UTF-16", 0 TSRMLS_CC);
- goto error;
- }
- }
-
- if(locale_len == 0) {
- locale = INTL_G(default_locale);
- }
-
- if( pattern_str && pattern_str_len>0 ){
- DATE_FORMAT_OBJECT(dfo) = udat_open(UDAT_IGNORE, UDAT_IGNORE, locale, timezone_utf16, timezone_utf16_len, svalue, slength, &INTL_DATA_ERROR_CODE(dfo));
- } else {
- DATE_FORMAT_OBJECT(dfo) = udat_open(time_type, date_type, locale, timezone_utf16, timezone_utf16_len, svalue, slength, &INTL_DATA_ERROR_CODE(dfo));
- }
-
- if (!U_FAILURE(INTL_DATA_ERROR_CODE(dfo))) {
- if (calendar != UCAL_TRADITIONAL) {
- ucal_obj = ucal_open(timezone_utf16, timezone_utf16_len, locale,
- calendar, &INTL_DATA_ERROR_CODE(dfo));
- if (!U_FAILURE(INTL_DATA_ERROR_CODE(dfo))) {
- udat_setCalendar(DATE_FORMAT_OBJECT(dfo), ucal_obj);
- ucal_close(ucal_obj);
- } else {
- intl_error_set(NULL, INTL_DATA_ERROR_CODE(dfo), "datefmt_create"
- ": error opening calendar", 0 TSRMLS_CC);
- goto error;
- }
- }
- } else {
- intl_error_set(NULL, INTL_DATA_ERROR_CODE(dfo), "datefmt_create: date "
- "formatter creation failed", 0 TSRMLS_CC);
- goto error;
- }
-
- /* Set the class variables */
- dfo->date_type = date_type;
- dfo->time_type = time_type;
- dfo->calendar = calendar;
- if( timezone_str && timezone_str_len > 0){
- dfo->timezone_id = estrndup( timezone_str, timezone_str_len);
- }
-
-error:
- if (svalue) {
- efree(svalue);
- }
- if (timezone_utf16) {
- efree(timezone_utf16);
- }
- if (U_FAILURE(intl_error_get_code(NULL TSRMLS_CC))) {
- /* free_object handles partially constructed instances fine */
- zval_dtor(return_value);
- RETVAL_NULL();
- }
-}
-/* }}} */
-
-/* {{{ proto IntlDateFormatter IntlDateFormatter::create(string $locale, long date_type, long time_type[, string $timezone_str, long $calendar, string $pattern] )
- * Create formatter. }}} */
-/* {{{ proto IntlDateFormatter datefmt_create(string $locale, long date_type, long time_type[, string $timezone_str, long $calendar, string $pattern] )
-
- * Create formatter.
- */
-PHP_FUNCTION( datefmt_create )
-{
- object_init_ex( return_value, IntlDateFormatter_ce_ptr );
- datefmt_ctor(INTERNAL_FUNCTION_PARAM_PASSTHRU);
-}
-/* }}} */
-
-/* {{{ proto void IntlDateFormatter::__construct(string $locale, long date_type, long time_type[, string $timezone_str, long $calendar, string $pattern])
- * IntlDateFormatter object constructor.
- */
-PHP_METHOD( IntlDateFormatter, __construct )
-{
- /* return_value param is being changed, therefore we will always return
- * NULL here */
- return_value = getThis();
- datefmt_ctor(INTERNAL_FUNCTION_PARAM_PASSTHRU);
-}
-/* }}} */
-
/* {{{ proto int IntlDateFormatter::getErrorCode()
* Get formatter's last error code. }}} */
/* {{{ proto int datefmt_get_error_code( IntlDateFormatter $nf )
diff --git a/ext/intl/dateformat/dateformat_attr.c b/ext/intl/dateformat/dateformat_attr.c
index b8c5f25e3a..bf6b544667 100644
--- a/ext/intl/dateformat/dateformat_attr.c
+++ b/ext/intl/dateformat/dateformat_attr.c
@@ -25,39 +25,6 @@
#include <unicode/ustring.h>
#include <unicode/udat.h>
-#include <unicode/ucal.h>
-
-static void internal_set_calendar(IntlDateFormatter_object *dfo, char* timezone_id, int timezone_id_len, int calendar, zval* return_value TSRMLS_DC){
- int timezone_utf16_len = 0;
- UChar* timezone_utf16 = NULL; /* timezone_id in UTF-16 */
- char* locale = NULL;
-
- UCalendar* ucal_obj = NULL;
-
- /* check for the validity of value of calendar passed */
- intl_error_reset( NULL TSRMLS_CC );
- if( calendar > 1){
- intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
- "datefmt_set_calendar: calendar value specified is out of valid range", 0 TSRMLS_CC);
- RETURN_FALSE;
- }
-
- /* Convert timezone to UTF-16. */
- intl_convert_utf8_to_utf16(&timezone_utf16, &timezone_utf16_len, timezone_id, timezone_id_len, &INTL_DATA_ERROR_CODE(dfo));
- INTL_METHOD_CHECK_STATUS(dfo, "Error converting timezone to UTF-16" );
-
- /* Get the locale for the dateformatter */
- locale = (char *)udat_getLocaleByType(DATE_FORMAT_OBJECT(dfo), ULOC_ACTUAL_LOCALE, &INTL_DATA_ERROR_CODE(dfo));
-
- /* Set the calendar if passed */
- ucal_obj = ucal_open(timezone_utf16, timezone_utf16_len, locale, calendar, &INTL_DATA_ERROR_CODE(dfo) );
- udat_setCalendar( DATE_FORMAT_OBJECT(dfo), ucal_obj );
- INTL_METHOD_CHECK_STATUS(dfo, "Error setting the calendar.");
-
- if( timezone_utf16){
- efree(timezone_utf16);
- }
-}
/* {{{ proto unicode IntlDateFormatter::getDateType( )
* Get formatter datetype. }}} */
@@ -111,97 +78,6 @@ PHP_FUNCTION( datefmt_get_timetype )
}
/* }}} */
-
-/* {{{ proto unicode IntlDateFormatter::getCalendar( )
- * Get formatter calendar. }}} */
-/* {{{ proto string datefmt_get_calendar( IntlDateFormatter $mf )
- * Get formatter calendar.
- */
-PHP_FUNCTION( datefmt_get_calendar )
-{
- DATE_FORMAT_METHOD_INIT_VARS;
-
- /* Parse parameters. */
- if( zend_parse_method_parameters( ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O", &object, IntlDateFormatter_ce_ptr ) == FAILURE )
- {
- intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,
- "datefmt_get_calendar: unable to parse input params", 0 TSRMLS_CC );
- RETURN_FALSE;
- }
-
- /* Fetch the object. */
- DATE_FORMAT_METHOD_FETCH_OBJECT;
-
- INTL_METHOD_CHECK_STATUS(dfo, "Error getting formatter calendar." );
-
- RETURN_LONG(dfo->calendar);
-}
-/* }}} */
-
-/* {{{ proto unicode IntlDateFormatter::getTimeZoneId( )
- * Get formatter timezone_id. }}} */
-/* {{{ proto string datefmt_get_timezone_id( IntlDateFormatter $mf )
- * Get formatter timezone_id.
- */
-PHP_FUNCTION( datefmt_get_timezone_id )
-{
- DATE_FORMAT_METHOD_INIT_VARS;
-
- /* Parse parameters. */
- if( zend_parse_method_parameters( ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O", &object, IntlDateFormatter_ce_ptr ) == FAILURE )
- {
- intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,
- "datefmt_get_timezone_id: unable to parse input params", 0 TSRMLS_CC );
- RETURN_FALSE;
- }
-
- /* Fetch the object. */
- DATE_FORMAT_METHOD_FETCH_OBJECT;
-
- INTL_METHOD_CHECK_STATUS(dfo, "Error getting formatter timezone_id." );
-
- if( dfo->timezone_id ){
- RETURN_STRING((char*)dfo->timezone_id, TRUE );
- }else{
- RETURN_NULL();
- }
-}
-
-/* {{{ proto boolean IntlDateFormatter::setTimeZoneId( $timezone_id)
- * Set formatter timezone_id. }}} */
-/* {{{ proto boolean datefmt_set_timezone_id( IntlDateFormatter $mf,$timezone_id)
- * Set formatter timezone_id.
- */
-PHP_FUNCTION( datefmt_set_timezone_id )
-{
- char* timezone_id = NULL;
- int timezone_id_len = 0;
-
- DATE_FORMAT_METHOD_INIT_VARS;
-
- /* Parse parameters. */
- if( zend_parse_method_parameters( ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Os", &object, IntlDateFormatter_ce_ptr,&timezone_id, &timezone_id_len) == FAILURE )
- {
- intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,
- "datefmt_set_timezone_id: unable to parse input params", 0 TSRMLS_CC );
- RETURN_FALSE;
- }
-
- /* Fetch the object. */
- DATE_FORMAT_METHOD_FETCH_OBJECT;
-
- /* set the timezone for the calendar */
- internal_set_calendar( dfo, timezone_id, timezone_id_len, dfo->calendar, return_value TSRMLS_CC );
-
- /* Set the IntlDateFormatter variable */
- if( dfo->timezone_id ){
- efree(dfo->timezone_id);
- }
- dfo->timezone_id = estrndup(timezone_id, timezone_id_len);
-
- RETURN_TRUE;
-}
-
/* {{{ proto string IntlDateFormatter::getPattern( )
* Get formatter pattern. }}} */
/* {{{ proto string datefmt_get_pattern( IntlDateFormatter $mf )
@@ -370,43 +246,3 @@ PHP_FUNCTION( datefmt_set_lenient )
udat_setLenient(DATE_FORMAT_OBJECT(dfo), (UBool)isLenient );
}
/* }}} */
-
-/* {{{ proto bool IntlDateFormatter::setPattern( int $calendar )
- * Set formatter calendar. }}} */
-/* {{{ proto bool datefmt_set_calendar( IntlDateFormatter $mf, int $calendar )
- * Set formatter calendar.
- */
-PHP_FUNCTION( datefmt_set_calendar )
-{
- long calendar = 0;
-
- DATE_FORMAT_METHOD_INIT_VARS;
-
- /* Parse parameters. */
- if( zend_parse_method_parameters( ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Ol",
- &object, IntlDateFormatter_ce_ptr, &calendar ) == FAILURE ) {
- intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
- "datefmt_set_calendar: unable to parse input params", 0 TSRMLS_CC);
- RETURN_FALSE;
- }
-
- /* check for the validity of value of calendar passed */
- intl_error_reset( NULL TSRMLS_CC );
- if (calendar > 1) {
- intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
- "datefmt_set_calendar: calendar value specified is out of valid range", 0 TSRMLS_CC);
- RETURN_FALSE;
- }
-
- DATE_FORMAT_METHOD_FETCH_OBJECT;
-
- internal_set_calendar( dfo, dfo->timezone_id, strlen(dfo->timezone_id), calendar, return_value TSRMLS_CC );
-
- /* Set the calendar value in the IntlDateFormatter object */
- dfo->calendar = calendar;
-
- RETURN_TRUE;
-}
-/* }}} */
-
-
diff --git a/ext/intl/dateformat/dateformat_attr.h b/ext/intl/dateformat/dateformat_attr.h
index bf28824d63..6fe82a6e00 100644
--- a/ext/intl/dateformat/dateformat_attr.h
+++ b/ext/intl/dateformat/dateformat_attr.h
@@ -21,11 +21,7 @@
//PHP_FUNCTION( datefmt_get_timezone );
PHP_FUNCTION( datefmt_get_datetype );
PHP_FUNCTION( datefmt_get_timetype );
-PHP_FUNCTION( datefmt_get_calendar );
-PHP_FUNCTION( datefmt_set_calendar );
PHP_FUNCTION( datefmt_get_locale );
-PHP_FUNCTION( datefmt_get_timezone_id );
-PHP_FUNCTION( datefmt_set_timezone_id );
PHP_FUNCTION( datefmt_get_pattern );
PHP_FUNCTION( datefmt_set_pattern );
PHP_FUNCTION( datefmt_is_lenient );
diff --git a/ext/intl/dateformat/dateformat_attrcpp.cpp b/ext/intl/dateformat/dateformat_attrcpp.cpp
new file mode 100644
index 0000000000..b68abec659
--- /dev/null
+++ b/ext/intl/dateformat/dateformat_attrcpp.cpp
@@ -0,0 +1,261 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Gustavo Lopes <cataphract@php.net> |
+ +----------------------------------------------------------------------+
+*/
+
+#include "../intl_cppshims.h"
+
+#include <unicode/timezone.h>
+#include <unicode/calendar.h>
+#include <unicode/datefmt.h>
+
+extern "C" {
+#include "../php_intl.h"
+#include "dateformat_class.h"
+#include "dateformat_attrcpp.h"
+#define USE_TIMEZONE_POINTER 1
+#include "../timezone/timezone_class.h"
+#define USE_CALENDAR_POINTER 1
+#include "../calendar/calendar_class.h"
+}
+
+#include "../intl_convertcpp.h"
+#include "dateformat_helpers.h"
+
+static inline DateFormat *fetch_datefmt(IntlDateFormatter_object *dfo) {
+ return (DateFormat *)dfo->datef_data.udatf;
+}
+
+/* {{{ proto string IntlDateFormatter::getTimeZoneId()
+ * Get formatter timezone_id. }}} */
+/* {{{ proto string datefmt_get_timezone_id(IntlDateFormatter $mf)
+ * Get formatter timezone_id.
+ */
+U_CFUNC PHP_FUNCTION(datefmt_get_timezone_id)
+{
+ DATE_FORMAT_METHOD_INIT_VARS;
+
+ if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O",
+ &object, IntlDateFormatter_ce_ptr ) == FAILURE) {
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, "datefmt_get_timezone_"
+ "id: unable to parse input params", 0 TSRMLS_CC);
+ RETURN_FALSE;
+ }
+
+ DATE_FORMAT_METHOD_FETCH_OBJECT;
+
+ UnicodeString res = UnicodeString();
+ fetch_datefmt(dfo)->getTimeZone().getID(res);
+ intl_charFromString(res, &Z_STRVAL_P(return_value),
+ &Z_STRLEN_P(return_value), &INTL_DATA_ERROR_CODE(dfo));
+ INTL_METHOD_CHECK_STATUS(dfo, "Could not convert time zone id to UTF-8");
+
+ Z_TYPE_P(return_value) = IS_STRING;
+}
+
+/* {{{ proto IntlTimeZone IntlDateFormatter::getTimeZone()
+ * Get formatter timezone. }}} */
+/* {{{ proto IntlTimeZone datefmt_get_timezone(IntlDateFormatter $mf)
+ * Get formatter timezone.
+ */
+U_CFUNC PHP_FUNCTION(datefmt_get_timezone)
+{
+ DATE_FORMAT_METHOD_INIT_VARS;
+
+ if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O",
+ &object, IntlDateFormatter_ce_ptr ) == FAILURE) {
+ intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "datefmt_get_timezone: unable to parse input params", 0 TSRMLS_CC );
+ RETURN_FALSE;
+ }
+
+ DATE_FORMAT_METHOD_FETCH_OBJECT;
+
+ const TimeZone& tz = fetch_datefmt(dfo)->getTimeZone();
+ TimeZone *tz_clone = tz.clone();
+ if (tz_clone == NULL) {
+ intl_errors_set(INTL_DATA_ERROR_P(dfo), U_MEMORY_ALLOCATION_ERROR,
+ "datefmt_get_timezone: Out of memory when cloning time zone",
+ 0 TSRMLS_CC);
+ RETURN_FALSE;
+ }
+
+ object_init_ex(return_value, TimeZone_ce_ptr);
+ timezone_object_construct(tz_clone, return_value, 1 TSRMLS_CC);
+}
+
+U_CFUNC PHP_FUNCTION(datefmt_set_timezone_id)
+{
+ php_error_docref0(NULL TSRMLS_CC, E_DEPRECATED,
+ "Use datefmt_set_timezone() instead, which also accepts a plain "
+ "time zone identifier and for which this function is now an "
+ "alias");
+ PHP_FN(datefmt_set_timezone)(INTERNAL_FUNCTION_PARAM_PASSTHRU);
+}
+
+/* {{{ proto boolean IntlDateFormatter::setTimeZone(mixed $timezone)
+ * Set formatter's timezone. }}} */
+/* {{{ proto boolean datefmt_set_timezone_id(IntlDateFormatter $mf, $timezone_id)
+ * Set formatter timezone_id.
+ */
+U_CFUNC PHP_FUNCTION(datefmt_set_timezone)
+{
+ zval **timezone_zv;
+ TimeZone *timezone;
+
+ DATE_FORMAT_METHOD_INIT_VARS;
+
+ if ( zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(),
+ "OZ", &object, IntlDateFormatter_ce_ptr, &timezone_zv) == FAILURE) {
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, "datefmt_set_timezone: "
+ "unable to parse input params", 0 TSRMLS_CC);
+ RETURN_FALSE;
+ }
+
+ DATE_FORMAT_METHOD_FETCH_OBJECT;
+
+ timezone = timezone_process_timezone_argument(timezone_zv,
+ INTL_DATA_ERROR_P(dfo), "datefmt_set_timezone" TSRMLS_CC);
+ if (timezone == NULL) {
+ RETURN_FALSE;
+ }
+
+ fetch_datefmt(dfo)->adoptTimeZone(timezone);
+}
+
+/* {{{ proto int IntlDateFormatter::getCalendar( )
+ * Get formatter calendar type. }}} */
+/* {{{ proto int datefmt_get_calendar(IntlDateFormatter $mf)
+ * Get formatter calendar type.
+ */
+U_CFUNC PHP_FUNCTION(datefmt_get_calendar)
+{
+ DATE_FORMAT_METHOD_INIT_VARS;
+
+ if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O",
+ &object, IntlDateFormatter_ce_ptr ) == FAILURE) {
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "datefmt_get_calendar: unable to parse input params", 0 TSRMLS_CC);
+ RETURN_FALSE;
+ }
+
+ DATE_FORMAT_METHOD_FETCH_OBJECT;
+
+ if (dfo->calendar == -1) {
+ /* an IntlCalendar was provided to the constructor */
+ RETURN_FALSE;
+ }
+
+ RETURN_LONG(dfo->calendar);
+}
+/* }}} */
+
+/* {{{ proto IntlCalendar IntlDateFormatter::getCalendarObject()
+ * Get formatter calendar. }}} */
+/* {{{ proto IntlCalendar datefmt_get_calendar_object(IntlDateFormatter $mf)
+ * Get formatter calendar.
+ */
+U_CFUNC PHP_FUNCTION(datefmt_get_calendar_object)
+{
+ DATE_FORMAT_METHOD_INIT_VARS;
+
+ if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O",
+ &object, IntlDateFormatter_ce_ptr ) == FAILURE) {
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "datefmt_get_calendar_object: unable to parse input params",
+ 0 TSRMLS_CC);
+ RETURN_FALSE;
+ }
+
+ DATE_FORMAT_METHOD_FETCH_OBJECT;
+
+ const Calendar *cal = fetch_datefmt(dfo)->getCalendar();
+ if (cal == NULL) {
+ RETURN_NULL();
+ }
+
+ Calendar *cal_clone = cal->clone();
+ if (cal_clone == NULL) {
+ intl_errors_set(INTL_DATA_ERROR_P(dfo), U_MEMORY_ALLOCATION_ERROR,
+ "datefmt_get_calendar_object: Out of memory when cloning "
+ "calendar", 0 TSRMLS_CC);
+ RETURN_FALSE;
+ }
+
+ calendar_object_create(return_value, cal_clone TSRMLS_CC);
+}
+/* }}} */
+
+/* {{{ proto bool IntlDateFormatter::setCalendar(mixed $calendar)
+ * Set formatter's calendar. }}} */
+/* {{{ proto bool datefmt_set_calendar(IntlDateFormatter $mf, mixed $calendar)
+ * Set formatter's calendar.
+ */
+U_CFUNC PHP_FUNCTION(datefmt_set_calendar)
+{
+ zval *calendar_zv;
+ DATE_FORMAT_METHOD_INIT_VARS;
+
+ if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Oz",
+ &object, IntlDateFormatter_ce_ptr, &calendar_zv) == FAILURE) {
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "datefmt_set_calendar: unable to parse input params", 0 TSRMLS_CC);
+ RETURN_FALSE;
+ }
+
+ DATE_FORMAT_METHOD_FETCH_OBJECT;
+
+ Calendar *cal;
+ long cal_type;
+ bool cal_owned;
+ Locale locale = Locale::createFromName(dfo->requested_locale);
+ // getting the actual locale from the DateFormat is not enough
+ // because we would have lost modifiers such as @calendar. We
+ // must store the requested locale on object creation
+
+ if (datefmt_process_calendar_arg(calendar_zv, locale,
+ "datefmt_set_calendar", INTL_DATA_ERROR_P(dfo), cal, cal_type,
+ cal_owned TSRMLS_CC) == FAILURE) {
+ RETURN_FALSE;
+ }
+
+ if (cal_owned) {
+ /* a non IntlCalendar was specified, we want to keep the timezone */
+ TimeZone *old_timezone = fetch_datefmt(dfo)->getTimeZone().clone();
+ if (old_timezone == NULL) {
+ intl_errors_set(INTL_DATA_ERROR_P(dfo), U_MEMORY_ALLOCATION_ERROR,
+ "datefmt_set_calendar: Out of memory when cloning calendar",
+ 0 TSRMLS_CC);
+ delete cal;
+ RETURN_FALSE;
+ }
+ cal->adoptTimeZone(old_timezone);
+ } else {
+ cal = cal->clone();
+ if (cal == NULL) {
+ intl_errors_set(INTL_DATA_ERROR_P(dfo), U_MEMORY_ALLOCATION_ERROR,
+ "datefmt_set_calendar: Out of memory when cloning calendar",
+ 0 TSRMLS_CC);
+ RETURN_FALSE;
+ }
+ }
+
+ fetch_datefmt(dfo)->adoptCalendar(cal);
+
+ dfo->calendar = cal_type;
+
+ RETURN_TRUE;
+}
+/* }}} */
+
diff --git a/ext/intl/dateformat/dateformat_attrcpp.h b/ext/intl/dateformat/dateformat_attrcpp.h
new file mode 100644
index 0000000000..408232f940
--- /dev/null
+++ b/ext/intl/dateformat/dateformat_attrcpp.h
@@ -0,0 +1,35 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Gustavo Lopes <cataphract@php.net> |
+ +----------------------------------------------------------------------+
+*/
+
+#ifndef DATEFORMAT_ATTRCPP_H
+#define DATEFORMAT_ATTRCPP_H
+
+PHP_FUNCTION(datefmt_get_timezone_id);
+
+PHP_FUNCTION(datefmt_set_timezone_id);
+
+PHP_FUNCTION(datefmt_get_timezone);
+
+PHP_FUNCTION(datefmt_set_timezone);
+
+PHP_FUNCTION(datefmt_get_calendar);
+
+PHP_FUNCTION(datefmt_set_calendar);
+
+PHP_FUNCTION(datefmt_get_calendar_object);
+
+#endif /* DATEFORMAT_ATTRCPP_H */
+
diff --git a/ext/intl/dateformat/dateformat_class.c b/ext/intl/dateformat/dateformat_class.c
index 49f316f787..211c87f59f 100644
--- a/ext/intl/dateformat/dateformat_class.c
+++ b/ext/intl/dateformat/dateformat_class.c
@@ -19,9 +19,11 @@
#include "php_intl.h"
#include "dateformat_data.h"
#include "dateformat_format.h"
+#include "dateformat_format_object.h"
#include "dateformat_parse.h"
#include "dateformat.h"
#include "dateformat_attr.h"
+#include "dateformat_attrcpp.h"
#include <zend_exceptions.h>
@@ -46,12 +48,12 @@ void IntlDateFormatter_object_free( zend_object *object TSRMLS_DC )
zend_object_std_dtor( &dfo->zo TSRMLS_CC );
- dateformat_data_free( &dfo->datef_data TSRMLS_CC );
-
- if( dfo->timezone_id ){
- efree(dfo->timezone_id);
+ if (dfo->requested_locale) {
+ efree( dfo->requested_locale );
}
+ dateformat_data_free( &dfo->datef_data TSRMLS_CC );
+
efree( dfo );
}
/* }}} */
@@ -66,10 +68,10 @@ zend_object_value IntlDateFormatter_object_create(zend_class_entry *ce TSRMLS_DC
dateformat_data_init( &intern->datef_data TSRMLS_CC );
zend_object_std_init( &intern->zo, ce TSRMLS_CC );
object_properties_init(&intern->zo, ce);
- intern->date_type = 0;
- intern->time_type = 0;
- intern->calendar = 1; /* Gregorian calendar */
- intern->timezone_id = NULL;
+ intern->date_type = 0;
+ intern->time_type = 0;
+ intern->calendar = -1;
+ intern->requested_locale = NULL;
retval.handle = zend_objects_store_put(
intern,
@@ -127,6 +129,12 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_intldateformatter_format, 0, 0, 0)
ZEND_ARG_INFO(0, array)
ZEND_END_ARG_INFO()
+ZEND_BEGIN_ARG_INFO_EX(arginfo_intldateformatter_format_object, 0, 0, 1)
+ ZEND_ARG_INFO(0, object)
+ ZEND_ARG_INFO(0, format)
+ ZEND_ARG_INFO(0, locale)
+ZEND_END_ARG_INFO()
+
ZEND_BEGIN_ARG_INFO(arginfo_intldateformatter_getdatetype, 0)
ZEND_END_ARG_INFO()
@@ -165,15 +173,19 @@ static zend_function_entry IntlDateFormatter_class_functions[] = {
PHP_NAMED_FE( getDateType, ZEND_FN( datefmt_get_datetype ), arginfo_intldateformatter_getdatetype )
PHP_NAMED_FE( getTimeType, ZEND_FN( datefmt_get_timetype ), arginfo_intldateformatter_getdatetype )
PHP_NAMED_FE( getCalendar, ZEND_FN( datefmt_get_calendar ), arginfo_intldateformatter_getdatetype )
+ PHP_NAMED_FE( getCalendarObject, ZEND_FN( datefmt_get_calendar_object ), arginfo_intldateformatter_getdatetype )
PHP_NAMED_FE( setCalendar, ZEND_FN( datefmt_set_calendar ), arginfo_intldateformatter_setcalendar )
PHP_NAMED_FE( getTimeZoneId, ZEND_FN( datefmt_get_timezone_id ), arginfo_intldateformatter_getdatetype )
PHP_NAMED_FE( setTimeZoneId, ZEND_FN( datefmt_set_timezone_id ), arginfo_intldateformatter_settimezoneid )
+ PHP_NAMED_FE( getTimeZone, ZEND_FN( datefmt_get_timezone ), arginfo_intldateformatter_getdatetype )
+ PHP_NAMED_FE( setTimeZone, ZEND_FN( datefmt_set_timezone ), arginfo_intldateformatter_settimezoneid )
PHP_NAMED_FE( setPattern, ZEND_FN( datefmt_set_pattern ), arginfo_intldateformatter_setpattern )
PHP_NAMED_FE( getPattern, ZEND_FN( datefmt_get_pattern ), arginfo_intldateformatter_getdatetype )
PHP_NAMED_FE( getLocale, ZEND_FN( datefmt_get_locale ), arginfo_intldateformatter_getdatetype )
PHP_NAMED_FE( setLenient, ZEND_FN( datefmt_set_lenient ), arginfo_intldateformatter_setlenient )
PHP_NAMED_FE( isLenient, ZEND_FN( datefmt_is_lenient ), arginfo_intldateformatter_getdatetype )
PHP_NAMED_FE( format, ZEND_FN( datefmt_format ), arginfo_intldateformatter_format )
+ PHP_ME_MAPPING( formatObject, datefmt_format_object, arginfo_intldateformatter_format_object, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
PHP_NAMED_FE( parse, ZEND_FN( datefmt_parse), datefmt_parse_args )
PHP_NAMED_FE( localtime, ZEND_FN( datefmt_localtime ), datefmt_parse_args )
PHP_NAMED_FE( getErrorCode, ZEND_FN( datefmt_get_error_code ), arginfo_intldateformatter_getdatetype )
diff --git a/ext/intl/dateformat/dateformat_class.h b/ext/intl/dateformat/dateformat_class.h
index d58abe42f5..b4304660e2 100644
--- a/ext/intl/dateformat/dateformat_class.h
+++ b/ext/intl/dateformat/dateformat_class.h
@@ -24,12 +24,12 @@
#include "dateformat_data.h"
typedef struct {
- zend_object zo;
- dateformat_data datef_data;
- int date_type ;
- int time_type ;
- int calendar ;
- char* timezone_id;
+ zend_object zo;
+ dateformat_data datef_data;
+ int date_type;
+ int time_type;
+ int calendar;
+ char *requested_locale;
} IntlDateFormatter_object;
void dateformat_register_IntlDateFormatter_class( TSRMLS_D );
diff --git a/ext/intl/dateformat/dateformat_create.cpp b/ext/intl/dateformat/dateformat_create.cpp
new file mode 100644
index 0000000000..a2899f7974
--- /dev/null
+++ b/ext/intl/dateformat/dateformat_create.cpp
@@ -0,0 +1,193 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Kirti Velankar <kirtig@yahoo-inc.com> |
+ | Gustavo Lopes <cataphract@php.net> |
+ +----------------------------------------------------------------------+
+*/
+
+#include "../intl_cppshims.h"
+
+#include <unicode/timezone.h>
+#include <unicode/calendar.h>
+#include <unicode/datefmt.h>
+
+extern "C" {
+#include <unicode/ustring.h>
+#include <unicode/udat.h>
+
+#include "php_intl.h"
+#include "dateformat_create.h"
+#include "dateformat_class.h"
+#define USE_TIMEZONE_POINTER 1
+#include "../timezone/timezone_class.h"
+#include "../intl_convert.h"
+}
+
+#include "dateformat_helpers.h"
+
+/* {{{ */
+static void datefmt_ctor(INTERNAL_FUNCTION_PARAMETERS)
+{
+ zval *object;
+
+ const char *locale_str;
+ int locale_len = 0;
+ Locale locale;
+ long date_type = 0;
+ long time_type = 0;
+ zval *calendar_zv = NULL;
+ Calendar *calendar = NULL;
+ long calendar_type;
+ bool calendar_owned;
+ zval **timezone_zv = NULL;
+ TimeZone *timezone = NULL;
+ bool explicit_tz;
+ char* pattern_str = NULL;
+ int pattern_str_len = 0;
+ UChar* svalue = NULL; /* UTF-16 pattern_str */
+ int slength = 0;
+ IntlDateFormatter_object* dfo;
+
+ intl_error_reset(NULL TSRMLS_CC);
+ object = return_value;
+ /* Parse parameters. */
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sll|Zzs",
+ &locale_str, &locale_len, &date_type, &time_type, &timezone_zv,
+ &calendar_zv, &pattern_str, &pattern_str_len) == FAILURE) {
+ intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR, "datefmt_create: "
+ "unable to parse input parameters", 0 TSRMLS_CC);
+ zval_dtor(return_value);
+ RETURN_NULL();
+ }
+
+ INTL_CHECK_LOCALE_LEN_OBJ(locale_len, return_value);
+ if (locale_len == 0) {
+ locale_str = intl_locale_get_default(TSRMLS_C);
+ }
+ locale = Locale::createFromName(locale_str);
+
+ DATE_FORMAT_METHOD_FETCH_OBJECT_NO_CHECK;
+
+ if (DATE_FORMAT_OBJECT(dfo) != NULL) {
+ intl_errors_set(INTL_DATA_ERROR_P(dfo), U_ILLEGAL_ARGUMENT_ERROR,
+ "datefmt_create: cannot call constructor twice", 0 TSRMLS_CC);
+ return;
+ }
+
+ /* process calendar */
+ if (datefmt_process_calendar_arg(calendar_zv, locale, "datefmt_create",
+ INTL_DATA_ERROR_P(dfo), calendar, calendar_type,
+ calendar_owned TSRMLS_CC)
+ == FAILURE) {
+ goto error;
+ }
+
+ /* process timezone */
+ explicit_tz = timezone_zv != NULL && Z_TYPE_PP(timezone_zv) != IS_NULL;
+
+ if (explicit_tz || calendar_owned ) {
+ //we have an explicit time zone or a non-object calendar
+ timezone = timezone_process_timezone_argument(timezone_zv,
+ INTL_DATA_ERROR_P(dfo), "datefmt_create" TSRMLS_CC);
+ if (timezone == NULL) {
+ goto error;
+ }
+ }
+
+ /* Convert pattern (if specified) to UTF-16. */
+ if (pattern_str && pattern_str_len > 0) {
+ intl_convert_utf8_to_utf16(&svalue, &slength,
+ pattern_str, pattern_str_len, &INTL_DATA_ERROR_CODE(dfo));
+ if (U_FAILURE(INTL_DATA_ERROR_CODE(dfo))) {
+ /* object construction -> only set global error */
+ intl_error_set(NULL, INTL_DATA_ERROR_CODE(dfo), "datefmt_create: "
+ "error converting pattern to UTF-16", 0 TSRMLS_CC);
+ goto error;
+ }
+ }
+
+ if (pattern_str && pattern_str_len > 0) {
+ DATE_FORMAT_OBJECT(dfo) = udat_open(UDAT_IGNORE, UDAT_IGNORE,
+ locale_str, NULL, 0, svalue, slength,
+ &INTL_DATA_ERROR_CODE(dfo));
+ } else {
+ DATE_FORMAT_OBJECT(dfo) = udat_open((UDateFormatStyle)time_type,
+ (UDateFormatStyle)date_type, locale_str, NULL, 0, svalue,
+ slength, &INTL_DATA_ERROR_CODE(dfo));
+ }
+
+ if (!U_FAILURE(INTL_DATA_ERROR_CODE(dfo))) {
+ DateFormat *df = (DateFormat*)DATE_FORMAT_OBJECT(dfo);
+ if (calendar_owned) {
+ df->adoptCalendar(calendar);
+ calendar_owned = false;
+ } else {
+ df->setCalendar(*calendar);
+ }
+
+ if (timezone != NULL) {
+ df->adoptTimeZone(timezone);
+ }
+ } else {
+ intl_error_set(NULL, INTL_DATA_ERROR_CODE(dfo), "datefmt_create: date "
+ "formatter creation failed", 0 TSRMLS_CC);
+ goto error;
+ }
+
+ /* Set the class variables */
+ dfo->date_type = date_type;
+ dfo->time_type = time_type;
+ dfo->calendar = calendar_type;
+ dfo->requested_locale = estrdup(locale_str);
+
+error:
+ if (svalue) {
+ efree(svalue);
+ }
+ if (timezone != NULL && DATE_FORMAT_OBJECT(dfo) == NULL) {
+ delete timezone;
+ }
+ if (calendar != NULL && calendar_owned) {
+ delete calendar;
+ }
+ if (U_FAILURE(intl_error_get_code(NULL TSRMLS_CC))) {
+ /* free_object handles partially constructed instances fine */
+ zval_dtor(return_value);
+ RETVAL_NULL();
+ }
+}
+/* }}} */
+
+/* {{{ proto IntlDateFormatter IntlDateFormatter::create(string $locale, long date_type, long time_type[, string $timezone_str, long $calendar, string $pattern] )
+ * Create formatter. }}} */
+/* {{{ proto IntlDateFormatter datefmt_create(string $locale, long date_type, long time_type[, string $timezone_str, long $calendar, string $pattern)
+ * Create formatter.
+ */
+U_CFUNC PHP_FUNCTION( datefmt_create )
+{
+ object_init_ex( return_value, IntlDateFormatter_ce_ptr );
+ datefmt_ctor(INTERNAL_FUNCTION_PARAM_PASSTHRU);
+}
+/* }}} */
+
+/* {{{ proto void IntlDateFormatter::__construct(string $locale, long date_type, long time_type[, string $timezone_str, long $calendar, string $pattern])
+ * IntlDateFormatter object constructor.
+ */
+U_CFUNC PHP_METHOD( IntlDateFormatter, __construct )
+{
+ /* return_value param is being changed, therefore we will always return
+ * NULL here */
+ return_value = getThis();
+ datefmt_ctor(INTERNAL_FUNCTION_PARAM_PASSTHRU);
+}
+/* }}} */
diff --git a/ext/intl/dateformat/dateformat_create.h b/ext/intl/dateformat/dateformat_create.h
new file mode 100644
index 0000000000..47e67c2f45
--- /dev/null
+++ b/ext/intl/dateformat/dateformat_create.h
@@ -0,0 +1,25 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Gustavo Lopes <cataphract@php.net> |
+ +----------------------------------------------------------------------+
+*/
+#ifndef DATE_FORMATTER_H
+#define DATE_FORMATTER_H
+
+#include <php.h>
+
+PHP_FUNCTION( datefmt_create );
+PHP_METHOD( IntlDateFormatter, __construct );
+void dateformat_register_constants( INIT_FUNC_ARGS );
+
+#endif // DATE_FORMATTER_H
diff --git a/ext/intl/dateformat/dateformat_format.c b/ext/intl/dateformat/dateformat_format.c
index 4d03d924c8..ffae15518b 100644
--- a/ext/intl/dateformat/dateformat_format.c
+++ b/ext/intl/dateformat/dateformat_format.c
@@ -21,13 +21,13 @@
#include <unicode/ustring.h>
#include <unicode/ucal.h>
-#include "php_intl.h"
-#include "intl_convert.h"
+#include "../php_intl.h"
+#include "../intl_convert.h"
+#include "../common/common_date.h"
#include "dateformat.h"
#include "dateformat_class.h"
#include "dateformat_format.h"
#include "dateformat_data.h"
-#include "ext/date/php_date.h"
/* {{{
* Internal function which calls the udat_format
@@ -59,20 +59,38 @@ static void internal_format(IntlDateFormatter_object *dfo, UDate timestamp, zval
/* {{{
* Internal function which fetches an element from the passed array for the key_name passed
*/
-static double internal_get_arr_ele(IntlDateFormatter_object *dfo, HashTable* hash_arr, char* key_name TSRMLS_DC)
+static int32_t internal_get_arr_ele(IntlDateFormatter_object *dfo,
+ HashTable* hash_arr, char* key_name, intl_error *err TSRMLS_DC)
{
- zval** ele_value = NULL;
- UDate result = -1;
-
- if( zend_hash_find( hash_arr, key_name, strlen(key_name) + 1, (void **)&ele_value ) == SUCCESS ){
- if( Z_TYPE_PP(ele_value)!= IS_LONG ){
- intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,
- "datefmt_format: parameter array does not contain a long element.", 0 TSRMLS_CC );
- }else{
- result = Z_LVAL_PP(ele_value);
+ zval **ele_value = NULL;
+ int32_t result = 0;
+ char *message;
+
+ if (U_FAILURE(err->code)) {
+ return result;
+ }
+
+ if (zend_hash_find(hash_arr, key_name, strlen(key_name) + 1,
+ (void **)&ele_value) == SUCCESS) {
+ if(Z_TYPE_PP(ele_value) != IS_LONG) {
+ spprintf(&message, 0, "datefmt_format: parameter array contains "
+ "a non-integer element for key '%s'", key_name);
+ intl_errors_set(err, U_ILLEGAL_ARGUMENT_ERROR, message, 1 TSRMLS_CC);
+ efree(message);
+ } else {
+ if (Z_LVAL_PP(ele_value) > INT32_MAX ||
+ Z_LVAL_PP(ele_value) < INT32_MIN) {
+ spprintf(&message, 0, "datefmt_format: value %ld is out of "
+ "bounds for a 32-bit integer in key '%s'",
+ Z_LVAL_PP(ele_value), key_name);
+ intl_errors_set(err, U_ILLEGAL_ARGUMENT_ERROR, message, 1 TSRMLS_CC);
+ efree(message);
+ } else {
+ result = Z_LVAL_PP(ele_value);
+ }
}
}
- /* printf("\n Inside internal_get_arr_ele key_name= %s, result = %g \n", key_name, result); */
+
return result;
}
/* }}} */
@@ -80,41 +98,51 @@ static double internal_get_arr_ele(IntlDateFormatter_object *dfo, HashTable* has
/* {{{
* Internal function which sets UCalendar from the passed array and retrieves timestamp
*/
-static UDate internal_get_timestamp(IntlDateFormatter_object *dfo, HashTable* hash_arr TSRMLS_DC)
+static UDate internal_get_timestamp(IntlDateFormatter_object *dfo,
+ HashTable *hash_arr TSRMLS_DC)
{
- long year =0;
- long month =0;
- long hour =0;
- long minute =0;
- long second =0;
- long wday =0;
- long yday =0;
- long mday =0;
- UBool isInDST = FALSE;
- UCalendar *pcal;
+ int32_t year,
+ month,
+ hour,
+ minute,
+ second,
+ mday;
+ UCalendar *pcal;
+ UDate result;
+ intl_error *err = &dfo->datef_data.error;
+
+#define INTL_GET_ELEM(elem) \
+ internal_get_arr_ele(dfo, hash_arr, (elem), err TSRMLS_CC)
/* Fetch values from the incoming array */
- year = internal_get_arr_ele( dfo, hash_arr, CALENDAR_YEAR TSRMLS_CC) + 1900; /* tm_year is years since 1900 */
+ year = INTL_GET_ELEM(CALENDAR_YEAR) + 1900; /* tm_year is years since 1900 */
/* Month in ICU and PHP starts from January =0 */
- month = internal_get_arr_ele( dfo, hash_arr, CALENDAR_MON TSRMLS_CC);
- hour = internal_get_arr_ele( dfo, hash_arr, CALENDAR_HOUR TSRMLS_CC);
- minute = internal_get_arr_ele( dfo, hash_arr, CALENDAR_MIN TSRMLS_CC);
- second = internal_get_arr_ele( dfo, hash_arr, CALENDAR_SEC TSRMLS_CC);
- wday = internal_get_arr_ele( dfo, hash_arr, CALENDAR_WDAY TSRMLS_CC);
- yday = internal_get_arr_ele( dfo, hash_arr, CALENDAR_YDAY TSRMLS_CC);
- isInDST = internal_get_arr_ele( dfo, hash_arr, CALENDAR_ISDST TSRMLS_CC);
+ month = INTL_GET_ELEM(CALENDAR_MON);
+ hour = INTL_GET_ELEM(CALENDAR_HOUR);
+ minute = INTL_GET_ELEM(CALENDAR_MIN);
+ second = INTL_GET_ELEM(CALENDAR_SEC);
/* For the ucal_setDateTime() function, this is the 'date' value */
- mday = internal_get_arr_ele( dfo, hash_arr, CALENDAR_MDAY TSRMLS_CC);
+ mday = INTL_GET_ELEM(CALENDAR_MDAY);
- pcal = udat_getCalendar(DATE_FORMAT_OBJECT(dfo));
- /* set the incoming values for the calendar */
- ucal_setDateTime( pcal, year, month, mday, hour, minute, second, &INTL_DATA_ERROR_CODE(dfo));
- if( INTL_DATA_ERROR_CODE(dfo) != U_ZERO_ERROR){
+#undef INTL_GET_ELEM
+
+ pcal = ucal_clone(udat_getCalendar(DATE_FORMAT_OBJECT(dfo)),
+ &INTL_DATA_ERROR_CODE(dfo));
+
+ if (INTL_DATA_ERROR_CODE(dfo) != U_ZERO_ERROR) {
+ intl_errors_set(err, INTL_DATA_ERROR_CODE(dfo), "datefmt_format: "
+ "error cloning calendar", 0 TSRMLS_CC);
return 0;
}
-
+
+ /* set the incoming values for the calendar */
+ ucal_setDateTime(pcal, year, month, mday, hour, minute, second, &INTL_DATA_ERROR_CODE(dfo));
+ /* actually, ucal_setDateTime cannot fail */
+
/* Fetch the timestamp from the UCalendar */
- return ucal_getMillis(pcal, &INTL_DATA_ERROR_CODE(dfo) );
+ result = ucal_getMillis(pcal, &INTL_DATA_ERROR_CODE(dfo));
+ ucal_close(pcal);
+ return result;
}
@@ -124,70 +152,39 @@ static UDate internal_get_timestamp(IntlDateFormatter_object *dfo, HashTable* ha
* Format the time value as a string. }}}*/
PHP_FUNCTION(datefmt_format)
{
- UDate timestamp =0;
- UDate p_timestamp =0;
- HashTable* hash_arr = NULL;
- zval* zarg = NULL;
+ UDate timestamp = 0;
+ HashTable *hash_arr = NULL;
+ zval *zarg = NULL;
DATE_FORMAT_METHOD_INIT_VARS;
/* Parse parameters. */
- if( zend_parse_method_parameters( ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Oz", &object, IntlDateFormatter_ce_ptr,&zarg ) == FAILURE )
- {
- intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR, "datefmt_format: unable to parse input params", 0 TSRMLS_CC );
+ if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Oz",
+ &object, IntlDateFormatter_ce_ptr, &zarg) == FAILURE) {
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, "datefmt_format: unable "
+ "to parse input params", 0 TSRMLS_CC );
RETURN_FALSE;
}
- /* Fetch the object. */
DATE_FORMAT_METHOD_FETCH_OBJECT;
- switch(Z_TYPE_P(zarg) ){
- case IS_LONG:
- p_timestamp = Z_LVAL_P(zarg) ;
- timestamp = p_timestamp * 1000;
- break;
- case IS_DOUBLE:
- /* timestamp*1000 since ICU expects it in milliseconds */
- p_timestamp = Z_DVAL_P(zarg) ;
- timestamp = p_timestamp * 1000;
- break;
- case IS_ARRAY:
- hash_arr = Z_ARRVAL_P(zarg);
- if( !hash_arr || zend_hash_num_elements( hash_arr ) == 0 )
- RETURN_FALSE;
-
- timestamp = internal_get_timestamp(dfo, hash_arr TSRMLS_CC);
- INTL_METHOD_CHECK_STATUS( dfo, "datefmt_format: Date formatting failed" )
- break;
- case IS_OBJECT: {
- zend_class_entry *date_ce = php_date_get_date_ce();
- zval retval;
- zval *zfuncname;
- if(!instanceof_function(Z_OBJCE_P(zarg), date_ce TSRMLS_CC)) {
- intl_errors_set(INTL_DATA_ERROR_P(dfo), U_ILLEGAL_ARGUMENT_ERROR, "datefmt_format: object must be an instance of DateTime", 0 TSRMLS_CC );
- RETURN_FALSE;
- }
- INIT_ZVAL(retval);
- MAKE_STD_ZVAL(zfuncname);
- ZVAL_STRING(zfuncname, "getTimestamp", 1);
- if(call_user_function(NULL, &zarg, zfuncname, &retval, 0, NULL TSRMLS_CC) != SUCCESS || Z_TYPE(retval) != IS_LONG) {
- intl_errors_set(INTL_DATA_ERROR_P(dfo), U_ILLEGAL_ARGUMENT_ERROR, "datefmt_format: cannot get timestamp", 0 TSRMLS_CC );
- zval_ptr_dtor(&zfuncname);
- RETURN_FALSE;
- }
- zval_ptr_dtor(&zfuncname);
- p_timestamp = Z_LVAL(retval);
- timestamp = p_timestamp*1000;
+ if (Z_TYPE_P(zarg) == IS_ARRAY) {
+ hash_arr = Z_ARRVAL_P(zarg);
+ if (!hash_arr || zend_hash_num_elements(hash_arr) == 0) {
+ RETURN_FALSE;
}
- break;
- default:
- intl_errors_set( INTL_DATA_ERROR_P(dfo), U_ILLEGAL_ARGUMENT_ERROR,
- "datefmt_format: takes either an array or an integer timestamp value or a DateTime object", 0 TSRMLS_CC );
+
+ timestamp = internal_get_timestamp(dfo, hash_arr TSRMLS_CC);
+ INTL_METHOD_CHECK_STATUS(dfo, "datefmt_format: date formatting failed")
+ } else {
+ timestamp = intl_zval_to_millis(zarg, INTL_DATA_ERROR_P(dfo),
+ "datefmt_format" TSRMLS_CC);
+ if (U_FAILURE(INTL_DATA_ERROR_CODE(dfo))) {
RETURN_FALSE;
+ }
}
-
- internal_format( dfo, timestamp, return_value TSRMLS_CC);
+ internal_format( dfo, timestamp, return_value TSRMLS_CC);
}
/* }}} */
diff --git a/ext/intl/dateformat/dateformat_format_object.cpp b/ext/intl/dateformat/dateformat_format_object.cpp
new file mode 100644
index 0000000000..e8981faa26
--- /dev/null
+++ b/ext/intl/dateformat/dateformat_format_object.cpp
@@ -0,0 +1,230 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Gustavo Lopes <cataphract@php.net> |
+ +----------------------------------------------------------------------+
+*/
+
+#include "../intl_cppshims.h"
+
+#include <unicode/calendar.h>
+#include <unicode/gregocal.h>
+#include <unicode/datefmt.h>
+#include <unicode/smpdtfmt.h>
+#include <unicode/locid.h>
+
+#include "../intl_convertcpp.h"
+
+extern "C" {
+#include "../php_intl.h"
+#include "../locale/locale.h"
+#define USE_CALENDAR_POINTER 1
+#include "../calendar/calendar_class.h"
+#include <ext/date/php_date.h>
+#include "../common/common_date.h"
+}
+
+static const DateFormat::EStyle valid_styles[] = {
+ DateFormat::kNone,
+ DateFormat::kFull,
+ DateFormat::kLong,
+ DateFormat::kMedium,
+ DateFormat::kShort,
+ DateFormat::kFullRelative,
+ DateFormat::kLongRelative,
+ DateFormat::kMediumRelative,
+ DateFormat::kShortRelative,
+};
+
+static bool valid_format(zval **z) {
+ if (Z_TYPE_PP(z) == IS_LONG) {
+ long lval = Z_LVAL_PP(z);
+ for (int i = 0; i < sizeof(valid_styles) / sizeof(*valid_styles); i++) {
+ if ((long)valid_styles[i] == lval) {
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+U_CFUNC PHP_FUNCTION(datefmt_format_object)
+{
+ zval *object,
+ **format = NULL;
+ const char *locale_str = NULL;
+ int locale_len;
+ bool pattern = false;
+ UDate date;
+ TimeZone *timeZone = NULL;
+ UErrorCode status = U_ZERO_ERROR;
+ DateFormat *df = NULL;
+ Calendar *cal = NULL;
+ DateFormat::EStyle dateStyle = DateFormat::kDefault,
+ timeStyle = DateFormat::kDefault;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "o|Zs!",
+ &object, &format, &locale_str, &locale_len) == FAILURE) {
+ RETURN_FALSE;
+ }
+
+ if (!locale_str) {
+ locale_str = intl_locale_get_default(TSRMLS_C);
+ }
+
+ if (format == NULL || Z_TYPE_PP(format) == IS_NULL) {
+ //nothing
+ } else if (Z_TYPE_PP(format) == IS_ARRAY) {
+ HashTable *ht = Z_ARRVAL_PP(format);
+ HashPosition pos = {0};
+ zval **z;
+ if (zend_hash_num_elements(ht) != 2) {
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "datefmt_format_object: bad format; if array, it must have "
+ "two elements", 0 TSRMLS_CC);
+ RETURN_FALSE;
+ }
+
+ zend_hash_internal_pointer_reset_ex(ht, &pos);
+ zend_hash_get_current_data_ex(ht, (void**)&z, &pos);
+ if (!valid_format(z)) {
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "datefmt_format_object: bad format; the date format (first "
+ "element of the array) is not valid", 0 TSRMLS_CC);
+ RETURN_FALSE;
+ }
+ dateStyle = (DateFormat::EStyle)Z_LVAL_PP(z);
+
+ zend_hash_move_forward_ex(ht, &pos);
+ zend_hash_get_current_data_ex(ht, (void**)&z, &pos);
+ if (!valid_format(z)) {
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "datefmt_format_object: bad format; the time format ("
+ "second element of the array) is not valid", 0 TSRMLS_CC);
+ RETURN_FALSE;
+ }
+ timeStyle = (DateFormat::EStyle)Z_LVAL_PP(z);
+ } else if (Z_TYPE_PP(format) == IS_LONG) {
+ if (!valid_format(format)) {
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "datefmt_format_object: the date/time format type is invalid",
+ 0 TSRMLS_CC);
+ RETURN_FALSE;
+ }
+ dateStyle = timeStyle = (DateFormat::EStyle)Z_LVAL_PP(format);
+ } else {
+ convert_to_string_ex(format);
+ if (Z_STRLEN_PP(format) == 0) {
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "datefmt_format_object: the format is empty", 0 TSRMLS_CC);
+ RETURN_FALSE;
+ }
+ pattern = true;
+ }
+
+ //there's no support for relative time in ICU yet
+ timeStyle = (DateFormat::EStyle)(timeStyle & ~DateFormat::kRelative);
+
+ zend_class_entry *instance_ce = Z_OBJCE_P(object);
+ if (instanceof_function(instance_ce, Calendar_ce_ptr TSRMLS_CC)) {
+ Calendar *obj_cal = calendar_fetch_native_calendar(object TSRMLS_CC);
+ if (obj_cal == NULL) {
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "datefmt_format_object: bad IntlCalendar instance: "
+ "not initialized properly", 0 TSRMLS_CC);
+ RETURN_FALSE;
+ }
+ timeZone = obj_cal->getTimeZone().clone();
+ date = obj_cal->getTime(status);
+ if (U_FAILURE(status)) {
+ intl_error_set(NULL, status,
+ "datefmt_format_object: error obtaining instant from "
+ "IntlCalendar", 0 TSRMLS_CC);
+ RETVAL_FALSE;
+ goto cleanup;
+ }
+ cal = obj_cal->clone();
+ } else if (instanceof_function(instance_ce, php_date_get_date_ce() TSRMLS_CC)) {
+ if (intl_datetime_decompose(object, &date, &timeZone, NULL,
+ "datefmt_format_object" TSRMLS_CC) == FAILURE) {
+ RETURN_FALSE;
+ }
+ cal = new GregorianCalendar(Locale::createFromName(locale_str), status);
+ if (U_FAILURE(status)) {
+ intl_error_set(NULL, status,
+ "datefmt_format_object: could not create GregorianCalendar",
+ 0 TSRMLS_CC);
+ RETVAL_FALSE;
+ goto cleanup;
+ }
+ } else {
+ intl_error_set(NULL, status, "datefmt_format_object: the passed object "
+ "must be an instance of either IntlCalendar or DateTime",
+ 0 TSRMLS_CC);
+ RETURN_FALSE;
+ }
+
+ if (pattern) {
+ df = new SimpleDateFormat(
+ UnicodeString(Z_STRVAL_PP(format), Z_STRLEN_PP(format),
+ UnicodeString::kInvariant),
+ Locale::createFromName(locale_str),
+ status);
+
+ if (U_FAILURE(status)) {
+ intl_error_set(NULL, status,
+ "datefmt_format_object: could not create SimpleDateFormat",
+ 0 TSRMLS_CC);
+ RETVAL_FALSE;
+ goto cleanup;
+ }
+ } else {
+ df = DateFormat::createDateTimeInstance(dateStyle, timeStyle,
+ Locale::createFromName(locale_str));
+
+ if (df == NULL) { /* according to ICU sources, this should never happen */
+ intl_error_set(NULL, status,
+ "datefmt_format_object: could not create DateFormat",
+ 0 TSRMLS_CC);
+ RETVAL_FALSE;
+ goto cleanup;
+ }
+ }
+
+ //must be in this order (or have the cal adopt the tz)
+ df->adoptCalendar(cal);
+ cal = NULL;
+ df->adoptTimeZone(timeZone);
+ timeZone = NULL;
+
+ {
+ UnicodeString result = UnicodeString();
+ df->format(date, result);
+
+ Z_TYPE_P(return_value) = IS_STRING;
+ if (intl_charFromString(result, &Z_STRVAL_P(return_value),
+ &Z_STRLEN_P(return_value), &status) == FAILURE) {
+ intl_error_set(NULL, status,
+ "datefmt_format_object: error converting result to UTF-8",
+ 0 TSRMLS_CC);
+ RETVAL_FALSE;
+ goto cleanup;
+ }
+ }
+
+
+cleanup:
+ delete df;
+ delete timeZone;
+ delete cal;
+}
diff --git a/ext/intl/dateformat/dateformat_format_object.h b/ext/intl/dateformat/dateformat_format_object.h
new file mode 100644
index 0000000000..d80ea87e0f
--- /dev/null
+++ b/ext/intl/dateformat/dateformat_format_object.h
@@ -0,0 +1,19 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Gustavo Lopes <cataphract@php.net> |
+ +----------------------------------------------------------------------+
+ */
+
+#include <php.h>
+
+PHP_FUNCTION(datefmt_format_object);
diff --git a/ext/intl/dateformat/dateformat_helpers.cpp b/ext/intl/dateformat/dateformat_helpers.cpp
new file mode 100644
index 0000000000..74758bbec9
--- /dev/null
+++ b/ext/intl/dateformat/dateformat_helpers.cpp
@@ -0,0 +1,106 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Gustavo Lopes <cataphract@php.net> |
+ +----------------------------------------------------------------------+
+*/
+
+#include "../intl_cppshims.h"
+
+#include <unicode/calendar.h>
+#include <unicode/gregocal.h>
+
+#include "dateformat_helpers.h"
+
+extern "C" {
+#include "../php_intl.h"
+#include <Zend/zend_operators.h>
+#define USE_CALENDAR_POINTER 1
+#include "../calendar/calendar_class.h"
+}
+
+int datefmt_process_calendar_arg(zval* calendar_zv,
+ Locale const& locale,
+ const char *func_name,
+ intl_error *err,
+ Calendar*& cal,
+ long& cal_int_type,
+ bool& calendar_owned TSRMLS_DC)
+{
+ char *msg;
+ UErrorCode status = UErrorCode();
+
+ if (calendar_zv == NULL || Z_TYPE_P(calendar_zv) == IS_NULL) {
+
+ // default requested
+ cal = new GregorianCalendar(locale, status);
+ calendar_owned = true;
+
+ cal_int_type = UCAL_GREGORIAN;
+
+ } else if (Z_TYPE_P(calendar_zv) == IS_LONG) {
+
+ long v = Z_LVAL_P(calendar_zv);
+ if (v != (long)UCAL_TRADITIONAL && v != (long)UCAL_GREGORIAN) {
+ spprintf(&msg, 0, "%s: invalid value for calendar type; it must be "
+ "one of IntlDateFormatter::TRADITIONAL (locale's default "
+ "calendar) or IntlDateFormatter::GREGORIAN. "
+ "Alternatively, it can be an IntlCalendar object",
+ func_name);
+ intl_errors_set(err, U_ILLEGAL_ARGUMENT_ERROR, msg, 1 TSRMLS_CC);
+ efree(msg);
+ return FAILURE;
+ } else if (v == (long)UCAL_TRADITIONAL) {
+ cal = Calendar::createInstance(locale, status);
+ } else { //UCAL_GREGORIAN
+ cal = new GregorianCalendar(locale, status);
+ }
+ calendar_owned = true;
+
+ cal_int_type = Z_LVAL_P(calendar_zv);
+
+ } else if (Z_TYPE_P(calendar_zv) == IS_OBJECT &&
+ instanceof_function_ex(Z_OBJCE_P(calendar_zv),
+ Calendar_ce_ptr, 0 TSRMLS_CC)) {
+
+ cal = calendar_fetch_native_calendar(calendar_zv TSRMLS_CC);
+ if (cal == NULL) {
+ spprintf(&msg, 0, "%s: Found unconstructed IntlCalendar object",
+ func_name);
+ intl_errors_set(err, U_ILLEGAL_ARGUMENT_ERROR, msg, 1 TSRMLS_CC);
+ efree(msg);
+ return FAILURE;
+ }
+ calendar_owned = false;
+
+ cal_int_type = -1;
+
+ } else {
+ spprintf(&msg, 0, "%s: Invalid calendar argument; should be an integer "
+ "or an IntlCalendar instance", func_name);
+ intl_errors_set(err, U_ILLEGAL_ARGUMENT_ERROR, msg, 1 TSRMLS_CC);
+ efree(msg);
+ return FAILURE;
+ }
+
+ if (cal == NULL && !U_FAILURE(status)) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ }
+ if (U_FAILURE(status)) {
+ spprintf(&msg, 0, "%s: Failure instantiating calendar", func_name);
+ intl_errors_set(err, U_ILLEGAL_ARGUMENT_ERROR, msg, 1 TSRMLS_CC);
+ efree(msg);
+ return FAILURE;
+ }
+
+ return SUCCESS;
+}
diff --git a/ext/intl/dateformat/dateformat_helpers.h b/ext/intl/dateformat/dateformat_helpers.h
new file mode 100644
index 0000000000..bded0b7d78
--- /dev/null
+++ b/ext/intl/dateformat/dateformat_helpers.h
@@ -0,0 +1,39 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Gustavo Lopes <cataphract@php.net> |
+ +----------------------------------------------------------------------+
+*/
+
+#ifndef DATEFORMAT_HELPERS_H
+#define DATEFORMAT_HELPERS_H
+
+#ifndef __cplusplus
+#error For C++ only
+#endif
+
+#include <unicode/calendar.h>
+
+extern "C" {
+#include "../php_intl.h"
+}
+
+int datefmt_process_calendar_arg(zval* calendar_zv,
+ Locale const& locale,
+ const char *func_name,
+ intl_error *err,
+ Calendar*& cal,
+ long& cal_int_type,
+ bool& calendar_owned TSRMLS_DC);
+
+#endif /* DATEFORMAT_HELPERS_H */
+
diff --git a/ext/intl/formatter/formatter_main.c b/ext/intl/formatter/formatter_main.c
index 5cb6483326..d0671a88b5 100644
--- a/ext/intl/formatter/formatter_main.c
+++ b/ext/intl/formatter/formatter_main.c
@@ -56,7 +56,7 @@ static void numfmt_ctor(INTERNAL_FUNCTION_PARAMETERS)
}
if(locale_len == 0) {
- locale = INTL_G(default_locale);
+ locale = intl_locale_get_default(TSRMLS_C);
}
/* Create an ICU number formatter. */
diff --git a/ext/intl/grapheme/grapheme.h b/ext/intl/grapheme/grapheme.h
index c0e697ac1e..756ce9173e 100644
--- a/ext/intl/grapheme/grapheme.h
+++ b/ext/intl/grapheme/grapheme.h
@@ -19,7 +19,6 @@
#include <php.h>
#include <unicode/utypes.h>
-#include <unicode/ubrk.h>
PHP_FUNCTION(grapheme_strlen);
PHP_FUNCTION(grapheme_strpos);
diff --git a/ext/intl/intl_convertcpp.cpp b/ext/intl/intl_convertcpp.cpp
new file mode 100644
index 0000000000..f699a3c61c
--- /dev/null
+++ b/ext/intl/intl_convertcpp.cpp
@@ -0,0 +1,89 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Gustavo Lopes <cataphract@php.net> |
+ +----------------------------------------------------------------------+
+*/
+
+/* $Id$ */
+
+#include "intl_cppshims.h"
+
+#include "intl_convertcpp.h"
+#include <unicode/ustring.h>
+extern "C" {
+#include <php.h>
+}
+
+/* {{{ intl_stringFromChar */
+int intl_stringFromChar(UnicodeString &ret, char *str, int32_t str_len, UErrorCode *status)
+{
+ //the number of UTF-16 code units is not larger than that of UTF-8 code
+ //units, + 1 for the terminator
+ int32_t capacity = str_len + 1;
+
+ //no check necessary -- if NULL will fail ahead
+ UChar *utf16 = ret.getBuffer(capacity);
+ int32_t utf16_len = 0;
+ *status = U_ZERO_ERROR;
+ u_strFromUTF8WithSub(utf16, ret.getCapacity(), &utf16_len,
+ str, str_len, U_SENTINEL /* no substitution */, NULL,
+ status);
+ ret.releaseBuffer(utf16_len);
+ if (U_FAILURE(*status)) {
+ ret.setToBogus();
+ return FAILURE;
+ }
+ return SUCCESS;
+}
+/* }}} */
+
+/* {{{ intl_charFromString
+ * faster than doing intl_convert_utf16_to_utf8(&res, &res_len,
+ * from.getBuffer(), from.length(), &status),
+ * but consumes more memory */
+int intl_charFromString(const UnicodeString &from, char **res, int *res_len, UErrorCode *status)
+{
+ if (from.isBogus()) {
+ return FAILURE;
+ }
+
+ //the number of UTF-8 code units is not larger than that of UTF-16 code
+ //units * 3 + 1 for the terminator
+ int32_t capacity = from.length() * 3 + 1;
+
+ if (from.isEmpty()) {
+ *res = (char*)emalloc(1);
+ **res = '\0';
+ *res_len = 0;
+ return SUCCESS;
+ }
+
+ *res = (char*)emalloc(capacity);
+ *res_len = 0; //tbd
+
+ const UChar *utf16buf = from.getBuffer();
+ int32_t actual_len;
+ u_strToUTF8WithSub(*res, capacity - 1, &actual_len, utf16buf, from.length(),
+ U_SENTINEL, NULL, status);
+
+ if (U_FAILURE(*status)) {
+ efree(*res);
+ *res = NULL;
+ return FAILURE;
+ }
+ (*res)[actual_len] = '\0';
+ *res_len = (int)actual_len;
+
+ return SUCCESS;
+}
+/* }}} */
diff --git a/ext/intl/intl_convertcpp.h b/ext/intl/intl_convertcpp.h
new file mode 100644
index 0000000000..89d4209dd3
--- /dev/null
+++ b/ext/intl/intl_convertcpp.h
@@ -0,0 +1,32 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Gustavo Lopes <cataphract@php.net> |
+ +----------------------------------------------------------------------+
+*/
+
+/* $Id$ */
+
+#ifndef INTL_CONVERTCPP_H
+#define INTL_CONVERTCPP_H
+
+#ifndef __cplusplus
+#error Should be included only in C++ Files
+#endif
+
+#include <unicode/unistr.h>
+
+int intl_stringFromChar(UnicodeString &ret, char *str, int32_t str_len, UErrorCode *status);
+
+int intl_charFromString(const UnicodeString &from, char **res, int *res_len, UErrorCode *status);
+
+#endif /* INTL_CONVERTCPP_H */
diff --git a/ext/intl/intl_cppshims.h b/ext/intl/intl_cppshims.h
new file mode 100644
index 0000000000..2fb70edfd0
--- /dev/null
+++ b/ext/intl/intl_cppshims.h
@@ -0,0 +1,34 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Gustavo Lopes <cataphract@php.net> |
+ +----------------------------------------------------------------------+
+*/
+
+#ifndef INTL_CPPSHIMS_H
+#define INTL_CPPSHIMS_H
+
+#ifndef __cplusplus
+#error For inclusion form C++ files only
+#endif
+
+#ifdef _MSC_VER
+//This is only required for old versions of ICU only
+#include <stdio.h>
+
+#include <math.h>
+
+/* avoid redefinition of int8_t, also defined in unicode/pwin32.h */
+#define _MSC_STDINT_H_ 1
+#endif
+
+#endif \ No newline at end of file
diff --git a/ext/intl/intl_error.c b/ext/intl/intl_error.c
index 9c2e13dfd5..99b1c6001c 100644
--- a/ext/intl/intl_error.c
+++ b/ext/intl/intl_error.c
@@ -21,12 +21,16 @@
#endif
#include <php.h>
+#include <zend_exceptions.h>
#include "php_intl.h"
#include "intl_error.h"
+#include "intl_convert.h"
ZEND_EXTERN_MODULE_GLOBALS( intl )
+static zend_class_entry *IntlException_ce_ptr;
+
/* {{{ intl_error* intl_g_error_get()
* Return global error structure.
*/
@@ -102,8 +106,11 @@ void intl_error_set_custom_msg( intl_error* err, char* msg, int copyMsg TSRMLS_D
if( !msg )
return;
- if(!err && INTL_G(error_level)) {
- php_error_docref(NULL TSRMLS_CC, INTL_G(error_level), "%s", msg);
+ if( !err ) {
+ if( INTL_G( error_level ) )
+ php_error_docref( NULL TSRMLS_CC, INTL_G( error_level ), "%s", msg );
+ if( INTL_G( use_exceptions ) )
+ zend_throw_exception_ex( IntlException_ce_ptr, 0 TSRMLS_CC, "%s", msg );
}
if( !err && !( err = intl_g_error_get( TSRMLS_C ) ) )
return;
@@ -223,6 +230,96 @@ void intl_errors_set_code( intl_error* err, UErrorCode err_code TSRMLS_DC )
}
/* }}} */
+void intl_register_IntlException_class( TSRMLS_D )
+{
+ zend_class_entry ce,
+ *default_exception_ce;
+
+ default_exception_ce = zend_exception_get_default( TSRMLS_C );
+
+ /* Create and register 'IntlException' class. */
+ INIT_CLASS_ENTRY_EX( ce, "IntlException", sizeof( "IntlException" ) - 1, NULL );
+ IntlException_ce_ptr = zend_register_internal_class_ex( &ce,
+ default_exception_ce, NULL TSRMLS_CC );
+ IntlException_ce_ptr->create_object = default_exception_ce->create_object;
+}
+
+smart_str intl_parse_error_to_string( UParseError* pe )
+{
+ smart_str ret = {0};
+ char *buf;
+ int u8len;
+ UErrorCode status;
+ int any = 0;
+
+ assert( pe != NULL );
+
+ smart_str_appends( &ret, "parse error " );
+ if( pe->line > 0 )
+ {
+ smart_str_appends( &ret, "on line " );
+ smart_str_append_long( &ret, (long ) pe->line );
+ any = 1;
+ }
+ if( pe->offset >= 0 ) {
+ if( any )
+ smart_str_appends( &ret, ", " );
+ else
+ smart_str_appends( &ret, "at " );
+
+ smart_str_appends( &ret, "offset " );
+ smart_str_append_long( &ret, (long ) pe->offset );
+ any = 1;
+ }
+
+ if (pe->preContext[0] != 0 ) {
+ if( any )
+ smart_str_appends( &ret, ", " );
+
+ smart_str_appends( &ret, "after \"" );
+ intl_convert_utf16_to_utf8( &buf, &u8len, pe->preContext, -1, &status );
+ if( U_FAILURE( status ) )
+ {
+ smart_str_appends( &ret, "(could not convert parser error pre-context to UTF-8)" );
+ }
+ else {
+ smart_str_appendl( &ret, buf, u8len );
+ efree( buf );
+ }
+ smart_str_appends( &ret, "\"" );
+ any = 1;
+ }
+
+ if( pe->postContext[0] != 0 )
+ {
+ if( any )
+ smart_str_appends( &ret, ", " );
+
+ smart_str_appends( &ret, "before or at \"" );
+ intl_convert_utf16_to_utf8( &buf, &u8len, pe->postContext, -1, &status );
+ if( U_FAILURE( status ) )
+ {
+ smart_str_appends( &ret, "(could not convert parser error post-context to UTF-8)" );
+ }
+ else
+ {
+ smart_str_appendl( &ret, buf, u8len );
+ efree( buf );
+ }
+ smart_str_appends( &ret, "\"" );
+ any = 1;
+ }
+
+ if( !any )
+ {
+ smart_str_free( &ret );
+ smart_str_appends( &ret, "no parse error" );
+ }
+
+ smart_str_0( &ret );
+ return ret;
+}
+
/*
* Local variables:
* tab-width: 4
diff --git a/ext/intl/intl_error.h b/ext/intl/intl_error.h
index 3adae85474..4d8eb79327 100644
--- a/ext/intl/intl_error.h
+++ b/ext/intl/intl_error.h
@@ -20,6 +20,8 @@
#define INTL_ERROR_H
#include <unicode/utypes.h>
+#include <unicode/parseerr.h>
+#include <ext/standard/php_smart_str.h>
#define INTL_ERROR_CODE(e) (e).code
@@ -44,4 +46,10 @@ void intl_errors_set_custom_msg( intl_error* err, char* msg, int copyMsg
void intl_errors_set_code( intl_error* err, UErrorCode err_code TSRMLS_DC );
void intl_errors_set( intl_error* err, UErrorCode code, char* msg, int copyMsg TSRMLS_DC );
+// Other error helpers
+smart_str intl_parse_error_to_string( UParseError* pe );
+
+// exported to be called on extension MINIT
+void intl_register_IntlException_class( TSRMLS_D );
+
#endif // INTL_ERROR_H
diff --git a/ext/intl/locale/locale_methods.c b/ext/intl/locale/locale_methods.c
index 1707c69f93..d1a86d8ee2 100644
--- a/ext/intl/locale/locale_methods.c
+++ b/ext/intl/locale/locale_methods.c
@@ -208,10 +208,7 @@ static int getSingletonPos(char* str)
Get default locale */
PHP_NAMED_FUNCTION(zif_locale_get_default)
{
- if( INTL_G(default_locale) == NULL ) {
- INTL_G(default_locale) = pestrdup( uloc_getDefault(), 1);
- }
- RETURN_STRING( INTL_G(default_locale), TRUE );
+ RETURN_STRING( intl_locale_get_default( TSRMLS_C ), TRUE );
}
/* }}} */
@@ -393,7 +390,7 @@ static void get_icu_value_src_php( char* tag_name, INTERNAL_FUNCTION_PARAMETERS)
}
if(loc_name_len == 0) {
- loc_name = INTL_G(default_locale);
+ loc_name = intl_locale_get_default(TSRMLS_C);
}
/* Call ICU get */
@@ -499,7 +496,7 @@ static void get_icu_disp_value_src_php( char* tag_name, INTERNAL_FUNCTION_PARAME
}
if(loc_name_len == 0) {
- loc_name = INTL_G(default_locale);
+ loc_name = intl_locale_get_default(TSRMLS_C);
}
if( strcmp(tag_name, DISP_NAME) != 0 ){
@@ -521,7 +518,7 @@ static void get_icu_disp_value_src_php( char* tag_name, INTERNAL_FUNCTION_PARAME
/* Check if disp_loc_name passed , if not use default locale */
if( !disp_loc_name){
- disp_loc_name = estrdup(INTL_G(default_locale));
+ disp_loc_name = estrdup(intl_locale_get_default(TSRMLS_C));
free_loc_name = 1;
}
@@ -693,7 +690,7 @@ PHP_FUNCTION( locale_get_keywords )
}
if(loc_name_len == 0) {
- loc_name = INTL_G(default_locale);
+ loc_name = intl_locale_get_default(TSRMLS_C);
}
/* Get the keywords */
@@ -1100,7 +1097,7 @@ PHP_FUNCTION(locale_parse)
}
if(loc_name_len == 0) {
- loc_name = INTL_G(default_locale);
+ loc_name = intl_locale_get_default(TSRMLS_C);
}
array_init( return_value );
@@ -1148,7 +1145,7 @@ PHP_FUNCTION(locale_get_all_variants)
}
if(loc_name_len == 0) {
- loc_name = INTL_G(default_locale);
+ loc_name = intl_locale_get_default(TSRMLS_C);
}
@@ -1254,7 +1251,7 @@ PHP_FUNCTION(locale_filter_matches)
}
if(loc_range_len == 0) {
- loc_range = INTL_G(default_locale);
+ loc_range = intl_locale_get_default(TSRMLS_C);
}
if( strcmp(loc_range,"*")==0){
@@ -1540,7 +1537,7 @@ PHP_FUNCTION(locale_lookup)
}
if(loc_range_len == 0) {
- loc_range = INTL_G(default_locale);
+ loc_range = intl_locale_get_default(TSRMLS_C);
}
hash_arr = HASH_OF(arr);
diff --git a/ext/intl/msgformat/msgformat.c b/ext/intl/msgformat/msgformat.c
index e3fb9425a9..6a9f04f32b 100644
--- a/ext/intl/msgformat/msgformat.c
+++ b/ext/intl/msgformat/msgformat.c
@@ -61,7 +61,7 @@ static void msgfmt_ctor(INTERNAL_FUNCTION_PARAMETERS)
}
if(locale_len == 0) {
- locale = INTL_G(default_locale);
+ locale = intl_locale_get_default(TSRMLS_C);
}
#ifdef MSG_FORMAT_QUOTE_APOS
diff --git a/ext/intl/msgformat/msgformat_attr.c b/ext/intl/msgformat/msgformat_attr.c
index ed2dae27d1..c333a24ee1 100644
--- a/ext/intl/msgformat/msgformat_attr.c
+++ b/ext/intl/msgformat/msgformat_attr.c
@@ -102,6 +102,12 @@ PHP_FUNCTION( msgfmt_set_pattern )
}
mfo->mf_data.orig_format = estrndup(value, value_len);
mfo->mf_data.orig_format_len = value_len;
+ /* invalidate cached format types */
+ if (mfo->mf_data.arg_types) {
+ zend_hash_destroy(mfo->mf_data.arg_types);
+ efree(mfo->mf_data.arg_types);
+ mfo->mf_data.arg_types = NULL;
+ }
RETURN_TRUE;
}
diff --git a/ext/intl/msgformat/msgformat_data.c b/ext/intl/msgformat/msgformat_data.c
index 527c1d4d17..5d49054473 100644
--- a/ext/intl/msgformat/msgformat_data.c
+++ b/ext/intl/msgformat/msgformat_data.c
@@ -31,8 +31,10 @@ void msgformat_data_init( msgformat_data* mf_data TSRMLS_DC )
if( !mf_data )
return;
- mf_data->umsgf = NULL;
- mf_data->orig_format = NULL;
+ mf_data->umsgf = NULL;
+ mf_data->orig_format = NULL;
+ mf_data->arg_types = NULL;
+ mf_data->tz_set = 0;
intl_error_reset( &mf_data->error TSRMLS_CC );
}
/* }}} */
@@ -40,21 +42,27 @@ void msgformat_data_init( msgformat_data* mf_data TSRMLS_DC )
/* {{{ void msgformat_data_free( msgformat_data* mf_data )
* Clean up memory allocated for msgformat_data
*/
-void msgformat_data_free( msgformat_data* mf_data TSRMLS_DC )
+void msgformat_data_free(msgformat_data* mf_data TSRMLS_DC)
{
- if( !mf_data )
+ if (!mf_data)
return;
- if( mf_data->umsgf )
- umsg_close( mf_data->umsgf );
+ if (mf_data->umsgf)
+ umsg_close(mf_data->umsgf);
- if(mf_data->orig_format) {
+ if (mf_data->orig_format) {
efree(mf_data->orig_format);
mf_data->orig_format = NULL;
}
+ if (mf_data->arg_types) {
+ zend_hash_destroy(mf_data->arg_types);
+ efree(mf_data->arg_types);
+ mf_data->arg_types = NULL;
+ }
+
mf_data->umsgf = NULL;
- intl_error_reset( &mf_data->error TSRMLS_CC );
+ intl_error_reset(&mf_data->error TSRMLS_CC);
}
/* }}} */
diff --git a/ext/intl/msgformat/msgformat_data.h b/ext/intl/msgformat/msgformat_data.h
index 6479888f8f..51d7687a3a 100644
--- a/ext/intl/msgformat/msgformat_data.h
+++ b/ext/intl/msgformat/msgformat_data.h
@@ -31,6 +31,8 @@ typedef struct {
UMessageFormat* umsgf;
char* orig_format;
ulong orig_format_len;
+ HashTable* arg_types;
+ int tz_set; /* if we've already the time zone in sub-formats */
} msgformat_data;
msgformat_data* msgformat_data_create( TSRMLS_D );
diff --git a/ext/intl/msgformat/msgformat_format.c b/ext/intl/msgformat/msgformat_format.c
index 9a18ac0a70..4b81cfe2b4 100644
--- a/ext/intl/msgformat/msgformat_format.c
+++ b/ext/intl/msgformat/msgformat_format.c
@@ -32,51 +32,34 @@
#endif
/* {{{ */
-static void msgfmt_do_format(MessageFormatter_object *mfo, zval *args, zval *return_value TSRMLS_DC)
+static void msgfmt_do_format(MessageFormatter_object *mfo, zval *args, zval *return_value TSRMLS_DC)
{
- zval **fargs;
int count;
UChar* formatted = NULL;
int formatted_len = 0;
- HashPosition pos;
- int i;
+ HashTable *args_copy;
count = zend_hash_num_elements(Z_ARRVAL_P(args));
- if(count < umsg_format_arg_count(MSG_FORMAT_OBJECT(mfo))) {
- /* Not enough aguments for format! */
- intl_error_set( INTL_DATA_ERROR_P(mfo), U_ILLEGAL_ARGUMENT_ERROR,
- "msgfmt_format: not enough parameters", 0 TSRMLS_CC );
- RETVAL_FALSE;
- return;
- }
-
- fargs = safe_emalloc(count, sizeof(zval *), 0);
+ ALLOC_HASHTABLE(args_copy);
+ zend_hash_init(args_copy, count, NULL, ZVAL_PTR_DTOR, 0);
+ zend_hash_copy(args_copy, Z_ARRVAL_P(args), (copy_ctor_func_t)zval_add_ref,
+ NULL, sizeof(zval*));
- zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(args), &pos);
- for(i=0;i<count;i++) {
- zval **val;
- zend_hash_get_current_data_ex(Z_ARRVAL_P(args), (void **)&val, &pos);
- fargs[i] = *val;
- Z_ADDREF_P(fargs[i]);
- /* TODO: needs refcount increase here? */
- zend_hash_move_forward_ex(Z_ARRVAL_P(args), &pos);
- }
+ umsg_format_helper(mfo, args_copy, &formatted, &formatted_len TSRMLS_CC);
- umsg_format_helper(MSG_FORMAT_OBJECT(mfo), count, fargs, &formatted, &formatted_len, &INTL_DATA_ERROR_CODE(mfo) TSRMLS_CC);
-
- for(i=0;i<count;i++) {
- zval_ptr_dtor(&fargs[i]);
- }
+ zend_hash_destroy(args_copy);
+ efree(args_copy);
- efree(fargs);
-
- if (formatted && U_FAILURE( INTL_DATA_ERROR_CODE(mfo) ) ) {
+ if (formatted && U_FAILURE(INTL_DATA_ERROR_CODE(mfo))) {
efree(formatted);
}
- INTL_METHOD_CHECK_STATUS( mfo, "Number formatting failed" );
- INTL_METHOD_RETVAL_UTF8( mfo, formatted, formatted_len, 1 );
+ if (U_FAILURE(INTL_DATA_ERROR_CODE(mfo))) {
+ RETURN_FALSE;
+ } else {
+ INTL_METHOD_RETVAL_UTF8(mfo, formatted, formatted_len, 1);
+ }
}
/* }}} */
@@ -151,7 +134,7 @@ PHP_FUNCTION( msgfmt_format_message )
}
if(slocale_len == 0) {
- slocale = INTL_G(default_locale);
+ slocale = intl_locale_get_default(TSRMLS_C);
}
#ifdef MSG_FORMAT_QUOTE_APOS
diff --git a/ext/intl/msgformat/msgformat_helpers.cpp b/ext/intl/msgformat/msgformat_helpers.cpp
index 1895de2c86..9ee1cdcfb0 100644
--- a/ext/intl/msgformat/msgformat_helpers.cpp
+++ b/ext/intl/msgformat/msgformat_helpers.cpp
@@ -18,9 +18,20 @@
#include "config.h"
#endif
-#include <math.h>
+#include "../intl_cppshims.h"
+
+#include <limits.h>
#include <unicode/msgfmt.h>
#include <unicode/chariter.h>
+#include <unicode/ustdio.h>
+#include <unicode/timezone.h>
+#include <unicode/datefmt.h>
+#include <unicode/calendar.h>
+
+#include <vector>
+
+#include "../intl_convertcpp.h"
+#include "../common/common_date.h"
extern "C" {
#include "php_intl.h"
@@ -28,8 +39,14 @@ extern "C" {
#include "msgformat_format.h"
#include "msgformat_helpers.h"
#include "intl_convert.h"
+#define USE_TIMEZONE_POINTER
+#include "../timezone/timezone_class.h"
}
+#if U_ICU_VERSION_MAJOR_NUM * 10 + U_ICU_VERSION_MINOR_NUM >= 48
+#define HAS_MESSAGE_PATTERN 1
+#endif
+
U_NAMESPACE_BEGIN
/**
* This class isolates our access to private internal methods of
@@ -40,96 +57,578 @@ class MessageFormatAdapter {
public:
static const Formattable::Type* getArgTypeList(const MessageFormat& m,
int32_t& count);
+#ifdef HAS_MESSAGE_PATTERN
+ static const MessagePattern getMessagePattern(MessageFormat* m);
+#endif
};
+
const Formattable::Type*
MessageFormatAdapter::getArgTypeList(const MessageFormat& m,
int32_t& count) {
return m.getArgTypeList(count);
}
+
+#ifdef HAS_MESSAGE_PATTERN
+const MessagePattern
+MessageFormatAdapter::getMessagePattern(MessageFormat* m) {
+ return m->msgPattern;
+}
+#endif
U_NAMESPACE_END
-U_CFUNC int32_t umsg_format_arg_count(UMessageFormat *fmt)
+U_CFUNC int32_t umsg_format_arg_count(UMessageFormat *fmt)
{
int32_t fmt_count = 0;
MessageFormatAdapter::getArgTypeList(*(const MessageFormat*)fmt, fmt_count);
return fmt_count;
}
-U_CFUNC void umsg_format_helper(UMessageFormat *fmt, int arg_count, zval **args, UChar **formatted, int *formatted_len, UErrorCode *status TSRMLS_DC)
+static HashTable *umsg_get_numeric_types(MessageFormatter_object *mfo,
+ intl_error& err TSRMLS_DC)
{
- int fmt_count = 0;
- const Formattable::Type* argTypes =
- MessageFormatAdapter::getArgTypeList(*(const MessageFormat*)fmt, fmt_count);
- Formattable* fargs = new Formattable[fmt_count ? fmt_count : 1];
+ HashTable *ret;
+ int32_t parts_count;
- for(int32_t i = 0; i < fmt_count; ++i) {
- UChar *stringVal = NULL;
- int stringLen = 0;
- int64_t tInt64 = 0;
+ if (U_FAILURE(err.code)) {
+ return NULL;
+ }
- switch(argTypes[i]) {
- case Formattable::kDate:
- convert_to_long_ex(&args[i]);
- fargs[i].setDate(U_MILLIS_PER_SECOND * (double)Z_LVAL_P(args[i]));
- break;
+ if (mfo->mf_data.arg_types) {
+ /* already cached */
+ return mfo->mf_data.arg_types;
+ }
- case Formattable::kDouble:
- convert_to_double_ex(&args[i]);
- fargs[i].setDouble(Z_DVAL_P(args[i]));
- break;
-
- case Formattable::kLong:
- convert_to_long_ex(&args[i]);
- fargs[i].setLong(Z_LVAL_P(args[i]));
- break;
+ const Formattable::Type *types = MessageFormatAdapter::getArgTypeList(
+ *(MessageFormat*)mfo->mf_data.umsgf, parts_count);
+
+ /* Hash table will store Formattable::Type objects directly,
+ * so no need for destructor */
+ ALLOC_HASHTABLE(ret);
+ zend_hash_init(ret, parts_count, NULL, NULL, 0);
+
+ for (int i = 0; i < parts_count; i++) {
+ const Formattable::Type t = types[i];
+ if (zend_hash_index_update(ret, (ulong)i, (void*)&t, sizeof(t), NULL)
+ == FAILURE) {
+ intl_errors_set(&err, U_MEMORY_ALLOCATION_ERROR,
+ "Write to argument types hash table failed", 0 TSRMLS_CC);
+ break;
+ }
+ }
+
+ if (U_FAILURE(err.code)) {
+ zend_hash_destroy(ret);
+ efree(ret);
+
+ return NULL;
+ }
+
+ mfo->mf_data.arg_types = ret;
- case Formattable::kInt64:
- if(Z_TYPE_P(args[i]) == IS_DOUBLE) {
- tInt64 = (int64_t)Z_DVAL_P(args[i]);
- } else if(Z_TYPE_P(args[i]) == IS_LONG) {
- tInt64 = (int64_t)Z_LVAL_P(args[i]);
+ return ret;
+}
+
+#ifdef HAS_MESSAGE_PATTERN
+static HashTable *umsg_parse_format(MessageFormatter_object *mfo,
+ const MessagePattern& mp,
+ intl_error& err TSRMLS_DC)
+{
+ HashTable *ret;
+ int32_t parts_count;
+
+ if (U_FAILURE(err.code)) {
+ return NULL;
+ }
+
+ if (!((MessageFormat *)mfo->mf_data.umsgf)->usesNamedArguments()) {
+ return umsg_get_numeric_types(mfo, err TSRMLS_CC);
+ }
+
+ if (mfo->mf_data.arg_types) {
+ /* already cached */
+ return mfo->mf_data.arg_types;
+ }
+
+ /* Hash table will store Formattable::Type objects directly,
+ * so no need for destructor */
+ ALLOC_HASHTABLE(ret);
+ zend_hash_init(ret, 32, NULL, NULL, 0);
+
+ parts_count = mp.countParts();
+
+ // See MessageFormat::cacheExplicitFormats()
+ /*
+ * Looking through the pattern, go to each arg_start part type.
+ * The arg-typeof that tells us the argument type (simple, complicated)
+ * then the next part is either the arg_name or arg number
+ * and then if it's simple after that there could be a part-type=arg-type
+ * while substring will tell us number, spellout, etc.
+ * If the next thing isn't an arg-type then assume string.
+ */
+ /* The last two "parts" can at most be ARG_LIMIT and MSG_LIMIT
+ * which we need not examine. */
+ for (int32_t i = 0; i < parts_count - 2 && U_SUCCESS(err.code); i++) {
+ MessagePattern::Part p = mp.getPart(i);
+
+ if (p.getType() != UMSGPAT_PART_TYPE_ARG_START) {
+ continue;
+ }
+
+ MessagePattern::Part name_part = mp.getPart(++i); /* Getting name, advancing i */
+ Formattable::Type type,
+ *storedType;
+
+ if (name_part.getType() == UMSGPAT_PART_TYPE_ARG_NAME) {
+ UnicodeString argName = mp.getSubstring(name_part);
+ if (zend_hash_find(ret, (char*)argName.getBuffer(), argName.length(),
+ (void**)&storedType) == FAILURE) {
+ /* not found already; create new entry in HT */
+ Formattable::Type bogusType = Formattable::kObject;
+ if (zend_hash_update(ret, (char*)argName.getBuffer(), argName.length(),
+ (void*)&bogusType, sizeof(bogusType), (void**)&storedType) == FAILURE) {
+ intl_errors_set(&err, U_MEMORY_ALLOCATION_ERROR,
+ "Write to argument types hash table failed", 0 TSRMLS_CC);
+ continue;
+ }
+ }
+ } else if (name_part.getType() == UMSGPAT_PART_TYPE_ARG_NUMBER) {
+ int32_t argNumber = name_part.getValue();
+ if (argNumber < 0) {
+ intl_errors_set(&err, U_INVALID_FORMAT_ERROR,
+ "Found part with negative number", 0 TSRMLS_CC);
+ continue;
+ }
+ if (zend_hash_index_find(ret, (ulong)argNumber, (void**)&storedType)
+ == FAILURE) {
+ /* not found already; create new entry in HT */
+ Formattable::Type bogusType = Formattable::kObject;
+ if (zend_hash_index_update(ret, (ulong)argNumber, (void*)&bogusType,
+ sizeof(bogusType), (void**)&storedType) == FAILURE) {
+ intl_errors_set(&err, U_MEMORY_ALLOCATION_ERROR,
+ "Write to argument types hash table failed", 0 TSRMLS_CC);
+ continue;
+ }
+ }
+ }
+
+ UMessagePatternArgType argType = p.getArgType();
+ /* No type specified, treat it as a string */
+ if (argType == UMSGPAT_ARG_TYPE_NONE) {
+ type = Formattable::kString;
+ } else { /* Some type was specified, might be simple or complicated */
+ if (argType == UMSGPAT_ARG_TYPE_SIMPLE) {
+ /* For a SIMPLE arg, after the name part, there should be
+ * an ARG_TYPE part whose string value tells us what to do */
+ MessagePattern::Part type_part = mp.getPart(++i); /* Getting type, advancing i */
+ if (type_part.getType() == UMSGPAT_PART_TYPE_ARG_TYPE) {
+ UnicodeString typeString = mp.getSubstring(type_part);
+ /* This is all based on the rules in the docs for MessageFormat
+ * @see http://icu-project.org/apiref/icu4c/classMessageFormat.html */
+ if (typeString == "number") {
+ MessagePattern::Part style_part = mp.getPart(i + 1); /* Not advancing i */
+ if (style_part.getType() == UMSGPAT_PART_TYPE_ARG_STYLE) {
+ UnicodeString styleString = mp.getSubstring(style_part);
+ if (styleString == "integer") {
+ type = Formattable::kInt64;
+ } else if (styleString == "currency") {
+ type = Formattable::kDouble;
+ } else if (styleString == "percent") {
+ type = Formattable::kDouble;
+ } else { /* some style invalid/unknown to us */
+ type = Formattable::kDouble;
+ }
+ } else { // if missing style, part, make it a double
+ type = Formattable::kDouble;
+ }
+ } else if ((typeString == "date") || (typeString == "time")) {
+ type = Formattable::kDate;
+ } else if ((typeString == "spellout") || (typeString == "ordinal")
+ || (typeString == "duration")) {
+ type = Formattable::kDouble;
+ }
} else {
- SEPARATE_ZVAL_IF_NOT_REF(&args[i]);
- convert_scalar_to_number( args[i] TSRMLS_CC );
- tInt64 = (Z_TYPE_P(args[i]) == IS_DOUBLE)?(int64_t)Z_DVAL_P(args[i]):Z_LVAL_P(args[i]);
+ /* If there's no UMSGPAT_PART_TYPE_ARG_TYPE right after a
+ * UMSGPAT_ARG_TYPE_SIMPLE argument, then the pattern
+ * is broken. */
+ intl_errors_set(&err, U_PARSE_ERROR,
+ "Expected UMSGPAT_PART_TYPE_ARG_TYPE part following "
+ "UMSGPAT_ARG_TYPE_SIMPLE part", 0 TSRMLS_CC);
+ continue;
+ }
+ } else if (argType == UMSGPAT_ARG_TYPE_PLURAL) {
+ type = Formattable::kDouble;
+ } else if (argType == UMSGPAT_ARG_TYPE_CHOICE) {
+ type = Formattable::kDouble;
+ } else if (argType == UMSGPAT_ARG_TYPE_SELECT) {
+ type = Formattable::kString;
+ } else {
+ type = Formattable::kString;
+ }
+ } /* was type specified? */
+
+ /* We found a different type for the same arg! */
+ if (*storedType != Formattable::kObject && *storedType != type) {
+ intl_errors_set(&err, U_ARGUMENT_TYPE_MISMATCH,
+ "Inconsistent types declared for an argument", 0 TSRMLS_CC);
+ continue;
+ }
+
+ *storedType = type;
+ } /* visiting each part */
+
+ if (U_FAILURE(err.code)) {
+ zend_hash_destroy(ret);
+ efree(ret);
+
+ return NULL;
+ }
+
+ mfo->mf_data.arg_types = ret;
+
+ return ret;
+}
+#endif
+
+static HashTable *umsg_get_types(MessageFormatter_object *mfo,
+ intl_error& err TSRMLS_DC)
+{
+ MessageFormat *mf = (MessageFormat *)mfo->mf_data.umsgf;
+
+#ifdef HAS_MESSAGE_PATTERN
+ const MessagePattern mp = MessageFormatAdapter::getMessagePattern(mf);
+
+ return umsg_parse_format(mfo, mp, err TSRMLS_CC);
+#else
+ if (mf->usesNamedArguments()) {
+ intl_errors_set(&err, U_UNSUPPORTED_ERROR,
+ "This extension supports named arguments only on ICU 4.8+",
+ 0 TSRMLS_CC);
+ return NULL;
+ }
+ return umsg_get_numeric_types(mfo, err TSRMLS_CC);
+#endif
+}
+
+static void umsg_set_timezone(MessageFormatter_object *mfo,
+ intl_error& err TSRMLS_DC)
+{
+ MessageFormat *mf = (MessageFormat *)mfo->mf_data.umsgf;
+ TimeZone *used_tz = NULL;
+ const Format **formats;
+ int32_t count;
+
+ /* Unfortanely, this cannot change the time zone for arguments that
+ * appear inside complex formats because ::getFormats() returns NULL
+ * for all uncached formats, which is the case for complex formats
+ * unless they were set via one of the ::setFormat() methods */
+
+ if (mfo->mf_data.tz_set) {
+ return; /* already done */
+ }
+
+ formats = mf->getFormats(count);
+
+ if (formats == NULL) {
+ intl_errors_set(&err, U_MEMORY_ALLOCATION_ERROR,
+ "Out of memory retrieving subformats", 0 TSRMLS_CC);
+ }
+
+ for (int i = 0; U_SUCCESS(err.code) && i < count; i++) {
+ DateFormat* df = dynamic_cast<DateFormat*>(
+ const_cast<Format *>(formats[i]));
+ if (df == NULL) {
+ continue;
+ }
+
+ if (used_tz == NULL) {
+ zval nullzv = zval_used_for_init,
+ *zvptr = &nullzv;
+ used_tz = timezone_process_timezone_argument(&zvptr, &err,
+ "msgfmt_format" TSRMLS_CC);
+ if (used_tz == NULL) {
+ continue;
+ }
+ }
+
+ df->setTimeZone(*used_tz);
+ }
+
+ if (U_SUCCESS(err.code)) {
+ mfo->mf_data.tz_set = 1;
+ }
+}
+
+U_CFUNC void umsg_format_helper(MessageFormatter_object *mfo,
+ HashTable *args,
+ UChar **formatted,
+ int *formatted_len TSRMLS_DC)
+{
+ int arg_count = zend_hash_num_elements(args);
+ std::vector<Formattable> fargs;
+ std::vector<UnicodeString> farg_names;
+ MessageFormat *mf = (MessageFormat *)mfo->mf_data.umsgf;
+ HashTable *types;
+ intl_error& err = INTL_DATA_ERROR(mfo);
+
+ if (U_FAILURE(err.code)) {
+ return;
+ }
+
+ types = umsg_get_types(mfo, err TSRMLS_CC);
+
+ umsg_set_timezone(mfo, err TSRMLS_CC);
+
+ fargs.resize(arg_count);
+ farg_names.resize(arg_count);
+
+ int argNum = 0;
+ HashPosition pos;
+ zval **elem;
+
+ // Key related variables
+ int key_type;
+ char *str_index;
+ uint str_len;
+ ulong num_index;
+
+ for (zend_hash_internal_pointer_reset_ex(args, &pos);
+ U_SUCCESS(err.code) &&
+ (key_type = zend_hash_get_current_key_ex(
+ args, &str_index, &str_len, &num_index, 0, &pos),
+ zend_hash_get_current_data_ex(args, (void **)&elem, &pos)
+ ) == SUCCESS;
+ zend_hash_move_forward_ex(args, &pos), argNum++)
+ {
+ Formattable& formattable = fargs[argNum];
+ UnicodeString& key = farg_names[argNum];
+ Formattable::Type argType = Formattable::kObject, //unknown
+ *storedArgType = NULL;
+
+ /* Process key and retrieve type */
+ if (key_type == HASH_KEY_IS_LONG) {
+ /* includes case where index < 0 because it's exposed as unsigned */
+ if (num_index > (ulong)INT32_MAX) {
+ intl_errors_set(&err, U_ILLEGAL_ARGUMENT_ERROR,
+ "Found negative or too large array key", 0 TSRMLS_CC);
+ continue;
+ }
+
+ UChar temp[16];
+ int32_t len = u_sprintf(temp, "%u", (uint32_t)num_index);
+ key.append(temp, len);
+
+ zend_hash_index_find(types, (ulong)num_index, (void**)&storedArgType);
+ } else { //string; assumed to be in UTF-8
+ intl_stringFromChar(key, str_index, str_len-1, &err.code);
+
+ if (U_FAILURE(err.code)) {
+ char *message;
+ spprintf(&message, 0,
+ "Invalid UTF-8 data in argument key: '%s'", str_index);
+ intl_errors_set(&err, err.code, message, 1 TSRMLS_CC);
+ efree(message);
+ continue;
+ }
+
+ zend_hash_find(types, (char*)key.getBuffer(), key.length(),
+ (void**)&storedArgType);
+ }
+
+ if (storedArgType != NULL) {
+ argType = *storedArgType;
+ }
+
+ /* Convert zval to formattable according to message format type
+ * or (as a fallback) the zval type */
+ if (argType != Formattable::kObject) {
+ switch (argType) {
+ case Formattable::kString:
+ {
+ string_arg:
+ /* This implicitly converts objects
+ * Note that our vectors will leak if object conversion fails
+ * and PHP ends up with a fatal error and calls longjmp
+ * as a result of that.
+ */
+ convert_to_string_ex(elem);
+
+ UnicodeString *text = new UnicodeString();
+ intl_stringFromChar(*text,
+ Z_STRVAL_PP(elem), Z_STRLEN_PP(elem), &err.code);
+
+ if (U_FAILURE(err.code)) {
+ char *message;
+ spprintf(&message, 0, "Invalid UTF-8 data in string argument: "
+ "'%s'", Z_STRVAL_PP(elem));
+ intl_errors_set(&err, err.code, message, 1 TSRMLS_CC);
+ efree(message);
+ delete text;
+ continue;
+ }
+ formattable.adoptString(text);
+ break;
}
- fargs[i].setInt64(tInt64);
+ case Formattable::kDouble:
+ {
+ double d;
+ if (Z_TYPE_PP(elem) == IS_DOUBLE) {
+ d = Z_DVAL_PP(elem);
+ } else if (Z_TYPE_PP(elem) == IS_LONG) {
+ d = (double)Z_LVAL_PP(elem);
+ } else {
+ SEPARATE_ZVAL_IF_NOT_REF(elem);
+ convert_scalar_to_number(*elem TSRMLS_CC);
+ d = (Z_TYPE_PP(elem) == IS_DOUBLE)
+ ? Z_DVAL_PP(elem)
+ : (double)Z_LVAL_PP(elem);
+ }
+ formattable.setDouble(d);
+ break;
+ }
+ case Formattable::kLong:
+ {
+ int32_t tInt32;
+retry_klong:
+ if (Z_TYPE_PP(elem) == IS_DOUBLE) {
+ if (Z_DVAL_PP(elem) > (double)INT32_MAX ||
+ Z_DVAL_PP(elem) < (double)INT32_MIN) {
+ intl_errors_set(&err, U_ILLEGAL_ARGUMENT_ERROR,
+ "Found PHP float with absolute value too large for "
+ "32 bit integer argument", 0 TSRMLS_CC);
+ } else {
+ tInt32 = (int32_t)Z_DVAL_PP(elem);
+ }
+ } else if (Z_TYPE_PP(elem) == IS_LONG) {
+ if (Z_LVAL_PP(elem) > INT32_MAX ||
+ Z_LVAL_PP(elem) < INT32_MIN) {
+ intl_errors_set(&err, U_ILLEGAL_ARGUMENT_ERROR,
+ "Found PHP integer with absolute value too large "
+ "for 32 bit integer argument", 0 TSRMLS_CC);
+ } else {
+ tInt32 = (int32_t)Z_LVAL_PP(elem);
+ }
+ } else {
+ SEPARATE_ZVAL_IF_NOT_REF(elem);
+ convert_scalar_to_number(*elem TSRMLS_CC);
+ goto retry_klong;
+ }
+ formattable.setLong(tInt32);
+ break;
+ }
+ case Formattable::kInt64:
+ {
+ int64_t tInt64;
+retry_kint64:
+ if (Z_TYPE_PP(elem) == IS_DOUBLE) {
+ if (Z_DVAL_PP(elem) > (double)U_INT64_MAX ||
+ Z_DVAL_PP(elem) < (double)U_INT64_MIN) {
+ intl_errors_set(&err, U_ILLEGAL_ARGUMENT_ERROR,
+ "Found PHP float with absolute value too large for "
+ "64 bit integer argument", 0 TSRMLS_CC);
+ } else {
+ tInt64 = (int64_t)Z_DVAL_PP(elem);
+ }
+ } else if (Z_TYPE_PP(elem) == IS_LONG) {
+ /* assume long is not wider than 64 bits */
+ tInt64 = (int64_t)Z_LVAL_PP(elem);
+ } else {
+ SEPARATE_ZVAL_IF_NOT_REF(elem);
+ convert_scalar_to_number(*elem TSRMLS_CC);
+ goto retry_kint64;
+ }
+ formattable.setInt64(tInt64);
+ break;
+ }
+ case Formattable::kDate:
+ {
+ double dd = intl_zval_to_millis(*elem, &err, "msgfmt_format" TSRMLS_CC);
+ if (U_FAILURE(err.code)) {
+ char *message, *key_char;
+ int key_len;
+ UErrorCode status = UErrorCode();
+ if (intl_charFromString(key, &key_char, &key_len,
+ &status) == SUCCESS) {
+ spprintf(&message, 0, "The argument for key '%s' "
+ "cannot be used as a date or time", key_char);
+ intl_errors_set(&err, err.code, message, 1 TSRMLS_CC);
+ efree(key_char);
+ efree(message);
+ }
+ continue;
+ }
+ formattable.setDate(dd);
+ break;
+ }
+ default:
+ intl_errors_set(&err, U_ILLEGAL_ARGUMENT_ERROR,
+ "Found unsupported argument type", 0 TSRMLS_CC);
+ break;
+ }
+ } else {
+ /* We couldn't find any information about the argument in the pattern, this
+ * means it's an extra argument. So convert it to a number if it's a number or
+ * bool or null and to a string if it's anything else except arrays . */
+ switch (Z_TYPE_PP(elem)) {
+ case IS_DOUBLE:
+ formattable.setDouble(Z_DVAL_PP(elem));
break;
-
- case Formattable::kString:
- convert_to_string_ex(&args[i]);
- intl_convert_utf8_to_utf16(&stringVal, &stringLen, Z_STRVAL_P(args[i]), Z_STRLEN_P(args[i]), status);
- if(U_FAILURE(*status)){
- delete[] fargs;
- return;
+ case IS_BOOL:
+ convert_to_long_ex(elem);
+ /* Intentional fallthrough */
+ case IS_LONG:
+ formattable.setInt64((int64_t)Z_LVAL_PP(elem));
+ break;
+ case IS_NULL:
+ formattable.setInt64((int64_t)0);
+ break;
+ case IS_STRING:
+ case IS_OBJECT:
+ goto string_arg;
+ default:
+ {
+ char *message, *key_char;
+ int key_len;
+ UErrorCode status = UErrorCode();
+ if (intl_charFromString(key, &key_char, &key_len,
+ &status) == SUCCESS) {
+ spprintf(&message, 0, "No strategy to convert the "
+ "value given for the argument with key '%s' "
+ "is available", key_char);
+ intl_errors_set(&err,
+ U_ILLEGAL_ARGUMENT_ERROR, message, 1 TSRMLS_CC);
+ efree(key_char);
+ efree(message);
+ }
}
- fargs[i].setString(stringVal);
- efree(stringVal);
- break;
-
- case Formattable::kArray:
- case Formattable::kObject:
- *status = U_UNSUPPORTED_ERROR;
- delete[] fargs;
- return;
- }
+ }
+ }
+ } // visiting each argument
+
+ if (U_FAILURE(err.code)) {
+ return;
}
- UnicodeString resultStr;
- FieldPosition fieldPosition(0);
-
- /* format the message */
- ((const MessageFormat*)fmt)->format(fargs, fmt_count, resultStr, fieldPosition, *status);
+ UnicodeString resultStr;
+ FieldPosition fieldPosition(0);
- delete[] fargs;
+ /* format the message */
+ mf->format(farg_names.empty() ? NULL : &farg_names[0],
+ fargs.empty() ? NULL : &fargs[0], arg_count, resultStr, err.code);
- if(U_FAILURE(*status)){
- return;
- }
+ if (U_FAILURE(err.code)) {
+ intl_errors_set(&err, err.code,
+ "Call to ICU MessageFormat::format() has failed", 0 TSRMLS_CC);
+ return;
+ }
*formatted_len = resultStr.length();
*formatted = eumalloc(*formatted_len+1);
- resultStr.extract(*formatted, *formatted_len+1, *status);
+ resultStr.extract(*formatted, *formatted_len+1, err.code);
+ if (U_FAILURE(err.code)) {
+ intl_errors_set(&err, err.code,
+ "Error copying format() result", 0 TSRMLS_CC);
+ return;
+ }
}
#define cleanup_zvals() for(int j=i;j>=0;j--) { zval_ptr_dtor((*args)+i); }
@@ -154,15 +653,11 @@ U_CFUNC void umsg_parse_helper(UMessageFormat *fmt, int *count, zval ***args, UC
int stmp_len;
ALLOC_INIT_ZVAL((*args)[i]);
-
+
switch(fargs[i].getType()) {
case Formattable::kDate:
aDate = ((double)fargs[i].getDate())/U_MILLIS_PER_SECOND;
- if(aDate > LONG_MAX || aDate < -LONG_MAX) {
- ZVAL_DOUBLE((*args)[i], aDate<0?ceil(aDate):floor(aDate));
- } else {
- ZVAL_LONG((*args)[i], (long)aDate);
- }
+ ZVAL_DOUBLE((*args)[i], aDate);
break;
case Formattable::kDouble:
diff --git a/ext/intl/msgformat/msgformat_helpers.h b/ext/intl/msgformat/msgformat_helpers.h
index 30c7e3930f..e6eda087d2 100644
--- a/ext/intl/msgformat/msgformat_helpers.h
+++ b/ext/intl/msgformat/msgformat_helpers.h
@@ -17,9 +17,9 @@
#ifndef MSG_FORMAT_HELPERS_H
#define MSG_FORMAT_HELPERS_H
-int32_t umsg_format_arg_count(UMessageFormat *fmt);
-void umsg_format_helper(UMessageFormat *fmt, int arg_count, zval **args,
- UChar **formatted, int *formatted_len, UErrorCode *status TSRMLS_DC);
+int32_t umsg_format_arg_count(UMessageFormat *fmt);
+void umsg_format_helper(MessageFormatter_object *mfo, HashTable *args,
+ UChar **formatted, int *formatted_len TSRMLS_DC);
void umsg_parse_helper(UMessageFormat *fmt, int *count, zval ***args,
UChar *source, int source_len, UErrorCode *status);
#endif // MSG_FORMAT_HELPERS_H
diff --git a/ext/intl/msgformat/msgformat_parse.c b/ext/intl/msgformat/msgformat_parse.c
index f540b1d0c4..413d3b1f15 100644
--- a/ext/intl/msgformat/msgformat_parse.c
+++ b/ext/intl/msgformat/msgformat_parse.c
@@ -126,7 +126,7 @@ PHP_FUNCTION( msgfmt_parse_message )
}
if(slocale_len == 0) {
- slocale = INTL_G(default_locale);
+ slocale = intl_locale_get_default(TSRMLS_C);
}
#ifdef MSG_FORMAT_QUOTE_APOS
diff --git a/ext/intl/php_intl.c b/ext/intl/php_intl.c
index 90e3573c1b..a2c4d77651 100644
--- a/ext/intl/php_intl.c
+++ b/ext/intl/php_intl.c
@@ -34,6 +34,8 @@
#include "collator/collator_create.h"
#include "collator/collator_error.h"
+#include "converter/converter.h"
+
#include "formatter/formatter.h"
#include "formatter/formatter_class.h"
#include "formatter/formatter_attr.h"
@@ -41,6 +43,8 @@
#include "formatter/formatter_main.h"
#include "formatter/formatter_parse.h"
+#include "grapheme/grapheme.h"
+
#include "msgformat/msgformat.h"
#include "msgformat/msgformat_class.h"
#include "msgformat/msgformat_attr.h"
@@ -58,7 +62,9 @@
#include "dateformat/dateformat.h"
#include "dateformat/dateformat_class.h"
#include "dateformat/dateformat_attr.h"
+#include "dateformat/dateformat_attrcpp.h"
#include "dateformat/dateformat_format.h"
+#include "dateformat/dateformat_format_object.h"
#include "dateformat/dateformat_parse.h"
#include "dateformat/dateformat_data.h"
@@ -68,6 +74,16 @@
#include "transliterator/transliterator_class.h"
#include "transliterator/transliterator_methods.h"
+#include "timezone/timezone_class.h"
+#include "timezone/timezone_methods.h"
+
+#include "calendar/calendar_class.h"
+#include "calendar/calendar_methods.h"
+#include "calendar/gregoriancalendar_methods.h"
+
+#include "breakiterator/breakiterator_class.h"
+#include "breakiterator/breakiterator_iterators.h"
+
#include "idn/idn.h"
#if U_ICU_VERSION_MAJOR_NUM * 1000 + U_ICU_VERSION_MINOR_NUM >= 4002
@@ -79,8 +95,10 @@
#include "msgformat/msgformat.h"
#include "common/common_error.h"
+#include "common/common_enum.h"
#include <unicode/uloc.h>
+#include <unicode/uclean.h>
#include <ext/standard/info.h>
#include "php_ini.h"
@@ -98,6 +116,14 @@
ZEND_DECLARE_MODULE_GLOBALS( intl )
+const char *intl_locale_get_default( TSRMLS_D )
+{
+ if( INTL_G(default_locale) == NULL ) {
+ return uloc_getDefault();
+ }
+ return INTL_G(default_locale);
+}
+
/* {{{ Arguments info */
ZEND_BEGIN_ARG_INFO_EX(collator_static_0_args, 0, 0, 0)
ZEND_END_ARG_INFO()
@@ -313,6 +339,11 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_datefmt_set_pattern, 0, 0, 2)
ZEND_ARG_INFO(0, pattern)
ZEND_END_ARG_INFO()
+ZEND_BEGIN_ARG_INFO_EX(arginfo_datefmt_set_timezone, 0, 0, 2)
+ ZEND_ARG_INFO(0, mf)
+ ZEND_ARG_INFO(0, timezone)
+ZEND_END_ARG_INFO()
+
ZEND_BEGIN_ARG_INFO_EX(arginfo_datefmt_set_calendar, 0, 0, 2)
ZEND_ARG_INFO(0, mf)
ZEND_ARG_INFO(0, calendar)
@@ -323,6 +354,13 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_datefmt_format, 0, 0, 0)
ZEND_ARG_INFO(0, array)
ZEND_END_ARG_INFO()
+ZEND_BEGIN_ARG_INFO_EX(arginfo_datefmt_format_object, 0, 0, 1)
+ ZEND_ARG_INFO(0, object)
+ ZEND_ARG_INFO(0, format)
+ ZEND_ARG_INFO(0, locale)
+ZEND_END_ARG_INFO()
+
+
ZEND_BEGIN_ARG_INFO_EX(arginfo_datefmt_create, 0, 0, 3)
ZEND_ARG_INFO(0, locale)
ZEND_ARG_INFO(0, date_type)
@@ -402,6 +440,189 @@ ZEND_BEGIN_ARG_INFO_EX( arginfo_transliterator_error, 0, 0, 1 )
ZEND_ARG_OBJ_INFO( 0, trans, Transliterator, 0 )
ZEND_END_ARG_INFO()
+ZEND_BEGIN_ARG_INFO_EX( arginfo_tz_idarg_static, 0, 0, 1 )
+ ZEND_ARG_INFO( 0, zoneId )
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX( arginfo_tz_from_date_time_zone, 0, 0, 1 )
+ ZEND_ARG_OBJ_INFO( 0, dateTimeZone, IntlDateTimeZone, 0 )
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX( arginfo_tz_create_enumeration, 0, 0, 0 )
+ ZEND_ARG_INFO( 0, countryOrRawOffset )
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX( arginfo_tz_count_equivalent_ids, 0, 0, 1 )
+ ZEND_ARG_INFO( 0, zoneId )
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX( arginfo_tz_create_time_zone_id_enumeration, 0, 0, 1 )
+ ZEND_ARG_INFO( 0, zoneType )
+ ZEND_ARG_INFO( 0, region )
+ ZEND_ARG_INFO( 0, rawOffset )
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX( arginfo_tz_get_canonical_id, 0, 0, 1 )
+ ZEND_ARG_INFO( 0, zoneId )
+ ZEND_ARG_INFO( 1, isSystemID )
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX( arginfo_tz_get_equivalent_id, 0, 0, 2 )
+ ZEND_ARG_INFO( 0, zoneId )
+ ZEND_ARG_INFO( 0, index )
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX( arginfo_tz_get_offset, 0, 0, 5 )
+ ZEND_ARG_OBJ_INFO( 0, timeZone, IntlTimeZone, 0 )
+ ZEND_ARG_INFO( 0, date )
+ ZEND_ARG_INFO( 0, local )
+ ZEND_ARG_INFO( 1, rawOffset )
+ ZEND_ARG_INFO( 1, dstOffset )
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX( arginfo_tz_has_same_rules, 0, 0, 1 )
+ ZEND_ARG_OBJ_INFO( 0, timeZone, IntlTimeZone, 0 )
+ ZEND_ARG_OBJ_INFO( 0, otherTimeZone, IntlTimeZone, 0 )
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX( arginfo_tz_get_display_name, 0, 0, 1 )
+ ZEND_ARG_OBJ_INFO( 0, timeZone, IntlTimeZone, 0 )
+ ZEND_ARG_INFO( 0, isDaylight )
+ ZEND_ARG_INFO( 0, style )
+ ZEND_ARG_INFO( 0, locale )
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX( arginfo_tz_only_tz, 0, 0, 1 )
+ ZEND_ARG_OBJ_INFO( 0, timeZone, IntlTimeZone, 0 )
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX( arginfo_tz_void, 0, 0, 0 )
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX( ainfo_cal_create_instance, 0, 0, 0 )
+ ZEND_ARG_INFO( 0, timeZone )
+ ZEND_ARG_INFO( 0, locale )
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX( ainfo_cal_only_cal, 0, 0, 1 )
+ ZEND_ARG_OBJ_INFO( 0, calendar, IntlCalendar, 0 )
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX( ainfo_cal_void, 0, 0, 0 )
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX( ainfo_cal_field, 0, 0, 2 )
+ ZEND_ARG_OBJ_INFO( 0, calendar, IntlCalendar, 0 )
+ ZEND_ARG_INFO( 0, field )
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX( ainfo_cal_dow, 0, 0, 2 )
+ ZEND_ARG_OBJ_INFO( 0, calendar, IntlCalendar, 0 )
+ ZEND_ARG_INFO( 0, dayOfWeek )
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX( ainfo_cal_other_cal, 0, 0, 2 )
+ ZEND_ARG_OBJ_INFO( 0, calendar, IntlCalendar, 0 )
+ ZEND_ARG_OBJ_INFO( 0, otherCalendar, IntlCalendar, 0 )
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX( ainfo_cal_date, 0, 0, 2 )
+ ZEND_ARG_OBJ_INFO( 0, calendar, IntlCalendar, 0 )
+ ZEND_ARG_INFO( 0, date )
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX( ainfo_cal_date_optional, 0, 0, 1 )
+ ZEND_ARG_OBJ_INFO( 0, calendar, IntlCalendar, 0 )
+ ZEND_ARG_INFO( 0, date )
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX( ainfo_cal_get_keyword_values_for_locale, 0, 0, 3)
+ ZEND_ARG_INFO( 0, key )
+ ZEND_ARG_INFO( 0, locale )
+ ZEND_ARG_INFO( 0, commonlyUsed )
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX( ainfo_cal_add, 0, 0, 3 )
+ ZEND_ARG_OBJ_INFO( 0, calendar, IntlCalendar, 0 )
+ ZEND_ARG_INFO( 0, field )
+ ZEND_ARG_INFO( 0, amount )
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX( ainfo_cal_set_time_zone, 0, 0, 2 )
+ ZEND_ARG_OBJ_INFO( 0, calendar, IntlCalendar, 0 )
+ ZEND_ARG_INFO( 0, timeZone )
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX( ainfo_cal_set, 0, 0, 3 )
+ ZEND_ARG_OBJ_INFO( 0, calendar, IntlCalendar, 0 )
+ ZEND_ARG_INFO( 0, fieldOrYear )
+ ZEND_ARG_INFO( 0, valueOrMonth )
+ ZEND_ARG_INFO( 0, dayOfMonth )
+ ZEND_ARG_INFO( 0, hour )
+ ZEND_ARG_INFO( 0, minute )
+ ZEND_ARG_INFO( 0, second )
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX( ainfo_cal_roll, 0, 0, 2 )
+ ZEND_ARG_OBJ_INFO( 0, calendar, IntlCalendar, 0 )
+ ZEND_ARG_INFO( 0, field )
+ ZEND_ARG_INFO( 0, amountOrUpOrDown )
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX( ainfo_cal_clear, 0, 0, 1 )
+ ZEND_ARG_OBJ_INFO( 0, calendar, IntlCalendar, 0 )
+ ZEND_ARG_INFO( 0, field )
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX( ainfo_cal_field_difference, 0, 0, 3 )
+ ZEND_ARG_OBJ_INFO( 0, calendar, IntlCalendar, 0 )
+ ZEND_ARG_INFO( 0, when )
+ ZEND_ARG_INFO( 0, field )
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX( ainfo_cal_get_locale, 0, 0, 2 )
+ ZEND_ARG_OBJ_INFO( 0, calendar, IntlCalendar, 0 )
+ ZEND_ARG_INFO( 0, localeType )
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX( ainfo_cal_set_lenient, 0, 0, 2 )
+ ZEND_ARG_OBJ_INFO( 0, calendar, IntlCalendar, 0 )
+ ZEND_ARG_INFO( 0, isLenient )
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX(ainfo_cal_from_date_time, 0, 0, 1)
+ ZEND_ARG_INFO(0, dateTime)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX( ainfo_cal_wall_time_option, 0, 0, 2 )
+ ZEND_ARG_OBJ_INFO( 0, calendar, IntlCalendar, 0 )
+ ZEND_ARG_INFO( 0, wallTimeOption )
+ZEND_END_ARG_INFO()
+
+/* Gregorian Calendar */
+ZEND_BEGIN_ARG_INFO_EX( ainfo_gregcal_create_instance, 0, 0, 0 )
+ ZEND_ARG_INFO(0, timeZoneOrYear)
+ ZEND_ARG_INFO(0, localeOrMonth)
+ ZEND_ARG_INFO(0, dayOfMonth)
+ ZEND_ARG_INFO(0, hour)
+ ZEND_ARG_INFO(0, minute)
+ ZEND_ARG_INFO(0, second)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX( ainfo_gregcal_is_leap_year, 0, 0, 2 )
+ ZEND_ARG_OBJ_INFO( 0, calendar, IntlGregorianCalendar, 0 )
+ ZEND_ARG_INFO( 0, year )
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX( ainfo_gregcal_only_gregcal, 0, 0, 1 )
+ ZEND_ARG_OBJ_INFO( 0, calendar, IntlGregorianCalendar, 0 )
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX( ainfo_gregcal_set_gregorian_change, 0, 0, 2 )
+ ZEND_ARG_OBJ_INFO( 0, calendar, IntlGregorianCalendar, 0 )
+ ZEND_ARG_INFO( 0, date )
+ZEND_END_ARG_INFO()
+
/* }}} */
/* {{{ intl_functions
@@ -484,15 +705,19 @@ zend_function_entry intl_functions[] = {
PHP_FE( datefmt_get_datetype, arginfo_msgfmt_get_locale )
PHP_FE( datefmt_get_timetype, arginfo_msgfmt_get_locale )
PHP_FE( datefmt_get_calendar, arginfo_msgfmt_get_locale )
+ PHP_FE( datefmt_get_calendar_object, arginfo_msgfmt_get_locale )
PHP_FE( datefmt_set_calendar, arginfo_datefmt_set_calendar )
PHP_FE( datefmt_get_locale, arginfo_msgfmt_get_locale )
PHP_FE( datefmt_get_timezone_id, arginfo_msgfmt_get_locale )
- PHP_FE( datefmt_set_timezone_id, arginfo_msgfmt_get_locale )
+ PHP_FE( datefmt_set_timezone_id, arginfo_datefmt_set_timezone )
+ PHP_FE( datefmt_get_timezone, arginfo_msgfmt_get_locale )
+ PHP_FE( datefmt_set_timezone, arginfo_datefmt_set_timezone )
PHP_FE( datefmt_get_pattern, arginfo_msgfmt_get_locale )
PHP_FE( datefmt_set_pattern, arginfo_datefmt_set_pattern )
PHP_FE( datefmt_is_lenient, arginfo_msgfmt_get_locale )
PHP_FE( datefmt_set_lenient, arginfo_msgfmt_get_locale )
PHP_FE( datefmt_format, arginfo_datefmt_format )
+ PHP_FE( datefmt_format_object, arginfo_datefmt_format_object )
PHP_FE( datefmt_parse, datefmt_parse_args )
PHP_FE( datefmt_localtime , datefmt_parse_args )
PHP_FE( datefmt_get_error_code, arginfo_msgfmt_get_error_code )
@@ -530,6 +755,96 @@ zend_function_entry intl_functions[] = {
PHP_FE( transliterator_get_error_code, arginfo_transliterator_error )
PHP_FE( transliterator_get_error_message, arginfo_transliterator_error )
+ /* TimeZone functions */
+ PHP_FE( intltz_create_time_zone, arginfo_tz_idarg_static )
+ PHP_FE( intltz_from_date_time_zone, arginfo_tz_from_date_time_zone )
+ PHP_FE( intltz_create_default, arginfo_tz_void )
+ PHP_FE( intltz_get_id, arginfo_tz_only_tz )
+ PHP_FE( intltz_get_gmt, arginfo_tz_void )
+#if U_ICU_VERSION_MAJOR_NUM >= 49
+ PHP_FE( intltz_get_unknown, arginfo_tz_void )
+#endif
+ PHP_FE( intltz_create_enumeration, arginfo_tz_create_enumeration )
+ PHP_FE( intltz_count_equivalent_ids, arginfo_tz_idarg_static )
+#if U_ICU_VERSION_MAJOR_NUM * 10 + U_ICU_VERSION_MINOR_NUM >= 48
+ PHP_FE( intltz_create_time_zone_id_enumeration, arginfo_tz_create_time_zone_id_enumeration )
+#endif
+ PHP_FE( intltz_get_canonical_id, arginfo_tz_get_canonical_id )
+#if U_ICU_VERSION_MAJOR_NUM * 10 + U_ICU_VERSION_MINOR_NUM >= 48
+ PHP_FE( intltz_get_region, arginfo_tz_idarg_static )
+#endif
+ PHP_FE( intltz_get_tz_data_version, arginfo_tz_void )
+ PHP_FE( intltz_get_equivalent_id, arginfo_tz_get_equivalent_id )
+ PHP_FE( intltz_use_daylight_time, arginfo_tz_only_tz )
+ PHP_FE( intltz_get_offset, arginfo_tz_get_offset )
+ PHP_FE( intltz_get_raw_offset, arginfo_tz_only_tz )
+ PHP_FE( intltz_has_same_rules, arginfo_tz_has_same_rules )
+ PHP_FE( intltz_get_display_name, arginfo_tz_get_display_name )
+ PHP_FE( intltz_get_dst_savings, arginfo_tz_only_tz )
+ PHP_FE( intltz_to_date_time_zone, arginfo_tz_only_tz )
+ PHP_FE( intltz_get_error_code, arginfo_tz_only_tz )
+ PHP_FE( intltz_get_error_message, arginfo_tz_only_tz )
+
+ PHP_FE( intlcal_create_instance, ainfo_cal_create_instance )
+#if U_ICU_VERSION_MAJOR_NUM * 10 + U_ICU_VERSION_MINOR_NUM >= 42
+ PHP_FE( intlcal_get_keyword_values_for_locale, ainfo_cal_get_keyword_values_for_locale )
+#endif
+ PHP_FE( intlcal_get_now, ainfo_cal_void )
+ PHP_FE( intlcal_get_available_locales, ainfo_cal_void )
+ PHP_FE( intlcal_get, ainfo_cal_field )
+ PHP_FE( intlcal_get_time, ainfo_cal_only_cal )
+ PHP_FE( intlcal_set_time, ainfo_cal_date )
+ PHP_FE( intlcal_add, ainfo_cal_add )
+ PHP_FE( intlcal_set_time_zone, ainfo_cal_set_time_zone )
+ PHP_FE( intlcal_after, ainfo_cal_other_cal )
+ PHP_FE( intlcal_before, ainfo_cal_other_cal )
+ PHP_FE( intlcal_set, ainfo_cal_set )
+ PHP_FE( intlcal_roll, ainfo_cal_roll )
+ PHP_FE( intlcal_clear, ainfo_cal_clear )
+ PHP_FE( intlcal_field_difference, ainfo_cal_field_difference )
+ PHP_FE( intlcal_get_actual_maximum, ainfo_cal_field )
+ PHP_FE( intlcal_get_actual_minimum, ainfo_cal_field )
+#if U_ICU_VERSION_MAJOR_NUM * 10 + U_ICU_VERSION_MINOR_NUM >= 44
+ PHP_FE( intlcal_get_day_of_week_type, ainfo_cal_dow )
+#endif
+ PHP_FE( intlcal_get_first_day_of_week, ainfo_cal_only_cal )
+ PHP_FE( intlcal_get_greatest_minimum, ainfo_cal_field )
+ PHP_FE( intlcal_get_least_maximum, ainfo_cal_field )
+ PHP_FE( intlcal_get_locale, ainfo_cal_get_locale )
+ PHP_FE( intlcal_get_maximum, ainfo_cal_field )
+ PHP_FE( intlcal_get_minimal_days_in_first_week, ainfo_cal_only_cal )
+ PHP_FE( intlcal_get_minimum, ainfo_cal_field )
+ PHP_FE( intlcal_get_time_zone, ainfo_cal_only_cal )
+ PHP_FE( intlcal_get_type, ainfo_cal_only_cal )
+#if U_ICU_VERSION_MAJOR_NUM * 10 + U_ICU_VERSION_MINOR_NUM >= 44
+ PHP_FE( intlcal_get_weekend_transition, ainfo_cal_dow )
+#endif
+ PHP_FE( intlcal_in_daylight_time, ainfo_cal_only_cal )
+ PHP_FE( intlcal_is_equivalent_to, ainfo_cal_other_cal )
+ PHP_FE( intlcal_is_lenient, ainfo_cal_only_cal )
+ PHP_FE( intlcal_is_set, ainfo_cal_field )
+#if U_ICU_VERSION_MAJOR_NUM * 10 + U_ICU_VERSION_MINOR_NUM >= 44
+ PHP_FE( intlcal_is_weekend, ainfo_cal_date_optional )
+#endif
+ PHP_FE( intlcal_set_first_day_of_week, ainfo_cal_dow )
+ PHP_FE( intlcal_set_lenient, ainfo_cal_set_lenient )
+ PHP_FE( intlcal_equals, ainfo_cal_other_cal )
+ PHP_FE( intlcal_from_date_time, ainfo_cal_from_date_time )
+ PHP_FE( intlcal_to_date_time, ainfo_cal_only_cal )
+#if U_ICU_VERSION_MAJOR_NUM >= 49
+ PHP_FE( intlcal_get_repeated_wall_time_option, ainfo_cal_only_cal )
+ PHP_FE( intlcal_get_skipped_wall_time_option, ainfo_cal_only_cal )
+ PHP_FE( intlcal_set_repeated_wall_time_option, ainfo_cal_wall_time_option )
+ PHP_FE( intlcal_set_skipped_wall_time_option, ainfo_cal_wall_time_option )
+#endif
+ PHP_FE( intlcal_get_error_code, ainfo_cal_only_cal )
+ PHP_FE( intlcal_get_error_message, ainfo_cal_only_cal )
+
+ PHP_FE( intlgregcal_create_instance, ainfo_gregcal_create_instance )
+ PHP_FE( intlgregcal_set_gregorian_change, ainfo_gregcal_set_gregorian_change )
+ PHP_FE( intlgregcal_get_gregorian_change, ainfo_gregcal_only_gregcal )
+ PHP_FE( intlgregcal_is_leap_year, ainfo_gregcal_is_leap_year )
+
/* common functions */
PHP_FE( intl_get_error_code, intl_0_args )
PHP_FE( intl_get_error_message, intl_0_args )
@@ -540,16 +855,14 @@ zend_function_entry intl_functions[] = {
};
/* }}} */
-
/* {{{ INI Settings */
PHP_INI_BEGIN()
STD_PHP_INI_ENTRY(LOCALE_INI_NAME, NULL, PHP_INI_ALL, OnUpdateStringUnempty, default_locale, zend_intl_globals, intl_globals)
STD_PHP_INI_ENTRY("intl.error_level", "0", PHP_INI_ALL, OnUpdateLong, error_level, zend_intl_globals, intl_globals)
-
+ STD_PHP_INI_ENTRY("intl.use_exceptions", "0", PHP_INI_ALL, OnUpdateBool, use_exceptions, zend_intl_globals, intl_globals)
PHP_INI_END()
/* }}} */
-
static PHP_GINIT_FUNCTION(intl);
/* {{{ intl_module_entry */
@@ -640,6 +953,12 @@ PHP_MINIT_FUNCTION( intl )
/* Register Transliterator constants */
transliterator_register_constants( INIT_FUNC_ARGS_PASSTHRU );
+ /* Register 'IntlTimeZone' PHP class */
+ timezone_register_IntlTimeZone_class( TSRMLS_C );
+
+ /* Register 'IntlCalendar' PHP class */
+ calendar_register_IntlCalendar_class( TSRMLS_C );
+
/* Expose ICU error codes to PHP scripts. */
intl_expose_icu_error_codes( INIT_FUNC_ARGS_PASSTHRU );
@@ -653,25 +972,44 @@ PHP_MINIT_FUNCTION( intl )
/* Expose Spoofchecker constants to PHP scripts */
spoofchecker_register_constants( INIT_FUNC_ARGS_PASSTHRU );
#endif
+
+ /* Register 'IntlException' PHP class */
+ intl_register_IntlException_class( TSRMLS_C );
+
+ /* Register 'IntlIterator' PHP class */
+ intl_register_IntlIterator_class( TSRMLS_C );
+
+ /* Register 'BreakIterator' class */
+ breakiterator_register_BreakIterator_class( TSRMLS_C );
+
+ /* Register 'IntlPartsIterator' class */
+ breakiterator_register_IntlPartsIterator_class( TSRMLS_C );
+
/* Global error handling. */
intl_error_init( NULL TSRMLS_CC );
- /* Set the default_locale value */
- if( INTL_G(default_locale) == NULL ) {
- INTL_G(default_locale) = pestrdup(uloc_getDefault(), 1) ;
- }
+ /* 'Converter' class for codepage conversions */
+ php_converter_minit(INIT_FUNC_ARGS_PASSTHRU);
return SUCCESS;
}
/* }}} */
+#define EXPLICIT_CLEANUP_ENV_VAR "INTL_EXPLICIT_CLEANUP"
+
/* {{{ PHP_MSHUTDOWN_FUNCTION
*/
PHP_MSHUTDOWN_FUNCTION( intl )
{
+ const char *cleanup;
/* For the default locale php.ini setting */
UNREGISTER_INI_ENTRIES();
+ cleanup = getenv(EXPLICIT_CLEANUP_ENV_VAR);
+ if (cleanup != NULL && !(cleanup[0] == '0' && cleanup[1] == '\0')) {
+ u_cleanup();
+ }
+
return SUCCESS;
}
/* }}} */
@@ -680,10 +1018,6 @@ PHP_MSHUTDOWN_FUNCTION( intl )
*/
PHP_RINIT_FUNCTION( intl )
{
- /* Set the default_locale value */
- if( INTL_G(default_locale) == NULL ) {
- INTL_G(default_locale) = pestrdup(uloc_getDefault(), 1) ;
- }
return SUCCESS;
}
/* }}} */
diff --git a/ext/intl/php_intl.h b/ext/intl/php_intl.h
index 4ede069e2a..7a7112317d 100644
--- a/ext/intl/php_intl.h
+++ b/ext/intl/php_intl.h
@@ -22,8 +22,13 @@
#include <php.h>
+/* Even if we're included from C++, don't introduce C++ definitions
+ * because we were included with extern "C". The effect would be that
+ * when the headers defined any method, they would do so with C linkage */
+#undef U_SHOW_CPLUSPLUS_API
+#define U_SHOW_CPLUSPLUS_API 0
#include "collator/collator_sort.h"
-#include "grapheme/grapheme.h"
+#include <unicode/ubrk.h>
#include "intl_error.h"
extern zend_module_entry intl_module_entry;
@@ -46,6 +51,7 @@ ZEND_BEGIN_MODULE_GLOBALS(intl)
UBreakIterator* grapheme_iterator;
intl_error g_error;
long error_level;
+ zend_bool use_exceptions;
ZEND_END_MODULE_GLOBALS(intl)
/* Macro to access request-wide global variables. */
@@ -63,6 +69,8 @@ PHP_RINIT_FUNCTION(intl);
PHP_RSHUTDOWN_FUNCTION(intl);
PHP_MINFO_FUNCTION(intl);
+const char *intl_locale_get_default( TSRMLS_D );
+
#define PHP_INTL_VERSION "1.1.0"
#endif /* PHP_INTL_H */
diff --git a/ext/intl/resourcebundle/resourcebundle_class.c b/ext/intl/resourcebundle/resourcebundle_class.c
index a6a73f5f04..db46bf5b16 100644
--- a/ext/intl/resourcebundle/resourcebundle_class.c
+++ b/ext/intl/resourcebundle/resourcebundle_class.c
@@ -79,13 +79,11 @@ static zend_object_value ResourceBundle_object_create( zend_class_entry *ce TSRM
/* {{{ ResourceBundle_ctor */
static void resourcebundle_ctor(INTERNAL_FUNCTION_PARAMETERS)
{
- char * bundlename;
- int bundlename_len = 0;
- char * locale;
- int locale_len = 0;
- zend_bool fallback = 1;
-
- char * pbuf;
+ const char *bundlename;
+ int bundlename_len = 0;
+ const char *locale;
+ int locale_len = 0;
+ zend_bool fallback = 1;
zval *object = return_value;
ResourceBundle_object *rb = (ResourceBundle_object *) zend_object_store_get_object( object TSRMLS_CC);
@@ -104,7 +102,7 @@ static void resourcebundle_ctor(INTERNAL_FUNCTION_PARAMETERS)
INTL_CHECK_LOCALE_LEN_OBJ(locale_len, return_value);
if (locale == NULL) {
- locale = INTL_G(default_locale);
+ locale = intl_locale_get_default(TSRMLS_C);
}
if (fallback) {
@@ -117,6 +115,7 @@ static void resourcebundle_ctor(INTERNAL_FUNCTION_PARAMETERS)
if (!fallback && (INTL_DATA_ERROR_CODE(rb) == U_USING_FALLBACK_WARNING ||
INTL_DATA_ERROR_CODE(rb) == U_USING_DEFAULT_WARNING)) {
+ char *pbuf;
intl_errors_set_code(NULL, INTL_DATA_ERROR_CODE(rb) TSRMLS_CC);
spprintf(&pbuf, 0, "resourcebundle_ctor: Cannot load libICU resource "
"'%s' without fallback from %s to %s",
diff --git a/ext/intl/tests/badargs.phpt b/ext/intl/tests/badargs.phpt
index 9232bbf0c1..b8f48b371e 100644
--- a/ext/intl/tests/badargs.phpt
+++ b/ext/intl/tests/badargs.phpt
@@ -13,7 +13,10 @@ foreach($funcs as $func) {
if($rfunc->getNumberOfRequiredParameters() == 0) {
continue;
}
- $res = $func($arg);
+
+ try {
+ $res = $func($arg);
+ } catch (Exception $e) { continue; }
if($res != false) {
echo "$func: ";
var_dump($res);
diff --git a/ext/intl/tests/breakiter___construct.phpt b/ext/intl/tests/breakiter___construct.phpt
new file mode 100644
index 0000000000..a818075a30
--- /dev/null
+++ b/ext/intl/tests/breakiter___construct.phpt
@@ -0,0 +1,14 @@
+--TEST--
+IntlBreakIterator::__construct() should not be callable
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+
+new IntlBreakIterator();
+--EXPECTF--
+
+Fatal error: Call to private IntlBreakIterator::__construct() from invalid context in %s on line %d
diff --git a/ext/intl/tests/breakiter___construct_error.phpt b/ext/intl/tests/breakiter___construct_error.phpt
new file mode 100644
index 0000000000..770f1403c7
--- /dev/null
+++ b/ext/intl/tests/breakiter___construct_error.phpt
@@ -0,0 +1,38 @@
+--TEST--
+IntlRuleBasedBreakIterator::__construct(): arg errors
+--SKIPIF--
+<?php if( !extension_loaded( 'intl' ) ) print 'skip'; ?>
+<?php if(version_compare(INTL_ICU_VERSION, '4.8') < 0) print 'skip ICU >= 4.8 only'; ?>
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+
+//missing ; at the end:
+var_dump(new IntlRuleBasedBreakIterator('[\p{Letter}\uFFFD]+;[:number:]+'));
+var_dump(new IntlRuleBasedBreakIterator());
+var_dump(new IntlRuleBasedBreakIterator(1,2,3));
+var_dump(new IntlRuleBasedBreakIterator('[\p{Letter}\uFFFD]+;[:number:]+;', array()));
+var_dump(new IntlRuleBasedBreakIterator('[\p{Letter}\uFFFD]+;[:number:]+;', true));
+
+--EXPECTF--
+
+Warning: IntlRuleBasedBreakIterator::__construct(): rbbi_create_instance: unable to create RuleBasedBreakIterator from rules (parse error on line 1, offset 31) in %s on line %d
+NULL
+
+Warning: IntlRuleBasedBreakIterator::__construct() expects at least 1 parameter, 0 given in %s on line %d
+
+Warning: IntlRuleBasedBreakIterator::__construct(): rbbi_create_instance: bad arguments in %s on line %d
+NULL
+
+Warning: IntlRuleBasedBreakIterator::__construct() expects at most 2 parameters, 3 given in %s on line %d
+
+Warning: IntlRuleBasedBreakIterator::__construct(): rbbi_create_instance: bad arguments in %s on line %d
+NULL
+
+Warning: IntlRuleBasedBreakIterator::__construct() expects parameter 2 to be boolean, array given in %s on line %d
+
+Warning: IntlRuleBasedBreakIterator::__construct(): rbbi_create_instance: bad arguments in %s on line %d
+NULL
+
+Warning: IntlRuleBasedBreakIterator::__construct(): rbbi_create_instance: unable to create instance from compiled rules in %s on line %d
+NULL
diff --git a/ext/intl/tests/breakiter_clone_basic.phpt b/ext/intl/tests/breakiter_clone_basic.phpt
new file mode 100644
index 0000000000..d838f81217
--- /dev/null
+++ b/ext/intl/tests/breakiter_clone_basic.phpt
@@ -0,0 +1,27 @@
+--TEST--
+IntlBreakIterator: clone handler
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+
+$bi = new IntlRuleBasedBreakIterator('[\p{Letter}\uFFFD]+;[:number:]+;');
+$bi_clone = clone $bi;
+var_dump(get_class($bi), get_class($bi_clone));
+var_dump($bi == $bi_clone);
+
+$bi->setText('foobar');
+$bi_clone = clone $bi;
+var_dump(get_class($bi), get_class($bi_clone));
+var_dump($bi == $bi_clone);
+
+--EXPECT--
+string(26) "IntlRuleBasedBreakIterator"
+string(26) "IntlRuleBasedBreakIterator"
+bool(true)
+string(26) "IntlRuleBasedBreakIterator"
+string(26) "IntlRuleBasedBreakIterator"
+bool(true)
diff --git a/ext/intl/tests/breakiter_createCodePointInstance_basic.phpt b/ext/intl/tests/breakiter_createCodePointInstance_basic.phpt
new file mode 100644
index 0000000000..a43e82760c
--- /dev/null
+++ b/ext/intl/tests/breakiter_createCodePointInstance_basic.phpt
@@ -0,0 +1,43 @@
+--TEST--
+IntlBreakIterator::createCodePointInstance(): basic test
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+ini_set("intl.default_locale", "pt_PT");
+
+$text = 'ตัวอย่างข้อความ';
+
+$codepoint_it = IntlBreakIterator::createCodePointInstance();
+var_dump(get_class($codepoint_it));
+$codepoint_it->setText($text);
+
+print_r(iterator_to_array($codepoint_it));
+
+?>
+==DONE==
+--EXPECT--
+string(26) "IntlCodePointBreakIterator"
+Array
+(
+ [0] => 0
+ [1] => 3
+ [2] => 6
+ [3] => 9
+ [4] => 12
+ [5] => 15
+ [6] => 18
+ [7] => 21
+ [8] => 24
+ [9] => 27
+ [10] => 30
+ [11] => 33
+ [12] => 36
+ [13] => 39
+ [14] => 42
+ [15] => 45
+)
+==DONE==
diff --git a/ext/intl/tests/breakiter_createCodePointInstance_error.phpt b/ext/intl/tests/breakiter_createCodePointInstance_error.phpt
new file mode 100644
index 0000000000..90228e128f
--- /dev/null
+++ b/ext/intl/tests/breakiter_createCodePointInstance_error.phpt
@@ -0,0 +1,18 @@
+--TEST--
+IntlBreakIterator::createCodePointInstance(): bad arguments
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+
+var_dump(IntlBreakIterator::createCodePointInstance(array()));
+--EXPECTF--
+
+Warning: IntlBreakIterator::createCodePointInstance() expects exactly 0 parameters, 1 given in %s on line %d
+
+Warning: IntlBreakIterator::createCodePointInstance(): breakiter_create_code_point_instance: bad arguments in %s on line %d
+NULL
+
diff --git a/ext/intl/tests/breakiter_current_basic.phpt b/ext/intl/tests/breakiter_current_basic.phpt
new file mode 100644
index 0000000000..2ce6da7697
--- /dev/null
+++ b/ext/intl/tests/breakiter_current_basic.phpt
@@ -0,0 +1,28 @@
+--TEST--
+IntlBreakIterator::current(): basic test
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+ini_set("intl.default_locale", "pt_PT");
+
+$bi = IntlBreakIterator::createWordInstance('pt');
+var_dump($bi->current());
+$bi->setText('foo bar trans zoo bee');
+
+var_dump($bi->first());
+var_dump($bi->current());
+var_dump($bi->next());
+var_dump($bi->current());
+?>
+==DONE==
+--EXPECT--
+int(0)
+int(0)
+int(0)
+int(3)
+int(3)
+==DONE== \ No newline at end of file
diff --git a/ext/intl/tests/breakiter_factories_basic.phpt b/ext/intl/tests/breakiter_factories_basic.phpt
new file mode 100644
index 0000000000..dcfcedef0c
--- /dev/null
+++ b/ext/intl/tests/breakiter_factories_basic.phpt
@@ -0,0 +1,46 @@
+--TEST--
+IntlBreakIterator factories: basic tests
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+ini_set("intl.default_locale", "ja");
+
+$m = array('createWordInstance', 'createLineInstance', 'createCharacterInstance',
+ 'createSentenceInstance', 'createTitleInstance');
+
+$t = 'Frase 1... Frase 2'.
+
+$o1 = $o2 = null;
+foreach ($m as $method) {
+ echo "===== $method =====\n";
+ $o1 = call_user_func(array('IntlBreakIterator', $method), 'ja');
+ var_dump($o1 == $o2);
+ $o2 = call_user_func(array('IntlBreakIterator', $method), NULL);
+ var_dump($o1 == $o2);
+ echo "\n";
+}
+--EXPECT--
+===== createWordInstance =====
+bool(false)
+bool(true)
+
+===== createLineInstance =====
+bool(false)
+bool(true)
+
+===== createCharacterInstance =====
+bool(false)
+bool(true)
+
+===== createSentenceInstance =====
+bool(false)
+bool(true)
+
+===== createTitleInstance =====
+bool(false)
+bool(true)
+
diff --git a/ext/intl/tests/breakiter_factories_error.phpt b/ext/intl/tests/breakiter_factories_error.phpt
new file mode 100644
index 0000000000..c35339f7a0
--- /dev/null
+++ b/ext/intl/tests/breakiter_factories_error.phpt
@@ -0,0 +1,43 @@
+--TEST--
+IntlBreakIterator factory methods: argument errors
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+
+var_dump(IntlBreakIterator::createWordInstance(array()));
+var_dump(IntlBreakIterator::createSentenceInstance(NULL, 2));
+var_dump(IntlBreakIterator::createCharacterInstance(NULL, 2));
+var_dump(IntlBreakIterator::createTitleInstance(NULL, 2));
+var_dump(IntlBreakIterator::createLineInstance(NULL, 2));
+
+
+--EXPECTF--
+
+Warning: IntlBreakIterator::createWordInstance() expects parameter 1 to be string, array given in %s on line %d
+
+Warning: IntlBreakIterator::createWordInstance(): breakiter_create_word_instance: bad arguments in %s on line %d
+NULL
+
+Warning: IntlBreakIterator::createSentenceInstance() expects exactly 1 parameter, 2 given in %s on line %d
+
+Warning: IntlBreakIterator::createSentenceInstance(): breakiter_create_sentence_instance: bad arguments in %s on line %d
+NULL
+
+Warning: IntlBreakIterator::createCharacterInstance() expects exactly 1 parameter, 2 given in %s on line %d
+
+Warning: IntlBreakIterator::createCharacterInstance(): breakiter_create_character_instance: bad arguments in %s on line %d
+NULL
+
+Warning: IntlBreakIterator::createTitleInstance() expects exactly 1 parameter, 2 given in %s on line %d
+
+Warning: IntlBreakIterator::createTitleInstance(): breakiter_create_title_instance: bad arguments in %s on line %d
+NULL
+
+Warning: IntlBreakIterator::createLineInstance() expects exactly 1 parameter, 2 given in %s on line %d
+
+Warning: IntlBreakIterator::createLineInstance(): breakiter_create_line_instance: bad arguments in %s on line %d
+NULL
diff --git a/ext/intl/tests/breakiter_first_basic.phpt b/ext/intl/tests/breakiter_first_basic.phpt
new file mode 100644
index 0000000000..364d5f2fa6
--- /dev/null
+++ b/ext/intl/tests/breakiter_first_basic.phpt
@@ -0,0 +1,22 @@
+--TEST--
+IntlBreakIterator::first(): basic test
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+
+$bi = IntlBreakIterator::createWordInstance('pt');
+$bi->setText('foo bar trans');
+
+var_dump($bi->current());
+var_dump($bi->next());
+var_dump($bi->first());
+var_dump($bi->current());
+--EXPECT--
+int(0)
+int(3)
+int(0)
+int(0)
diff --git a/ext/intl/tests/breakiter_first_last_previous_current_error.phpt b/ext/intl/tests/breakiter_first_last_previous_current_error.phpt
new file mode 100644
index 0000000000..2ab681228e
--- /dev/null
+++ b/ext/intl/tests/breakiter_first_last_previous_current_error.phpt
@@ -0,0 +1,39 @@
+--TEST--
+IntlBreakIterator::first()/last()/previous()/current(): arg errors
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+
+$bi = new IntlRuleBasedBreakIterator('[\p{Letter}\uFFFD]+;[:number:]+;');
+$bi->setText("\x80sdfé\x90d888 dfsa9");
+
+var_dump($bi->first(1));
+var_dump($bi->last(1));
+var_dump($bi->previous(1));
+var_dump($bi->current(1));
+
+--EXPECTF--
+
+Warning: IntlBreakIterator::first() expects exactly 0 parameters, 1 given in %s on line %d
+
+Warning: IntlBreakIterator::first(): breakiter_first: bad arguments in %s on line %d
+bool(false)
+
+Warning: IntlBreakIterator::last() expects exactly 0 parameters, 1 given in %s on line %d
+
+Warning: IntlBreakIterator::last(): breakiter_last: bad arguments in %s on line %d
+bool(false)
+
+Warning: IntlBreakIterator::previous() expects exactly 0 parameters, 1 given in %s on line %d
+
+Warning: IntlBreakIterator::previous(): breakiter_previous: bad arguments in %s on line %d
+bool(false)
+
+Warning: IntlBreakIterator::current() expects exactly 0 parameters, 1 given in %s on line %d
+
+Warning: IntlBreakIterator::current(): breakiter_current: bad arguments in %s on line %d
+bool(false)
diff --git a/ext/intl/tests/breakiter_following_basic.phpt b/ext/intl/tests/breakiter_following_basic.phpt
new file mode 100644
index 0000000000..30798d99a3
--- /dev/null
+++ b/ext/intl/tests/breakiter_following_basic.phpt
@@ -0,0 +1,24 @@
+--TEST--
+IntlBreakIterator::following(): basic test
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+ini_set("intl.default_locale", "pt_PT");
+
+$bi = IntlBreakIterator::createWordInstance('pt');
+$bi->setText('foo bar trans zoo bee');
+
+var_dump($bi->following(5));
+var_dump($bi->following(50));
+var_dump($bi->following(-1));
+?>
+==DONE==
+--EXPECT--
+int(7)
+int(-1)
+int(0)
+==DONE== \ No newline at end of file
diff --git a/ext/intl/tests/breakiter_following_preceding_isBoundary_error.phpt b/ext/intl/tests/breakiter_following_preceding_isBoundary_error.phpt
new file mode 100644
index 0000000000..5550ccf0a0
--- /dev/null
+++ b/ext/intl/tests/breakiter_following_preceding_isBoundary_error.phpt
@@ -0,0 +1,51 @@
+--TEST--
+IntlBreakIterator::following()/preceding()/isBoundary(): arg errors
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+
+$bi = new IntlRuleBasedBreakIterator('[\p{Letter}\uFFFD]+;[:number:]+;');
+$bi->setText("\x80sdfé\x90d888 dfsa9");
+
+var_dump($bi->following(1, 2));
+var_dump($bi->following(array()));
+var_dump($bi->preceding(1, 2));
+var_dump($bi->preceding(array()));
+var_dump($bi->isBoundary(1, 2));
+var_dump($bi->isBoundary(array()));
+
+--EXPECTF--
+
+Warning: IntlBreakIterator::following() expects exactly 1 parameter, 2 given in %s on line %d
+
+Warning: IntlBreakIterator::following(): breakiter_following: bad arguments in %s on line %d
+bool(false)
+
+Warning: IntlBreakIterator::following() expects parameter 1 to be long, array given in %s on line %d
+
+Warning: IntlBreakIterator::following(): breakiter_following: bad arguments in %s on line %d
+bool(false)
+
+Warning: IntlBreakIterator::preceding() expects exactly 1 parameter, 2 given in %s on line %d
+
+Warning: IntlBreakIterator::preceding(): breakiter_preceding: bad arguments in %s on line %d
+bool(false)
+
+Warning: IntlBreakIterator::preceding() expects parameter 1 to be long, array given in %s on line %d
+
+Warning: IntlBreakIterator::preceding(): breakiter_preceding: bad arguments in %s on line %d
+bool(false)
+
+Warning: IntlBreakIterator::isBoundary() expects exactly 1 parameter, 2 given in %s on line %d
+
+Warning: IntlBreakIterator::isBoundary(): breakiter_is_boundary: bad arguments in %s on line %d
+bool(false)
+
+Warning: IntlBreakIterator::isBoundary() expects parameter 1 to be long, array given in %s on line %d
+
+Warning: IntlBreakIterator::isBoundary(): breakiter_is_boundary: bad arguments in %s on line %d
+bool(false)
diff --git a/ext/intl/tests/breakiter_getLocale_basic.phpt b/ext/intl/tests/breakiter_getLocale_basic.phpt
new file mode 100644
index 0000000000..b0112cc847
--- /dev/null
+++ b/ext/intl/tests/breakiter_getLocale_basic.phpt
@@ -0,0 +1,21 @@
+--TEST--
+IntlBreakIterator::getLocale(): basic test
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+ini_set("intl.default_locale", "pt_PT");
+
+$bi = IntlBreakIterator::createSentenceInstance('pt');
+
+var_dump($bi->getLocale(0));
+var_dump($bi->getLocale(1));
+?>
+==DONE==
+--EXPECT--
+string(4) "root"
+string(4) "root"
+==DONE== \ No newline at end of file
diff --git a/ext/intl/tests/breakiter_getLocale_error.phpt b/ext/intl/tests/breakiter_getLocale_error.phpt
new file mode 100644
index 0000000000..9acd08ab63
--- /dev/null
+++ b/ext/intl/tests/breakiter_getLocale_error.phpt
@@ -0,0 +1,33 @@
+--TEST--
+IntlBreakIterator::getLocale(): arg errors
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+
+$bi = new IntlRuleBasedBreakIterator('[\p{Letter}\uFFFD]+;[:number:]+;');
+$bi->setText("\x80sdfé\x90d888 dfsa9");
+
+var_dump($bi->getLocale(1, 2));
+var_dump($bi->getLocale(array()));
+var_dump($bi->getLocale());
+
+--EXPECTF--
+
+Warning: IntlBreakIterator::getLocale() expects exactly 1 parameter, 2 given in %s on line %d
+
+Warning: IntlBreakIterator::getLocale(): breakiter_get_locale: bad arguments in %s on line %d
+bool(false)
+
+Warning: IntlBreakIterator::getLocale() expects parameter 1 to be long, array given in %s on line %d
+
+Warning: IntlBreakIterator::getLocale(): breakiter_get_locale: bad arguments in %s on line %d
+bool(false)
+
+Warning: IntlBreakIterator::getLocale() expects exactly 1 parameter, 0 given in %s on line %d
+
+Warning: IntlBreakIterator::getLocale(): breakiter_get_locale: bad arguments in %s on line %d
+bool(false)
diff --git a/ext/intl/tests/breakiter_getPartsIterator_basic.phpt b/ext/intl/tests/breakiter_getPartsIterator_basic.phpt
new file mode 100644
index 0000000000..36ad80d5fb
--- /dev/null
+++ b/ext/intl/tests/breakiter_getPartsIterator_basic.phpt
@@ -0,0 +1,37 @@
+--TEST--
+IntlBreakIterator::getPartsIterator(): basic test
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+ini_set("intl.default_locale", "pt_PT");
+
+$bi = IntlBreakIterator::createWordInstance('pt');
+$pi = $bi->getPartsIterator();
+var_dump(get_class($pi));
+print_r(iterator_to_array($pi));
+
+$bi->setText("foo bar");
+$pi = $bi->getPartsIterator();
+var_dump(get_class($pi->getBreakIterator()));
+print_r(iterator_to_array($pi));
+var_dump($pi->getRuleStatus());
+?>
+==DONE==
+--EXPECT--
+string(17) "IntlPartsIterator"
+Array
+(
+)
+string(26) "IntlRuleBasedBreakIterator"
+Array
+(
+ [0] => foo
+ [1] =>
+ [2] => bar
+)
+int(0)
+==DONE== \ No newline at end of file
diff --git a/ext/intl/tests/breakiter_getPartsIterator_error.phpt b/ext/intl/tests/breakiter_getPartsIterator_error.phpt
new file mode 100644
index 0000000000..9737618033
--- /dev/null
+++ b/ext/intl/tests/breakiter_getPartsIterator_error.phpt
@@ -0,0 +1,33 @@
+--TEST--
+IntlBreakIterator::getPartsIterator(): bad args
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+ini_set("intl.default_locale", "pt_PT");
+
+$it = IntlBreakIterator::createWordInstance(NULL);
+var_dump($it->getPartsIterator(array()));
+var_dump($it->getPartsIterator(1, 2));
+var_dump($it->getPartsIterator(-1));
+
+?>
+==DONE==
+--EXPECTF--
+
+Warning: IntlBreakIterator::getPartsIterator() expects parameter 1 to be long, array given in %s on line %d
+
+Warning: IntlBreakIterator::getPartsIterator(): breakiter_get_parts_iterator: bad arguments in %s on line %d
+bool(false)
+
+Warning: IntlBreakIterator::getPartsIterator() expects at most 1 parameter, 2 given in %s on line %d
+
+Warning: IntlBreakIterator::getPartsIterator(): breakiter_get_parts_iterator: bad arguments in %s on line %d
+bool(false)
+
+Warning: IntlBreakIterator::getPartsIterator(): breakiter_get_parts_iterator: bad key type in %s on line %d
+bool(false)
+==DONE==
diff --git a/ext/intl/tests/breakiter_getPartsIterator_var1.phpt b/ext/intl/tests/breakiter_getPartsIterator_var1.phpt
new file mode 100644
index 0000000000..7bbd27ea45
--- /dev/null
+++ b/ext/intl/tests/breakiter_getPartsIterator_var1.phpt
@@ -0,0 +1,60 @@
+--TEST--
+IntlBreakIterator::getPartsIterator(): argument variations
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+ini_set("intl.default_locale", "pt_PT");
+
+$text = 'foo bar tao';
+
+$it = IntlBreakIterator::createWordInstance(NULL);
+$it->setText($text);
+
+var_dump(iterator_to_array($it->getPartsIterator(IntlPartsIterator::KEY_SEQUENTIAL)));
+var_dump(iterator_to_array($it->getPartsIterator(IntlPartsIterator::KEY_LEFT)));
+var_dump(iterator_to_array($it->getPartsIterator(IntlPartsIterator::KEY_RIGHT)));
+
+?>
+==DONE==
+--EXPECT--
+array(5) {
+ [0]=>
+ string(3) "foo"
+ [1]=>
+ string(1) " "
+ [2]=>
+ string(3) "bar"
+ [3]=>
+ string(1) " "
+ [4]=>
+ string(3) "tao"
+}
+array(5) {
+ [0]=>
+ string(3) "foo"
+ [4]=>
+ string(1) " "
+ [5]=>
+ string(3) "bar"
+ [8]=>
+ string(1) " "
+ [9]=>
+ string(3) "tao"
+}
+array(5) {
+ [3]=>
+ string(3) "foo"
+ [5]=>
+ string(1) " "
+ [8]=>
+ string(3) "bar"
+ [9]=>
+ string(1) " "
+ [12]=>
+ string(3) "tao"
+}
+==DONE==
diff --git a/ext/intl/tests/breakiter_getText_basic.phpt b/ext/intl/tests/breakiter_getText_basic.phpt
new file mode 100644
index 0000000000..0e5a26c16a
--- /dev/null
+++ b/ext/intl/tests/breakiter_getText_basic.phpt
@@ -0,0 +1,17 @@
+--TEST--
+IntlBreakIterator::getText(): basic test
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+
+$bi = IntlBreakIterator::createWordInstance('pt');
+var_dump($bi->getText());
+$bi->setText('foo bar');
+var_dump($bi->getText());
+--EXPECTF--
+NULL
+string(7) "foo bar"
diff --git a/ext/intl/tests/breakiter_getText_error.phpt b/ext/intl/tests/breakiter_getText_error.phpt
new file mode 100644
index 0000000000..91e9919c15
--- /dev/null
+++ b/ext/intl/tests/breakiter_getText_error.phpt
@@ -0,0 +1,19 @@
+--TEST--
+IntlBreakIterator::getText(): arg errors
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+
+$bi = new IntlRuleBasedBreakIterator('[\p{Letter}]+;');
+var_dump($bi->getText(array()));
+
+--EXPECTF--
+
+Warning: IntlBreakIterator::getText() expects exactly 0 parameters, 1 given in %s on line %d
+
+Warning: IntlBreakIterator::getText(): breakiter_get_text: bad arguments in %s on line %d
+bool(false)
diff --git a/ext/intl/tests/breakiter_isBoundary_basic.phpt b/ext/intl/tests/breakiter_isBoundary_basic.phpt
new file mode 100644
index 0000000000..1f416630a0
--- /dev/null
+++ b/ext/intl/tests/breakiter_isBoundary_basic.phpt
@@ -0,0 +1,28 @@
+--TEST--
+IntlBreakIterator::isBoundary(): basic test
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+ini_set("intl.default_locale", "pt_PT");
+
+$bi = IntlBreakIterator::createWordInstance('pt');
+$bi->setText('foo bar trans zoo bee');
+
+var_dump($bi->isBoundary(0));
+var_dump($bi->isBoundary(7));
+var_dump($bi->isBoundary(-1));
+var_dump($bi->isBoundary(1));
+var_dump($bi->isBoundary(50));
+?>
+==DONE==
+--EXPECT--
+bool(true)
+bool(true)
+bool(false)
+bool(false)
+bool(false)
+==DONE== \ No newline at end of file
diff --git a/ext/intl/tests/breakiter_last_basic.phpt b/ext/intl/tests/breakiter_last_basic.phpt
new file mode 100644
index 0000000000..cf816c3670
--- /dev/null
+++ b/ext/intl/tests/breakiter_last_basic.phpt
@@ -0,0 +1,20 @@
+--TEST--
+IntlBreakIterator::last(): basic test
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+
+$bi = IntlBreakIterator::createWordInstance('pt');
+$bi->setText('foo bar trans');
+
+var_dump($bi->current());
+var_dump($bi->last());
+var_dump($bi->current());
+--EXPECTF--
+int(0)
+int(13)
+int(13)
diff --git a/ext/intl/tests/breakiter_next_basic.phpt b/ext/intl/tests/breakiter_next_basic.phpt
new file mode 100644
index 0000000000..4deb4144e3
--- /dev/null
+++ b/ext/intl/tests/breakiter_next_basic.phpt
@@ -0,0 +1,30 @@
+--TEST--
+IntlBreakIterator::next(): basic test
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+ini_set("intl.default_locale", "pt_PT");
+
+$bi = IntlBreakIterator::createWordInstance('pt');
+$bi->setText('foo bar trans zoo bee');
+
+var_dump($bi->first());
+var_dump($bi->next());
+var_dump($bi->next(2));
+var_dump($bi->next(-1));
+var_dump($bi->next(0));
+var_dump($bi->next(NULL));
+?>
+==DONE==
+--EXPECT--
+int(0)
+int(3)
+int(7)
+int(4)
+int(4)
+int(7)
+==DONE==
diff --git a/ext/intl/tests/breakiter_next_error.phpt b/ext/intl/tests/breakiter_next_error.phpt
new file mode 100644
index 0000000000..ed718bc2a5
--- /dev/null
+++ b/ext/intl/tests/breakiter_next_error.phpt
@@ -0,0 +1,27 @@
+--TEST--
+IntlBreakIterator::next(): arg errors
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+
+$bi = new IntlRuleBasedBreakIterator('[\p{Letter}\uFFFD]+;[:number:]+;');
+$bi->setText("\x80sdfé\x90d888 dfsa9");
+
+var_dump($bi->next(1, 2));
+var_dump($bi->next(array()));
+
+--EXPECTF--
+
+Warning: IntlBreakIterator::next() expects exactly 1 parameter, 2 given in %s on line %d
+
+Warning: IntlBreakIterator::next(): breakiter_next: bad arguments in %s on line %d
+bool(false)
+
+Warning: IntlBreakIterator::next() expects parameter 1 to be long, array given in %s on line %d
+
+Warning: IntlBreakIterator::next(): breakiter_next: bad arguments in %s on line %d
+bool(false)
diff --git a/ext/intl/tests/breakiter_preceding_basic.phpt b/ext/intl/tests/breakiter_preceding_basic.phpt
new file mode 100644
index 0000000000..6fa8dd7fa7
--- /dev/null
+++ b/ext/intl/tests/breakiter_preceding_basic.phpt
@@ -0,0 +1,24 @@
+--TEST--
+IntlBreakIterator::preceding(): basic test
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+ini_set("intl.default_locale", "pt_PT");
+
+$bi = IntlBreakIterator::createWordInstance('pt');
+$bi->setText('foo bar trans zoo bee');
+
+var_dump($bi->preceding(5));
+var_dump($bi->preceding(50));
+var_dump($bi->preceding(-1));
+?>
+==DONE==
+--EXPECT--
+int(4)
+int(21)
+int(0)
+==DONE== \ No newline at end of file
diff --git a/ext/intl/tests/breakiter_previous_basic.phpt b/ext/intl/tests/breakiter_previous_basic.phpt
new file mode 100644
index 0000000000..c3343af57c
--- /dev/null
+++ b/ext/intl/tests/breakiter_previous_basic.phpt
@@ -0,0 +1,22 @@
+--TEST--
+IntlBreakIterator::previous(): basic test
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+ini_set("intl.default_locale", "pt_PT");
+
+$bi = IntlBreakIterator::createWordInstance('pt');
+$bi->setText('foo bar trans');
+
+var_dump($bi->last());
+var_dump($bi->previous());
+?>
+==DONE==
+--EXPECT--
+int(13)
+int(8)
+==DONE== \ No newline at end of file
diff --git a/ext/intl/tests/breakiter_setText_basic.phpt b/ext/intl/tests/breakiter_setText_basic.phpt
new file mode 100644
index 0000000000..a5e4f86b65
--- /dev/null
+++ b/ext/intl/tests/breakiter_setText_basic.phpt
@@ -0,0 +1,36 @@
+--TEST--
+IntlBreakIterator::setText(): basic test
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+
+class A {
+function __tostring() { return 'aaa'; }
+}
+
+$bi = IntlBreakIterator::createWordInstance('pt');
+var_dump($bi->setText('foo bar'));
+var_dump($bi->getText());
+var_dump($bi->setText(1));
+var_dump($bi->getText());
+var_dump($bi->setText(new A));
+var_dump($bi->getText());
+
+/* setText resets the pointer */
+var_dump($bi->next());
+var_dump($bi->setText('foo bar'));
+var_dump($bi->current());
+--EXPECT--
+bool(true)
+string(7) "foo bar"
+bool(true)
+string(1) "1"
+bool(true)
+string(3) "aaa"
+int(3)
+bool(true)
+int(0)
diff --git a/ext/intl/tests/breakiter_setText_error.phpt b/ext/intl/tests/breakiter_setText_error.phpt
new file mode 100644
index 0000000000..a7a73a08d8
--- /dev/null
+++ b/ext/intl/tests/breakiter_setText_error.phpt
@@ -0,0 +1,44 @@
+--TEST--
+IntlBreakIterator::setText(): arg errors
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+
+$bi = new IntlRuleBasedBreakIterator('[\p{Letter}]+;');
+var_dump($bi->setText());
+var_dump($bi->setText(array()));
+var_dump($bi->setText(1,2));
+
+class A {
+function __destruct() { var_dump('destructed'); throw new Exception('e'); }
+function __tostring() { return 'foo'; }
+}
+
+try {
+var_dump($bi->setText(new A));
+} catch (Exception $e) {
+var_dump($e->getMessage());
+}
+
+--EXPECTF--
+
+Warning: IntlBreakIterator::setText() expects exactly 1 parameter, 0 given in %s on line %d
+
+Warning: IntlBreakIterator::setText(): breakiter_set_text: bad arguments in %s on line %d
+bool(false)
+
+Warning: IntlBreakIterator::setText() expects parameter 1 to be string, array given in %s on line %d
+
+Warning: IntlBreakIterator::setText(): breakiter_set_text: bad arguments in %s on line %d
+bool(false)
+
+Warning: IntlBreakIterator::setText() expects exactly 1 parameter, 2 given in %s on line %d
+
+Warning: IntlBreakIterator::setText(): breakiter_set_text: bad arguments in %s on line %d
+bool(false)
+string(10) "destructed"
+string(1) "e"
diff --git a/ext/intl/tests/bug50590.phpt b/ext/intl/tests/bug50590.phpt
index c39c333b23..4784d37877 100644
--- a/ext/intl/tests/bug50590.phpt
+++ b/ext/intl/tests/bug50590.phpt
@@ -1,5 +1,7 @@
--TEST--
Bug #50590 (IntlDateFormatter::parse result is limited to the integer range)
+--INI--
+date.timezone=Atlantic/Azores
--SKIPIF--
<?php if( !extension_loaded( 'intl' ) ) print 'skip'; ?>
--FILE--
diff --git a/ext/intl/tests/bug58756_MessageFormatter.phpt b/ext/intl/tests/bug58756_MessageFormatter.phpt
new file mode 100644
index 0000000000..bbe96b7045
--- /dev/null
+++ b/ext/intl/tests/bug58756_MessageFormatter.phpt
@@ -0,0 +1,34 @@
+--TEST--
+Bug #58756: w.r.t MessageFormatter
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+//ini_set("intl.default_locale", "nl");
+
+$time = 1247013673;
+
+ini_set('date.timezone', 'America/New_York');
+
+$msgf = new MessageFormatter('en_US', '{0,date,full} {0,time,h:m:s a V}');
+
+echo "date: " . date('l, F j, Y g:i:s A T', $time) . "\n";
+echo "msgf: " . $msgf->format(array($time)) . "\n";
+
+//NOT FIXED:
+/*$msgf = new MessageFormatter('en_US',
+'{1, select, date {{0,date,full}} other {{0,time,h:m:s a V}}}');
+
+echo "msgf2: ", $msgf->format(array($time, 'date')), " ",
+ $msgf->format(array($time, 'time')), "\n";
+*/
+
+?>
+==DONE==
+--EXPECT--
+date: Tuesday, July 7, 2009 8:41:13 PM EDT
+msgf: Tuesday, July 7, 2009 8:41:13 PM EDT
+==DONE== \ No newline at end of file
diff --git a/ext/intl/tests/bug62017.phpt b/ext/intl/tests/bug62017.phpt
index 13c4fe5df0..50aeae4806 100644
--- a/ext/intl/tests/bug62017.phpt
+++ b/ext/intl/tests/bug62017.phpt
@@ -14,7 +14,7 @@ var_dump(
new IntlDateFormatter('', IntlDateFormatter::NONE, IntlDateFormatter::NONE, "Europe/Lisbon",
IntlDateFormatter::GREGORIAN, "\x80"));
--EXPECTF--
-Warning: datefmt_create(): datefmt_create: error converting timezone_str to UTF-16 in %s on line %d
+Warning: datefmt_create(): datefmt_create: Time zone identifier given is not a valid UTF-8 string in %s on line %d
NULL
Warning: IntlDateFormatter::__construct(): datefmt_create: error converting pattern to UTF-16 in %s on line %d
diff --git a/ext/intl/tests/bug62081.phpt b/ext/intl/tests/bug62081.phpt
index 7d9e2cec47..44ad4beec7 100644
--- a/ext/intl/tests/bug62081.phpt
+++ b/ext/intl/tests/bug62081.phpt
@@ -1,5 +1,7 @@
--TEST--
Bug #62081: IntlDateFormatter leaks memory if called twice
+--INI--
+date.timezone=Atlantic/Azores
--SKIPIF--
<?php
if (!extension_loaded('intl'))
@@ -7,8 +9,8 @@ if (!extension_loaded('intl'))
--FILE--
<?php
ini_set('intl.error_level', E_WARNING);
-$x = new IntlDateFormatter(1,1,1,1,1);
-var_dump($x->__construct(1,1,1,1,1));
+$x = new IntlDateFormatter('en', 1, 1);
+var_dump($x->__construct('en', 1, 1));
--EXPECTF--
Warning: IntlDateFormatter::__construct(): datefmt_create: cannot call constructor twice in %s on line %d
NULL
diff --git a/ext/intl/tests/bug62915.phpt b/ext/intl/tests/bug62915.phpt
new file mode 100644
index 0000000000..e541d72d63
--- /dev/null
+++ b/ext/intl/tests/bug62915.phpt
@@ -0,0 +1,24 @@
+--TEST--
+Bug #62915: incomplete cloning of IntlTimeZone objects
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+--FILE--
+<?php
+
+class foo extends IntlTimeZone {
+ public $foo = 'test';
+
+ public function __construct() { }
+}
+
+$x = new foo;
+
+try {
+ $z = clone $x;
+} catch (Exception $e) {
+ var_dump($e->getMessage());
+}
+--EXPECT--
+string(39) "Cannot clone unconstructed IntlTimeZone"
diff --git a/ext/intl/tests/calendar_add_basic.phpt b/ext/intl/tests/calendar_add_basic.phpt
new file mode 100644
index 0000000000..b0e44d5895
--- /dev/null
+++ b/ext/intl/tests/calendar_add_basic.phpt
@@ -0,0 +1,33 @@
+--TEST--
+IntlCalendar::add() basic test
+--INI--
+date.timezone=Atlantic/Azores
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+ini_set("intl.default_locale", "nl");
+
+$time = strtotime('2012-02-29 00:00:00 +0000');
+$time2 = strtotime('2012-03-01 05:06:07 +0000');
+
+$intlcal = IntlCalendar::createInstance('UTC');
+$intlcal->setTime($time * 1000);
+$intlcal->add(IntlCalendar::FIELD_DAY_OF_MONTH, 1);
+$intlcal->add(IntlCalendar::FIELD_HOUR, 5);
+$intlcal->add(IntlCalendar::FIELD_MINUTE, 6);
+intlcal_add($intlcal, IntlCalendar::FIELD_SECOND, 7);
+
+var_dump(
+ (float)$time2*1000,
+ $intlcal->getTime());
+
+?>
+==DONE==
+--EXPECT--
+float(1330578367000)
+float(1330578367000)
+==DONE== \ No newline at end of file
diff --git a/ext/intl/tests/calendar_add_error.phpt b/ext/intl/tests/calendar_add_error.phpt
new file mode 100644
index 0000000000..2e5fadb4ec
--- /dev/null
+++ b/ext/intl/tests/calendar_add_error.phpt
@@ -0,0 +1,41 @@
+--TEST--
+IntlCalendar::add(): bad arguments
+--INI--
+date.timezone=Atlantic/Azores
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+
+$c = new IntlGregorianCalendar(NULL, 'pt_PT');
+
+var_dump($c->add(1, 2, 3));
+var_dump($c->add(-1, 2));
+var_dump($c->add(1));
+
+var_dump(intlcal_add($c, 1, 2, 3));
+var_dump(intlcal_add(1, 2, 3));
+--EXPECTF--
+
+Warning: IntlCalendar::add() expects exactly 2 parameters, 3 given in %s on line %d
+
+Warning: IntlCalendar::add(): intlcal_add: bad arguments in %s on line %d
+bool(false)
+
+Warning: IntlCalendar::add(): intlcal_add: invalid field in %s on line %d
+bool(false)
+
+Warning: IntlCalendar::add() expects exactly 2 parameters, 1 given in %s on line %d
+
+Warning: IntlCalendar::add(): intlcal_add: bad arguments in %s on line %d
+bool(false)
+
+Warning: intlcal_add() expects exactly 3 parameters, 4 given in %s on line %d
+
+Warning: intlcal_add(): intlcal_add: bad arguments in %s on line %d
+bool(false)
+
+Catchable fatal error: Argument 1 passed to intlcal_add() must be an instance of IntlCalendar, integer given in %s on line %d
diff --git a/ext/intl/tests/calendar_before_after_error.phpt b/ext/intl/tests/calendar_before_after_error.phpt
new file mode 100644
index 0000000000..10011ef852
--- /dev/null
+++ b/ext/intl/tests/calendar_before_after_error.phpt
@@ -0,0 +1,57 @@
+--TEST--
+IntlCalendar::before()/after(): bad arguments
+--INI--
+date.timezone=Atlantic/Azores
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+
+$c = new IntlGregorianCalendar(NULL, 'pt_PT');
+
+function eh($errno, $errstr) {
+echo "error: $errno, $errstr\n";
+}
+set_error_handler('eh');
+
+var_dump($c->after());
+var_dump($c->before());
+
+var_dump($c->after(1));
+var_dump($c->before(1));
+
+var_dump($c->after($c, 1));
+var_dump($c->before($c, 1));
+
+var_dump(intlcal_after($c));
+var_dump(intlcal_before($c));
+--EXPECT--
+error: 2, IntlCalendar::after() expects exactly 1 parameter, 0 given
+error: 2, IntlCalendar::after(): intlcal_before/after: bad arguments
+bool(false)
+error: 2, IntlCalendar::before() expects exactly 1 parameter, 0 given
+error: 2, IntlCalendar::before(): intlcal_before/after: bad arguments
+bool(false)
+error: 4096, Argument 1 passed to IntlCalendar::after() must be an instance of IntlCalendar, integer given
+error: 2, IntlCalendar::after() expects parameter 1 to be IntlCalendar, integer given
+error: 2, IntlCalendar::after(): intlcal_before/after: bad arguments
+bool(false)
+error: 4096, Argument 1 passed to IntlCalendar::before() must be an instance of IntlCalendar, integer given
+error: 2, IntlCalendar::before() expects parameter 1 to be IntlCalendar, integer given
+error: 2, IntlCalendar::before(): intlcal_before/after: bad arguments
+bool(false)
+error: 2, IntlCalendar::after() expects exactly 1 parameter, 2 given
+error: 2, IntlCalendar::after(): intlcal_before/after: bad arguments
+bool(false)
+error: 2, IntlCalendar::before() expects exactly 1 parameter, 2 given
+error: 2, IntlCalendar::before(): intlcal_before/after: bad arguments
+bool(false)
+error: 2, intlcal_after() expects exactly 2 parameters, 1 given
+error: 2, intlcal_after(): intlcal_before/after: bad arguments
+bool(false)
+error: 2, intlcal_before() expects exactly 2 parameters, 1 given
+error: 2, intlcal_before(): intlcal_before/after: bad arguments
+bool(false)
diff --git a/ext/intl/tests/calendar_clear_basic.phpt b/ext/intl/tests/calendar_clear_basic.phpt
new file mode 100644
index 0000000000..f7e4371d92
--- /dev/null
+++ b/ext/intl/tests/calendar_clear_basic.phpt
@@ -0,0 +1,40 @@
+--TEST--
+IntlCalendar::clear() basic test
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+ini_set("intl.default_locale", "nl");
+
+$intlcal = IntlCalendar::createInstance('UTC');
+var_dump($intlcal->clear());
+var_dump(
+ $intlcal->get(IntlCalendar::FIELD_YEAR),
+ $intlcal->get(IntlCalendar::FIELD_MONTH),
+ $intlcal->get(IntlCalendar::FIELD_DAY_OF_MONTH),
+ $intlcal->get(IntlCalendar::FIELD_HOUR),
+ $intlcal->get(IntlCalendar::FIELD_MINUTE),
+ $intlcal->get(IntlCalendar::FIELD_SECOND),
+ $intlcal->get(IntlCalendar::FIELD_MILLISECOND)
+);
+
+$intlcal2 = IntlCalendar::createInstance('Europe/Amsterdam');
+intlcal_clear($intlcal2, null);
+var_dump($intlcal2->getTime());
+
+?>
+==DONE==
+--EXPECT--
+bool(true)
+int(1970)
+int(0)
+int(1)
+int(0)
+int(0)
+int(0)
+int(0)
+float(-3600000)
+==DONE== \ No newline at end of file
diff --git a/ext/intl/tests/calendar_clear_error.phpt b/ext/intl/tests/calendar_clear_error.phpt
new file mode 100644
index 0000000000..9bde7e2c8d
--- /dev/null
+++ b/ext/intl/tests/calendar_clear_error.phpt
@@ -0,0 +1,31 @@
+--TEST--
+IntlCalendar::clear(): bad arguments
+--INI--
+date.timezone=Atlantic/Azores
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+
+$c = new IntlGregorianCalendar(NULL, 'pt_PT');
+
+var_dump($c->clear(1, 2));
+var_dump($c->clear(-1));
+
+var_dump(intlcal_clear($c, -1));
+var_dump(intlcal_clear(1, 2));
+--EXPECTF--
+
+Warning: IntlCalendar::clear(): intlcal_clear: too many arguments in %s on line %d
+bool(false)
+
+Warning: IntlCalendar::clear(): intlcal_clear: invalid field in %s on line %d
+bool(false)
+
+Warning: intlcal_clear(): intlcal_clear: invalid field in %s on line %d
+bool(false)
+
+Catchable fatal error: Argument 1 passed to intlcal_clear() must be an instance of IntlCalendar, integer given in %s on line %d
diff --git a/ext/intl/tests/calendar_clear_variation1.phpt b/ext/intl/tests/calendar_clear_variation1.phpt
new file mode 100644
index 0000000000..6adbcaa353
--- /dev/null
+++ b/ext/intl/tests/calendar_clear_variation1.phpt
@@ -0,0 +1,33 @@
+--TEST--
+IntlCalendar::clear() 1 arg variation
+--INI--
+date.timezone=Atlantic/Azores
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+ini_set("intl.default_locale", "nl");
+
+$intlcal = IntlCalendar::createInstance('UTC');
+$intlcal->setTime(strtotime('2012-02-29 05:06:07 +0000') * 1000);
+//print_R($intlcal);
+var_dump($intlcal->isSet(IntlCalendar::FIELD_MONTH));
+var_dump($intlcal->clear(IntlCalendar::FIELD_MONTH));
+var_dump($intlcal->isSet(IntlCalendar::FIELD_MONTH));
+//print_R($intlcal);
+var_dump(
+ $intlcal->getTime(),
+ strtotime('2012-01-29 05:06:07 +0000') * 1000.
+);
+?>
+==DONE==
+--EXPECT--
+bool(true)
+bool(true)
+bool(false)
+float(1327813567000)
+float(1327813567000)
+==DONE== \ No newline at end of file
diff --git a/ext/intl/tests/calendar_createInstance_basic.phpt b/ext/intl/tests/calendar_createInstance_basic.phpt
new file mode 100644
index 0000000000..e062030fec
--- /dev/null
+++ b/ext/intl/tests/calendar_createInstance_basic.phpt
@@ -0,0 +1,42 @@
+--TEST--
+IntlCalendar::createInstance() basic test
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+if (version_compare(INTL_ICU_VERSION, '4.8') < 0)
+ die('skip for ICU 4.8+');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+ini_set("intl.default_locale", "nl");
+
+date_default_timezone_set('Europe/Amsterdam');
+
+$cal = IntlCalendar::createInstance();
+print_R($cal->getTimeZone());
+print_R($cal->getLocale(Locale::ACTUAL_LOCALE));
+echo "\n";
+print_R($cal->getType());
+echo "\n";
+
+$timeMillis = $cal->getTime();
+$time = time();
+
+var_dump(abs($timeMillis - $time * 1000) < 1000);
+
+?>
+==DONE==
+
+--EXPECTF--
+IntlTimeZone Object
+(
+ [valid] => 1
+ [id] => Europe/Amsterdam
+ [rawOffset] => 3600000
+ [currentOffset] => %d
+)
+nl
+gregorian
+bool(true)
+==DONE==
diff --git a/ext/intl/tests/calendar_createInstance_error.phpt b/ext/intl/tests/calendar_createInstance_error.phpt
new file mode 100644
index 0000000000..bf655bee79
--- /dev/null
+++ b/ext/intl/tests/calendar_createInstance_error.phpt
@@ -0,0 +1,38 @@
+--TEST--
+IntlCalendar::createInstance: bad arguments
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+
+class X extends IntlTimeZone {
+function __construct() {}
+}
+
+var_dump(IntlCalendar::createInstance(1, 2, 3));
+var_dump(intlcal_create_instance(1, 2, 3));
+var_dump(intlcal_create_instance(new X, NULL));
+var_dump(intlcal_create_instance(NULL, array()));
+
+--EXPECTF--
+
+Warning: IntlCalendar::createInstance() expects at most 2 parameters, 3 given in %s on line %d
+
+Warning: IntlCalendar::createInstance(): intlcal_create_calendar: bad arguments in %s on line %d
+NULL
+
+Warning: intlcal_create_instance() expects at most 2 parameters, 3 given in %s on line %d
+
+Warning: intlcal_create_instance(): intlcal_create_calendar: bad arguments in %s on line %d
+NULL
+
+Warning: intlcal_create_instance(): intlcal_create_instance: passed IntlTimeZone is not properly constructed in %s on line %d
+NULL
+
+Warning: intlcal_create_instance() expects parameter 2 to be string, array given in %s on line %d
+
+Warning: intlcal_create_instance(): intlcal_create_calendar: bad arguments in %s on line %d
+NULL
diff --git a/ext/intl/tests/calendar_createInstance_variation1.phpt b/ext/intl/tests/calendar_createInstance_variation1.phpt
new file mode 100644
index 0000000000..138f2a2afd
--- /dev/null
+++ b/ext/intl/tests/calendar_createInstance_variation1.phpt
@@ -0,0 +1,84 @@
+--TEST--
+IntlCalendar::createInstance() argument variations
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+if (version_compare(INTL_ICU_VERSION, '4.8') < 0)
+ die('skip for ICU 4.8+');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+ini_set("intl.default_locale", "nl");
+
+date_default_timezone_set('Europe/Amsterdam');
+
+$cal = intlcal_create_instance('Europe/Amsterdam');
+print_R($cal->getTimeZone());
+print_R($cal->getLocale(Locale::ACTUAL_LOCALE));
+echo "\n";
+
+$cal = intlcal_create_instance('Europe/Lisbon', null);
+print_R($cal->getTimeZone());
+print_R($cal->getLocale(Locale::ACTUAL_LOCALE));
+echo "\n";
+
+$cal = intlcal_create_instance(IntlTimeZone::createTimeZone('Europe/Lisbon'));
+print_R($cal->getTimeZone());
+print_R($cal->getLocale(Locale::ACTUAL_LOCALE));
+echo "\n";
+
+$cal = intlcal_create_instance(null, "pt");
+print_R($cal->getTimeZone());
+print_R($cal->getLocale(Locale::ACTUAL_LOCALE));
+echo "\n";
+
+$cal = intlcal_create_instance("Europe/Lisbon", "pt");
+print_R($cal->getTimeZone());
+print_R($cal->getLocale(Locale::ACTUAL_LOCALE));
+echo "\n";
+
+?>
+==DONE==
+--EXPECTF--
+IntlTimeZone Object
+(
+ [valid] => 1
+ [id] => Europe/Amsterdam
+ [rawOffset] => 3600000
+ [currentOffset] => %d
+)
+nl
+IntlTimeZone Object
+(
+ [valid] => 1
+ [id] => Europe/Lisbon
+ [rawOffset] => 0
+ [currentOffset] => %d
+)
+nl
+IntlTimeZone Object
+(
+ [valid] => 1
+ [id] => Europe/Lisbon
+ [rawOffset] => 0
+ [currentOffset] => %d
+)
+nl
+IntlTimeZone Object
+(
+ [valid] => 1
+ [id] => Europe/Amsterdam
+ [rawOffset] => 3600000
+ [currentOffset] => %d
+)
+pt
+IntlTimeZone Object
+(
+ [valid] => 1
+ [id] => Europe/Lisbon
+ [rawOffset] => 0
+ [currentOffset] => %d
+)
+pt
+==DONE== \ No newline at end of file
diff --git a/ext/intl/tests/calendar_equals_before_after_basic.phpt b/ext/intl/tests/calendar_equals_before_after_basic.phpt
new file mode 100644
index 0000000000..50543ad0b4
--- /dev/null
+++ b/ext/intl/tests/calendar_equals_before_after_basic.phpt
@@ -0,0 +1,59 @@
+--TEST--
+IntlCalendar::equals(), ::before() and ::after() basic test
+--INI--
+date.timezone=Atlantic/Azores
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+ini_set("intl.default_locale", "nl");
+
+$intlcal1 = new IntlGregorianCalendar(2012, 1, 29, 16, 59, 59);
+$intlcal2 = IntlCalendar::createInstance(null, '@calendar=japanese');
+$intlcal3 = new IntlGregorianCalendar(2012, 1, 29, 17, 00, 00);
+$intlcal2->setTime($intlcal1->getTime());
+
+var_dump($intlcal2->getType());
+
+var_dump("1 eq 1", $intlcal1->equals($intlcal1));
+
+var_dump("1 eq 2", $intlcal1->equals($intlcal2));
+var_dump("1 before 2", $intlcal1->before($intlcal2));
+var_dump("1 after 2", $intlcal1->after($intlcal2));
+
+var_dump("1 eq 3", $intlcal1->equals($intlcal3));
+var_dump("1 before 3", $intlcal1->before($intlcal3));
+var_dump("1 after 3", $intlcal1->after($intlcal3));
+
+var_dump("3 eq 2", intlcal_equals($intlcal3, $intlcal2));
+var_dump("3 before 2", intlcal_before($intlcal3, $intlcal2));
+var_dump("3 after 2", intlcal_after($intlcal3, $intlcal2));
+
+?>
+==DONE==
+--EXPECT--
+string(8) "japanese"
+string(6) "1 eq 1"
+bool(true)
+string(6) "1 eq 2"
+bool(true)
+string(10) "1 before 2"
+bool(false)
+string(9) "1 after 2"
+bool(false)
+string(6) "1 eq 3"
+bool(false)
+string(10) "1 before 3"
+bool(true)
+string(9) "1 after 3"
+bool(false)
+string(6) "3 eq 2"
+bool(false)
+string(10) "3 before 2"
+bool(false)
+string(9) "3 after 2"
+bool(true)
+==DONE== \ No newline at end of file
diff --git a/ext/intl/tests/calendar_equals_error.phpt b/ext/intl/tests/calendar_equals_error.phpt
new file mode 100644
index 0000000000..a947b42bfe
--- /dev/null
+++ b/ext/intl/tests/calendar_equals_error.phpt
@@ -0,0 +1,46 @@
+--TEST--
+IntlCalendar::equals(): bad arguments
+--INI--
+date.timezone=Atlantic/Azores
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+
+$c = new IntlGregorianCalendar(NULL, 'pt_PT');
+
+function eh($errno, $errstr) {
+echo "error: $errno, $errstr\n";
+}
+set_error_handler('eh');
+
+var_dump($c->equals());
+var_dump($c->equals(new stdclass));
+var_dump($c->equals(1, 2));
+
+var_dump(intlcal_equals($c, array()));
+var_dump(intlcal_equals(1, $c));
+
+--EXPECT--
+error: 2, IntlCalendar::equals() expects exactly 1 parameter, 0 given
+error: 2, IntlCalendar::equals(): intlcal_equals: bad arguments
+bool(false)
+error: 4096, Argument 1 passed to IntlCalendar::equals() must be an instance of IntlCalendar, instance of stdClass given
+error: 2, IntlCalendar::equals() expects parameter 1 to be IntlCalendar, object given
+error: 2, IntlCalendar::equals(): intlcal_equals: bad arguments
+bool(false)
+error: 4096, Argument 1 passed to IntlCalendar::equals() must be an instance of IntlCalendar, integer given
+error: 2, IntlCalendar::equals() expects exactly 1 parameter, 2 given
+error: 2, IntlCalendar::equals(): intlcal_equals: bad arguments
+bool(false)
+error: 4096, Argument 2 passed to intlcal_equals() must be an instance of IntlCalendar, array given
+error: 2, intlcal_equals() expects parameter 2 to be IntlCalendar, array given
+error: 2, intlcal_equals(): intlcal_equals: bad arguments
+bool(false)
+error: 4096, Argument 1 passed to intlcal_equals() must be an instance of IntlCalendar, integer given
+error: 2, intlcal_equals() expects parameter 1 to be IntlCalendar, integer given
+error: 2, intlcal_equals(): intlcal_equals: bad arguments
+bool(false)
diff --git a/ext/intl/tests/calendar_fieldDifference_basic.phpt b/ext/intl/tests/calendar_fieldDifference_basic.phpt
new file mode 100644
index 0000000000..3432420df4
--- /dev/null
+++ b/ext/intl/tests/calendar_fieldDifference_basic.phpt
@@ -0,0 +1,35 @@
+--TEST--
+IntlCalendar::fieldDifference() basic test
+--INI--
+date.timezone=Atlantic/Azores
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+ini_set("intl.default_locale", "nl");
+
+$intlcal = IntlCalendar::createInstance('UTC');
+$intlcal->setTime(strtotime('2012-02-29 05:06:07 +0000') * 1000);
+var_dump(
+ $intlcal->fieldDifference(
+ strtotime('2012-02-29 06:06:08 +0000') * 1000,
+ IntlCalendar::FIELD_SECOND),
+ $intlcal->get(IntlCalendar::FIELD_HOUR_OF_DAY));
+
+
+$intlcal->setTime(strtotime('2012-02-29 05:06:07 +0000') * 1000);
+var_dump(
+ intlcal_field_difference(
+ $intlcal,
+ strtotime('2012-02-29 06:07:08 +0000') * 1000,
+ IntlCalendar::FIELD_MINUTE));
+?>
+==DONE==
+--EXPECT--
+int(3601)
+int(6)
+int(61)
+==DONE== \ No newline at end of file
diff --git a/ext/intl/tests/calendar_fieldDifference_error.phpt b/ext/intl/tests/calendar_fieldDifference_error.phpt
new file mode 100644
index 0000000000..ef7e4fc8dc
--- /dev/null
+++ b/ext/intl/tests/calendar_fieldDifference_error.phpt
@@ -0,0 +1,42 @@
+--TEST--
+IntlCalendar::fieldDifference(): bad arguments
+--INI--
+date.timezone=Atlantic/Azores
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+
+$c = new IntlGregorianCalendar(NULL, 'pt_PT');
+
+var_dump($c->fieldDifference($c, 2, 3));
+var_dump($c->fieldDifference(INF, 2));
+var_dump($c->fieldDifference(1));
+
+var_dump(intlcal_field_difference($c, 0, 1, 2));
+var_dump(intlcal_field_difference(1, 0, 1));
+
+--EXPECTF--
+
+Warning: IntlCalendar::fieldDifference() expects exactly 2 parameters, 3 given in %s on line %d
+
+Warning: IntlCalendar::fieldDifference(): intlcal_field_difference: bad arguments in %s on line %d
+bool(false)
+
+Warning: IntlCalendar::fieldDifference(): intlcal_field_difference: Call to ICU method has failed in %s on line %d
+bool(false)
+
+Warning: IntlCalendar::fieldDifference() expects exactly 2 parameters, 1 given in %s on line %d
+
+Warning: IntlCalendar::fieldDifference(): intlcal_field_difference: bad arguments in %s on line %d
+bool(false)
+
+Warning: intlcal_field_difference() expects exactly 3 parameters, 4 given in %s on line %d
+
+Warning: intlcal_field_difference(): intlcal_field_difference: bad arguments in %s on line %d
+bool(false)
+
+Catchable fatal error: Argument 1 passed to intlcal_field_difference() must be an instance of IntlCalendar, integer given in %s on line %d
diff --git a/ext/intl/tests/calendar_fromDateTime_basic.phpt b/ext/intl/tests/calendar_fromDateTime_basic.phpt
new file mode 100644
index 0000000000..1863b7815c
--- /dev/null
+++ b/ext/intl/tests/calendar_fromDateTime_basic.phpt
@@ -0,0 +1,52 @@
+--TEST--
+IntlCalendar::fromDateTime(): basic test
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+ini_set("intl.default_locale", "nl_NL");
+date_default_timezone_set('Europe/Lisbon');
+
+$cal = IntlCalendar::fromDateTime('2012-01-01 00:00:00 Europe/Rome');
+var_dump(
+ $cal->getTime(),
+ strtotime('2012-01-01 00:00:00 Europe/Rome') * 1000.,
+ $cal->getTimeZone()->getID(),
+ $cal->getLocale(1)
+);
+echo "\n";
+
+$cal = IntlCalendar::fromDateTime(new DateTime('2012-01-01 00:00:00 PST'), "pt_PT");
+var_dump(
+ $cal->getTime(),
+ strtotime('2012-01-01 00:00:00 PST') * 1000.,
+ $cal->getTimeZone()->getID(),
+ $cal->getLocale(1)
+);
+
+echo "\n";
+
+$cal = intlcal_from_date_time(new DateTime('2012-01-01 00:00:00 +03:40'));
+var_dump(
+ $cal->getTime(),
+ strtotime('2012-01-01 00:00:00 +03:40') * 1000.,
+ $cal->getTimeZone()->getID()
+);
+
+--EXPECTF--
+float(1325372400000)
+float(1325372400000)
+string(11) "Europe/Rome"
+string(5) "nl_NL"
+
+float(1325404800000)
+float(1325404800000)
+string(3) "PST"
+string(5) "pt_PT"
+
+float(1325362800000)
+float(1325362800000)
+string(%d) "GMT+03%S40"
diff --git a/ext/intl/tests/calendar_fromDateTime_error.phpt b/ext/intl/tests/calendar_fromDateTime_error.phpt
new file mode 100644
index 0000000000..2fbf7196f9
--- /dev/null
+++ b/ext/intl/tests/calendar_fromDateTime_error.phpt
@@ -0,0 +1,59 @@
+--TEST--
+IntlCalendar::fromDateTime(): errors
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+ini_set("intl.default_locale", "nl");
+date_default_timezone_set('Europe/Lisbon');
+
+var_dump(IntlCalendar::fromDateTime());
+var_dump(IntlCalendar::fromDateTime(0,1,2));
+
+try {
+IntlCalendar::fromDateTime("foobar");
+} catch (Exception $e) {
+ echo "threw exception, OK";
+}
+class A extends DateTime {
+function __construct() {}
+}
+
+var_dump(IntlCalendar::fromDateTime(new A));
+
+$date = new DateTime('2012-01-01 00:00:00 +24:00');
+var_dump(IntlCalendar::fromDateTime($date));
+
+$date = new DateTime('2012-01-01 00:00:00 WEST');
+var_dump(IntlCalendar::fromDateTime($date));
+
+var_dump(intlcal_from_date_time());
+
+--EXPECTF--
+
+Warning: IntlCalendar::fromDateTime() expects at least 1 parameter, 0 given in %s on line %d
+
+Warning: IntlCalendar::fromDateTime(): intlcal_from_date_time: bad arguments in %s on line %d
+NULL
+
+Warning: IntlCalendar::fromDateTime() expects at most 2 parameters, 3 given in %s on line %d
+
+Warning: IntlCalendar::fromDateTime(): intlcal_from_date_time: bad arguments in %s on line %d
+NULL
+threw exception, OK
+Warning: IntlCalendar::fromDateTime(): intlcal_from_date_time: DateTime object is unconstructed in %s on line %d
+NULL
+
+Warning: IntlCalendar::fromDateTime(): intlcal_from_date_time: object has an time zone offset that's too large in %s on line %d
+NULL
+
+Warning: IntlCalendar::fromDateTime(): intlcal_from_date_time: time zone id 'WEST' extracted from ext/date DateTimeZone not recognized in %s on line %d
+NULL
+
+Warning: intlcal_from_date_time() expects at least 1 parameter, 0 given in %s on line %d
+
+Warning: intlcal_from_date_time(): intlcal_from_date_time: bad arguments in %s on line %d
+NULL
diff --git a/ext/intl/tests/calendar_getAvailableLocales_basic.phpt b/ext/intl/tests/calendar_getAvailableLocales_basic.phpt
new file mode 100644
index 0000000000..5d5b79c020
--- /dev/null
+++ b/ext/intl/tests/calendar_getAvailableLocales_basic.phpt
@@ -0,0 +1,23 @@
+--TEST--
+IntlCalendar::getAvailableLocales() basic test
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+ini_set("intl.default_locale", "nl");
+
+$locales = IntlCalendar::getAvailableLocales();
+var_dump(count($locales) > 100);
+
+$locales = intlcal_get_available_locales();
+var_dump(in_array('pt', $locales));
+
+?>
+==DONE==
+--EXPECT--
+bool(true)
+bool(true)
+==DONE== \ No newline at end of file
diff --git a/ext/intl/tests/calendar_getAvailableLocales_error.phpt b/ext/intl/tests/calendar_getAvailableLocales_error.phpt
new file mode 100644
index 0000000000..e9edc468e5
--- /dev/null
+++ b/ext/intl/tests/calendar_getAvailableLocales_error.phpt
@@ -0,0 +1,24 @@
+--TEST--
+IntlCalendar::getAvailableLocales(): bad arguments
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+
+var_dump(intlcal_get_available_locales(1));
+var_dump(IntlCalendar::getAvailableLocales(2));
+
+--EXPECTF--
+
+Warning: intlcal_get_available_locales() expects exactly 0 parameters, 1 given in %s on line %d
+
+Warning: intlcal_get_available_locales(): intlcal_get_available_locales: bad arguments in %s on line %d
+bool(false)
+
+Warning: IntlCalendar::getAvailableLocales() expects exactly 0 parameters, 1 given in %s on line %d
+
+Warning: IntlCalendar::getAvailableLocales(): intlcal_get_available_locales: bad arguments in %s on line %d
+bool(false)
diff --git a/ext/intl/tests/calendar_getDayOfWeekType_basic.phpt b/ext/intl/tests/calendar_getDayOfWeekType_basic.phpt
new file mode 100644
index 0000000000..d5319f1471
--- /dev/null
+++ b/ext/intl/tests/calendar_getDayOfWeekType_basic.phpt
@@ -0,0 +1,34 @@
+--TEST--
+IntlCalendar::getDayOfWeekType() basic test
+--INI--
+date.timezone=Atlantic/Azores
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+if (version_compare(INTL_ICU_VERSION, '4.4') < 0)
+ die('skip for ICU 4.4+');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+ini_set("intl.default_locale", "nl");
+
+$intlcal = IntlCalendar::createInstance('UTC');
+$intlcal->setTime(strtotime('2012-02-29 00:00:00 +0000') * 1000);
+var_dump(
+ intlcal_get_day_of_week_type($intlcal, IntlCalendar::DOW_SUNDAY),
+ $intlcal->getDayOfWeekType(IntlCalendar::DOW_MONDAY),
+ $intlcal->getDayOfWeekType(IntlCalendar::DOW_TUESDAY),
+ $intlcal->getDayOfWeekType(IntlCalendar::DOW_FRIDAY),
+ $intlcal->getDayOfWeekType(IntlCalendar::DOW_SATURDAY)
+);
+
+?>
+==DONE==
+--EXPECT--
+int(3)
+int(0)
+int(0)
+int(0)
+int(1)
+==DONE== \ No newline at end of file
diff --git a/ext/intl/tests/calendar_getDayOfWeekType_error.phpt b/ext/intl/tests/calendar_getDayOfWeekType_error.phpt
new file mode 100644
index 0000000000..3926655615
--- /dev/null
+++ b/ext/intl/tests/calendar_getDayOfWeekType_error.phpt
@@ -0,0 +1,44 @@
+--TEST--
+IntlCalendar::getDayOfWeekOfType(): bad arguments
+--INI--
+date.timezone=Atlantic/Azores
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+if (version_compare(INTL_ICU_VERSION, '4.4') < 0)
+ die('skip for ICU 4.4+');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+
+$c = new IntlGregorianCalendar(NULL, 'pt_PT');
+
+var_dump($c->getDayOfWeekType(1, 2));
+var_dump($c->getDayOfWeekType(0));
+var_dump($c->getDayOfWeekType());
+
+var_dump(intlcal_get_day_of_week_type($c, "foo"));
+var_dump(intlcal_get_day_of_week_type(1, 1));
+
+--EXPECTF--
+
+Warning: IntlCalendar::getDayOfWeekType() expects exactly 1 parameter, 2 given in %s on line %d
+
+Warning: IntlCalendar::getDayOfWeekType(): intlcal_get_day_of_week_type: bad arguments in %s on line %d
+bool(false)
+
+Warning: IntlCalendar::getDayOfWeekType(): intlcal_get_day_of_week_type: invalid day of week in %s on line %d
+bool(false)
+
+Warning: IntlCalendar::getDayOfWeekType() expects exactly 1 parameter, 0 given in %s on line %d
+
+Warning: IntlCalendar::getDayOfWeekType(): intlcal_get_day_of_week_type: bad arguments in %s on line %d
+bool(false)
+
+Warning: intlcal_get_day_of_week_type() expects parameter 2 to be long, string given in %s on line %d
+
+Warning: intlcal_get_day_of_week_type(): intlcal_get_day_of_week_type: bad arguments in %s on line %d
+bool(false)
+
+Catchable fatal error: Argument 1 passed to intlcal_get_day_of_week_type() must be an instance of IntlCalendar, integer given in %s on line %d
diff --git a/ext/intl/tests/calendar_getErrorCode_error.phpt b/ext/intl/tests/calendar_getErrorCode_error.phpt
new file mode 100644
index 0000000000..13aab81923
--- /dev/null
+++ b/ext/intl/tests/calendar_getErrorCode_error.phpt
@@ -0,0 +1,26 @@
+--TEST--
+IntlCalendar::getErrorCode(): bad arguments
+--INI--
+date.timezone=Atlantic/Azores
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+
+$c = new IntlGregorianCalendar(NULL, 'pt_PT');
+
+var_dump($c->getErrorCode(array()));
+
+var_dump(intlcal_get_error_code(null));
+
+--EXPECTF--
+
+Warning: IntlCalendar::getErrorCode() expects exactly 0 parameters, 1 given in %s on line %d
+
+Warning: IntlCalendar::getErrorCode(): intlcal_get_error_code: bad arguments in %s on line %d
+bool(false)
+
+Catchable fatal error: Argument 1 passed to intlcal_get_error_code() must be an instance of IntlCalendar, null given in %s on line %d
diff --git a/ext/intl/tests/calendar_getErrorCode_getErrorMessage_basic.phpt b/ext/intl/tests/calendar_getErrorCode_getErrorMessage_basic.phpt
new file mode 100644
index 0000000000..71c053492f
--- /dev/null
+++ b/ext/intl/tests/calendar_getErrorCode_getErrorMessage_basic.phpt
@@ -0,0 +1,43 @@
+--TEST--
+IntlCalendar::getErrorCode(), ::getErrorMessage() basic test
+--INI--
+date.timezone=Atlantic/Azores
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+ini_set("intl.default_locale", "nl");
+
+$intlcal = new IntlGregorianCalendar(2012, 1, 29);
+var_dump(
+ $intlcal->getErrorCode(),
+ intlcal_get_error_code($intlcal),
+ $intlcal->getErrorMessage(),
+ intlcal_get_error_message($intlcal)
+);
+$intlcal->add(IntlCalendar::FIELD_SECOND, 2147483647);
+$intlcal->fieldDifference(-PHP_INT_MAX, IntlCalendar::FIELD_SECOND);
+
+var_dump(
+ $intlcal->getErrorCode(),
+ intlcal_get_error_code($intlcal),
+ $intlcal->getErrorMessage(),
+ intlcal_get_error_message($intlcal)
+);
+?>
+==DONE==
+--EXPECTF--
+int(0)
+int(0)
+string(12) "U_ZERO_ERROR"
+string(12) "U_ZERO_ERROR"
+
+Warning: IntlCalendar::fieldDifference(): intlcal_field_difference: Call to ICU method has failed in %s on line %d
+int(1)
+int(1)
+string(81) "intlcal_field_difference: Call to ICU method has failed: U_ILLEGAL_ARGUMENT_ERROR"
+string(81) "intlcal_field_difference: Call to ICU method has failed: U_ILLEGAL_ARGUMENT_ERROR"
+==DONE==
diff --git a/ext/intl/tests/calendar_getErrorMessage_error.phpt b/ext/intl/tests/calendar_getErrorMessage_error.phpt
new file mode 100644
index 0000000000..6081833904
--- /dev/null
+++ b/ext/intl/tests/calendar_getErrorMessage_error.phpt
@@ -0,0 +1,26 @@
+--TEST--
+IntlCalendar::getErrorMessage(): bad arguments
+--INI--
+date.timezone=Atlantic/Azores
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+
+$c = new IntlGregorianCalendar(NULL, 'pt_PT');
+
+var_dump($c->getErrorMessage(array()));
+
+var_dump(intlcal_get_error_message(null));
+
+--EXPECTF--
+
+Warning: IntlCalendar::getErrorMessage() expects exactly 0 parameters, 1 given in %s on line %d
+
+Warning: IntlCalendar::getErrorMessage(): intlcal_get_error_message: bad arguments in %s on line %d
+bool(false)
+
+Catchable fatal error: Argument 1 passed to intlcal_get_error_message() must be an instance of IntlCalendar, null given in %s on line %d
diff --git a/ext/intl/tests/calendar_getFirstDayOfWeek_basic.phpt b/ext/intl/tests/calendar_getFirstDayOfWeek_basic.phpt
new file mode 100644
index 0000000000..82a0bc85cc
--- /dev/null
+++ b/ext/intl/tests/calendar_getFirstDayOfWeek_basic.phpt
@@ -0,0 +1,20 @@
+--TEST--
+IntlCalendar::getFirstDayOfWeek() basic test
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+ini_set("intl.default_locale", "nl");
+
+$intlcal = IntlCalendar::createInstance('UTC');
+var_dump($intlcal->getFirstDayOfWeek());
+var_dump(intlcal_get_first_day_of_week($intlcal));
+?>
+==DONE==
+--EXPECT--
+int(2)
+int(2)
+==DONE== \ No newline at end of file
diff --git a/ext/intl/tests/calendar_getFirstDayOfWeek_error.phpt b/ext/intl/tests/calendar_getFirstDayOfWeek_error.phpt
new file mode 100644
index 0000000000..e13b5138a7
--- /dev/null
+++ b/ext/intl/tests/calendar_getFirstDayOfWeek_error.phpt
@@ -0,0 +1,32 @@
+--TEST--
+IntlCalendar::getFirstDayOfWeek(): bad arguments
+--INI--
+date.timezone=Atlantic/Azores
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+
+$c = new IntlGregorianCalendar(NULL, 'pt_PT');
+
+var_dump($c->getFirstDayOfWeek(1));
+
+var_dump(intlcal_get_first_day_of_week($c, 1));
+var_dump(intlcal_get_first_day_of_week(1));
+
+--EXPECTF--
+
+Warning: IntlCalendar::getFirstDayOfWeek() expects exactly 0 parameters, 1 given in %s on line %d
+
+Warning: IntlCalendar::getFirstDayOfWeek(): intlcal_get_first_day_of_week: bad arguments in %s on line %d
+bool(false)
+
+Warning: intlcal_get_first_day_of_week() expects exactly 1 parameter, 2 given in %s on line %d
+
+Warning: intlcal_get_first_day_of_week(): intlcal_get_first_day_of_week: bad arguments in %s on line %d
+bool(false)
+
+Catchable fatal error: Argument 1 passed to intlcal_get_first_day_of_week() must be an instance of IntlCalendar, integer given in %s on line %d
diff --git a/ext/intl/tests/calendar_getKeywordValuesForLocale_basic.phpt b/ext/intl/tests/calendar_getKeywordValuesForLocale_basic.phpt
new file mode 100644
index 0000000000..dedfcea8fe
--- /dev/null
+++ b/ext/intl/tests/calendar_getKeywordValuesForLocale_basic.phpt
@@ -0,0 +1,36 @@
+--TEST--
+IntlCalendar::getKeywordValuesForLocale() basic test
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+if (version_compare(INTL_ICU_VERSION, '4.2') < 0)
+ die('skip for ICU 4.2+');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+ini_set("intl.default_locale", "nl");
+
+print_r(
+iterator_to_array(
+IntlCalendar::getKeywordValuesForLocale('calendar', 'pt', true)
+));
+echo "\n";
+
+$var = iterator_to_array(
+intlcal_get_keyword_values_for_locale('calendar', 'pt', false)
+);
+var_dump(count($var) > 8);
+var_dump(in_array('japanese', $var));
+
+?>
+==DONE==
+--EXPECT--
+Array
+(
+ [0] => gregorian
+)
+
+bool(true)
+bool(true)
+==DONE== \ No newline at end of file
diff --git a/ext/intl/tests/calendar_getKeywordValuesForLocale_error.phpt b/ext/intl/tests/calendar_getKeywordValuesForLocale_error.phpt
new file mode 100644
index 0000000000..2aa8002bd1
--- /dev/null
+++ b/ext/intl/tests/calendar_getKeywordValuesForLocale_error.phpt
@@ -0,0 +1,26 @@
+--TEST--
+IntlCalendar::getKeywordValuesForLocale(): bad arguments
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+if (version_compare(INTL_ICU_VERSION, '4.2') < 0)
+ die('skip for ICU 4.2+');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+
+var_dump(intlcal_get_keyword_values_for_locale(1, 2));
+var_dump(IntlCalendar::getKeywordValuesForLocale(1, 2, array()));
+
+--EXPECTF--
+
+Warning: intlcal_get_keyword_values_for_locale() expects exactly 3 parameters, 2 given in %s on line %d
+
+Warning: intlcal_get_keyword_values_for_locale(): intlcal_get_keyword_values_for_locale: bad arguments in %s on line %d
+bool(false)
+
+Warning: IntlCalendar::getKeywordValuesForLocale() expects parameter 3 to be boolean, array given in %s on line %d
+
+Warning: IntlCalendar::getKeywordValuesForLocale(): intlcal_get_keyword_values_for_locale: bad arguments in %s on line %d
+bool(false)
diff --git a/ext/intl/tests/calendar_getLocale_basic.phpt b/ext/intl/tests/calendar_getLocale_basic.phpt
new file mode 100644
index 0000000000..63f846f9a8
--- /dev/null
+++ b/ext/intl/tests/calendar_getLocale_basic.phpt
@@ -0,0 +1,22 @@
+--TEST--
+IntlCalendar::getLocale() basic test
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+if (version_compare(INTL_ICU_VERSION, '4.8') < 0)
+ die('skip for ICU 4.8+');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+ini_set("intl.default_locale", "nl");
+
+$intlcal = IntlCalendar::createInstance('UTC');
+var_dump($intlcal->getLocale(Locale::ACTUAL_LOCALE));
+var_dump(intlcal_get_locale($intlcal, Locale::VALID_LOCALE));
+?>
+==DONE==
+--EXPECT--
+string(2) "nl"
+string(5) "nl_NL"
+==DONE== \ No newline at end of file
diff --git a/ext/intl/tests/calendar_getLocale_error.phpt b/ext/intl/tests/calendar_getLocale_error.phpt
new file mode 100644
index 0000000000..42970a9e7f
--- /dev/null
+++ b/ext/intl/tests/calendar_getLocale_error.phpt
@@ -0,0 +1,42 @@
+--TEST--
+IntlCalendar::getLocale(): bad arguments
+--INI--
+date.timezone=Atlantic/Azores
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+
+$c = new IntlGregorianCalendar(NULL, 'pt_PT');
+
+var_dump($c->getLocale());
+var_dump($c->getLocale(2));
+var_dump($c->getLocale(2, 3));
+
+var_dump(intlcal_get_locale($c));
+var_dump(intlcal_get_locale(1));
+
+--EXPECTF--
+
+Warning: IntlCalendar::getLocale() expects exactly 1 parameter, 0 given in %s on line %d
+
+Warning: IntlCalendar::getLocale(): intlcal_get_locale: bad arguments in %s on line %d
+bool(false)
+
+Warning: IntlCalendar::getLocale(): intlcal_get_locale: invalid locale type in %s on line %d
+bool(false)
+
+Warning: IntlCalendar::getLocale() expects exactly 1 parameter, 2 given in %s on line %d
+
+Warning: IntlCalendar::getLocale(): intlcal_get_locale: bad arguments in %s on line %d
+bool(false)
+
+Warning: intlcal_get_locale() expects exactly 2 parameters, 1 given in %s on line %d
+
+Warning: intlcal_get_locale(): intlcal_get_locale: bad arguments in %s on line %d
+bool(false)
+
+Catchable fatal error: Argument 1 passed to intlcal_get_locale() must be an instance of IntlCalendar, integer given in %s on line %d
diff --git a/ext/intl/tests/calendar_getMinimalDaysInFirstWeek_basic.phpt b/ext/intl/tests/calendar_getMinimalDaysInFirstWeek_basic.phpt
new file mode 100644
index 0000000000..eeaa3104a8
--- /dev/null
+++ b/ext/intl/tests/calendar_getMinimalDaysInFirstWeek_basic.phpt
@@ -0,0 +1,22 @@
+--TEST--
+IntlCalendar::getMinimalDaysInFirstWeek() basic test
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+if (version_compare(INTL_ICU_VERSION, '4.8') < 0)
+ die('skip for ICU 4.8+');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+ini_set("intl.default_locale", "nl");
+
+$intlcal = IntlCalendar::createInstance('UTC');
+var_dump($intlcal->getMinimalDaysInFirstWeek());
+var_dump(intlcal_get_minimal_days_in_first_week($intlcal));
+?>
+==DONE==
+--EXPECT--
+int(4)
+int(4)
+==DONE== \ No newline at end of file
diff --git a/ext/intl/tests/calendar_getMinimalDaysInFirstWeek_error.phpt b/ext/intl/tests/calendar_getMinimalDaysInFirstWeek_error.phpt
new file mode 100644
index 0000000000..8e1971dc2b
--- /dev/null
+++ b/ext/intl/tests/calendar_getMinimalDaysInFirstWeek_error.phpt
@@ -0,0 +1,32 @@
+--TEST--
+IntlCalendar::getMinimalDaysInFirstWeek(): bad arguments
+--INI--
+date.timezone=Atlantic/Azores
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+
+$c = new IntlGregorianCalendar(NULL, 'pt_PT');
+
+var_dump($c->getMinimalDaysInFirstWeek(1));
+
+var_dump(intlcal_get_minimal_days_in_first_week($c, 1));
+var_dump(intlcal_get_minimal_days_in_first_week(1));
+
+--EXPECTF--
+
+Warning: IntlCalendar::getMinimalDaysInFirstWeek() expects exactly 0 parameters, 1 given in %s on line %d
+
+Warning: IntlCalendar::getMinimalDaysInFirstWeek(): intlcal_get_minimal_days_in_first_week: bad arguments in %s on line %d
+bool(false)
+
+Warning: intlcal_get_minimal_days_in_first_week() expects exactly 1 parameter, 2 given in %s on line %d
+
+Warning: intlcal_get_minimal_days_in_first_week(): intlcal_get_minimal_days_in_first_week: bad arguments in %s on line %d
+bool(false)
+
+Catchable fatal error: Argument 1 passed to intlcal_get_minimal_days_in_first_week() must be an instance of IntlCalendar, integer given in %s on line %d
diff --git a/ext/intl/tests/calendar_getNow_basic.phpt b/ext/intl/tests/calendar_getNow_basic.phpt
new file mode 100644
index 0000000000..18325dfa60
--- /dev/null
+++ b/ext/intl/tests/calendar_getNow_basic.phpt
@@ -0,0 +1,23 @@
+--TEST--
+IntlCalendar::getNow() basic test
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+ini_set("intl.default_locale", "nl");
+
+$now = IntlCalendar::getNow();
+$proc_now = intlcal_get_now();
+$time = time();
+var_dump(abs($now - $proc_now) < 500);
+var_dump(abs($time * 1000 - $proc_now) < 1000);
+
+?>
+==DONE==
+--EXPECT--
+bool(true)
+bool(true)
+==DONE== \ No newline at end of file
diff --git a/ext/intl/tests/calendar_getNow_error.phpt b/ext/intl/tests/calendar_getNow_error.phpt
new file mode 100644
index 0000000000..31991bb591
--- /dev/null
+++ b/ext/intl/tests/calendar_getNow_error.phpt
@@ -0,0 +1,24 @@
+--TEST--
+IntlCalendar::getNow(): bad arguments
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+
+var_dump(intlcal_get_now(1));
+var_dump(IntlCalendar::getNow(2));
+
+--EXPECTF--
+
+Warning: intlcal_get_now() expects exactly 0 parameters, 1 given in %s on line %d
+
+Warning: intlcal_get_now(): intlcal_get_now: bad arguments in %s on line %d
+bool(false)
+
+Warning: IntlCalendar::getNow() expects exactly 0 parameters, 1 given in %s on line %d
+
+Warning: IntlCalendar::getNow(): intlcal_get_now: bad arguments in %s on line %d
+bool(false)
diff --git a/ext/intl/tests/calendar_getSkipped_RepeatedWallTimeOption_error.phpt b/ext/intl/tests/calendar_getSkipped_RepeatedWallTimeOption_error.phpt
new file mode 100644
index 0000000000..e07135586c
--- /dev/null
+++ b/ext/intl/tests/calendar_getSkipped_RepeatedWallTimeOption_error.phpt
@@ -0,0 +1,47 @@
+--TEST--
+IntlCalendar::getSkipped/RepeatedWallTimeOption(): bad arguments
+--INI--
+date.timezone=Atlantic/Azores
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+if (version_compare(INTL_ICU_VERSION, '49') < 0)
+ die('skip for ICU 49+');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+
+$c = new IntlGregorianCalendar(NULL, 'pt_PT');
+
+var_dump($c->getSkippedWallTimeOption(1));
+var_dump($c->getRepeatedWallTimeOption(1));
+
+var_dump(intlcal_get_skipped_wall_time_option($c, 1));
+var_dump(intlcal_get_repeated_wall_time_option($c, 1));
+
+var_dump(intlcal_get_skipped_wall_time_option(1));
+
+--EXPECTF--
+
+Warning: IntlCalendar::getSkippedWallTimeOption() expects exactly 0 parameters, 1 given in %s on line %d
+
+Warning: IntlCalendar::getSkippedWallTimeOption(): intlcal_get_skipped_wall_time_option: bad arguments in %s on line %d
+bool(false)
+
+Warning: IntlCalendar::getRepeatedWallTimeOption() expects exactly 0 parameters, 1 given in %s on line %d
+
+Warning: IntlCalendar::getRepeatedWallTimeOption(): intlcal_get_repeated_wall_time_option: bad arguments in %s on line %d
+bool(false)
+
+Warning: intlcal_get_skipped_wall_time_option() expects exactly 1 parameter, 2 given in %s on line %d
+
+Warning: intlcal_get_skipped_wall_time_option(): intlcal_get_skipped_wall_time_option: bad arguments in %s on line %d
+bool(false)
+
+Warning: intlcal_get_repeated_wall_time_option() expects exactly 1 parameter, 2 given in %s on line %d
+
+Warning: intlcal_get_repeated_wall_time_option(): intlcal_get_repeated_wall_time_option: bad arguments in %s on line %d
+bool(false)
+
+Catchable fatal error: Argument 1 passed to intlcal_get_skipped_wall_time_option() must be an instance of IntlCalendar, integer given in %s on line %d
diff --git a/ext/intl/tests/calendar_getTimeZone_basic.phpt b/ext/intl/tests/calendar_getTimeZone_basic.phpt
new file mode 100644
index 0000000000..fd9aff1f99
--- /dev/null
+++ b/ext/intl/tests/calendar_getTimeZone_basic.phpt
@@ -0,0 +1,34 @@
+--TEST--
+IntlCalendar::getTimeZone() basic test
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+if (version_compare(INTL_ICU_VERSION, '4.8') < 0)
+ die('skip for ICU 4.8+');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+ini_set("intl.default_locale", "nl");
+
+$intlcal = IntlCalendar::createInstance('GMT+00:01');
+print_r($intlcal->getTimeZone());
+print_r(intlcal_get_time_zone($intlcal));
+?>
+==DONE==
+--EXPECT--
+IntlTimeZone Object
+(
+ [valid] => 1
+ [id] => GMT+00:01
+ [rawOffset] => 60000
+ [currentOffset] => 60000
+)
+IntlTimeZone Object
+(
+ [valid] => 1
+ [id] => GMT+00:01
+ [rawOffset] => 60000
+ [currentOffset] => 60000
+)
+==DONE== \ No newline at end of file
diff --git a/ext/intl/tests/calendar_getTimeZone_error.phpt b/ext/intl/tests/calendar_getTimeZone_error.phpt
new file mode 100644
index 0000000000..470701cd91
--- /dev/null
+++ b/ext/intl/tests/calendar_getTimeZone_error.phpt
@@ -0,0 +1,32 @@
+--TEST--
+IntlCalendar::getTimeZone(): bad arguments
+--INI--
+date.timezone=Atlantic/Azores
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+
+$c = new IntlGregorianCalendar(NULL, 'pt_PT');
+
+var_dump($c->getTimeZone(1));
+
+var_dump(intlcal_get_time_zone($c, 1));
+var_dump(intlcal_get_time_zone(1));
+
+--EXPECTF--
+
+Warning: IntlCalendar::getTimeZone() expects exactly 0 parameters, 1 given in %s on line %d
+
+Warning: IntlCalendar::getTimeZone(): intlcal_get_time_zone: bad arguments in %s on line %d
+bool(false)
+
+Warning: intlcal_get_time_zone() expects exactly 1 parameter, 2 given in %s on line %d
+
+Warning: intlcal_get_time_zone(): intlcal_get_time_zone: bad arguments in %s on line %d
+bool(false)
+
+Catchable fatal error: Argument 1 passed to intlcal_get_time_zone() must be an instance of IntlCalendar, integer given in %s on line %d
diff --git a/ext/intl/tests/calendar_getTime_basic.phpt b/ext/intl/tests/calendar_getTime_basic.phpt
new file mode 100644
index 0000000000..659c71c961
--- /dev/null
+++ b/ext/intl/tests/calendar_getTime_basic.phpt
@@ -0,0 +1,29 @@
+--TEST--
+IntlCalendar::getTime() basic test
+--INI--
+date.timezone=Atlantic/Azores
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+ini_set("intl.default_locale", "nl");
+
+$intlcal = IntlCalendar::createInstance('UTC');
+$intlcal->clear();
+$intlcal->set(IntlCalendar::FIELD_YEAR, 2012);
+$intlcal->set(IntlCalendar::FIELD_MONTH, 1 /* Feb */);
+$intlcal->set(IntlCalendar::FIELD_DAY_OF_MONTH, 29);
+
+$time = strtotime('2012-02-29 00:00:00 +0000');
+
+var_dump((float)$time*1000, $intlcal->getTime());
+
+?>
+==DONE==
+--EXPECT--
+float(1330473600000)
+float(1330473600000)
+==DONE== \ No newline at end of file
diff --git a/ext/intl/tests/calendar_getTime_error.phpt b/ext/intl/tests/calendar_getTime_error.phpt
new file mode 100644
index 0000000000..5d27e21101
--- /dev/null
+++ b/ext/intl/tests/calendar_getTime_error.phpt
@@ -0,0 +1,31 @@
+--TEST--
+IntlCalendar::getTime(): bad arguments
+--INI--
+date.timezone=Atlantic/Azores
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+
+$c = new IntlGregorianCalendar(NULL, 'pt_PT');
+
+var_dump($c->getTime(1));
+
+var_dump(intlcal_get_time($c, 1));
+var_dump(intlcal_get_time(1));
+--EXPECTF--
+
+Warning: IntlCalendar::getTime() expects exactly 0 parameters, 1 given in %s on line %d
+
+Warning: IntlCalendar::getTime(): intlcal_get_time: bad arguments in %s on line %d
+bool(false)
+
+Warning: intlcal_get_time() expects exactly 1 parameter, 2 given in %s on line %d
+
+Warning: intlcal_get_time(): intlcal_get_time: bad arguments in %s on line %d
+bool(false)
+
+Catchable fatal error: Argument 1 passed to intlcal_get_time() must be an instance of IntlCalendar, integer given in %s on line %d
diff --git a/ext/intl/tests/calendar_getType_basic.phpt b/ext/intl/tests/calendar_getType_basic.phpt
new file mode 100644
index 0000000000..ba32dd0526
--- /dev/null
+++ b/ext/intl/tests/calendar_getType_basic.phpt
@@ -0,0 +1,23 @@
+--TEST--
+IntlCalendar::getType() basic test
+--INI--
+date.timezone=Atlantic/Azores
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+ini_set("intl.default_locale", "nl");
+
+$intlcal = IntlCalendar::createInstance();
+VAR_DUMP($intlcal->getType());
+$intlcal = IntlCalendar::createInstance(null, "nl_NL@calendar=hebrew");
+VAR_DUMP(intlcal_get_type($intlcal));
+?>
+==DONE==
+--EXPECT--
+string(9) "gregorian"
+string(6) "hebrew"
+==DONE== \ No newline at end of file
diff --git a/ext/intl/tests/calendar_getType_error.phpt b/ext/intl/tests/calendar_getType_error.phpt
new file mode 100644
index 0000000000..668ebeafb4
--- /dev/null
+++ b/ext/intl/tests/calendar_getType_error.phpt
@@ -0,0 +1,32 @@
+--TEST--
+IntlCalendar::getType(): bad arguments
+--INI--
+date.timezone=Atlantic/Azores
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+
+$c = new IntlGregorianCalendar(NULL, 'pt_PT');
+
+var_dump($c->getType(1));
+
+var_dump(intlcal_get_type($c, 1));
+var_dump(intlcal_get_type(1));
+
+--EXPECTF--
+
+Warning: IntlCalendar::getType() expects exactly 0 parameters, 1 given in %s on line %d
+
+Warning: IntlCalendar::getType(): intlcal_get_type: bad arguments in %s on line %d
+bool(false)
+
+Warning: intlcal_get_type() expects exactly 1 parameter, 2 given in %s on line %d
+
+Warning: intlcal_get_type(): intlcal_get_type: bad arguments in %s on line %d
+bool(false)
+
+Catchable fatal error: Argument 1 passed to intlcal_get_type() must be an instance of IntlCalendar, integer given in %s on line %d
diff --git a/ext/intl/tests/calendar_getWeekendTransition_basic.phpt b/ext/intl/tests/calendar_getWeekendTransition_basic.phpt
new file mode 100644
index 0000000000..e725743006
--- /dev/null
+++ b/ext/intl/tests/calendar_getWeekendTransition_basic.phpt
@@ -0,0 +1,24 @@
+--TEST--
+IntlCalendar::getWeekendTransition() basic test
+--INI--
+date.timezone=Atlantic/Azores
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+if (version_compare(INTL_ICU_VERSION, '4.4') < 0)
+ die('skip for ICU 4.4+');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+ini_set("intl.default_locale", "nl");
+
+$intlcal = IntlCalendar::createInstance();
+var_dump($intlcal->getWeekendTransition(IntlCalendar::DOW_SUNDAY));
+var_dump(intlcal_get_weekend_transition($intlcal, IntlCalendar::DOW_SUNDAY));
+?>
+==DONE==
+--EXPECT--
+int(86400000)
+int(86400000)
+==DONE== \ No newline at end of file
diff --git a/ext/intl/tests/calendar_getWeekendTransition_error.phpt b/ext/intl/tests/calendar_getWeekendTransition_error.phpt
new file mode 100644
index 0000000000..f7c9cc7ed1
--- /dev/null
+++ b/ext/intl/tests/calendar_getWeekendTransition_error.phpt
@@ -0,0 +1,44 @@
+--TEST--
+IntlCalendar::getWeekendTransition(): bad arguments
+--INI--
+date.timezone=Atlantic/Azores
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+if (version_compare(INTL_ICU_VERSION, '4.4') < 0)
+ die('skip for ICU 4.4+');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+
+$c = new IntlGregorianCalendar(NULL, 'pt_PT');
+
+var_dump($c->getWeekendTransition());
+var_dump($c->getWeekendTransition(1, 2));
+var_dump($c->getWeekendTransition(0));
+
+var_dump(intlcal_get_weekend_transition($c));
+var_dump(intlcal_get_weekend_transition(1, 1));
+
+--EXPECTF--
+
+Warning: IntlCalendar::getWeekendTransition() expects exactly 1 parameter, 0 given in %s on line %d
+
+Warning: IntlCalendar::getWeekendTransition(): intlcal_get_weekend_transition: bad arguments in %s on line %d
+bool(false)
+
+Warning: IntlCalendar::getWeekendTransition() expects exactly 1 parameter, 2 given in %s on line %d
+
+Warning: IntlCalendar::getWeekendTransition(): intlcal_get_weekend_transition: bad arguments in %s on line %d
+bool(false)
+
+Warning: IntlCalendar::getWeekendTransition(): intlcal_get_weekend_transition: invalid day of week in %s on line %d
+bool(false)
+
+Warning: intlcal_get_weekend_transition() expects exactly 2 parameters, 1 given in %s on line %d
+
+Warning: intlcal_get_weekend_transition(): intlcal_get_weekend_transition: bad arguments in %s on line %d
+bool(false)
+
+Catchable fatal error: Argument 1 passed to intlcal_get_weekend_transition() must be an instance of IntlCalendar, integer given in %s on line %d
diff --git a/ext/intl/tests/calendar_getXMaximum_basic.phpt b/ext/intl/tests/calendar_getXMaximum_basic.phpt
new file mode 100644
index 0000000000..9b840212d9
--- /dev/null
+++ b/ext/intl/tests/calendar_getXMaximum_basic.phpt
@@ -0,0 +1,34 @@
+--TEST--
+IntlCalendar::getMaximum(), ::getActualMaximum(), ::getLeastMaximum() basic test
+--INI--
+date.timezone=Atlantic/Azores
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+ini_set("intl.default_locale", "nl");
+
+$intlcal = IntlCalendar::createInstance('UTC');
+$intlcal->setTime(strtotime('2012-02-29 05:06:07 +0000') * 1000);
+var_dump(
+ $intlcal->getLeastMaximum(IntlCalendar::FIELD_DAY_OF_MONTH),
+ intlcal_get_least_maximum($intlcal, IntlCalendar::FIELD_DAY_OF_MONTH),
+ $intlcal->getActualMaximum(IntlCalendar::FIELD_DAY_OF_MONTH),
+ intlcal_get_actual_maximum($intlcal, IntlCalendar::FIELD_DAY_OF_MONTH),
+ $intlcal->getMaximum(IntlCalendar::FIELD_DAY_OF_MONTH),
+ intlcal_get_maximum($intlcal, IntlCalendar::FIELD_DAY_OF_MONTH)
+);
+
+?>
+==DONE==
+--EXPECT--
+int(28)
+int(28)
+int(29)
+int(29)
+int(31)
+int(31)
+==DONE== \ No newline at end of file
diff --git a/ext/intl/tests/calendar_getXMinimum_basic.phpt b/ext/intl/tests/calendar_getXMinimum_basic.phpt
new file mode 100644
index 0000000000..83fd163809
--- /dev/null
+++ b/ext/intl/tests/calendar_getXMinimum_basic.phpt
@@ -0,0 +1,34 @@
+--TEST--
+IntlCalendar::getMinimum(), ::getActualMinimum(), ::getGreatestMinimum() basic test
+--INI--
+date.timezone=Atlantic/Azores
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+ini_set("intl.default_locale", "nl");
+
+$intlcal = IntlCalendar::createInstance('UTC');
+$intlcal->setTime(strtotime('2012-02-29 05:06:07 +0000') * 1000);
+var_dump(
+ $intlcal->getGreatestMinimum(IntlCalendar::FIELD_DAY_OF_MONTH),
+ intlcal_get_greatest_minimum($intlcal, IntlCalendar::FIELD_DAY_OF_MONTH),
+ $intlcal->getActualMinimum(IntlCalendar::FIELD_DAY_OF_MONTH),
+ intlcal_get_actual_minimum($intlcal, IntlCalendar::FIELD_DAY_OF_MONTH),
+ $intlcal->getMinimum(IntlCalendar::FIELD_DAY_OF_MONTH),
+ intlcal_get_minimum($intlcal, IntlCalendar::FIELD_DAY_OF_MONTH)
+);
+
+?>
+==DONE==
+--EXPECT--
+int(1)
+int(1)
+int(1)
+int(1)
+int(1)
+int(1)
+==DONE== \ No newline at end of file
diff --git a/ext/intl/tests/calendar_get_Least_Greatest_Minimum_Maximum_error.phpt b/ext/intl/tests/calendar_get_Least_Greatest_Minimum_Maximum_error.phpt
new file mode 100644
index 0000000000..acd9b58c1d
--- /dev/null
+++ b/ext/intl/tests/calendar_get_Least_Greatest_Minimum_Maximum_error.phpt
@@ -0,0 +1,100 @@
+--TEST--
+IntlCalendar::get/Least/Greatest/Minimum/Maximum(): bad arguments
+--INI--
+date.timezone=Atlantic/Azores
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+
+$c = new IntlGregorianCalendar(NULL, 'pt_PT');
+
+var_dump($c->getLeastMaximum());
+var_dump($c->getMaximum());
+var_dump($c->getGreatestMinimum());
+var_dump($c->getMinimum());
+
+var_dump($c->getLeastMaximum(-1));
+var_dump($c->getMaximum(-1));
+var_dump($c->getGreatestMinimum(-1));
+var_dump($c->getMinimum(-1));
+
+var_dump(intlcal_get_least_maximum($c, -1));
+var_dump(intlcal_get_maximum($c, -1));
+var_dump(intlcal_get_greatest_minimum($c, -1));
+var_dump(intlcal_get_minimum($c, -1));
+
+function eh($errno, $errstr) {
+echo "error: $errno, $errstr\n";
+}
+set_error_handler('eh');
+
+var_dump(intlcal_get_least_maximum(1, 1));
+var_dump(intlcal_get_maximum(1, 1));
+var_dump(intlcal_get_greatest_minimum(1, -1));
+var_dump(intlcal_get_minimum(1, -1));
+
+--EXPECTF--
+
+Warning: IntlCalendar::getLeastMaximum() expects exactly 1 parameter, 0 given in %s on line %d
+
+Warning: IntlCalendar::getLeastMaximum(): intlcal_get_least_maximum: bad arguments in %s on line %d
+bool(false)
+
+Warning: IntlCalendar::getMaximum() expects exactly 1 parameter, 0 given in %s on line %d
+
+Warning: IntlCalendar::getMaximum(): intlcal_get_maximum: bad arguments in %s on line %d
+bool(false)
+
+Warning: IntlCalendar::getGreatestMinimum() expects exactly 1 parameter, 0 given in %s on line %d
+
+Warning: IntlCalendar::getGreatestMinimum(): intlcal_get_greatest_minimum: bad arguments in %s on line %d
+bool(false)
+
+Warning: IntlCalendar::getMinimum() expects exactly 1 parameter, 0 given in %s on line %d
+
+Warning: IntlCalendar::getMinimum(): intlcal_get_minimum: bad arguments in %s on line %d
+bool(false)
+
+Warning: IntlCalendar::getLeastMaximum(): intlcal_get_least_maximum: invalid field in %s on line %d
+bool(false)
+
+Warning: IntlCalendar::getMaximum(): intlcal_get_maximum: invalid field in %s on line %d
+bool(false)
+
+Warning: IntlCalendar::getGreatestMinimum(): intlcal_get_greatest_minimum: invalid field in %s on line %d
+bool(false)
+
+Warning: IntlCalendar::getMinimum(): intlcal_get_minimum: invalid field in %s on line %d
+bool(false)
+
+Warning: intlcal_get_least_maximum(): intlcal_get_least_maximum: invalid field in %s on line %d
+bool(false)
+
+Warning: intlcal_get_maximum(): intlcal_get_maximum: invalid field in %s on line %d
+bool(false)
+
+Warning: intlcal_get_greatest_minimum(): intlcal_get_greatest_minimum: invalid field in %s on line %d
+bool(false)
+
+Warning: intlcal_get_minimum(): intlcal_get_minimum: invalid field in %s on line %d
+bool(false)
+error: 4096, Argument 1 passed to intlcal_get_least_maximum() must be an instance of IntlCalendar, integer given
+error: 2, intlcal_get_least_maximum() expects parameter 1 to be IntlCalendar, integer given
+error: 2, intlcal_get_least_maximum(): intlcal_get_least_maximum: bad arguments
+bool(false)
+error: 4096, Argument 1 passed to intlcal_get_maximum() must be an instance of IntlCalendar, integer given
+error: 2, intlcal_get_maximum() expects parameter 1 to be IntlCalendar, integer given
+error: 2, intlcal_get_maximum(): intlcal_get_maximum: bad arguments
+bool(false)
+error: 4096, Argument 1 passed to intlcal_get_greatest_minimum() must be an instance of IntlCalendar, integer given
+error: 2, intlcal_get_greatest_minimum() expects parameter 1 to be IntlCalendar, integer given
+error: 2, intlcal_get_greatest_minimum(): intlcal_get_greatest_minimum: bad arguments
+bool(false)
+error: 4096, Argument 1 passed to intlcal_get_minimum() must be an instance of IntlCalendar, integer given
+error: 2, intlcal_get_minimum() expects parameter 1 to be IntlCalendar, integer given
+error: 2, intlcal_get_minimum(): intlcal_get_minimum: bad arguments
+bool(false)
diff --git a/ext/intl/tests/calendar_get_basic.phpt b/ext/intl/tests/calendar_get_basic.phpt
new file mode 100644
index 0000000000..c617639610
--- /dev/null
+++ b/ext/intl/tests/calendar_get_basic.phpt
@@ -0,0 +1,23 @@
+--TEST--
+IntlCalendar::get() basic test
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+ini_set("intl.default_locale", "nl");
+
+$intlcal = IntlCalendar::createInstance('UTC');
+$intlcal->set(IntlCalendar::FIELD_DAY_OF_MONTH, 4);
+
+var_dump($intlcal->get(IntlCalendar::FIELD_DAY_OF_MONTH));
+var_dump(intlcal_get($intlcal, IntlCalendar::FIELD_DAY_OF_MONTH));
+
+?>
+==DONE==
+--EXPECT--
+int(4)
+int(4)
+==DONE== \ No newline at end of file
diff --git a/ext/intl/tests/calendar_get_getActualMaximum_Minumum_error.phpt b/ext/intl/tests/calendar_get_getActualMaximum_Minumum_error.phpt
new file mode 100644
index 0000000000..f6ccb128ee
--- /dev/null
+++ b/ext/intl/tests/calendar_get_getActualMaximum_Minumum_error.phpt
@@ -0,0 +1,84 @@
+--TEST--
+IntlCalendar::get/getActualMaximum/getActualMinimum(): bad arguments
+--INI--
+date.timezone=Atlantic/Azores
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+
+$c = new IntlGregorianCalendar(NULL, 'pt_PT');
+
+var_dump($c->get());
+var_dump($c->getActualMaximum());
+var_dump($c->getActualMinimum());
+
+var_dump($c->get(-1));
+var_dump($c->getActualMaximum(-1));
+var_dump($c->getActualMinimum(-1));
+
+var_dump($c->get("s"));
+var_dump($c->getActualMaximum("s"));
+var_dump($c->getActualMinimum("s"));
+
+var_dump($c->get(1, 2));
+var_dump($c->getActualMaximum(1, 2));
+var_dump($c->getActualMinimum(1, 2));
+--EXPECTF--
+
+Warning: IntlCalendar::get() expects exactly 1 parameter, 0 given in %s on line %d
+
+Warning: IntlCalendar::get(): intlcal_get: bad arguments in %s on line %d
+bool(false)
+
+Warning: IntlCalendar::getActualMaximum() expects exactly 1 parameter, 0 given in %s on line %d
+
+Warning: IntlCalendar::getActualMaximum(): intlcal_get_actual_maximum: bad arguments in %s on line %d
+bool(false)
+
+Warning: IntlCalendar::getActualMinimum() expects exactly 1 parameter, 0 given in %s on line %d
+
+Warning: IntlCalendar::getActualMinimum(): intlcal_get_actual_minimum: bad arguments in %s on line %d
+bool(false)
+
+Warning: IntlCalendar::get(): intlcal_get: invalid field in %s on line %d
+bool(false)
+
+Warning: IntlCalendar::getActualMaximum(): intlcal_get_actual_maximum: invalid field in %s on line %d
+bool(false)
+
+Warning: IntlCalendar::getActualMinimum(): intlcal_get_actual_minimum: invalid field in %s on line %d
+bool(false)
+
+Warning: IntlCalendar::get() expects parameter 1 to be long, string given in %s on line %d
+
+Warning: IntlCalendar::get(): intlcal_get: bad arguments in %s on line %d
+bool(false)
+
+Warning: IntlCalendar::getActualMaximum() expects parameter 1 to be long, string given in %s on line %d
+
+Warning: IntlCalendar::getActualMaximum(): intlcal_get_actual_maximum: bad arguments in %s on line %d
+bool(false)
+
+Warning: IntlCalendar::getActualMinimum() expects parameter 1 to be long, string given in %s on line %d
+
+Warning: IntlCalendar::getActualMinimum(): intlcal_get_actual_minimum: bad arguments in %s on line %d
+bool(false)
+
+Warning: IntlCalendar::get() expects exactly 1 parameter, 2 given in %s on line %d
+
+Warning: IntlCalendar::get(): intlcal_get: bad arguments in %s on line %d
+bool(false)
+
+Warning: IntlCalendar::getActualMaximum() expects exactly 1 parameter, 2 given in %s on line %d
+
+Warning: IntlCalendar::getActualMaximum(): intlcal_get_actual_maximum: bad arguments in %s on line %d
+bool(false)
+
+Warning: IntlCalendar::getActualMinimum() expects exactly 1 parameter, 2 given in %s on line %d
+
+Warning: IntlCalendar::getActualMinimum(): intlcal_get_actual_minimum: bad arguments in %s on line %d
+bool(false)
diff --git a/ext/intl/tests/calendar_get_getActualMaximum_Minumum_error2.phpt b/ext/intl/tests/calendar_get_getActualMaximum_Minumum_error2.phpt
new file mode 100644
index 0000000000..a8d1a4aa2f
--- /dev/null
+++ b/ext/intl/tests/calendar_get_getActualMaximum_Minumum_error2.phpt
@@ -0,0 +1,71 @@
+--TEST--
+IntlCalendar::get/getActualMaximum/getActualMinimum(): bad arguments (procedural)
+--INI--
+date.timezone=Atlantic/Azores
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+
+$c = new IntlGregorianCalendar(NULL, 'pt_PT');
+
+function eh($errno, $errstr) {
+echo "error: $errno, $errstr\n";
+}
+set_error_handler('eh');
+
+var_dump(intlcal_get($c));
+var_dump(intlcal_get_actual_maximum($c));
+var_dump(intlcal_get_actual_minimum($c));
+
+var_dump(intlcal_get($c, -1));
+var_dump(intlcal_get_actual_maximum($c, -1));
+var_dump(intlcal_get_actual_minimum($c, -1));
+
+var_dump(intlcal_get($c, "s"));
+var_dump(intlcal_get_actual_maximum($c, "s"));
+var_dump(intlcal_get_actual_minimum($c, "s"));
+
+var_dump(intlcal_get(1));
+var_dump(intlcal_get_actual_maximum(1));
+var_dump(intlcal_get_actual_minimum(1));
+--EXPECT--
+error: 2, intlcal_get() expects exactly 2 parameters, 1 given
+error: 2, intlcal_get(): intlcal_get: bad arguments
+bool(false)
+error: 2, intlcal_get_actual_maximum() expects exactly 2 parameters, 1 given
+error: 2, intlcal_get_actual_maximum(): intlcal_get_actual_maximum: bad arguments
+bool(false)
+error: 2, intlcal_get_actual_minimum() expects exactly 2 parameters, 1 given
+error: 2, intlcal_get_actual_minimum(): intlcal_get_actual_minimum: bad arguments
+bool(false)
+error: 2, intlcal_get(): intlcal_get: invalid field
+bool(false)
+error: 2, intlcal_get_actual_maximum(): intlcal_get_actual_maximum: invalid field
+bool(false)
+error: 2, intlcal_get_actual_minimum(): intlcal_get_actual_minimum: invalid field
+bool(false)
+error: 2, intlcal_get() expects parameter 2 to be long, string given
+error: 2, intlcal_get(): intlcal_get: bad arguments
+bool(false)
+error: 2, intlcal_get_actual_maximum() expects parameter 2 to be long, string given
+error: 2, intlcal_get_actual_maximum(): intlcal_get_actual_maximum: bad arguments
+bool(false)
+error: 2, intlcal_get_actual_minimum() expects parameter 2 to be long, string given
+error: 2, intlcal_get_actual_minimum(): intlcal_get_actual_minimum: bad arguments
+bool(false)
+error: 4096, Argument 1 passed to intlcal_get() must be an instance of IntlCalendar, integer given
+error: 2, intlcal_get() expects exactly 2 parameters, 1 given
+error: 2, intlcal_get(): intlcal_get: bad arguments
+bool(false)
+error: 4096, Argument 1 passed to intlcal_get_actual_maximum() must be an instance of IntlCalendar, integer given
+error: 2, intlcal_get_actual_maximum() expects exactly 2 parameters, 1 given
+error: 2, intlcal_get_actual_maximum(): intlcal_get_actual_maximum: bad arguments
+bool(false)
+error: 4096, Argument 1 passed to intlcal_get_actual_minimum() must be an instance of IntlCalendar, integer given
+error: 2, intlcal_get_actual_minimum() expects exactly 2 parameters, 1 given
+error: 2, intlcal_get_actual_minimum(): intlcal_get_actual_minimum: bad arguments
+bool(false)
diff --git a/ext/intl/tests/calendar_get_setRepeatedWallTimeOption_basic.phpt b/ext/intl/tests/calendar_get_setRepeatedWallTimeOption_basic.phpt
new file mode 100644
index 0000000000..52765433fe
--- /dev/null
+++ b/ext/intl/tests/calendar_get_setRepeatedWallTimeOption_basic.phpt
@@ -0,0 +1,49 @@
+--TEST--
+IntlCalendar::get/setRepeatedWallTimeOption(): basic test
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+if (version_compare(INTL_ICU_VERSION, '49') < 0)
+ die('skip for ICU 49+');
+--FILE--
+
+<?php
+ini_set("intl.error_level", E_WARNING);
+ini_set("intl.default_locale", "nl");
+
+date_default_timezone_set('Europe/Amsterdam');
+
+//28 October 2012, transition from DST
+$intlcal = new IntlGregorianCalendar(2012, 9, 28, 0, 0, 0);
+var_dump($intlcal->setRepeatedWallTimeOption(IntlCalendar::WALLTIME_LAST));
+var_dump($intlcal->getRepeatedWallTimeOption());
+$intlcal->set(IntlCalendar::FIELD_HOUR_OF_DAY, 2);
+$intlcal->set(IntlCalendar::FIELD_MINUTE, 30);
+var_dump(
+ strtotime('2012-10-28 02:30:00 +0100'),
+ (int)($intlcal->getTime() /1000)
+);
+
+var_dump(intlcal_set_repeated_wall_time_option($intlcal, IntlCalendar::WALLTIME_FIRST));
+var_dump(intlcal_get_repeated_wall_time_option($intlcal));
+$intlcal->set(IntlCalendar::FIELD_HOUR_OF_DAY, 2);
+$intlcal->set(IntlCalendar::FIELD_MINUTE, 30);
+var_dump(
+ strtotime('2012-10-28 02:30:00 +0200'),
+ (int)($intlcal->getTime() /1000)
+);
+
+?>
+==DONE==
+--EXPECT--
+
+bool(true)
+int(0)
+int(1351387800)
+int(1351387800)
+bool(true)
+int(1)
+int(1351384200)
+int(1351384200)
+==DONE== \ No newline at end of file
diff --git a/ext/intl/tests/calendar_get_setSkippedWallTimeOption_basic.phpt b/ext/intl/tests/calendar_get_setSkippedWallTimeOption_basic.phpt
new file mode 100644
index 0000000000..bbbf031c88
--- /dev/null
+++ b/ext/intl/tests/calendar_get_setSkippedWallTimeOption_basic.phpt
@@ -0,0 +1,67 @@
+--TEST--
+IntlCalendar::get/setSkippedWallTimeOption(): basic test
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+if (version_compare(INTL_ICU_VERSION, '49') < 0)
+ die('skip for ICU 49+');
+--FILE--
+
+<?php
+ini_set("intl.error_level", E_WARNING);
+ini_set("intl.default_locale", "nl");
+
+date_default_timezone_set('Europe/Amsterdam');
+
+//25 March 2012, transition to DST
+$intlcal = new IntlGregorianCalendar(2012, 2, 25, 0, 0, 0);
+var_dump($intlcal->getSkippedWallTimeOption());
+$intlcal->set(IntlCalendar::FIELD_HOUR_OF_DAY, 2);
+$intlcal->set(IntlCalendar::FIELD_MINUTE, 30);
+echo "Should be 3h30\n";
+var_dump(
+ $intlcal->get(IntlCalendar::FIELD_HOUR_OF_DAY),
+ $intlcal->get(IntlCalendar::FIELD_MINUTE)
+);
+
+var_dump($intlcal->setSkippedWallTimeOption(IntlCalendar::WALLTIME_FIRST));
+var_dump(intlcal_get_skipped_wall_time_option($intlcal));
+$intlcal->set(IntlCalendar::FIELD_HOUR_OF_DAY, 2);
+$intlcal->set(IntlCalendar::FIELD_MINUTE, 30);
+echo "Should be 1h30\n";
+var_dump(
+ $intlcal->get(IntlCalendar::FIELD_HOUR_OF_DAY),
+ $intlcal->get(IntlCalendar::FIELD_MINUTE)
+);
+
+var_dump(intlcal_set_skipped_wall_time_option($intlcal, IntlCalendar::WALLTIME_NEXT_VALID));
+var_dump($intlcal->getSkippedWallTimeOption());
+$intlcal->set(IntlCalendar::FIELD_HOUR_OF_DAY, 2);
+$intlcal->set(IntlCalendar::FIELD_MINUTE, 30);
+echo "Should be 3h00\n";
+var_dump(
+ $intlcal->get(IntlCalendar::FIELD_HOUR_OF_DAY),
+ $intlcal->get(IntlCalendar::FIELD_MINUTE)
+);
+
+
+?>
+==DONE==
+--EXPECT--
+
+int(0)
+Should be 3h30
+int(3)
+int(30)
+bool(true)
+int(1)
+Should be 1h30
+int(1)
+int(30)
+bool(true)
+int(2)
+Should be 3h00
+int(3)
+int(0)
+==DONE== \ No newline at end of file
diff --git a/ext/intl/tests/calendar_inDaylightTime_basic.phpt b/ext/intl/tests/calendar_inDaylightTime_basic.phpt
new file mode 100644
index 0000000000..dff8ef50d3
--- /dev/null
+++ b/ext/intl/tests/calendar_inDaylightTime_basic.phpt
@@ -0,0 +1,24 @@
+--TEST--
+IntlCalendar::inDaylightTime() basic test
+--INI--
+date.timezone=Atlantic/Azores
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+ini_set("intl.default_locale", "nl");
+
+$intlcal = IntlCalendar::createInstance('Europe/Amsterdam');
+$intlcal->setTime(strtotime('2012-01-01') * 1000);
+var_dump($intlcal->inDaylightTime());
+$intlcal->setTime(strtotime('2012-04-01') * 1000);
+var_dump(intlcal_in_daylight_time($intlcal));
+?>
+==DONE==
+--EXPECT--
+bool(false)
+bool(true)
+==DONE== \ No newline at end of file
diff --git a/ext/intl/tests/calendar_inDaylightTime_error.phpt b/ext/intl/tests/calendar_inDaylightTime_error.phpt
new file mode 100644
index 0000000000..9af9aa5048
--- /dev/null
+++ b/ext/intl/tests/calendar_inDaylightTime_error.phpt
@@ -0,0 +1,32 @@
+--TEST--
+IntlCalendar::inDaylightTime(): bad arguments
+--INI--
+date.timezone=Atlantic/Azores
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+
+$c = new IntlGregorianCalendar(NULL, 'pt_PT');
+
+var_dump($c->inDaylightTime(1));
+
+var_dump(intlcal_in_daylight_time($c, 1));
+var_dump(intlcal_in_daylight_time(1));
+
+--EXPECTF--
+
+Warning: IntlCalendar::inDaylightTime() expects exactly 0 parameters, 1 given in %s on line %d
+
+Warning: IntlCalendar::inDaylightTime(): intlcal_in_daylight_time: bad arguments in %s on line %d
+bool(false)
+
+Warning: intlcal_in_daylight_time() expects exactly 1 parameter, 2 given in %s on line %d
+
+Warning: intlcal_in_daylight_time(): intlcal_in_daylight_time: bad arguments in %s on line %d
+bool(false)
+
+Catchable fatal error: Argument 1 passed to intlcal_in_daylight_time() must be an instance of IntlCalendar, integer given in %s on line %d
diff --git a/ext/intl/tests/calendar_isEquivalentTo_basic.phpt b/ext/intl/tests/calendar_isEquivalentTo_basic.phpt
new file mode 100644
index 0000000000..f71fd8ad5b
--- /dev/null
+++ b/ext/intl/tests/calendar_isEquivalentTo_basic.phpt
@@ -0,0 +1,40 @@
+--TEST--
+IntlCalendar::isEquivalentTo() basic test
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+ini_set("intl.default_locale", "nl");
+
+$intlcal1 = IntlCalendar::createInstance('Europe/Amsterdam');
+$intlcal2 = IntlCalendar::createInstance('Europe/Lisbon');
+$intlcal3 = IntlCalendar::createInstance('Europe/Amsterdam', "nl_NL@calendar=islamic");
+$intlcal4 = IntlCalendar::createInstance('Europe/Amsterdam');
+$intlcal4->roll(IntlCalendar::FIELD_MONTH, true);
+
+var_dump(
+ "1 - 1",
+ $intlcal1->isEquivalentTo($intlcal1),
+ "1 - 2",
+ $intlcal1->isEquivalentTo($intlcal2),
+ "1 - 3",
+ $intlcal1->isEquivalentTo($intlcal3),
+ "1 - 4",
+ $intlcal1->isEquivalentTo($intlcal4)
+);
+
+?>
+==DONE==
+--EXPECT--
+string(5) "1 - 1"
+bool(true)
+string(5) "1 - 2"
+bool(false)
+string(5) "1 - 3"
+bool(false)
+string(5) "1 - 4"
+bool(true)
+==DONE== \ No newline at end of file
diff --git a/ext/intl/tests/calendar_isEquivalentTo_error.phpt b/ext/intl/tests/calendar_isEquivalentTo_error.phpt
new file mode 100644
index 0000000000..4fa7da5eb6
--- /dev/null
+++ b/ext/intl/tests/calendar_isEquivalentTo_error.phpt
@@ -0,0 +1,50 @@
+--TEST--
+IntlCalendar::isEquivalentTo(): bad arguments
+--INI--
+date.timezone=Atlantic/Azores
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+
+$c = new IntlGregorianCalendar(NULL, 'pt_PT');
+
+function eh($errno, $errstr) {
+echo "error: $errno, $errstr\n";
+}
+set_error_handler('eh');
+
+var_dump($c->isEquivalentTo(0));
+var_dump($c->isEquivalentTo($c, 1));
+var_dump($c->isEquivalentTo(1));
+
+var_dump(intlcal_is_equivalent_to($c));
+var_dump(intlcal_is_equivalent_to($c, 1));
+var_dump(intlcal_is_equivalent_to(1, $c));
+
+--EXPECT--
+error: 4096, Argument 1 passed to IntlCalendar::isEquivalentTo() must be an instance of IntlCalendar, integer given
+error: 2, IntlCalendar::isEquivalentTo() expects parameter 1 to be IntlCalendar, integer given
+error: 2, IntlCalendar::isEquivalentTo(): intlcal_is_equivalent_to: bad arguments
+bool(false)
+error: 2, IntlCalendar::isEquivalentTo() expects exactly 1 parameter, 2 given
+error: 2, IntlCalendar::isEquivalentTo(): intlcal_is_equivalent_to: bad arguments
+bool(false)
+error: 4096, Argument 1 passed to IntlCalendar::isEquivalentTo() must be an instance of IntlCalendar, integer given
+error: 2, IntlCalendar::isEquivalentTo() expects parameter 1 to be IntlCalendar, integer given
+error: 2, IntlCalendar::isEquivalentTo(): intlcal_is_equivalent_to: bad arguments
+bool(false)
+error: 2, intlcal_is_equivalent_to() expects exactly 2 parameters, 1 given
+error: 2, intlcal_is_equivalent_to(): intlcal_is_equivalent_to: bad arguments
+bool(false)
+error: 4096, Argument 2 passed to intlcal_is_equivalent_to() must be an instance of IntlCalendar, integer given
+error: 2, intlcal_is_equivalent_to() expects parameter 2 to be IntlCalendar, integer given
+error: 2, intlcal_is_equivalent_to(): intlcal_is_equivalent_to: bad arguments
+bool(false)
+error: 4096, Argument 1 passed to intlcal_is_equivalent_to() must be an instance of IntlCalendar, integer given
+error: 2, intlcal_is_equivalent_to() expects parameter 1 to be IntlCalendar, integer given
+error: 2, intlcal_is_equivalent_to(): intlcal_is_equivalent_to: bad arguments
+bool(false)
diff --git a/ext/intl/tests/calendar_isLenient_error.phpt b/ext/intl/tests/calendar_isLenient_error.phpt
new file mode 100644
index 0000000000..7ddde1ae02
--- /dev/null
+++ b/ext/intl/tests/calendar_isLenient_error.phpt
@@ -0,0 +1,32 @@
+--TEST--
+IntlCalendar::isLenient(): bad arguments
+--INI--
+date.timezone=Atlantic/Azores
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+
+$c = new IntlGregorianCalendar(NULL, 'pt_PT');
+
+var_dump($c->isLenient(1));
+
+var_dump(intlcal_is_lenient($c, 1));
+var_dump(intlcal_is_lenient(1));
+
+--EXPECTF--
+
+Warning: IntlCalendar::isLenient() expects exactly 0 parameters, 1 given in %s on line %d
+
+Warning: IntlCalendar::isLenient(): intlcal_is_lenient: bad arguments in %s on line %d
+bool(false)
+
+Warning: intlcal_is_lenient() expects exactly 1 parameter, 2 given in %s on line %d
+
+Warning: intlcal_is_lenient(): intlcal_is_lenient: bad arguments in %s on line %d
+bool(false)
+
+Catchable fatal error: Argument 1 passed to intlcal_is_lenient() must be an instance of IntlCalendar, integer given in %s on line %d
diff --git a/ext/intl/tests/calendar_isSet_basic.phpt b/ext/intl/tests/calendar_isSet_basic.phpt
new file mode 100644
index 0000000000..8ef01448d5
--- /dev/null
+++ b/ext/intl/tests/calendar_isSet_basic.phpt
@@ -0,0 +1,24 @@
+--TEST--
+IntlCalendar::isSet() basic test
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+ini_set("intl.default_locale", "nl");
+
+$intlcal = IntlCalendar::createInstance('UTC');
+var_dump($intlcal->isSet(IntlCalendar::FIELD_MINUTE));
+$intlcal->clear(IntlCalendar::FIELD_MINUTE);
+var_dump($intlcal->isSet(IntlCalendar::FIELD_MINUTE));
+$intlcal->set(IntlCalendar::FIELD_MINUTE, 0);
+var_dump(intlcal_is_set($intlcal, IntlCalendar::FIELD_MINUTE));
+?>
+==DONE==
+--EXPECT--
+bool(true)
+bool(false)
+bool(true)
+==DONE== \ No newline at end of file
diff --git a/ext/intl/tests/calendar_isSet_error.phpt b/ext/intl/tests/calendar_isSet_error.phpt
new file mode 100644
index 0000000000..f238d776b2
--- /dev/null
+++ b/ext/intl/tests/calendar_isSet_error.phpt
@@ -0,0 +1,42 @@
+--TEST--
+IntlCalendar::isSet(): bad arguments
+--INI--
+date.timezone=Atlantic/Azores
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+
+$c = new IntlGregorianCalendar(NULL, 'pt_PT');
+
+var_dump($c->isSet());
+var_dump($c->isSet(1, 2));
+var_dump($c->isSet(-1));
+
+var_dump(intlcal_is_set($c));
+var_dump(intlcal_is_set(1, 2));
+
+--EXPECTF--
+
+Warning: IntlCalendar::isSet() expects exactly 1 parameter, 0 given in %s on line %d
+
+Warning: IntlCalendar::isSet(): intlcal_is_set: bad arguments in %s on line %d
+bool(false)
+
+Warning: IntlCalendar::isSet() expects exactly 1 parameter, 2 given in %s on line %d
+
+Warning: IntlCalendar::isSet(): intlcal_is_set: bad arguments in %s on line %d
+bool(false)
+
+Warning: IntlCalendar::isSet(): intlcal_is_set: invalid field in %s on line %d
+bool(false)
+
+Warning: intlcal_is_set() expects exactly 2 parameters, 1 given in %s on line %d
+
+Warning: intlcal_is_set(): intlcal_is_set: bad arguments in %s on line %d
+bool(false)
+
+Catchable fatal error: Argument 1 passed to intlcal_is_set() must be an instance of IntlCalendar, integer given in %s on line %d
diff --git a/ext/intl/tests/calendar_isWeekend_basic.phpt b/ext/intl/tests/calendar_isWeekend_basic.phpt
new file mode 100644
index 0000000000..d6452c71f7
--- /dev/null
+++ b/ext/intl/tests/calendar_isWeekend_basic.phpt
@@ -0,0 +1,26 @@
+--TEST--
+IntlCalendar::isWeekend basic test
+--INI--
+date.timezone=Atlantic/Azores
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+if (version_compare(INTL_ICU_VERSION, '4.4') < 0)
+ die('skip for ICU 4.4+');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+ini_set("intl.default_locale", "nl");
+
+$intlcal = IntlCalendar::createInstance('UTC');
+var_dump($intlcal->isWeekend(strtotime('2012-02-29 12:00:00 +0000') * 1000));
+var_dump(intlcal_is_weekend($intlcal, strtotime('2012-02-29 12:00:00 +0000') * 1000));
+var_dump($intlcal->isWeekend(strtotime('2012-03-11 12:00:00 +0000') * 1000));
+?>
+==DONE==
+--EXPECT--
+bool(false)
+bool(false)
+bool(true)
+==DONE== \ No newline at end of file
diff --git a/ext/intl/tests/calendar_isWeekend_error.phpt b/ext/intl/tests/calendar_isWeekend_error.phpt
new file mode 100644
index 0000000000..7939a66a14
--- /dev/null
+++ b/ext/intl/tests/calendar_isWeekend_error.phpt
@@ -0,0 +1,38 @@
+--TEST--
+IntlCalendar::isWeekend(): bad arguments
+--INI--
+date.timezone=Atlantic/Azores
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+if (version_compare(INTL_ICU_VERSION, '4.4') < 0)
+ die('skip for ICU 4.4+');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+
+$c = new IntlGregorianCalendar(NULL, 'pt_PT');
+
+var_dump($c->isWeekend(1, 2));
+var_dump($c->isWeekend("jhhk"));
+
+var_dump(intlcal_is_weekend($c, "jj"));
+var_dump(intlcal_is_weekend(1));
+
+--EXPECTF--
+
+Warning: IntlCalendar::isWeekend(): intlcal_is_weekend: bad arguments in %s on line %d
+bool(false)
+
+Warning: IntlCalendar::isWeekend() expects parameter 1 to be double, string given in %s on line %d
+
+Warning: IntlCalendar::isWeekend(): intlcal_is_weekend: bad arguments in %s on line %d
+bool(false)
+
+Warning: intlcal_is_weekend() expects parameter 2 to be double, string given in %s on line %d
+
+Warning: intlcal_is_weekend(): intlcal_is_weekend: bad arguments in %s on line %d
+bool(false)
+
+Catchable fatal error: Argument 1 passed to intlcal_is_weekend() must be an instance of IntlCalendar, integer given in %s on line %d
diff --git a/ext/intl/tests/calendar_is_set_lenient_basic.phpt b/ext/intl/tests/calendar_is_set_lenient_basic.phpt
new file mode 100644
index 0000000000..64f537f9bc
--- /dev/null
+++ b/ext/intl/tests/calendar_is_set_lenient_basic.phpt
@@ -0,0 +1,28 @@
+--TEST--
+IntlCalendar::isLenient(), ::setLenient() basic test
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+ini_set("intl.default_locale", "nl");
+
+$intlcal1 = IntlCalendar::createInstance('UTC');
+var_dump($intlcal1->isLenient());
+var_dump(intlcal_is_lenient($intlcal1));
+var_dump($intlcal1->setLenient(false));
+var_dump($intlcal1->isLenient());
+var_dump(intlcal_set_lenient($intlcal1, true));
+var_dump($intlcal1->isLenient());
+?>
+==DONE==
+--EXPECT--
+bool(true)
+bool(true)
+bool(true)
+bool(false)
+bool(true)
+bool(true)
+==DONE== \ No newline at end of file
diff --git a/ext/intl/tests/calendar_roll_basic.phpt b/ext/intl/tests/calendar_roll_basic.phpt
new file mode 100644
index 0000000000..971c36217b
--- /dev/null
+++ b/ext/intl/tests/calendar_roll_basic.phpt
@@ -0,0 +1,34 @@
+--TEST--
+IntlCalendar::roll() basic test
+--INI--
+date.timezone=Atlantic/Azores
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+ini_set("intl.default_locale", "nl");
+
+$intlcal = new IntlGregorianCalendar(2012, 1, 28);
+var_dump($intlcal->roll(IntlCalendar::FIELD_DAY_OF_MONTH, 2));
+var_dump($intlcal->get(IntlCalendar::FIELD_MONTH)); //1 (Feb)
+var_dump($intlcal->get(IntlCalendar::FIELD_DAY_OF_MONTH)); //1
+
+$intlcal = new IntlGregorianCalendar(2012, 1, 28);
+var_dump(intlcal_roll($intlcal, IntlCalendar::FIELD_DAY_OF_MONTH, 2));
+var_dump($intlcal->get(IntlCalendar::FIELD_MONTH)); //1 (Feb)
+var_dump($intlcal->get(IntlCalendar::FIELD_DAY_OF_MONTH)); //1
+
+
+?>
+==DONE==
+--EXPECT--
+bool(true)
+int(1)
+int(1)
+bool(true)
+int(1)
+int(1)
+==DONE== \ No newline at end of file
diff --git a/ext/intl/tests/calendar_roll_error.phpt b/ext/intl/tests/calendar_roll_error.phpt
new file mode 100644
index 0000000000..a567394699
--- /dev/null
+++ b/ext/intl/tests/calendar_roll_error.phpt
@@ -0,0 +1,37 @@
+--TEST--
+IntlCalendar::roll(): bad arguments
+--INI--
+date.timezone=Atlantic/Azores
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+
+$c = new IntlGregorianCalendar(NULL, 'pt_PT');
+
+var_dump($c->roll(1, 2, 3));
+var_dump($c->roll(-1, 2));
+var_dump($c->roll(1));
+
+var_dump(intlcal_roll($c, 1, 2, 3));
+var_dump(intlcal_roll(1, 2, 3));
+--EXPECTF--
+
+Warning: IntlCalendar::roll(): intlcal_set: too many arguments in %s on line %d
+bool(false)
+
+Warning: IntlCalendar::roll(): intlcal_roll: invalid field in %s on line %d
+bool(false)
+
+Warning: IntlCalendar::roll() expects exactly 2 parameters, 1 given in %s on line %d
+
+Warning: IntlCalendar::roll(): intlcal_roll: bad arguments in %s on line %d
+bool(false)
+
+Warning: intlcal_roll(): intlcal_set: too many arguments in %s on line %d
+bool(false)
+
+Catchable fatal error: Argument 1 passed to intlcal_roll() must be an instance of IntlCalendar, integer given in %s on line %d
diff --git a/ext/intl/tests/calendar_roll_variation1.phpt b/ext/intl/tests/calendar_roll_variation1.phpt
new file mode 100644
index 0000000000..9fb8d75e5a
--- /dev/null
+++ b/ext/intl/tests/calendar_roll_variation1.phpt
@@ -0,0 +1,32 @@
+--TEST--
+IntlCalendar::roll() bool argument variation
+--INI--
+date.timezone=Atlantic/Azores
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+ini_set("intl.default_locale", "nl");
+
+$intlcal = new IntlGregorianCalendar(2012, 1, 28);
+var_dump($intlcal->roll(IntlCalendar::FIELD_DAY_OF_MONTH, true));
+var_dump($intlcal->get(IntlCalendar::FIELD_MONTH)); //1 (Feb)
+var_dump($intlcal->get(IntlCalendar::FIELD_DAY_OF_MONTH)); //29
+
+var_dump(intlcal_roll($intlcal, IntlCalendar::FIELD_DAY_OF_MONTH, false));
+var_dump($intlcal->get(IntlCalendar::FIELD_MONTH)); //1 (Feb)
+var_dump($intlcal->get(IntlCalendar::FIELD_DAY_OF_MONTH)); //28
+
+?>
+==DONE==
+--EXPECT--
+bool(true)
+int(1)
+int(29)
+bool(true)
+int(1)
+int(28)
+==DONE== \ No newline at end of file
diff --git a/ext/intl/tests/calendar_setFirstDayOfWeek_basic.phpt b/ext/intl/tests/calendar_setFirstDayOfWeek_basic.phpt
new file mode 100644
index 0000000000..79b38104e4
--- /dev/null
+++ b/ext/intl/tests/calendar_setFirstDayOfWeek_basic.phpt
@@ -0,0 +1,28 @@
+--TEST--
+IntlCalendar::setFirstDayOfWeek() basic test
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+ini_set("intl.default_locale", "nl");
+
+$intlcal = IntlCalendar::createInstance('UTC');
+var_dump(
+ IntlCalendar::DOW_TUESDAY,
+ $intlcal->setFirstDayOfWeek(IntlCalendar::DOW_TUESDAY),
+ $intlcal->getFirstDayOfWeek(),
+ intlcal_set_first_day_of_week($intlcal, IntlCalendar::DOW_WEDNESDAY),
+ $intlcal->getFirstDayOfWeek()
+);
+?>
+==DONE==
+--EXPECT--
+int(3)
+bool(true)
+int(3)
+bool(true)
+int(4)
+==DONE== \ No newline at end of file
diff --git a/ext/intl/tests/calendar_setFirstDayOfWeek_error.phpt b/ext/intl/tests/calendar_setFirstDayOfWeek_error.phpt
new file mode 100644
index 0000000000..98237e56fa
--- /dev/null
+++ b/ext/intl/tests/calendar_setFirstDayOfWeek_error.phpt
@@ -0,0 +1,40 @@
+--TEST--
+IntlCalendar::setFirstDayOfWeek(): bad arguments
+--INI--
+date.timezone=Atlantic/Azores
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+
+$c = new IntlGregorianCalendar(NULL, 'pt_PT');
+
+var_dump($c->setFirstDayOfWeek());
+var_dump($c->setFirstDayOfWeek(1, 2));
+var_dump($c->setFirstDayOfWeek(0));
+
+var_dump(intlcal_set_first_day_of_week($c, 0));
+var_dump(intlcal_set_first_day_of_week(1, 2));
+
+--EXPECTF--
+
+Warning: IntlCalendar::setFirstDayOfWeek() expects exactly 1 parameter, 0 given in %s on line %d
+
+Warning: IntlCalendar::setFirstDayOfWeek(): intlcal_set_first_day_of_week: bad arguments in %s on line %d
+bool(false)
+
+Warning: IntlCalendar::setFirstDayOfWeek() expects exactly 1 parameter, 2 given in %s on line %d
+
+Warning: IntlCalendar::setFirstDayOfWeek(): intlcal_set_first_day_of_week: bad arguments in %s on line %d
+bool(false)
+
+Warning: IntlCalendar::setFirstDayOfWeek(): intlcal_set_first_day_of_week: invalid day of week in %s on line %d
+bool(false)
+
+Warning: intlcal_set_first_day_of_week(): intlcal_set_first_day_of_week: invalid day of week in %s on line %d
+bool(false)
+
+Catchable fatal error: Argument 1 passed to intlcal_set_first_day_of_week() must be an instance of IntlCalendar, integer given in %s on line %d
diff --git a/ext/intl/tests/calendar_setLenient_error.phpt b/ext/intl/tests/calendar_setLenient_error.phpt
new file mode 100644
index 0000000000..2b1d7b016d
--- /dev/null
+++ b/ext/intl/tests/calendar_setLenient_error.phpt
@@ -0,0 +1,44 @@
+--TEST--
+IntlCalendar::setLenient(): bad arguments
+--INI--
+date.timezone=Atlantic/Azores
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+
+$c = new IntlGregorianCalendar(NULL, 'pt_PT');
+
+var_dump($c->setLenient());
+var_dump($c->setLenient(array()));
+var_dump($c->setLenient(1, 2));
+
+var_dump(intlcal_set_lenient($c, array()));
+var_dump(intlcal_set_lenient(1, false));
+
+--EXPECTF--
+
+Warning: IntlCalendar::setLenient() expects exactly 1 parameter, 0 given in %s on line %d
+
+Warning: IntlCalendar::setLenient(): intlcal_set_lenient: bad arguments in %s on line %d
+bool(false)
+
+Warning: IntlCalendar::setLenient() expects parameter 1 to be boolean, array given in %s on line %d
+
+Warning: IntlCalendar::setLenient(): intlcal_set_lenient: bad arguments in %s on line %d
+bool(false)
+
+Warning: IntlCalendar::setLenient() expects exactly 1 parameter, 2 given in %s on line %d
+
+Warning: IntlCalendar::setLenient(): intlcal_set_lenient: bad arguments in %s on line %d
+bool(false)
+
+Warning: intlcal_set_lenient() expects parameter 2 to be boolean, array given in %s on line %d
+
+Warning: intlcal_set_lenient(): intlcal_set_lenient: bad arguments in %s on line %d
+bool(false)
+
+Catchable fatal error: Argument 1 passed to intlcal_set_lenient() must be an instance of IntlCalendar, integer given in %s on line %d
diff --git a/ext/intl/tests/calendar_setSkipped_RepeatedWallTimeOption_error.phpt b/ext/intl/tests/calendar_setSkipped_RepeatedWallTimeOption_error.phpt
new file mode 100644
index 0000000000..dab55d2b29
--- /dev/null
+++ b/ext/intl/tests/calendar_setSkipped_RepeatedWallTimeOption_error.phpt
@@ -0,0 +1,82 @@
+--TEST--
+IntlCalendar::setSkipped/RepeatedWallTimeOption(): bad arguments
+--INI--
+date.timezone=Atlantic/Azores
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+if (version_compare(INTL_ICU_VERSION, '49') < 0)
+ die('skip for ICU 49+');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+
+$c = new IntlGregorianCalendar(NULL, 'pt_PT');
+
+var_dump($c->setSkippedWallTimeOption());
+var_dump($c->setRepeatedWallTimeOption());
+
+var_dump($c->setSkippedWallTimeOption(1, 2));
+var_dump($c->setRepeatedWallTimeOption(1, 2));
+
+var_dump($c->setSkippedWallTimeOption(array()));
+var_dump($c->setRepeatedWallTimeOption(array()));
+
+var_dump($c->setSkippedWallTimeOption(3));
+var_dump($c->setRepeatedWallTimeOption(2));
+
+var_dump(intlcal_set_skipped_wall_time_option($c));
+var_dump(intlcal_set_repeated_wall_time_option($c));
+
+var_dump(intlcal_set_repeated_wall_time_option(1, 1));
+
+--EXPECTF--
+
+Warning: IntlCalendar::setSkippedWallTimeOption() expects exactly 1 parameter, 0 given in %s on line %d
+
+Warning: IntlCalendar::setSkippedWallTimeOption(): intlcal_set_skipped_wall_time_option: bad arguments in %s on line %d
+bool(false)
+
+Warning: IntlCalendar::setRepeatedWallTimeOption() expects exactly 1 parameter, 0 given in %s on line %d
+
+Warning: IntlCalendar::setRepeatedWallTimeOption(): intlcal_set_repeated_wall_time_option: bad arguments in %s on line %d
+bool(false)
+
+Warning: IntlCalendar::setSkippedWallTimeOption() expects exactly 1 parameter, 2 given in %s on line %d
+
+Warning: IntlCalendar::setSkippedWallTimeOption(): intlcal_set_skipped_wall_time_option: bad arguments in %s on line %d
+bool(false)
+
+Warning: IntlCalendar::setRepeatedWallTimeOption() expects exactly 1 parameter, 2 given in %s on line %d
+
+Warning: IntlCalendar::setRepeatedWallTimeOption(): intlcal_set_repeated_wall_time_option: bad arguments in %s on line %d
+bool(false)
+
+Warning: IntlCalendar::setSkippedWallTimeOption() expects parameter 1 to be long, array given in %s on line %d
+
+Warning: IntlCalendar::setSkippedWallTimeOption(): intlcal_set_skipped_wall_time_option: bad arguments in %s on line %d
+bool(false)
+
+Warning: IntlCalendar::setRepeatedWallTimeOption() expects parameter 1 to be long, array given in %s on line %d
+
+Warning: IntlCalendar::setRepeatedWallTimeOption(): intlcal_set_repeated_wall_time_option: bad arguments in %s on line %d
+bool(false)
+
+Warning: IntlCalendar::setSkippedWallTimeOption(): intlcal_set_skipped_wall_time_option: invalid option in %s on line %d
+bool(false)
+
+Warning: IntlCalendar::setRepeatedWallTimeOption(): intlcal_set_repeated_wall_time_option: invalid option in %s on line %d
+bool(false)
+
+Warning: intlcal_set_skipped_wall_time_option() expects exactly 2 parameters, 1 given in %s on line %d
+
+Warning: intlcal_set_skipped_wall_time_option(): intlcal_set_skipped_wall_time_option: bad arguments in %s on line %d
+bool(false)
+
+Warning: intlcal_set_repeated_wall_time_option() expects exactly 2 parameters, 1 given in %s on line %d
+
+Warning: intlcal_set_repeated_wall_time_option(): intlcal_set_repeated_wall_time_option: bad arguments in %s on line %d
+bool(false)
+
+Catchable fatal error: Argument 1 passed to intlcal_set_repeated_wall_time_option() must be an instance of IntlCalendar, integer given in %s on line %d
diff --git a/ext/intl/tests/calendar_setTimeZone_basic.phpt b/ext/intl/tests/calendar_setTimeZone_basic.phpt
new file mode 100644
index 0000000000..525840ddd6
--- /dev/null
+++ b/ext/intl/tests/calendar_setTimeZone_basic.phpt
@@ -0,0 +1,39 @@
+--TEST--
+IntlCalendar::setTimeZone() basic test
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+if (version_compare(INTL_ICU_VERSION, '4.8') < 0)
+ die('skip for ICU 4.8+');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+ini_set("intl.default_locale", "nl");
+
+$intlcal = IntlCalendar::createInstance('Europe/Amsterdam');
+print_r($intlcal->getTimeZone()->getID());
+echo "\n";
+var_dump($intlcal->get(IntlCalendar::FIELD_ZONE_OFFSET));
+
+$intlcal->setTimeZone(IntlTimeZone::getGMT());
+print_r($intlcal->getTimeZone()->getID());
+echo "\n";
+var_dump($intlcal->get(IntlCalendar::FIELD_ZONE_OFFSET));
+
+intlcal_set_time_zone($intlcal,
+ IntlTimeZone::createTimeZone('GMT+05:30'));
+print_r($intlcal->getTimeZone()->getID());
+echo "\n";
+var_dump($intlcal->get(IntlCalendar::FIELD_ZONE_OFFSET));
+
+?>
+==DONE==
+--EXPECT--
+Europe/Amsterdam
+int(3600000)
+GMT
+int(0)
+GMT+05:30
+int(19800000)
+==DONE== \ No newline at end of file
diff --git a/ext/intl/tests/calendar_setTimeZone_error.phpt b/ext/intl/tests/calendar_setTimeZone_error.phpt
new file mode 100644
index 0000000000..ebe4d119ea
--- /dev/null
+++ b/ext/intl/tests/calendar_setTimeZone_error.phpt
@@ -0,0 +1,41 @@
+--TEST--
+IntlCalendar::setTimeZone(): bad arguments
+--INI--
+date.timezone=Atlantic/Azores
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+
+$c = new IntlGregorianCalendar(NULL, 'pt_PT');
+
+$gmt = IntlTimeZone::getGMT();
+
+function eh($errno, $errstr) {
+echo "error: $errno, $errstr\n";
+}
+set_error_handler('eh');
+
+var_dump($c->setTimeZone($gmt, 2));
+var_dump($c->setTimeZone());
+
+var_dump(intlcal_set_time_zone($c, 1, 2));
+var_dump(intlcal_set_time_zone(1, $gmt));
+
+--EXPECT--
+error: 2, IntlCalendar::setTimeZone() expects exactly 1 parameter, 2 given
+error: 2, IntlCalendar::setTimeZone(): intlcal_set_time_zone: bad arguments
+bool(false)
+error: 2, IntlCalendar::setTimeZone() expects exactly 1 parameter, 0 given
+error: 2, IntlCalendar::setTimeZone(): intlcal_set_time_zone: bad arguments
+bool(false)
+error: 2, intlcal_set_time_zone() expects exactly 2 parameters, 3 given
+error: 2, intlcal_set_time_zone(): intlcal_set_time_zone: bad arguments
+bool(false)
+error: 4096, Argument 1 passed to intlcal_set_time_zone() must be an instance of IntlCalendar, integer given
+error: 2, intlcal_set_time_zone() expects parameter 1 to be IntlCalendar, integer given
+error: 2, intlcal_set_time_zone(): intlcal_set_time_zone: bad arguments
+bool(false)
diff --git a/ext/intl/tests/calendar_setTimeZone_error2.phpt b/ext/intl/tests/calendar_setTimeZone_error2.phpt
new file mode 100644
index 0000000000..aa1eaba209
--- /dev/null
+++ b/ext/intl/tests/calendar_setTimeZone_error2.phpt
@@ -0,0 +1,29 @@
+--TEST--
+IntlCalendar::setTimeZone(): valid time zones for DateTime but not ICU
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+ini_set("intl.default_locale", "nl");
+date_default_timezone_set('Europe/Amsterdam');
+
+$intlcal = new IntlGregorianCalendar();
+
+$pstdate = new DateTime('2012-01-01 00:00:00 WEST');
+$intlcal->setTimeZone($pstdate->getTimeZone());
+var_dump($intlcal->getTimeZone()->getID());
+
+$pstdate = new DateTime('2012-01-01 00:00:00 +24:00');
+$intlcal->setTimeZone($pstdate->getTimeZone());
+var_dump($intlcal->getTimeZone()->getID());
+
+--EXPECTF--
+
+Warning: IntlCalendar::setTimeZone(): intlcal_set_time_zone: time zone id 'WEST' extracted from ext/date DateTimeZone not recognized in %s on line %d
+string(16) "Europe/Amsterdam"
+
+Warning: IntlCalendar::setTimeZone(): intlcal_set_time_zone: object has an time zone offset that's too large in %s on line %d
+string(16) "Europe/Amsterdam"
diff --git a/ext/intl/tests/calendar_setTimeZone_variation1.phpt b/ext/intl/tests/calendar_setTimeZone_variation1.phpt
new file mode 100644
index 0000000000..b1cbb74edf
--- /dev/null
+++ b/ext/intl/tests/calendar_setTimeZone_variation1.phpt
@@ -0,0 +1,30 @@
+--TEST--
+IntlCalendar::setTimeZone() variation with NULL arg
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+ini_set("intl.default_locale", "nl");
+
+$intlcal = IntlCalendar::createInstance('Europe/Amsterdam');
+print_r($intlcal->getTimeZone()->getID());
+echo "\n";
+var_dump($intlcal->get(IntlCalendar::FIELD_ZONE_OFFSET));
+
+/* passing NULL has no effect */
+$intlcal->setTimeZone(null);
+print_r($intlcal->getTimeZone()->getID());
+echo "\n";
+var_dump($intlcal->get(IntlCalendar::FIELD_ZONE_OFFSET));
+
+?>
+==DONE==
+--EXPECT--
+Europe/Amsterdam
+int(3600000)
+Europe/Amsterdam
+int(3600000)
+==DONE== \ No newline at end of file
diff --git a/ext/intl/tests/calendar_setTimeZone_variation2.phpt b/ext/intl/tests/calendar_setTimeZone_variation2.phpt
new file mode 100644
index 0000000000..7f4a7ffa37
--- /dev/null
+++ b/ext/intl/tests/calendar_setTimeZone_variation2.phpt
@@ -0,0 +1,30 @@
+--TEST--
+IntlCalendar::setTimeZone(): different ways to specify time zone
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+ini_set("intl.default_locale", "nl");
+date_default_timezone_set('Europe/Amsterdam');
+
+$intlcal = new IntlGregorianCalendar();
+$intlcal->setTimeZone('Europe/Paris');
+var_dump($intlcal->getTimeZone()->getID());
+$intlcal->setTimeZone(new DateTimeZone('Europe/Madrid'));
+var_dump($intlcal->getTimeZone()->getID());
+
+$pstdate = new DateTime('2012-01-01 00:00:00 PST');
+$intlcal->setTimeZone($pstdate->getTimeZone());
+var_dump($intlcal->getTimeZone()->getID());
+
+$offsetdate = new DateTime('2012-01-01 00:00:00 -02:30');
+$intlcal->setTimeZone($offsetdate->getTimeZone());
+var_dump($intlcal->getTimeZone()->getID());
+--EXPECTF--
+string(12) "Europe/Paris"
+string(13) "Europe/Madrid"
+string(3) "PST"
+string(%d) "GMT-02%S30"
diff --git a/ext/intl/tests/calendar_setTime_basic.phpt b/ext/intl/tests/calendar_setTime_basic.phpt
new file mode 100644
index 0000000000..f7f213c0d8
--- /dev/null
+++ b/ext/intl/tests/calendar_setTime_basic.phpt
@@ -0,0 +1,33 @@
+--TEST--
+IntlCalendar::setTime() basic test
+--INI--
+date.timezone=Atlantic/Azores
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+ini_set("intl.default_locale", "nl");
+
+$time = strtotime('2012-02-29 00:00:00 +0000');
+
+$intlcal = IntlCalendar::createInstance('UTC');
+$intlcal->setTime($time * 1000);
+
+var_dump(
+ (float)$time*1000,
+ $intlcal->getTime());
+
+$intlcal = IntlCalendar::createInstance('UTC');
+intlcal_set_time($intlcal,$time * 1000);
+var_dump(intlcal_get_time($intlcal));
+
+?>
+==DONE==
+--EXPECT--
+float(1330473600000)
+float(1330473600000)
+float(1330473600000)
+==DONE== \ No newline at end of file
diff --git a/ext/intl/tests/calendar_setTime_error.phpt b/ext/intl/tests/calendar_setTime_error.phpt
new file mode 100644
index 0000000000..71c5b0a1bd
--- /dev/null
+++ b/ext/intl/tests/calendar_setTime_error.phpt
@@ -0,0 +1,37 @@
+--TEST--
+IntlCalendar::setTime(): bad arguments
+--INI--
+date.timezone=Atlantic/Azores
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+
+$c = new IntlGregorianCalendar(NULL, 'pt_PT');
+
+var_dump($c->setTime(1, 2));
+var_dump($c->setTime("jjj"));
+
+var_dump(intlcal_set_time($c, 1, 2));
+var_dump(intlcal_set_time(1));
+--EXPECTF--
+
+Warning: IntlCalendar::setTime() expects exactly 1 parameter, 2 given in %s on line %d
+
+Warning: IntlCalendar::setTime(): intlcal_set_time: bad arguments in %s on line %d
+bool(false)
+
+Warning: IntlCalendar::setTime() expects parameter 1 to be double, string given in %s on line %d
+
+Warning: IntlCalendar::setTime(): intlcal_set_time: bad arguments in %s on line %d
+bool(false)
+
+Warning: intlcal_set_time() expects exactly 2 parameters, 3 given in %s on line %d
+
+Warning: intlcal_set_time(): intlcal_set_time: bad arguments in %s on line %d
+bool(false)
+
+Catchable fatal error: Argument 1 passed to intlcal_set_time() must be an instance of IntlCalendar, integer given in %s on line %d
diff --git a/ext/intl/tests/calendar_set_basic.phpt b/ext/intl/tests/calendar_set_basic.phpt
new file mode 100644
index 0000000000..8eccb32da6
--- /dev/null
+++ b/ext/intl/tests/calendar_set_basic.phpt
@@ -0,0 +1,27 @@
+--TEST--
+IntlCalendar::set() basic test
+--INI--
+date.timezone=Atlantic/Azores
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+ini_set("intl.default_locale", "nl");
+
+$intlcal = IntlCalendar::createInstance();
+var_dump($intlcal->set(IntlCalendar::FIELD_DAY_OF_MONTH, 2));
+var_dump($intlcal->get(IntlCalendar::FIELD_DAY_OF_MONTH));
+var_dump(intlcal_set($intlcal, IntlCalendar::FIELD_DAY_OF_MONTH, 3));
+var_dump($intlcal->get(IntlCalendar::FIELD_DAY_OF_MONTH));
+
+?>
+==DONE==
+--EXPECT--
+bool(true)
+int(2)
+bool(true)
+int(3)
+==DONE== \ No newline at end of file
diff --git a/ext/intl/tests/calendar_set_error.phpt b/ext/intl/tests/calendar_set_error.phpt
new file mode 100644
index 0000000000..669b1888e0
--- /dev/null
+++ b/ext/intl/tests/calendar_set_error.phpt
@@ -0,0 +1,41 @@
+--TEST--
+IntlCalendar::set(): bad arguments
+--INI--
+date.timezone=Atlantic/Azores
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+
+$c = new IntlGregorianCalendar(NULL, 'pt_PT');
+
+var_dump($c->set(1));
+var_dump($c->set(1, 2, 3, 4));
+var_dump($c->set(1, 2, 3, 4, 5, 6, 7));
+var_dump($c->set(-1, 2));
+
+var_dump(intlcal_set($c, -1, 2));
+var_dump(intlcal_set(1, 2, 3));
+--EXPECTF--
+
+Warning: IntlCalendar::set() expects at least 2 parameters, 1 given in %s on line %d
+
+Warning: IntlCalendar::set(): intlcal_set: bad arguments in %s on line %d
+bool(false)
+
+Warning: IntlCalendar::set(): intlcal_set: bad arguments in %s on line %d
+bool(false)
+
+Warning: IntlCalendar::set(): intlcal_set: too many arguments in %s on line %d
+bool(false)
+
+Warning: IntlCalendar::set(): intlcal_set: invalid field in %s on line %d
+bool(false)
+
+Warning: intlcal_set(): intlcal_set: invalid field in %s on line %d
+bool(false)
+
+Catchable fatal error: Argument 1 passed to intlcal_set() must be an instance of IntlCalendar, integer given in %s on line %d
diff --git a/ext/intl/tests/calendar_set_variation1.phpt b/ext/intl/tests/calendar_set_variation1.phpt
new file mode 100644
index 0000000000..8ea016ed61
--- /dev/null
+++ b/ext/intl/tests/calendar_set_variation1.phpt
@@ -0,0 +1,41 @@
+--TEST--
+IntlCalendar::set() argument variations
+--INI--
+date.timezone=Atlantic/Azores
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+ini_set("intl.default_locale", "nl");
+
+$intlcal = IntlCalendar::createInstance('UTC');
+$intlcal->clear();
+var_dump($intlcal->set(2012, 1, 29));
+var_dump($intlcal->getTime(),
+ strtotime('2012-02-29 00:00:00 +0000') * 1000.);
+
+//two minutes to midnight!
+var_dump($intlcal->set(2012, 1, 29, 23, 58));
+var_dump($intlcal->getTime(),
+ strtotime('2012-02-29 23:58:00 +0000') * 1000.);
+
+var_dump($intlcal->set(2012, 1, 29, 23, 58, 31));
+var_dump($intlcal->getTime(),
+ strtotime('2012-02-29 23:58:31 +0000') * 1000.);
+
+?>
+==DONE==
+--EXPECT--
+bool(true)
+float(1330473600000)
+float(1330473600000)
+bool(true)
+float(1330559880000)
+float(1330559880000)
+bool(true)
+float(1330559911000)
+float(1330559911000)
+==DONE== \ No newline at end of file
diff --git a/ext/intl/tests/calendar_toDateTime_basic.phpt b/ext/intl/tests/calendar_toDateTime_basic.phpt
new file mode 100644
index 0000000000..d38487dabf
--- /dev/null
+++ b/ext/intl/tests/calendar_toDateTime_basic.phpt
@@ -0,0 +1,23 @@
+--TEST--
+IntlCalendar::toDateTime(): basic test
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+//ini_set("intl.default_locale", "nl");
+ini_set('date.timezone', 'Europe/Lisbon');
+
+$cal = new IntlGregorianCalendar(2012,04,17,17,35,36);
+
+$dt = $cal->toDateTime();
+
+var_dump($dt->format("c"), $dt->getTimeZone()->getName());
+?>
+==DONE==
+--EXPECT--
+string(25) "2012-05-17T17:35:36+01:00"
+string(13) "Europe/Lisbon"
+==DONE== \ No newline at end of file
diff --git a/ext/intl/tests/calendar_toDateTime_error.phpt b/ext/intl/tests/calendar_toDateTime_error.phpt
new file mode 100644
index 0000000000..961a9c86a6
--- /dev/null
+++ b/ext/intl/tests/calendar_toDateTime_error.phpt
@@ -0,0 +1,41 @@
+--TEST--
+IntlCalendar::toDateTime(): bad arguments
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+ini_set('date.timezone', 'Europe/Lisbon');
+
+$cal = new IntlGregorianCalendar();
+var_dump($cal->toDateTime(3));
+
+var_dump(intlcal_to_date_time($cal, 3));
+
+$cal = new IntlGregorianCalendar("Etc/Unknown");
+try {
+var_dump($cal->toDateTime());
+} catch (Exception $e) {
+var_dump("exception: {$e->getMessage()}");
+}
+
+var_dump(intlcal_to_date_time(3));
+
+--EXPECTF--
+
+Warning: IntlCalendar::toDateTime() expects exactly 0 parameters, 1 given in %s on line %d
+
+Warning: IntlCalendar::toDateTime(): intlcal_to_date_time: bad arguments in %s on line %d
+bool(false)
+
+Warning: intlcal_to_date_time() expects exactly 1 parameter, 2 given in %s on line %d
+
+Warning: intlcal_to_date_time(): intlcal_to_date_time: bad arguments in %s on line %d
+bool(false)
+
+Warning: IntlCalendar::toDateTime(): intlcal_to_date_time: DateTimeZone constructor threw exception in %s on line %d
+string(77) "exception: DateTimeZone::__construct(): Unknown or bad timezone (Etc/Unknown)"
+
+Catchable fatal error: Argument 1 passed to intlcal_to_date_time() must be an instance of IntlCalendar, integer given in %s on line %d
diff --git a/ext/intl/tests/cpbi_clone_equality.phpt b/ext/intl/tests/cpbi_clone_equality.phpt
new file mode 100644
index 0000000000..c62b452747
--- /dev/null
+++ b/ext/intl/tests/cpbi_clone_equality.phpt
@@ -0,0 +1,33 @@
+--TEST--
+IntlCodePointBreakIterator: clone and equality
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+ini_set("intl.default_locale", "pt_PT");
+
+$text = 'ตัวอย่างข้อความ';
+$text2 = 'foo';
+
+$it = IntlBreakIterator::createCodePointInstance();
+$it->setText($text);
+
+$it_clone = clone $it;
+var_dump($it == $it_clone);
+
+$it->setText($text2 );
+var_dump($it == $it_clone);
+
+$it_clone->setText($text2);
+var_dump($it == $it_clone);
+
+?>
+==DONE==
+--EXPECT--
+bool(true)
+bool(false)
+bool(true)
+==DONE==
diff --git a/ext/intl/tests/cpbi_getLastCodePoint_basic.phpt b/ext/intl/tests/cpbi_getLastCodePoint_basic.phpt
new file mode 100644
index 0000000000..74a07a6292
--- /dev/null
+++ b/ext/intl/tests/cpbi_getLastCodePoint_basic.phpt
@@ -0,0 +1,82 @@
+--TEST--
+IntlCodepointBreakIterator::getLastCodePoint(): basic test
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+ini_set("intl.default_locale", "pt_PT");
+
+$text = 'ตัวอย่างข้อความ';
+
+$codepoint_it = IntlBreakIterator::createCodePointInstance();
+$codepoint_it->setText($text);
+
+var_dump($codepoint_it->getLastCodePoint());
+//first() and last() don't read codepoint and set the last code point var to -1
+//The pointer is after the last read codepoint if moving forward and
+//before the last read codepoint is moving backwards
+$p = $codepoint_it->first();
+while ($p != IntlBreakIterator::DONE) {
+ $c = $codepoint_it->getLastCodePoint();
+ if ($c > 0)
+ var_dump(sprintf('U+%04X', $codepoint_it->getLastCodePoint()));
+ else
+ var_dump($c);
+ //it's a post-increment operation as to the codepoint, i.e., it gives the codepoint
+ //starting at the initial position and only then moves the pointer forward
+ $p = $codepoint_it->next();
+}
+
+echo "Now backwards\n";
+$p = $codepoint_it->last();
+while ($p != IntlBreakIterator::DONE) {
+ $c = $codepoint_it->getLastCodePoint();
+ if ($c > 0)
+ var_dump(sprintf('U+%04X', $codepoint_it->getLastCodePoint()));
+ else
+ var_dump($c);
+ $p = $codepoint_it->previous();
+}
+
+
+?>
+==DONE==
+--EXPECT--
+int(-1)
+int(-1)
+string(6) "U+0E15"
+string(6) "U+0E31"
+string(6) "U+0E27"
+string(6) "U+0E2D"
+string(6) "U+0E22"
+string(6) "U+0E48"
+string(6) "U+0E32"
+string(6) "U+0E07"
+string(6) "U+0E02"
+string(6) "U+0E49"
+string(6) "U+0E2D"
+string(6) "U+0E04"
+string(6) "U+0E27"
+string(6) "U+0E32"
+string(6) "U+0E21"
+Now backwards
+int(-1)
+string(6) "U+0E21"
+string(6) "U+0E32"
+string(6) "U+0E27"
+string(6) "U+0E04"
+string(6) "U+0E2D"
+string(6) "U+0E49"
+string(6) "U+0E02"
+string(6) "U+0E07"
+string(6) "U+0E32"
+string(6) "U+0E48"
+string(6) "U+0E22"
+string(6) "U+0E2D"
+string(6) "U+0E27"
+string(6) "U+0E31"
+string(6) "U+0E15"
+==DONE==
diff --git a/ext/intl/tests/cpbi_getLastCodePoint_error.phpt b/ext/intl/tests/cpbi_getLastCodePoint_error.phpt
new file mode 100644
index 0000000000..78bd216629
--- /dev/null
+++ b/ext/intl/tests/cpbi_getLastCodePoint_error.phpt
@@ -0,0 +1,19 @@
+--TEST--
+IntlBreakIterator::getLastCodePoint(): bad args
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+
+$it = IntlBreakIterator::createCodePointInstance();
+var_dump($it->getLastCodePoint(array()));
+--EXPECTF--
+
+Warning: IntlCodePointBreakIterator::getLastCodePoint() expects exactly 0 parameters, 1 given in %s on line %d
+
+Warning: IntlCodePointBreakIterator::getLastCodePoint(): cpbi_get_last_code_point: bad arguments in %s on line %d
+bool(false)
+
diff --git a/ext/intl/tests/cpbi_parts_iterator.phpt b/ext/intl/tests/cpbi_parts_iterator.phpt
new file mode 100644
index 0000000000..4754c12371
--- /dev/null
+++ b/ext/intl/tests/cpbi_parts_iterator.phpt
@@ -0,0 +1,40 @@
+--TEST--
+IntlCodepointBreakIterator's part iterator
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+ini_set("intl.default_locale", "pt_PT");
+
+$text = 'ตัวอย่างข้อความ';
+
+$it = IntlBreakIterator::createCodePointInstance()->getPartsIterator();
+$it->getBreakIterator()->setText($text);
+
+foreach ($it as $k => $v) {
+ echo "$k. $v (" . sprintf("U+%04X", $it->getBreakIterator()->getLastCodePoint()) .
+ ") at {$it->getBreakIterator()->current()}\r\n";
+}
+
+?>
+==DONE==
+--EXPECT--
+0. ต (U+0E15) at 3
+1. ั (U+0E31) at 6
+2. ว (U+0E27) at 9
+3. อ (U+0E2D) at 12
+4. ย (U+0E22) at 15
+5. ่ (U+0E48) at 18
+6. า (U+0E32) at 21
+7. ง (U+0E07) at 24
+8. ข (U+0E02) at 27
+9. ้ (U+0E49) at 30
+10. อ (U+0E2D) at 33
+11. ค (U+0E04) at 36
+12. ว (U+0E27) at 39
+13. า (U+0E32) at 42
+14. ม (U+0E21) at 45
+==DONE==
diff --git a/ext/intl/tests/dateformat___construct_bad_tz_cal.phpt b/ext/intl/tests/dateformat___construct_bad_tz_cal.phpt
new file mode 100644
index 0000000000..cfd9338717
--- /dev/null
+++ b/ext/intl/tests/dateformat___construct_bad_tz_cal.phpt
@@ -0,0 +1,32 @@
+--TEST--
+IntlDateFormatter::__construct(): bad timezone or calendar
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+ini_set("intl.default_locale", "pt_PT");
+ini_set("date.timezone", 'Atlantic/Azores');
+
+var_dump(new IntlDateFormatter(NULL, 0, 0, 'bad timezone'));
+
+var_dump(new IntlDateFormatter(NULL, 0, 0, NULL, 3));
+
+var_dump(new IntlDateFormatter(NULL, 0, 0, NULL, new stdclass));
+
+
+?>
+==DONE==
+--EXPECTF--
+
+Warning: IntlDateFormatter::__construct(): datefmt_create: no such time zone: 'bad timezone' in %s on line %d
+NULL
+
+Warning: IntlDateFormatter::__construct(): datefmt_create: invalid value for calendar type; it must be one of IntlDateFormatter::TRADITIONAL (locale's default calendar) or IntlDateFormatter::GREGORIAN. Alternatively, it can be an IntlCalendar object in %s on line %d
+NULL
+
+Warning: IntlDateFormatter::__construct(): datefmt_create: Invalid calendar argument; should be an integer or an IntlCalendar instance in %s on line %d
+NULL
+==DONE==
diff --git a/ext/intl/tests/dateformat_calendars.phpt b/ext/intl/tests/dateformat_calendars.phpt
index 27f380c718..6af02e51c1 100644
--- a/ext/intl/tests/dateformat_calendars.phpt
+++ b/ext/intl/tests/dateformat_calendars.phpt
@@ -41,5 +41,5 @@ string(44) "Sunday, January 1, 2012 5:12:00 AM GMT+05:12"
string(44) "Sunday, January 1, 2012 5:12:00 AM GMT+05:12"
string(42) "Sunday, Tevet 6, 5772 5:12:00 AM GMT+05:12"
-Warning: IntlDateFormatter::__construct(): datefmt_create: invalid value for calendar type; it must be one of IntlDateFormatter::TRADITIONAL (locale's default calendar) or IntlDateFormatter::GREGORIAN in %s on line %d
+Warning: IntlDateFormatter::__construct(): datefmt_create: invalid value for calendar type; it must be one of IntlDateFormatter::TRADITIONAL (locale's default calendar) or IntlDateFormatter::GREGORIAN. Alternatively, it can be an IntlCalendar object in %s on line %d
==DONE==
diff --git a/ext/intl/tests/dateformat_create_cal_arg.phpt b/ext/intl/tests/dateformat_create_cal_arg.phpt
new file mode 100644
index 0000000000..53fb084af9
--- /dev/null
+++ b/ext/intl/tests/dateformat_create_cal_arg.phpt
@@ -0,0 +1,53 @@
+--TEST--
+IntlDateFormatter: several forms of the calendar arg
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+ini_set("intl.default_locale", "pt_PT");
+ini_set("date.timezone", 'Atlantic/Azores');
+
+$ts = strtotime('2012-01-01 00:00:00 UTC');
+
+$cal = new IntlGregorianCalendar('UTC', NULL);
+$df = new IntlDateFormatter('es_ES', 0, 0, NULL, $cal);
+echo $df->format($ts), "\n";
+
+$cal = IntlCalendar::createInstance('UTC', 'en@calendar=islamic');
+$df = new IntlDateFormatter('es_ES', 0, 0, NULL, $cal);
+echo $df->format($ts), "\n";
+
+//override calendar's timezone
+$cal = new IntlGregorianCalendar('UTC', NULL);
+$df = new IntlDateFormatter('es_ES', 0, 0, 'Europe/Madrid', $cal);
+echo $df->format($ts), "\n";
+
+//default calendar is gregorian
+$df = new IntlDateFormatter('es_ES@calendar=islamic', 0, 0);
+echo $df->format($ts), "\n";
+
+//try now with traditional
+$df = new IntlDateFormatter('es_ES@calendar=islamic', 0, 0, NULL, IntlDateFormatter::TRADITIONAL);
+echo $df->format($ts), "\n";
+
+//the timezone can be overridden when not specifying a calendar
+$df = new IntlDateFormatter('es_ES@calendar=islamic', 0, 0, 'UTC', IntlDateFormatter::TRADITIONAL);
+echo $df->format($ts), "\n";
+
+$df = new IntlDateFormatter('es_ES', 0, 0, 'UTC', 0);
+echo $df->format($ts), "\n";
+
+?>
+==DONE==
+--EXPECTF--
+domingo%S 1 de enero de 2012 00:00:00 GMT
+domingo%S 8 de Safar de 1433 00:00:00 GMT
+domingo%S 1 de enero de 2012 01:00:00 Hora estándar de Europa Central
+sábado%S 31 de diciembre de 2011 d.C. 23:00:00 Hora %Sde las Azores
+sábado%S 7 de Safar de 1433 AH 23:00:00 Hora %Sde las Azores
+domingo%S 8 de Safar de 1433 AH 00:00:00 GMT
+domingo%S 1 de enero de 2012 00:00:00 GMT
+==DONE==
diff --git a/ext/intl/tests/dateformat_format.phpt b/ext/intl/tests/dateformat_format.phpt
index e5548196d1..8664eea319 100644
--- a/ext/intl/tests/dateformat_format.phpt
+++ b/ext/intl/tests/dateformat_format.phpt
@@ -5,6 +5,8 @@ datefmt_format_code()
--FILE--
<?php
+//ini_set("intl.error_level", E_WARNING);
+
/*
* Test for the datefmt_format function
*/
@@ -12,7 +14,7 @@ datefmt_format_code()
function ut_main()
{
- $timezone = 'GMT-10';
+ $timezone = 'GMT-10:00';
$locale_arr = array (
'en_US'
@@ -397,24 +399,24 @@ Formatted DateTime is : 20001230 05:04 PM
Date is: stdClass::__set_state(array(
))
------------
-Error while formatting as: 'datefmt_format: object must be an instance of DateTime: U_ILLEGAL_ARGUMENT_ERROR'
+Error while formatting as: 'datefmt_format: invalid object type for date/time (only IntlCalendar and DateTime permitted): U_ILLEGAL_ARGUMENT_ERROR'
------------
Date is: stdClass::__set_state(array(
))
------------
-Error while formatting as: 'datefmt_format: object must be an instance of DateTime: U_ILLEGAL_ARGUMENT_ERROR'
+Error while formatting as: 'datefmt_format: invalid object type for date/time (only IntlCalendar and DateTime permitted): U_ILLEGAL_ARGUMENT_ERROR'
------------
Date is: stdClass::__set_state(array(
))
------------
-Error while formatting as: 'datefmt_format: object must be an instance of DateTime: U_ILLEGAL_ARGUMENT_ERROR'
+Error while formatting as: 'datefmt_format: invalid object type for date/time (only IntlCalendar and DateTime permitted): U_ILLEGAL_ARGUMENT_ERROR'
------------
Date is: stdClass::__set_state(array(
))
------------
-Error while formatting as: 'datefmt_format: object must be an instance of DateTime: U_ILLEGAL_ARGUMENT_ERROR'
+Error while formatting as: 'datefmt_format: invalid object type for date/time (only IntlCalendar and DateTime permitted): U_ILLEGAL_ARGUMENT_ERROR'
------------
Date is: stdClass::__set_state(array(
))
------------
-Error while formatting as: 'datefmt_format: object must be an instance of DateTime: U_ILLEGAL_ARGUMENT_ERROR'
+Error while formatting as: 'datefmt_format: invalid object type for date/time (only IntlCalendar and DateTime permitted): U_ILLEGAL_ARGUMENT_ERROR'
diff --git a/ext/intl/tests/dateformat_formatObject_calendar.phpt b/ext/intl/tests/dateformat_formatObject_calendar.phpt
new file mode 100644
index 0000000000..0c61e4f2d0
--- /dev/null
+++ b/ext/intl/tests/dateformat_formatObject_calendar.phpt
@@ -0,0 +1,41 @@
+--TEST--
+IntlDateFormatter::formatObject(): IntlCalendar tests
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+ini_set("intl.default_locale", "pt_PT");
+ini_set("date.timezone", "Europe/Lisbon");
+
+$cal = IntlCalendar::fromDateTime('2012-01-01 00:00:00'); //Europe/Lisbon
+echo IntlDateFormatter::formatObject($cal), "\n";
+echo IntlDateFormatter::formatObject($cal, IntlDateFormatter::FULL), "\n";
+echo IntlDateFormatter::formatObject($cal, null, "en-US"), "\n";
+echo IntlDateFormatter::formatObject($cal, array(IntlDateFormatter::SHORT, IntlDateFormatter::FULL), "en-US"), "\n";
+echo IntlDateFormatter::formatObject($cal, 'E y-MM-d HH,mm,ss.SSS v', "en-US"), "\n";
+
+$cal = IntlCalendar::fromDateTime('2012-01-01 05:00:00+03:00');
+echo datefmt_format_object($cal, IntlDateFormatter::FULL), "\n";
+
+$cal = IntlCalendar::createInstance(null,'en-US@calendar=islamic-civil');
+$cal->setTime(strtotime('2012-01-01 00:00:00')*1000.);
+echo IntlDateFormatter::formatObject($cal), "\n";
+echo IntlDateFormatter::formatObject($cal, IntlDateFormatter::FULL, "en-US"), "\n";
+
+?>
+==DONE==
+
+--EXPECTF--
+01/01/2012 00:00:00
+Domingo, 1 de Janeiro de 2012 0:00:00 Hora %Sda Europa Ocidental
+Jan 1, 2012 12:00:00 AM
+1/1/12 12:00:00 AM Western European %STime
+Sun 2012-01-1 00,00,00.000 Portugal Time (Lisbon)
+Domingo, 1 de Janeiro de 2012 5:00:00 GMT+03:00
+06/02/1433 00:00:00
+Sunday, Safar 6, 1433 12:00:00 AM Western European %STime
+==DONE==
+
diff --git a/ext/intl/tests/dateformat_formatObject_datetime.phpt b/ext/intl/tests/dateformat_formatObject_datetime.phpt
new file mode 100644
index 0000000000..6427ad5a98
--- /dev/null
+++ b/ext/intl/tests/dateformat_formatObject_datetime.phpt
@@ -0,0 +1,34 @@
+--TEST--
+IntlDateFormatter::formatObject(): DateTime tests
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+ini_set("intl.default_locale", "pt_PT");
+ini_set("date.timezone", "Europe/Lisbon");
+
+$dt = new DateTime('2012-01-01 00:00:00'); //Europe/Lisbon
+echo IntlDateFormatter::formatObject($dt), "\n";
+echo IntlDateFormatter::formatObject($dt, IntlDateFormatter::FULL), "\n";
+echo IntlDateFormatter::formatObject($dt, null, "en-US"), "\n";
+echo IntlDateFormatter::formatObject($dt, array(IntlDateFormatter::SHORT, IntlDateFormatter::FULL), "en-US"), "\n";
+echo IntlDateFormatter::formatObject($dt, 'E y-MM-d HH,mm,ss.SSS v', "en-US"), "\n";
+
+$dt = new DateTime('2012-01-01 05:00:00+03:00');
+echo IntlDateFormatter::formatObject($dt, IntlDateFormatter::FULL), "\n";
+
+?>
+==DONE==
+
+--EXPECTF--
+01/01/2012 00:00:00
+Domingo, 1 de Janeiro de 2012 0:00:00 Hora %Sda Europa Ocidental
+Jan 1, 2012 12:00:00 AM
+1/1/12 12:00:00 AM Western European %STime
+Sun 2012-01-1 00,00,00.000 Portugal Time (Lisbon)
+Domingo, 1 de Janeiro de 2012 5:00:00 GMT+03:00
+==DONE==
+
diff --git a/ext/intl/tests/dateformat_formatObject_error.phpt b/ext/intl/tests/dateformat_formatObject_error.phpt
new file mode 100644
index 0000000000..7aaf69e54e
--- /dev/null
+++ b/ext/intl/tests/dateformat_formatObject_error.phpt
@@ -0,0 +1,74 @@
+--TEST--
+IntlDateFormatter::formatObject(): error conditions
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+ini_set("intl.default_locale", "pt_PT");
+ini_set("date.timezone", "Europe/Lisbon");
+
+var_dump(IntlDateFormatter::formatObject());
+var_dump(IntlDateFormatter::formatObject(1));
+var_dump(IntlDateFormatter::formatObject(new stdclass));
+
+class A extends IntlCalendar {function __construct(){}}
+var_dump(IntlDateFormatter::formatObject(new A));
+class B extends DateTime {function __construct(){}}
+var_dump(IntlDateFormatter::formatObject(new B));
+
+$cal = IntlCalendar::createInstance();
+var_dump(IntlDateFormatter::formatObject($cal, -2));
+var_dump(IntlDateFormatter::formatObject($cal, array()));
+var_dump(IntlDateFormatter::formatObject($cal, array(1,2,3)));
+var_dump(IntlDateFormatter::formatObject($cal, array(array(), 1)));
+var_dump(IntlDateFormatter::formatObject($cal, array(1, -2)));
+var_dump(IntlDateFormatter::formatObject($cal, ""));
+var_dump(IntlDateFormatter::formatObject($cal, "YYYY", array()));
+
+?>
+==DONE==
+
+--EXPECTF--
+
+Warning: IntlDateFormatter::formatObject() expects at least 1 parameter, 0 given in %s on line %d
+bool(false)
+
+Warning: IntlDateFormatter::formatObject() expects parameter 1 to be object, integer given in %s on line %d
+bool(false)
+
+Warning: IntlDateFormatter::formatObject(): datefmt_format_object: the passed object must be an instance of either IntlCalendar or DateTime in %s on line %d
+bool(false)
+
+Warning: IntlDateFormatter::formatObject(): datefmt_format_object: bad IntlCalendar instance: not initialized properly in %s on line %d
+bool(false)
+
+Warning: DateTime::getTimestamp(): The DateTime object has not been correctly initialized by its constructor in %s on line %d
+
+Warning: IntlDateFormatter::formatObject(): datefmt_format_object: error calling ::getTimeStamp() on the object in %s on line %d
+bool(false)
+
+Warning: IntlDateFormatter::formatObject(): datefmt_format_object: the date/time format type is invalid in %s on line %d
+bool(false)
+
+Warning: IntlDateFormatter::formatObject(): datefmt_format_object: bad format; if array, it must have two elements in %s on line %d
+bool(false)
+
+Warning: IntlDateFormatter::formatObject(): datefmt_format_object: bad format; if array, it must have two elements in %s on line %d
+bool(false)
+
+Warning: IntlDateFormatter::formatObject(): datefmt_format_object: bad format; the date format (first element of the array) is not valid in %s on line %d
+bool(false)
+
+Warning: IntlDateFormatter::formatObject(): datefmt_format_object: bad format; the time format (second element of the array) is not valid in %s on line %d
+bool(false)
+
+Warning: IntlDateFormatter::formatObject(): datefmt_format_object: the format is empty in %s on line %d
+bool(false)
+
+Warning: IntlDateFormatter::formatObject() expects parameter 3 to be string, array given in %s on line %d
+bool(false)
+==DONE==
+
diff --git a/ext/intl/tests/dateformat_format_parse.phpt b/ext/intl/tests/dateformat_format_parse.phpt
index bd41d715b9..6bd3d8a8ff 100644
--- a/ext/intl/tests/dateformat_format_parse.phpt
+++ b/ext/intl/tests/dateformat_format_parse.phpt
@@ -12,7 +12,7 @@ datefmt_format_code() and datefmt_parse_code()
function ut_main()
{
- $timezone = 'GMT+5';
+ $timezone = 'GMT+05:00';
$locale_arr = array (
'en_US'
diff --git a/ext/intl/tests/dateformat_getCalendarObject_error.phpt b/ext/intl/tests/dateformat_getCalendarObject_error.phpt
new file mode 100644
index 0000000000..d2ad66c829
--- /dev/null
+++ b/ext/intl/tests/dateformat_getCalendarObject_error.phpt
@@ -0,0 +1,43 @@
+--TEST--
+IntlDateFormatter::getCalendarObject(): bad args
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+ini_set("intl.default_locale", "pt_PT");
+ini_set("date.timezone", 'Atlantic/Azores');
+
+$df = new IntlDateFormatter(NULL, 0, 0);
+
+var_dump($df->getCalendarObject(9));
+var_dump(datefmt_get_calendar_object($df, 9));
+var_dump(datefmt_get_calendar_object($df, 9));
+var_dump(datefmt_get_calendar_object(new stdclass));
+
+?>
+==DONE==
+--EXPECTF--
+
+Warning: IntlDateFormatter::getCalendarObject() expects exactly 0 parameters, 1 given in %s on line %d
+
+Warning: IntlDateFormatter::getCalendarObject(): datefmt_get_calendar_object: unable to parse input params in %s on line %d
+bool(false)
+
+Warning: datefmt_get_calendar_object() expects exactly 1 parameter, 2 given in %s on line %d
+
+Warning: datefmt_get_calendar_object(): datefmt_get_calendar_object: unable to parse input params in %s on line %d
+bool(false)
+
+Warning: datefmt_get_calendar_object() expects exactly 1 parameter, 2 given in %s on line %d
+
+Warning: datefmt_get_calendar_object(): datefmt_get_calendar_object: unable to parse input params in %s on line %d
+bool(false)
+
+Warning: datefmt_get_calendar_object() expects parameter 1 to be IntlDateFormatter, object given in %s on line %d
+
+Warning: datefmt_get_calendar_object(): datefmt_get_calendar_object: unable to parse input params in %s on line %d
+bool(false)
+==DONE==
diff --git a/ext/intl/tests/dateformat_getTimeZone_error.phpt b/ext/intl/tests/dateformat_getTimeZone_error.phpt
new file mode 100644
index 0000000000..4ac5555d88
--- /dev/null
+++ b/ext/intl/tests/dateformat_getTimeZone_error.phpt
@@ -0,0 +1,43 @@
+--TEST--
+IntlDateFormatter::getTimeZone(): bad args
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+ini_set("intl.default_locale", "pt_PT");
+ini_set("date.timezone", 'Atlantic/Azores');
+
+$df = new IntlDateFormatter(NULL, 0, 0);
+
+var_dump($df->getTimeZone(9));
+var_dump(datefmt_get_timezone($df, 9));
+var_dump(datefmt_get_timezone($df, 9));
+var_dump(datefmt_get_timezone(new stdclass));
+
+?>
+==DONE==
+--EXPECTF--
+
+Warning: IntlDateFormatter::getTimeZone() expects exactly 0 parameters, 1 given in %s on line %d
+
+Warning: IntlDateFormatter::getTimeZone(): datefmt_get_timezone: unable to parse input params in %s on line %d
+bool(false)
+
+Warning: datefmt_get_timezone() expects exactly 1 parameter, 2 given in %s on line %d
+
+Warning: datefmt_get_timezone(): datefmt_get_timezone: unable to parse input params in %s on line %d
+bool(false)
+
+Warning: datefmt_get_timezone() expects exactly 1 parameter, 2 given in %s on line %d
+
+Warning: datefmt_get_timezone(): datefmt_get_timezone: unable to parse input params in %s on line %d
+bool(false)
+
+Warning: datefmt_get_timezone() expects parameter 1 to be IntlDateFormatter, object given in %s on line %d
+
+Warning: datefmt_get_timezone(): datefmt_get_timezone: unable to parse input params in %s on line %d
+bool(false)
+==DONE==
diff --git a/ext/intl/tests/dateformat_get_set_calendar.phpt b/ext/intl/tests/dateformat_get_set_calendar.phpt
index bfd4e578e1..dbb3e6cd23 100644
--- a/ext/intl/tests/dateformat_get_set_calendar.phpt
+++ b/ext/intl/tests/dateformat_get_set_calendar.phpt
@@ -1,60 +1,55 @@
--TEST--
-datefmt_get_calendar_code() datefmt_set_calendar_code()
+IntlDateFormatter: setCalendar()/getCalendar()/getCalendarObject()
--SKIPIF--
-<?php if( !extension_loaded( 'intl' ) ) print 'skip'; ?>
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
--FILE--
<?php
+ini_set("intl.error_level", E_WARNING);
+ini_set("intl.default_locale", "pt_PT");
+ini_set("date.timezone", 'Atlantic/Azores');
+
+$ts = strtotime('2012-01-01 00:00:00 UTC');
+
+function d(IntlDateFormatter $df) {
+global $ts;
+echo $df->format($ts), "\n";
+var_dump($df->getCalendar(),
+$df->getCalendarObject()->getType(),
+$df->getCalendarObject()->getTimeZone()->getId());
+echo "\n";
+}
-/*
- * Test for the datefmt_get_calendar and datefmt_set_calendar functions
- */
-
-
-function ut_main()
-{
- $calendar_arr = array (
- IntlDateFormatter::GREGORIAN,
- IntlDateFormatter::TRADITIONAL,
- 3
- );
-
- $res_str = '';
-
- $start_calendar = IntlDateFormatter::GREGORIAN;
- $res_str .= "\nCreating IntlDateFormatter with calendar = $start_calendar";
- $fmt = ut_datefmt_create( "de-DE", IntlDateFormatter::SHORT, IntlDateFormatter::SHORT ,'America/Los_Angeles', IntlDateFormatter::GREGORIAN);
- $calendar = ut_datefmt_get_calendar( $fmt);
- $res_str .= "\nAfter call to get_calendar : calendar= $calendar";
- $res_str .= "\n-------------------";
-
- foreach( $calendar_arr as $calendar_entry )
- {
- $res_str .= "\nSetting IntlDateFormatter with calendar = $calendar_entry";
- ut_datefmt_set_calendar( $fmt, $calendar_entry);
- $calendar = ut_datefmt_get_calendar( $fmt);
- $res_str .= "\nAfter call to get_calendar : calendar= $calendar";
- $res_str .= "\n-------------------";
- }
-
- return $res_str;
+$df = new IntlDateFormatter('fr@calendar=islamic', 0, 0, 'Europe/Minsk');
+d($df);
-}
-include_once( 'ut_common.inc' );
+//changing the calendar with a cal type should not change tz
+$df->setCalendar(IntlDateFormatter::TRADITIONAL);
+d($df);
+
+//but changing with an actual calendar should
+$cal = IntlCalendar::createInstance("UTC");
+$df->setCalendar($cal);
+d($df);
-// Run the test
-ut_run();
?>
+==DONE==
--EXPECT--
-Creating IntlDateFormatter with calendar = 1
-After call to get_calendar : calendar= 1
--------------------
-Setting IntlDateFormatter with calendar = 1
-After call to get_calendar : calendar= 1
--------------------
-Setting IntlDateFormatter with calendar = 0
-After call to get_calendar : calendar= 0
--------------------
-Setting IntlDateFormatter with calendar = 3
-After call to get_calendar : calendar= 0
-------------------- \ No newline at end of file
+dimanche 1 janvier 2012 ap. J.-C. 03:00:00 UTC+03:00
+int(1)
+string(9) "gregorian"
+string(12) "Europe/Minsk"
+
+dimanche 8 Safar 1433 AH 03:00:00 UTC+03:00
+int(0)
+string(7) "islamic"
+string(12) "Europe/Minsk"
+
+dimanche 1 janvier 2012 ap. J.-C. 00:00:00 UTC
+bool(false)
+string(9) "gregorian"
+string(3) "UTC"
+
+==DONE==
diff --git a/ext/intl/tests/dateformat_get_set_timezone.phpt b/ext/intl/tests/dateformat_get_set_timezone.phpt
new file mode 100644
index 0000000000..41aa35b9cf
--- /dev/null
+++ b/ext/intl/tests/dateformat_get_set_timezone.phpt
@@ -0,0 +1,62 @@
+--TEST--
+IntlDateFormatter: get/setTimeZone()
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+ini_set("intl.default_locale", "pt_PT");
+ini_set("date.timezone", 'Atlantic/Azores');
+
+$ts = strtotime('2012-01-01 00:00:00 UTC');
+
+function d(IntlDateFormatter $df) {
+global $ts;
+echo $df->format($ts), "\n";
+var_dump(
+$df->getTimeZoneID(),
+$df->getTimeZone()->getID());
+echo "\n";
+}
+
+$df = new IntlDateFormatter('pt_PT', 0, 0, 'Europe/Minsk');
+d($df);
+
+$df->setTimeZone(NULL);
+d($df);
+
+$df->setTimeZone('Europe/Madrid');
+d($df);
+
+$df->setTimeZone(IntlTimeZone::createTimeZone('Europe/Paris'));
+d($df);
+
+$df->setTimeZone(new DateTimeZone('Europe/Amsterdam'));
+d($df);
+
+?>
+==DONE==
+--EXPECTF--
+Domingo, 1 de Janeiro de 2012 3:00:00 GMT+03:00
+string(12) "Europe/Minsk"
+string(12) "Europe/Minsk"
+
+Sábado, 31 de Dezembro de 2011 23:00:00 Hor%s %Sdos Açores
+string(15) "Atlantic/Azores"
+string(15) "Atlantic/Azores"
+
+Domingo, 1 de Janeiro de 2012 1:00:00 Hor%s %Sda Europa Central
+string(13) "Europe/Madrid"
+string(13) "Europe/Madrid"
+
+Domingo, 1 de Janeiro de 2012 1:00:00 Hor%s %Sda Europa Central
+string(12) "Europe/Paris"
+string(12) "Europe/Paris"
+
+Domingo, 1 de Janeiro de 2012 1:00:00 Hor%s %Sda Europa Central
+string(16) "Europe/Amsterdam"
+string(16) "Europe/Amsterdam"
+
+==DONE==
diff --git a/ext/intl/tests/dateformat_get_timezone_id.phpt b/ext/intl/tests/dateformat_get_timezone_id.phpt
index 80cbdbbf0f..a9701c3868 100644
--- a/ext/intl/tests/dateformat_get_timezone_id.phpt
+++ b/ext/intl/tests/dateformat_get_timezone_id.phpt
@@ -1,5 +1,8 @@
--TEST--
datefmt_get_timezone_id_code()
+--INI--
+date.timezone=Atlantic/Azores
+intl.error_level=E_WARNING
--SKIPIF--
<?php if( !extension_loaded( 'intl' ) ) print 'skip'; ?>
--FILE--
@@ -14,8 +17,8 @@ function ut_main()
{
$timezone_id_arr = array (
'America/New_York',
- 'America/Los_Angeles',
- 'America/Dallas'
+ 'US/Pacific',
+ 'US/Central'
);
$res_str = '';
@@ -42,8 +45,8 @@ ut_run();
Creating IntlDateFormatter with timezone_id = America/New_York
After call to get_timezone_id : timezone_id= America/New_York
-Creating IntlDateFormatter with timezone_id = America/Los_Angeles
-After call to get_timezone_id : timezone_id= America/Los_Angeles
+Creating IntlDateFormatter with timezone_id = US/Pacific
+After call to get_timezone_id : timezone_id= US/Pacific
-Creating IntlDateFormatter with timezone_id = America/Dallas
-After call to get_timezone_id : timezone_id= America/Dallas
+Creating IntlDateFormatter with timezone_id = US/Central
+After call to get_timezone_id : timezone_id= US/Central
diff --git a/ext/intl/tests/dateformat_setTimeZoneID_deprecation.phpt b/ext/intl/tests/dateformat_setTimeZoneID_deprecation.phpt
new file mode 100644
index 0000000000..5ee5b94d24
--- /dev/null
+++ b/ext/intl/tests/dateformat_setTimeZoneID_deprecation.phpt
@@ -0,0 +1,22 @@
+--TEST--
+IntlDateFormatter: setTimeZoneID() deprecation
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+ini_set("intl.default_locale", "pt_PT");
+ini_set("date.timezone", 'Atlantic/Azores');
+
+$df = new IntlDateFormatter('pt_PT', 0, 0, 'Europe/Minsk');
+
+$df->setTimeZoneId('Europe/Madrid');
+
+?>
+==DONE==
+--EXPECTF--
+
+Deprecated: IntlDateFormatter::setTimeZoneId(): Use datefmt_set_timezone() instead, which also accepts a plain time zone identifier and for which this function is now an alias in %s on line %d
+==DONE==
diff --git a/ext/intl/tests/dateformat_setTimeZone_error.phpt b/ext/intl/tests/dateformat_setTimeZone_error.phpt
new file mode 100644
index 0000000000..bd37031325
--- /dev/null
+++ b/ext/intl/tests/dateformat_setTimeZone_error.phpt
@@ -0,0 +1,53 @@
+--TEST--
+IntlDateFormatter::setTimeZone() bad args
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+ini_set("intl.default_locale", "pt_PT");
+ini_set("date.timezone", 'Atlantic/Azores');
+
+$df = new IntlDateFormatter(NULL, 0, 0);
+
+var_dump($df->setTimeZone());
+var_dump(datefmt_set_timezone());
+var_dump($df->setTimeZone(array()));
+var_dump($df->setTimeZone(1, 2));
+var_dump($df->setTimeZone('non existing timezone'));
+var_dump(datefmt_set_timezone(new stdclass, 'UTC'));
+
+?>
+==DONE==
+--EXPECTF--
+
+Warning: IntlDateFormatter::setTimeZone() expects exactly 1 parameter, 0 given in %s on line %d
+
+Warning: IntlDateFormatter::setTimeZone(): datefmt_set_timezone: unable to parse input params in %s on line %d
+bool(false)
+
+Warning: datefmt_set_timezone() expects exactly 2 parameters, 0 given in %s on line %d
+
+Warning: datefmt_set_timezone(): datefmt_set_timezone: unable to parse input params in %s on line %d
+bool(false)
+
+Notice: Array to string conversion in %s on line %d
+
+Warning: IntlDateFormatter::setTimeZone(): datefmt_set_timezone: no such time zone: 'Array' in %s on line %d
+bool(false)
+
+Warning: IntlDateFormatter::setTimeZone() expects exactly 1 parameter, 2 given in %s on line %d
+
+Warning: IntlDateFormatter::setTimeZone(): datefmt_set_timezone: unable to parse input params in %s on line %d
+bool(false)
+
+Warning: IntlDateFormatter::setTimeZone(): datefmt_set_timezone: no such time zone: 'non existing timezone' in %s on line %d
+bool(false)
+
+Warning: datefmt_set_timezone() expects parameter 1 to be IntlDateFormatter, object given in %s on line %d
+
+Warning: datefmt_set_timezone(): datefmt_set_timezone: unable to parse input params in %s on line %d
+bool(false)
+==DONE==
diff --git a/ext/intl/tests/dateformat_set_timezone_id2.phpt b/ext/intl/tests/dateformat_set_timezone_id2.phpt
index 23aacda90a..ce9b89d1fd 100644
--- a/ext/intl/tests/dateformat_set_timezone_id2.phpt
+++ b/ext/intl/tests/dateformat_set_timezone_id2.phpt
@@ -1,11 +1,16 @@
--TEST--
datefmt_set_timezone_id_code() icu >= 4.8
+--INI--
+date.timezone=Atlantic/Azores
--SKIPIF--
<?php if( !extension_loaded( 'intl' ) ) print 'skip'; ?>
<?php if(version_compare(INTL_ICU_VERSION, '4.8') < 0) print 'skip'; ?>
--FILE--
<?php
+ini_set("intl.error_level", E_WARNING);
+ini_set("error_reporting", ~E_DEPRECATED);
+
/*
* Test for the datefmt_set_timezone_id function
*/
@@ -23,7 +28,7 @@ function ut_main()
$res_str = '';
- $fmt = ut_datefmt_create( "en_US", IntlDateFormatter::FULL, IntlDateFormatter::FULL, 'America/San_Francisco' , IntlDateFormatter::GREGORIAN );
+ $fmt = ut_datefmt_create( "en_US", IntlDateFormatter::FULL, IntlDateFormatter::FULL, 'US/Pacific' , IntlDateFormatter::GREGORIAN );
$timezone_id = ut_datefmt_get_timezone_id( $fmt );
$res_str .= "\nAfter creation of the dateformatter : timezone_id= $timezone_id\n";
@@ -52,8 +57,13 @@ include_once( 'ut_common.inc' );
// Run the test
ut_run();
?>
---EXPECT--
-After creation of the dateformatter : timezone_id= America/San_Francisco
+--EXPECTF--
+
+Warning: IntlDateFormatter::setTimeZoneId(): datefmt_set_timezone: no such time zone: 'CN' in %s on line %d
+
+Warning: datefmt_set_timezone_id(): datefmt_set_timezone: no such time zone: 'CN' in %s on line %d
+
+After creation of the dateformatter : timezone_id= US/Pacific
-----------
Trying to set timezone_id= America/New_York
After call to set_timezone_id : timezone_id= America/New_York
@@ -71,6 +81,6 @@ Formatting timestamp=0 resulted in Wednesday, December 31, 1969 6:00:00 PM Cent
Formatting timestamp=3600 resulted in Wednesday, December 31, 1969 7:00:00 PM Central Standard Time
-----------
Trying to set timezone_id= CN
-After call to set_timezone_id : timezone_id= CN
-Formatting timestamp=0 resulted in Thursday, January 1, 1970 12:00:00 AM GMT
-Formatting timestamp=3600 resulted in Thursday, January 1, 1970 1:00:00 AM GMT
+After call to set_timezone_id : timezone_id= America/Chicago
+Formatting timestamp=0 resulted in Wednesday, December 31, 1969 6:00:00 PM Central Standard Time
+Formatting timestamp=3600 resulted in Wednesday, December 31, 1969 7:00:00 PM Central Standard Time
diff --git a/ext/intl/tests/dateformat_timezone_arg_variations.phpt b/ext/intl/tests/dateformat_timezone_arg_variations.phpt
new file mode 100644
index 0000000000..ccfb5e1964
--- /dev/null
+++ b/ext/intl/tests/dateformat_timezone_arg_variations.phpt
@@ -0,0 +1,45 @@
+--TEST--
+IntlDateFormatter: several forms of the timezone arg
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+ini_set("date.timezone", 'Atlantic/Azores');
+
+$ts = strtotime('2012-01-01 00:00:00 UTC');
+
+//should use Atlantic/Azores
+$df = new IntlDateFormatter('es_ES', 0, 0, NULL);
+echo $df->format($ts), "\n";
+
+$df = new IntlDateFormatter('es_ES', 0, 0, 'Europe/Amsterdam');
+echo $df->format($ts), "\n";
+
+$df = new IntlDateFormatter('es_ES', 0, 0, new DateTimeZone('Europe/Lisbon'));
+echo $df->format($ts), "\n";
+
+$df = new IntlDateFormatter('es_ES', 0, 0, IntlTimeZone::createTimeZone('America/New_York'));
+echo $df->format($ts), "\n";
+
+//time zone has priority
+$df = new IntlDateFormatter('es_ES', 0, 0, 'Europe/Amsterdam', new IntlGregorianCalendar('Europe/Lisbon'));
+echo $df->format($ts), "\n";
+
+//calendar has priority
+$df = new IntlDateFormatter('es_ES', 0, 0, NULL, new IntlGregorianCalendar('Europe/Lisbon'));
+echo $df->format($ts), "\n";
+
+$df = new IntlDateFormatter('es_ES', 0, 0, 'Europe/Amsterdam', 0);
+echo $df->format($ts), "\n";
+
+--EXPECTF--
+sábado%S 31 de diciembre de 2011 23:00:00 Hora%S de las Azores
+domingo%S 1 de enero de 2012 01:00:00 Hora estándar de Europa Central
+domingo%S 1 de enero de 2012 00:00:00 Hora%S de Europa Occidental
+sábado%S 31 de diciembre de 2011 19:00:00 Hora estándar oriental
+domingo%S 1 de enero de 2012 01:00:00 Hora estándar de Europa Central
+domingo%S 1 de enero de 2012 00:00:00 Hora%S de Europa Occidental
+domingo%S 1 de enero de 2012 01:00:00 Hora estándar de Europa Central
diff --git a/ext/intl/tests/gregoriancalendar___construct_basic.phpt b/ext/intl/tests/gregoriancalendar___construct_basic.phpt
new file mode 100644
index 0000000000..bdbef6725b
--- /dev/null
+++ b/ext/intl/tests/gregoriancalendar___construct_basic.phpt
@@ -0,0 +1,51 @@
+--TEST--
+IntlGregorianCalendar::__construct(): basic
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+if (version_compare(INTL_ICU_VERSION, '4.8') < 0)
+ die('skip for ICU 4.8+');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+ini_set("intl.default_locale", "nl");
+
+date_default_timezone_set('Europe/Amsterdam');
+
+$intlcal = intlgregcal_create_instance();
+var_dump($intlcal->getTimeZone()->getId());
+var_dump($intlcal->getLocale(1));
+
+$intlcal = new IntlGregorianCalendar('Europe/Lisbon', NULL);
+var_dump($intlcal->getTimeZone()->getId());
+var_dump($intlcal->getLocale(1));
+
+$intlcal = new IntlGregorianCalendar(NULL, 'pt_PT');
+var_dump($intlcal->getTimeZone()->getId());
+var_dump($intlcal->getLocale(1));
+
+$intlcal = new IntlGregorianCalendar('Europe/Lisbon', 'pt_PT');
+var_dump($intlcal->getTimeZone()->getId());
+var_dump($intlcal->getLocale(1));
+
+$intlcal = new IntlGregorianCalendar('Europe/Paris', 'fr_CA', NULL, NULL, NULL, NULL);
+var_dump($intlcal->getTimeZone()->getId());
+var_dump($intlcal->getLocale(1));
+
+var_dump($intlcal->getType());
+?>
+==DONE==
+--EXPECT--
+string(16) "Europe/Amsterdam"
+string(5) "nl_NL"
+string(13) "Europe/Lisbon"
+string(5) "nl_NL"
+string(16) "Europe/Amsterdam"
+string(5) "pt_PT"
+string(13) "Europe/Lisbon"
+string(5) "pt_PT"
+string(12) "Europe/Paris"
+string(5) "fr_CA"
+string(9) "gregorian"
+==DONE== \ No newline at end of file
diff --git a/ext/intl/tests/gregoriancalendar___construct_error.phpt b/ext/intl/tests/gregoriancalendar___construct_error.phpt
new file mode 100644
index 0000000000..0e85394a48
--- /dev/null
+++ b/ext/intl/tests/gregoriancalendar___construct_error.phpt
@@ -0,0 +1,35 @@
+--TEST--
+IntlGregorianCalendar::__construct(): bad arguments
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+
+var_dump(intlgregcal_create_instance(1,2,3,4,5,6,7));
+var_dump(intlgregcal_create_instance(1,2,3,4,5,6,7,8));
+var_dump(intlgregcal_create_instance(1,2,3,4));
+var_dump(new IntlGregorianCalendar(1,2,NULL,4));
+var_dump(new IntlGregorianCalendar(1,2,3,4,NULL,array()));
+
+
+--EXPECTF--
+
+Warning: intlgregcal_create_instance(): intlgregcal_create_instance: too many arguments in %s on line %d
+NULL
+
+Warning: intlgregcal_create_instance(): intlgregcal_create_instance: too many arguments in %s on line %d
+NULL
+
+Warning: intlgregcal_create_instance(): intlgregcal_create_instance: no variant with 4 arguments (excluding trailing NULLs) in %s on line %d
+NULL
+
+Warning: IntlGregorianCalendar::__construct(): intlgregcal_create_instance: no variant with 4 arguments (excluding trailing NULLs) in %s on line %d
+NULL
+
+Warning: IntlGregorianCalendar::__construct() expects parameter 6 to be long, array given in %s on line %d
+
+Warning: IntlGregorianCalendar::__construct(): intlgregcal_create_instance: bad arguments in %s on line %d
+NULL
diff --git a/ext/intl/tests/gregoriancalendar___construct_variant1.phpt b/ext/intl/tests/gregoriancalendar___construct_variant1.phpt
new file mode 100644
index 0000000000..63266b792e
--- /dev/null
+++ b/ext/intl/tests/gregoriancalendar___construct_variant1.phpt
@@ -0,0 +1,30 @@
+--TEST--
+IntlGregorianCalendar::__construct(): argument variants
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+
+date_default_timezone_set('Europe/Amsterdam');
+
+$intlcal = intlgregcal_create_instance(2012, 1, 29, 16, 0, NULL);
+var_dump($intlcal->getTimeZone()->getId());
+var_dump($intlcal->getTime(), (float)strtotime('2012-02-29 16:00:00') * 1000);
+
+$intlcal = new IntlGregorianCalendar(2012, 1, 29, 16, 7, 8);
+var_dump($intlcal->getTime(), (float)strtotime('2012-02-29 16:07:08') * 1000);
+
+var_dump($intlcal->getType());
+?>
+==DONE==
+--EXPECT--
+string(16) "Europe/Amsterdam"
+float(1330527600000)
+float(1330527600000)
+float(1330528028000)
+float(1330528028000)
+string(9) "gregorian"
+==DONE==
diff --git a/ext/intl/tests/gregoriancalendar_getGregorianChange_error.phpt b/ext/intl/tests/gregoriancalendar_getGregorianChange_error.phpt
new file mode 100644
index 0000000000..58d566223b
--- /dev/null
+++ b/ext/intl/tests/gregoriancalendar_getGregorianChange_error.phpt
@@ -0,0 +1,30 @@
+--TEST--
+IntlGregorianCalendar::getGregorianChange(): bad arguments
+--INI--
+date.timezone=Atlantic/Azores
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+
+$c = new IntlGregorianCalendar(NULL, 'pt_PT');
+var_dump($c->getGregorianChange(1));
+
+var_dump(intlgregcal_get_gregorian_change($c, 1));
+var_dump(intlgregcal_get_gregorian_change(1));
+--EXPECTF--
+
+Warning: IntlGregorianCalendar::getGregorianChange() expects exactly 0 parameters, 1 given in %s on line %d
+
+Warning: IntlGregorianCalendar::getGregorianChange(): intlgregcal_get_gregorian_change: bad arguments in %s on line %d
+bool(false)
+
+Warning: intlgregcal_get_gregorian_change() expects exactly 1 parameter, 2 given in %s on line %d
+
+Warning: intlgregcal_get_gregorian_change(): intlgregcal_get_gregorian_change: bad arguments in %s on line %d
+bool(false)
+
+Catchable fatal error: Argument 1 passed to intlgregcal_get_gregorian_change() must be an instance of IntlGregorianCalendar, integer given in %s on line %d
diff --git a/ext/intl/tests/gregoriancalendar_get_setGregorianChange_basic.phpt b/ext/intl/tests/gregoriancalendar_get_setGregorianChange_basic.phpt
new file mode 100644
index 0000000000..b08ad7981f
--- /dev/null
+++ b/ext/intl/tests/gregoriancalendar_get_setGregorianChange_basic.phpt
@@ -0,0 +1,32 @@
+--TEST--
+IntlGregorianCalendar::get/setGregorianChange(): basic test
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+ini_set("intl.default_locale", "nl");
+
+date_default_timezone_set('Europe/Amsterdam');
+
+$intlcal = new IntlGregorianCalendar();
+
+var_dump($intlcal->getGregorianChange());
+
+var_dump($intlcal->setGregorianChange(0));
+var_dump(intlgregcal_get_gregorian_change($intlcal));
+
+var_dump(intlgregcal_set_gregorian_change($intlcal, 1));
+var_dump($intlcal->getGregorianChange());
+
+?>
+==DONE==
+--EXPECT--
+float(-12219292800000)
+bool(true)
+float(0)
+bool(true)
+float(1)
+==DONE== \ No newline at end of file
diff --git a/ext/intl/tests/gregoriancalendar_isLeapYear_basic.phpt b/ext/intl/tests/gregoriancalendar_isLeapYear_basic.phpt
new file mode 100644
index 0000000000..b37452fcba
--- /dev/null
+++ b/ext/intl/tests/gregoriancalendar_isLeapYear_basic.phpt
@@ -0,0 +1,28 @@
+--TEST--
+IntlGregorianCalendar::isLeapYear(): basic test
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+ini_set("intl.default_locale", "nl");
+
+date_default_timezone_set('Europe/Amsterdam');
+
+$intlcal = new IntlGregorianCalendar();
+
+var_dump($intlcal->isLeapYear(2012));
+var_dump($intlcal->isLeapYear(1900));
+
+var_dump(intlgregcal_is_leap_year($intlcal, 2012));
+var_dump(intlgregcal_is_leap_year($intlcal, 1900));
+?>
+==DONE==
+--EXPECT--
+bool(true)
+bool(false)
+bool(true)
+bool(false)
+==DONE== \ No newline at end of file
diff --git a/ext/intl/tests/gregoriancalendar_isLeapYear_error.phpt b/ext/intl/tests/gregoriancalendar_isLeapYear_error.phpt
new file mode 100644
index 0000000000..40a6c85396
--- /dev/null
+++ b/ext/intl/tests/gregoriancalendar_isLeapYear_error.phpt
@@ -0,0 +1,48 @@
+--TEST--
+IntlGregorianCalendar::isLeapYear(): bad arguments
+--INI--
+date.timezone=Atlantic/Azores
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+
+$c = new IntlGregorianCalendar(NULL, 'pt_PT');
+var_dump($c->isLeapYear(2000, 2011));
+var_dump($c->isLeapYear());
+var_dump($c->isLeapYear("fgdf"));
+
+var_dump(intlgregcal_is_leap_year($c, 1, 2));
+var_dump(intlgregcal_is_leap_year($c));
+var_dump(intlgregcal_is_leap_year(1, 2));
+--EXPECTF--
+
+Warning: IntlGregorianCalendar::isLeapYear() expects exactly 1 parameter, 2 given in %s on line %d
+
+Warning: IntlGregorianCalendar::isLeapYear(): intlgregcal_is_leap_year: bad arguments in %s on line %d
+bool(false)
+
+Warning: IntlGregorianCalendar::isLeapYear() expects exactly 1 parameter, 0 given in %s on line %d
+
+Warning: IntlGregorianCalendar::isLeapYear(): intlgregcal_is_leap_year: bad arguments in %s on line %d
+bool(false)
+
+Warning: IntlGregorianCalendar::isLeapYear() expects parameter 1 to be long, string given in %s on line %d
+
+Warning: IntlGregorianCalendar::isLeapYear(): intlgregcal_is_leap_year: bad arguments in %s on line %d
+bool(false)
+
+Warning: intlgregcal_is_leap_year() expects exactly 2 parameters, 3 given in %s on line %d
+
+Warning: intlgregcal_is_leap_year(): intlgregcal_is_leap_year: bad arguments in %s on line %d
+bool(false)
+
+Warning: intlgregcal_is_leap_year() expects exactly 2 parameters, 1 given in %s on line %d
+
+Warning: intlgregcal_is_leap_year(): intlgregcal_is_leap_year: bad arguments in %s on line %d
+bool(false)
+
+Catchable fatal error: Argument 1 passed to intlgregcal_is_leap_year() must be an instance of IntlGregorianCalendar, integer given in %s on line %d
diff --git a/ext/intl/tests/gregoriancalendar_setGregorianChange_error.phpt b/ext/intl/tests/gregoriancalendar_setGregorianChange_error.phpt
new file mode 100644
index 0000000000..eac8deb61b
--- /dev/null
+++ b/ext/intl/tests/gregoriancalendar_setGregorianChange_error.phpt
@@ -0,0 +1,42 @@
+--TEST--
+IntlGregorianCalendar::setGregorianChange(): bad arguments
+--INI--
+date.timezone=Atlantic/Azores
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+
+$c = new IntlGregorianCalendar();
+var_dump($c->setGregorianChange());
+var_dump($c->setGregorianChange(1, 2));
+var_dump($c->setGregorianChange("sdfds"));
+
+var_dump(intlgregcal_set_gregorian_change($c));
+var_dump(intlgregcal_set_gregorian_change(1, 4.));
+--EXPECTF--
+
+Warning: IntlGregorianCalendar::setGregorianChange() expects exactly 1 parameter, 0 given in %s on line %d
+
+Warning: IntlGregorianCalendar::setGregorianChange(): intlgregcal_set_gregorian_change: bad arguments in %s on line %d
+bool(false)
+
+Warning: IntlGregorianCalendar::setGregorianChange() expects exactly 1 parameter, 2 given in %s on line %d
+
+Warning: IntlGregorianCalendar::setGregorianChange(): intlgregcal_set_gregorian_change: bad arguments in %s on line %d
+bool(false)
+
+Warning: IntlGregorianCalendar::setGregorianChange() expects parameter 1 to be double, string given in %s on line %d
+
+Warning: IntlGregorianCalendar::setGregorianChange(): intlgregcal_set_gregorian_change: bad arguments in %s on line %d
+bool(false)
+
+Warning: intlgregcal_set_gregorian_change() expects exactly 2 parameters, 1 given in %s on line %d
+
+Warning: intlgregcal_set_gregorian_change(): intlgregcal_set_gregorian_change: bad arguments in %s on line %d
+bool(false)
+
+Catchable fatal error: Argument 1 passed to intlgregcal_set_gregorian_change() must be an instance of IntlGregorianCalendar, integer given in %s on line %d
diff --git a/ext/intl/tests/ini_use_exceptions_basic.phpt b/ext/intl/tests/ini_use_exceptions_basic.phpt
new file mode 100644
index 0000000000..36ccbcb8a0
--- /dev/null
+++ b/ext/intl/tests/ini_use_exceptions_basic.phpt
@@ -0,0 +1,21 @@
+--TEST--
+intl.use_exceptions INI setting
+--SKIPIF--
+<?php if( !extension_loaded( 'intl' ) ) print 'skip'; ?>
+--FILE--
+<?php
+ini_set("intl.use_exceptions", true);
+$t = transliterator_create('any-hex');
+try {
+ var_dump($t->transliterate('a', 3));
+} catch (IntlException $intlE) {
+ var_dump($intlE->getMessage());
+}
+ini_set("intl.use_exceptions", false);
+ini_set("intl.error_level", E_NOTICE);
+var_dump($t->transliterate('a', 3));
+--EXPECTF--
+string(130) "transliterator_transliterate: Neither "start" nor the "end" arguments can exceed the number of UTF-16 code units (in this case, 1)"
+
+Notice: Transliterator::transliterate(): transliterator_transliterate: Neither "start" nor the "end" arguments can exceed the number of UTF-16 code units (in this case, 1) in %s on line %d
+bool(false)
diff --git a/ext/intl/tests/msgfmt_format_datetime.phpt b/ext/intl/tests/msgfmt_format_datetime.phpt
new file mode 100644
index 0000000000..07e7d68f14
--- /dev/null
+++ b/ext/intl/tests/msgfmt_format_datetime.phpt
@@ -0,0 +1,28 @@
+--TEST--
+MessageFormatter::format(): DateTime accepted to format dates and times
+--INI--
+date.timezone=Atlantic/Azores
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+//ini_set("intl.default_locale", "nl");
+
+$fmt = <<<EOD
+{0,date} {0,time}
+EOD;
+
+$dt = new DateTime("2012-05-06 18:00:42", new DateTimeZone("Europe/Lisbon"));
+
+$mf = new MessageFormatter('en_US', $fmt);
+
+var_dump($mf->format(array($dt)));
+
+?>
+==DONE==
+--EXPECTF--
+string(%s) "May %d, 2012 %d:%d:42 %s"
+==DONE==
diff --git a/ext/intl/tests/msgfmt_format_error1.phpt b/ext/intl/tests/msgfmt_format_error1.phpt
new file mode 100644
index 0000000000..684b05970a
--- /dev/null
+++ b/ext/intl/tests/msgfmt_format_error1.phpt
@@ -0,0 +1,19 @@
+--TEST--
+MessageFormatter::format() insufficient numeric arguments
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+
+$fmt = <<<EOD
+{0} {1}
+EOD;
+
+$mf = new MessageFormatter('en_US', $fmt);
+var_dump($mf->format(array(7)));
+
+--EXPECTF--
+string(5) "7 {1}"
diff --git a/ext/intl/tests/msgfmt_format_error2.phpt b/ext/intl/tests/msgfmt_format_error2.phpt
new file mode 100644
index 0000000000..85d1b1c83d
--- /dev/null
+++ b/ext/intl/tests/msgfmt_format_error2.phpt
@@ -0,0 +1,23 @@
+--TEST--
+MessageFormatter::format() inconsistent types in named argument
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+if (version_compare(INTL_ICU_VERSION, '4.8') < 0)
+ die('skip for ICU 4.8+');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+
+$fmt = <<<EOD
+{foo,number} {foo}
+EOD;
+
+$mf = new MessageFormatter('en_US', $fmt);
+var_dump($mf->format(array(7)));
+
+--EXPECTF--
+
+Warning: MessageFormatter::format(): Inconsistent types declared for an argument in %s on line %d
+bool(false)
diff --git a/ext/intl/tests/msgfmt_format_error3.phpt b/ext/intl/tests/msgfmt_format_error3.phpt
new file mode 100644
index 0000000000..6dfbee3c90
--- /dev/null
+++ b/ext/intl/tests/msgfmt_format_error3.phpt
@@ -0,0 +1,23 @@
+--TEST--
+MessageFormatter::format() given negative arg key
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+if (version_compare(INTL_ICU_VERSION, '4.8') < 0)
+ die('skip for ICU 4.8+');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+
+$fmt = <<<EOD
+{foo,number,percent}
+EOD;
+
+$mf = new MessageFormatter('en_US', $fmt);
+var_dump($mf->format(array("foo" => 7, -1 => "bar")));
+
+--EXPECTF--
+
+Warning: MessageFormatter::format(): Found negative or too large array key in %s on line %d
+bool(false)
diff --git a/ext/intl/tests/msgfmt_format_error4.phpt b/ext/intl/tests/msgfmt_format_error4.phpt
new file mode 100644
index 0000000000..3b92b48b8b
--- /dev/null
+++ b/ext/intl/tests/msgfmt_format_error4.phpt
@@ -0,0 +1,28 @@
+--TEST--
+MessageFormatter::format() invalid UTF-8 for arg key or value
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+if (version_compare(INTL_ICU_VERSION, '4.8') < 0)
+ die('skip for ICU 4.8+');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+
+$fmt = <<<EOD
+{foo}
+EOD;
+
+$mf = new MessageFormatter('en_US', $fmt);
+var_dump($mf->format(array("foo" => 7, "\x80" => "bar")));
+
+var_dump($mf->format(array("foo" => "\x80")));
+
+--EXPECTF--
+
+Warning: MessageFormatter::format(): Invalid UTF-8 data in argument key: '€' in %s on line %d
+bool(false)
+
+Warning: MessageFormatter::format(): Invalid UTF-8 data in string argument: '€' in %s on line %d
+bool(false)
diff --git a/ext/intl/tests/msgfmt_format_error5.phpt b/ext/intl/tests/msgfmt_format_error5.phpt
new file mode 100644
index 0000000000..ebbd4550e8
--- /dev/null
+++ b/ext/intl/tests/msgfmt_format_error5.phpt
@@ -0,0 +1,26 @@
+--TEST--
+MessageFormatter::format() invalid date/time argument
+--INI--
+date.timezone=Atlantic/Azores
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+if (version_compare(INTL_ICU_VERSION, '4.8') < 0)
+ die('skip for ICU 4.8+');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+
+$fmt = <<<EOD
+{foo,date}
+EOD;
+
+$mf = new MessageFormatter('en_US', $fmt);
+var_dump($mf->format(array("foo" => new stdclass())));
+
+--EXPECTF--
+Warning: MessageFormatter::format(): msgfmt_format: invalid object type for date/time (only IntlCalendar and DateTime permitted) in %s on line %d
+
+Warning: MessageFormatter::format(): The argument for key 'foo' cannot be used as a date or time in %s on line %d
+bool(false)
diff --git a/ext/intl/tests/msgfmt_format_error6.phpt b/ext/intl/tests/msgfmt_format_error6.phpt
new file mode 100644
index 0000000000..b07d2ab774
--- /dev/null
+++ b/ext/intl/tests/msgfmt_format_error6.phpt
@@ -0,0 +1,23 @@
+--TEST--
+MessageFormatter::format() invalid type for key not in pattern
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+if (version_compare(INTL_ICU_VERSION, '4.8') < 0)
+ die('skip for ICU 4.8+');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+
+$fmt = <<<EOD
+{foo}
+EOD;
+
+$mf = new MessageFormatter('en_US', $fmt);
+var_dump($mf->format(array("foo" => 'bar', 7 => fopen('php://memory', 'r+'))));
+
+--EXPECTF--
+
+Warning: MessageFormatter::format(): No strategy to convert the value given for the argument with key '7' is available in %s on line %d
+bool(false)
diff --git a/ext/intl/tests/msgfmt_format_intlcalendar.phpt b/ext/intl/tests/msgfmt_format_intlcalendar.phpt
new file mode 100644
index 0000000000..6ae78a9140
--- /dev/null
+++ b/ext/intl/tests/msgfmt_format_intlcalendar.phpt
@@ -0,0 +1,30 @@
+--TEST--
+MessageFormat accepts IntlCalendar args
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+//ini_set("intl.default_locale", "nl");
+ini_set('date.timezone', 'Europe/Lisbon');
+
+$cal = new IntlGregorianCalendar(2012,04,17,17,35,36);
+
+$msgf = new MessageFormatter('pt_PT', '{0,date,full} {0,time,h:m:s a V}');
+echo $msgf->format(array($cal)), "\n";
+
+//NOT FIXED:
+/*$msgf = new MessageFormatter('en_US',
+'{1, select, date {{0,date,full}} other {{0,time,h:m:s a V}}}');
+
+echo "msgf2: ", $msgf->format(array($time, 'date')), " ",
+ $msgf->format(array($time, 'time')), "\n";
+*/
+
+?>
+==DONE==
+--EXPECT--
+Quinta-feira, 17 de Maio de 2012 5:35:36 p.m. WEST
+==DONE== \ No newline at end of file
diff --git a/ext/intl/tests/msgfmt_format_mixed_params.phpt b/ext/intl/tests/msgfmt_format_mixed_params.phpt
new file mode 100644
index 0000000000..93412f49e2
--- /dev/null
+++ b/ext/intl/tests/msgfmt_format_mixed_params.phpt
@@ -0,0 +1,25 @@
+--TEST--
+MessageFormatter::format(): mixed named and numeric parameters
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+if (version_compare(INTL_ICU_VERSION, '4.8') < 0)
+ die('skip for ICU 4.8+');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+//ini_set("intl.default_locale", "nl");
+
+$mf = new MessageFormatter('en_US',
+ "{0,number} -- {foo,ordinal}");
+
+var_dump($mf->format(array(2.3, "foo" => 1.3)));
+var_dump($mf->format(array("foo" => 1.3, 0 => 2.3)));
+
+?>
+==DONE==
+--EXPECT--
+string(10) "2.3 -- 1st"
+string(10) "2.3 -- 1st"
+==DONE== \ No newline at end of file
diff --git a/ext/intl/tests/msgfmt_format_simple_types_numeric_strings.phpt b/ext/intl/tests/msgfmt_format_simple_types_numeric_strings.phpt
new file mode 100644
index 0000000000..299ae483a4
--- /dev/null
+++ b/ext/intl/tests/msgfmt_format_simple_types_numeric_strings.phpt
@@ -0,0 +1,58 @@
+--TEST--
+MessageFormatter::format(): simple types handling with numeric strings
+--INI--
+date.timezone=Atlantic/Azores
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+if (version_compare(INTL_ICU_VERSION, '4.8') < 0)
+ die('skip for ICU 4.8+');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+//ini_set("intl.default_locale", "nl");
+
+$mf = new MessageFormatter('en_US',"
+ none {a}
+ number {b,number}
+ number integer {c,number,integer}
+ number currency {d,number,currency}
+ number percent {e,number,percent}
+ date {f,date}
+ time {g,time}
+ spellout {h,spellout}
+ ordinal {i,ordinal}
+ duration {j,duration}
+ ");
+
+$ex = "1336317965.5 str";
+var_dump($mf->format(array(
+'a' => $ex,
+'b' => $ex,
+'c' => $ex,
+'d' => $ex,
+'e' => $ex,
+'f' => " 1336317965.5",
+'g' => " 1336317965.5",
+'h' => $ex,
+'i' => $ex,
+'j' => $ex,
+)));
+
+?>
+==DONE==
+--EXPECTF--
+string(%d) "
+ none 1336317965.5 str
+ number 1,336,317,965.5
+ number integer 1,336,317,965
+ number currency $1,336,317,965.50
+ number percent 133,631,796,550%
+ date May %d, 2012
+ time %d:%d:05 PM
+ spellout one billion three hundred thirty-six million three hundred seventeen thousand nine hundred sixty-five point five
+ ordinal 1,336,317,966th
+ duration 371,199:26:06
+ "
+==DONE==
diff --git a/ext/intl/tests/msgfmt_format_subpatterns.phpt b/ext/intl/tests/msgfmt_format_subpatterns.phpt
new file mode 100644
index 0000000000..9f11e3e255
--- /dev/null
+++ b/ext/intl/tests/msgfmt_format_subpatterns.phpt
@@ -0,0 +1,75 @@
+--TEST--
+msgfmt_format() with subpatterns
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+if (version_compare(INTL_ICU_VERSION, '4.8') < 0)
+ die('skip for ICU 4.8+');
+--FILE--
+<?php
+
+/*
+ * Format a number using misc locales/patterns.
+ */
+
+
+function ut_main()
+{
+
+$pattern=<<<_MSG_
+{0, select,
+ female {{1, plural, offset:1
+ =0 {{2} does not give a party.}
+ =1 {{2} invites {3} to her party.}
+ =2 {{2} invites {3} and one other person to her party.}
+ other {{2} invites {3} as one of the # people invited to her party.}}}
+ male {{1, plural, offset:1
+ =0 {{2} does not give a party.}
+ =1 {{2} invites {3} to his party.}
+ =2 {{2} invites {3} and one other person to his party.}
+ other {{2} invites {3} as one of the # other people invited to his party.}}}
+ other {{1, plural, offset:1
+ =0 {{2} does not give a party.}
+ =1 {{2} invites {3} to their party.}
+ =2 {{2} invites {3} and one other person to their party.}
+ other {{2} invites {3} as one of the # other people invited to their party.}}}}
+_MSG_;
+
+
+$args = array(
+ array('female', 0, 'Alice', 'Bob'),
+ array('male', 1, 'Alice', 'Bob'),
+ array('none', 2, 'Alice', 'Bob'),
+ array('female', 27, 'Alice', 'Bob'),
+);
+
+$str_res = '';
+
+ $fmt = ut_msgfmt_create( 'en_US', $pattern );
+ if(!$fmt) {
+ $str_res .= dump(intl_get_error_message())."\n";
+ return $str_res;
+ }
+ foreach ($args as $arg) {
+ $str_res .= dump( ut_msgfmt_format($fmt, $arg) ). "\n";
+ $str_res .= dump( ut_msgfmt_format_message('en_US', $pattern, $arg) ) . "\n";
+ }
+ return $str_res;
+}
+
+include_once( 'ut_common.inc' );
+
+// Run the test
+ut_run();
+
+?>
+--EXPECT--
+'Alice does not give a party.'
+'Alice does not give a party.'
+'Alice invites Bob to his party.'
+'Alice invites Bob to his party.'
+'Alice invites Bob and one other person to their party.'
+'Alice invites Bob and one other person to their party.'
+'Alice invites Bob as one of the 26 people invited to her party.'
+'Alice invites Bob as one of the 26 people invited to her party.'
diff --git a/ext/intl/tests/msgfmt_format_subpatterns_named.phpt b/ext/intl/tests/msgfmt_format_subpatterns_named.phpt
new file mode 100644
index 0000000000..f6af02561b
--- /dev/null
+++ b/ext/intl/tests/msgfmt_format_subpatterns_named.phpt
@@ -0,0 +1,75 @@
+--TEST--
+msgfmt_format() with named subpatterns
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+if (version_compare(INTL_ICU_VERSION, '4.8') < 0)
+ die('skip for ICU 4.8+');
+--FILE--
+<?php
+
+/*
+ * Format a number using misc locales/patterns.
+ */
+
+
+function ut_main()
+{
+
+$pattern=<<<_MSG_
+{gender_of_host, select,
+ female {{num_guests, plural, offset:1
+ =0 {{host} does not give a party.}
+ =1 {{host} invites {guest} to her party.}
+ =2 {{host} invites {guest} and one other person to her party.}
+ other {{host} invites {guest} as one of the # people invited to her party.}}}
+ male {{num_guests, plural, offset:1
+ =0 {{host} does not give a party.}
+ =1 {{host} invites {guest} to his party.}
+ =2 {{host} invites {guest} and one other person to his party.}
+ other {{host} invites {guest} as one of the # people invited to his party.}}}
+ other {{num_guests, plural, offset:1
+ =0 {{host} does not give a party.}
+ =1 {{host} invites {guest} to their party.}
+ =2 {{host} invites {guest} and one other person to their party.}
+ other {{host} invites {guest} as one of the # people invited to their party.}}}}
+_MSG_;
+
+
+$args = array(
+ array('gender_of_host' => 'female', 'num_guests' => 0, 'host' => 'Alice', 'guest' => 'Bob'),
+ array('gender_of_host' => 'male', 'num_guests' => 1, 'host' => 'Alice', 'guest' => 'Bob'),
+ array('gender_of_host' => 'none', 'num_guests' => 2, 'host' => 'Alice', 'guest' => 'Bob'),
+ array('gender_of_host' => 'female', 'num_guests' => 27, 'host' => 'Alice', 'guest' => 'Bob'),
+);
+
+$str_res = '';
+
+ $fmt = ut_msgfmt_create( 'en_US', $pattern );
+ if(!$fmt) {
+ $str_res .= dump(intl_get_error_message())."\n";
+ return $str_res;
+ }
+ foreach ($args as $arg) {
+ $str_res .= dump( ut_msgfmt_format($fmt, $arg) ). "\n";
+ $str_res .= dump( ut_msgfmt_format_message('en_US', $pattern, $arg) ) . "\n";
+ }
+ return $str_res;
+}
+
+include_once( 'ut_common.inc' );
+
+// Run the test
+ut_run();
+
+?>
+--EXPECT--
+'Alice does not give a party.'
+'Alice does not give a party.'
+'Alice invites Bob to his party.'
+'Alice invites Bob to his party.'
+'Alice invites Bob and one other person to their party.'
+'Alice invites Bob and one other person to their party.'
+'Alice invites Bob as one of the 26 people invited to her party.'
+'Alice invites Bob as one of the 26 people invited to her party.'
diff --git a/ext/intl/tests/msgfmt_get_error.phpt b/ext/intl/tests/msgfmt_get_error.phpt
deleted file mode 100644
index 015c50d465..0000000000
--- a/ext/intl/tests/msgfmt_get_error.phpt
+++ /dev/null
@@ -1,29 +0,0 @@
---TEST--
-msgmfmt_get_error_message/code()
---SKIPIF--
-<?php if( !extension_loaded( 'intl' ) ) print 'skip'; ?>
---FILE--
-<?php
-
-/*
- * Error handling.
- */
-
-
-function ut_main()
-{
- $fmt = ut_msgfmt_create( "en_US", "{0, number} monkeys on {1, number} trees" );
- $num = ut_msgfmt_format( $fmt, array());
- if( $num === false )
- return $fmt->getErrorMessage() . " (" . $fmt->getErrorCode() . ")\n";
- else
- return "Ooops, an error should have occured.";
-}
-
-include_once( 'ut_common.inc' );
-
-// Run the test
-ut_run();
-?>
---EXPECT--
-msgfmt_format: not enough parameters: U_ILLEGAL_ARGUMENT_ERROR (1)
diff --git a/ext/intl/tests/msgfmt_millisecond_dates.phpt b/ext/intl/tests/msgfmt_millisecond_dates.phpt
new file mode 100644
index 0000000000..7dd051426b
--- /dev/null
+++ b/ext/intl/tests/msgfmt_millisecond_dates.phpt
@@ -0,0 +1,29 @@
+--TEST--
+MessageFrormatter parses and formats dates with millisecond precision
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+date_default_timezone_set('Europe/Lisbon'); //ignored for now, see bug #58756
+
+$d = 1336308097.123;
+$mf = new MessageFormatter('en_US',
+ "On {0,time,yyyy-MM-dd G 'at' HH:mm:ss.SSS zzz} something odd happened");
+
+var_dump($mf->format(array(1336310569.123)));
+
+$p = 'On 2012-05-06 AD at 15:22:49.123 GMT+02:00 something odd happened';
+var_dump($mf->parse($p));
+
+?>
+==DONE==
+--EXPECTF--
+string(%d) "On 2012-05-0%d AD at %d:%d:49.123 %s something odd happened"
+array(1) {
+ [0]=>
+ float(1336310569.123)
+}
+==DONE==
diff --git a/ext/intl/tests/msgfmt_setPattern_cache.phpt b/ext/intl/tests/msgfmt_setPattern_cache.phpt
new file mode 100644
index 0000000000..35ec463c2a
--- /dev/null
+++ b/ext/intl/tests/msgfmt_setPattern_cache.phpt
@@ -0,0 +1,26 @@
+--TEST--
+MessageFormatter::setPattern() invalidates arg types cache
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+//ini_set("intl.default_locale", "nl");
+
+$mf = new MessageFormatter('en_US',
+ "{0,number} -- {1,ordinal}");
+
+var_dump($mf->format(array(1.3, 1.3)));
+var_dump($mf->format(array(1.3, 1.3)));
+$mf->setPattern("{0,ordinal} -- {1,number}");
+var_dump($mf->format(array(1.3, 1.3)));
+
+?>
+==DONE==
+--EXPECT--
+string(10) "1.3 -- 1st"
+string(10) "1.3 -- 1st"
+string(10) "1st -- 1.3"
+==DONE== \ No newline at end of file
diff --git a/ext/intl/tests/rbbiter___construct_basic.phpt b/ext/intl/tests/rbbiter___construct_basic.phpt
new file mode 100644
index 0000000000..6fb584fdee
--- /dev/null
+++ b/ext/intl/tests/rbbiter___construct_basic.phpt
@@ -0,0 +1,31 @@
+--TEST--
+IntlRuleBasedBreakIterator::__construct: basic test
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+ini_set("intl.default_locale", "pt_PT");
+
+$rules = <<<RULES
+\$LN = [[:letter:] [:number:]];
+\$S = [.;,:];
+
+!!forward;
+\$LN+ {1};
+\$S+ {42};
+!!reverse;
+\$LN+ {1};
+\$S+ {42};
+!!safe_forward;
+!!safe_reverse;
+RULES;
+$rbbi = new IntlRuleBasedBreakIterator($rules);
+var_dump(get_class($rbbi));
+?>
+==DONE==
+--EXPECT--
+string(26) "IntlRuleBasedBreakIterator"
+==DONE== \ No newline at end of file
diff --git a/ext/intl/tests/rbbiter_getBinaryRules_basic.phpt b/ext/intl/tests/rbbiter_getBinaryRules_basic.phpt
new file mode 100644
index 0000000000..dce0714d4d
--- /dev/null
+++ b/ext/intl/tests/rbbiter_getBinaryRules_basic.phpt
@@ -0,0 +1,39 @@
+--TEST--
+IntlRuleBasedBreakIterator::getBinaryRules(): basic test
+--SKIPIF--
+<?php if( !extension_loaded( 'intl' ) ) print 'skip'; ?>
+<?php if(version_compare(INTL_ICU_VERSION, '4.8') < 0) print 'skip ICU >= 4.8 only'; ?>
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+ini_set("intl.default_locale", "pt_PT");
+
+$rules = <<<RULES
+\$LN = [[:letter:] [:number:]];
+\$S = [.;,:];
+
+!!forward;
+\$LN+ {1};
+\$S+ {42};
+!!reverse;
+\$LN+ {1};
+\$S+ {42};
+!!safe_forward;
+!!safe_reverse;
+RULES;
+$rbbi = new IntlRuleBasedBreakIterator($rules);
+$rbbi->setText('sdfkjsdf88á.... ,;');;
+
+$br = $rbbi->getBinaryRules();
+
+$rbbi2 = new IntlRuleBasedBreakIterator($br, true);
+
+var_dump($rbbi->getRules(), $rbbi2->getRules());
+var_dump($rbbi->getRules() == $rbbi2->getRules());
+?>
+==DONE==
+--EXPECT--
+string(128) "$LN = [[:letter:] [:number:]];$S = [.;,:];!!forward;$LN+ {1};$S+ {42};!!reverse;$LN+ {1};$S+ {42};!!safe_forward;!!safe_reverse;"
+string(128) "$LN = [[:letter:] [:number:]];$S = [.;,:];!!forward;$LN+ {1};$S+ {42};!!reverse;$LN+ {1};$S+ {42};!!safe_forward;!!safe_reverse;"
+bool(true)
+==DONE==
diff --git a/ext/intl/tests/rbbiter_getRuleStatusVec_basic.phpt b/ext/intl/tests/rbbiter_getRuleStatusVec_basic.phpt
new file mode 100644
index 0000000000..a56f6bc488
--- /dev/null
+++ b/ext/intl/tests/rbbiter_getRuleStatusVec_basic.phpt
@@ -0,0 +1,59 @@
+--TEST--
+IntlRuleBasedBreakIterator::getRuleStatusVec(): basic test
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+ini_set("intl.default_locale", "pt_PT");
+
+$rules = <<<RULES
+\$LN = [[:letter:] [:number:]];
+\$S = [.;,:];
+
+!!forward;
+\$LN+ {1};
+[^.]+ {4};
+\$S+ {42};
+!!reverse;
+\$LN+ {1};
+[^.]+ {4};
+\$S+ {42};
+!!safe_forward;
+!!safe_reverse;
+RULES;
+$rbbi = new IntlRuleBasedBreakIterator($rules);
+$rbbi->setText('sdfkjsdf88á.... ,;');;
+
+do {
+ var_dump($rbbi->current(), $rbbi->getRuleStatusVec());
+} while ($rbbi->next() != IntlBreakIterator::DONE);
+
+?>
+==DONE==
+--EXPECT--
+int(0)
+array(1) {
+ [0]=>
+ int(0)
+}
+int(12)
+array(2) {
+ [0]=>
+ int(1)
+ [1]=>
+ int(4)
+}
+int(16)
+array(1) {
+ [0]=>
+ int(42)
+}
+int(19)
+array(1) {
+ [0]=>
+ int(4)
+}
+==DONE== \ No newline at end of file
diff --git a/ext/intl/tests/rbbiter_getRuleStatus_basic.phpt b/ext/intl/tests/rbbiter_getRuleStatus_basic.phpt
new file mode 100644
index 0000000000..80eedbfba5
--- /dev/null
+++ b/ext/intl/tests/rbbiter_getRuleStatus_basic.phpt
@@ -0,0 +1,46 @@
+--TEST--
+IntlRuleBasedBreakIterator::getRuleStatus(): basic test
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+ini_set("intl.default_locale", "pt_PT");
+
+$rules = <<<RULES
+\$LN = [[:letter:] [:number:]];
+\$S = [.;,:];
+
+!!forward;
+\$LN+ {1};
+\$S+ {42};
+!!reverse;
+\$LN+ {1};
+\$S+ {42};
+!!safe_forward;
+!!safe_reverse;
+RULES;
+$rbbi = new IntlRuleBasedBreakIterator($rules);
+$rbbi->setText('sdfkjsdf88á.... ,;');
+
+do {
+ echo "pos : {$rbbi->current()}\n",
+ "rule status: {$rbbi->getRuleStatus()}\n";
+} while ($rbbi->next() != IntlBreakIterator::DONE);
+
+?>
+==DONE==
+--EXPECT--
+pos : 0
+rule status: 0
+pos : 12
+rule status: 1
+pos : 16
+rule status: 42
+pos : 17
+rule status: 0
+pos : 19
+rule status: 42
+==DONE== \ No newline at end of file
diff --git a/ext/intl/tests/rbbiter_getRules_basic.phpt b/ext/intl/tests/rbbiter_getRules_basic.phpt
new file mode 100644
index 0000000000..2f7a40eb71
--- /dev/null
+++ b/ext/intl/tests/rbbiter_getRules_basic.phpt
@@ -0,0 +1,32 @@
+--TEST--
+IntlRuleBasedBreakIterator::getRules(): basic test
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+ini_set("intl.default_locale", "pt_PT");
+
+$rules = <<<RULES
+\$LN = [[:letter:] [:number:]];
+\$S = [.;,:];
+
+!!forward;
+\$LN+ {1};
+\$S+ {42};
+!!reverse;
+\$LN+ {1};
+\$S+ {42};
+!!safe_forward;
+!!safe_reverse;
+RULES;
+$rbbi = new IntlRuleBasedBreakIterator($rules);
+var_dump($rbbi->getRules());
+
+?>
+==DONE==
+--EXPECT--
+string(128) "$LN = [[:letter:] [:number:]];$S = [.;,:];!!forward;$LN+ {1};$S+ {42};!!reverse;$LN+ {1};$S+ {42};!!safe_forward;!!safe_reverse;"
+==DONE== \ No newline at end of file
diff --git a/ext/intl/tests/timezone_clone_basic.phpt b/ext/intl/tests/timezone_clone_basic.phpt
new file mode 100644
index 0000000000..a8ef83f864
--- /dev/null
+++ b/ext/intl/tests/timezone_clone_basic.phpt
@@ -0,0 +1,51 @@
+--TEST--
+IntlTimeZone clone handler: basic test
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+
+$tz1 = IntlTimeZone::createTimeZone('Europe/Amsterdam');
+print_r($tz1);
+print_r(clone $tz1);
+
+//clone non-owned object
+$gmt = IntlTimeZone::getGMT();
+print_r($gmt);
+print_r(clone $gmt);
+
+?>
+==DONE==
+--EXPECTF--
+IntlTimeZone Object
+(
+ [valid] => 1
+ [id] => Europe/Amsterdam
+ [rawOffset] => 3600000
+ [currentOffset] => %d
+)
+IntlTimeZone Object
+(
+ [valid] => 1
+ [id] => Europe/Amsterdam
+ [rawOffset] => 3600000
+ [currentOffset] => %d
+)
+IntlTimeZone Object
+(
+ [valid] => 1
+ [id] => GMT
+ [rawOffset] => 0
+ [currentOffset] => 0
+)
+IntlTimeZone Object
+(
+ [valid] => 1
+ [id] => GMT
+ [rawOffset] => 0
+ [currentOffset] => 0
+)
+==DONE== \ No newline at end of file
diff --git a/ext/intl/tests/timezone_clone_error.phpt b/ext/intl/tests/timezone_clone_error.phpt
new file mode 100644
index 0000000000..df501be3b4
--- /dev/null
+++ b/ext/intl/tests/timezone_clone_error.phpt
@@ -0,0 +1,32 @@
+--TEST--
+IntlTimeZone clone handler: error test
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+
+class A extends IntlTimeZone {
+function __construct() {}
+}
+
+$tz = new A();
+var_dump($tz);
+try {
+var_dump(clone $tz);
+} catch (Exception $e) {
+ var_dump(get_class($e), $e->getMessage());
+}
+
+?>
+==DONE==
+--EXPECT--
+object(A)#1 (1) {
+ ["valid"]=>
+ bool(false)
+}
+string(9) "Exception"
+string(39) "Cannot clone unconstructed IntlTimeZone"
+==DONE== \ No newline at end of file
diff --git a/ext/intl/tests/timezone_countEquivalentIDs_basic.phpt b/ext/intl/tests/timezone_countEquivalentIDs_basic.phpt
new file mode 100644
index 0000000000..ec3e4050ab
--- /dev/null
+++ b/ext/intl/tests/timezone_countEquivalentIDs_basic.phpt
@@ -0,0 +1,20 @@
+--TEST--
+IntlTimeZone::countEquivalentIDs(): basic test
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+$count = IntlTimeZone::countEquivalentIDs('Europe/Lisbon');
+var_dump($count >= 2);
+
+$count2 = intltz_count_equivalent_ids('Europe/Lisbon');
+var_dump($count2 == $count);
+?>
+==DONE==
+--EXPECT--
+bool(true)
+bool(true)
+==DONE== \ No newline at end of file
diff --git a/ext/intl/tests/timezone_countEquivalentIDs_error.phpt b/ext/intl/tests/timezone_countEquivalentIDs_error.phpt
new file mode 100644
index 0000000000..4d8f4bc3e3
--- /dev/null
+++ b/ext/intl/tests/timezone_countEquivalentIDs_error.phpt
@@ -0,0 +1,35 @@
+--TEST--
+IntlTimeZone::countEquivalentIDs(): errors
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+
+var_dump(IntlTimeZone::countEquivalentIDs());
+var_dump(IntlTimeZone::countEquivalentIDs(array()));
+var_dump(IntlTimeZone::countEquivalentIDs("foo\x80"));
+var_dump(IntlTimeZone::countEquivalentIDs("foo bar", 7));
+
+
+--EXPECTF--
+
+Warning: IntlTimeZone::countEquivalentIDs() expects exactly 1 parameter, 0 given in %s on line %d
+
+Warning: IntlTimeZone::countEquivalentIDs(): intltz_count_equivalent_ids: bad arguments in %s on line %d
+bool(false)
+
+Warning: IntlTimeZone::countEquivalentIDs() expects parameter 1 to be string, array given in %s on line %d
+
+Warning: IntlTimeZone::countEquivalentIDs(): intltz_count_equivalent_ids: bad arguments in %s on line %d
+bool(false)
+
+Warning: IntlTimeZone::countEquivalentIDs(): intltz_count_equivalent_ids: could not convert time zone id to UTF-16 in %s on line %d
+bool(false)
+
+Warning: IntlTimeZone::countEquivalentIDs() expects exactly 1 parameter, 2 given in %s on line %d
+
+Warning: IntlTimeZone::countEquivalentIDs(): intltz_count_equivalent_ids: bad arguments in %s on line %d
+bool(false)
diff --git a/ext/intl/tests/timezone_createDefault_basic.phpt b/ext/intl/tests/timezone_createDefault_basic.phpt
new file mode 100644
index 0000000000..1988d3b9e5
--- /dev/null
+++ b/ext/intl/tests/timezone_createDefault_basic.phpt
@@ -0,0 +1,31 @@
+--TEST--
+IntlTimeZone::createDefault(): basic test
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+$tz = IntlTimeZone::createDefault();
+print_r($tz);
+$tz = intltz_create_default();
+print_r($tz);
+?>
+==DONE==
+--EXPECTF--
+IntlTimeZone Object
+(
+ [valid] => 1
+ [id] => %s
+ [rawOffset] => %i
+ [currentOffset] => %i
+)
+IntlTimeZone Object
+(
+ [valid] => 1
+ [id] => %s
+ [rawOffset] => %i
+ [currentOffset] => %i
+)
+==DONE==
diff --git a/ext/intl/tests/timezone_createDefault_error.phpt b/ext/intl/tests/timezone_createDefault_error.phpt
new file mode 100644
index 0000000000..0724898219
--- /dev/null
+++ b/ext/intl/tests/timezone_createDefault_error.phpt
@@ -0,0 +1,19 @@
+--TEST--
+IntlTimeZone::createDefault(): errors
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+
+var_dump(IntlTimeZone::createDefault(4));
+
+
+--EXPECTF--
+
+Warning: IntlTimeZone::createDefault() expects exactly 0 parameters, 1 given in %s on line %d
+
+Warning: IntlTimeZone::createDefault(): intltz_create_default: bad arguments in %s on line %d
+NULL
diff --git a/ext/intl/tests/timezone_createEnumeration_basic.phpt b/ext/intl/tests/timezone_createEnumeration_basic.phpt
new file mode 100644
index 0000000000..2df32562b1
--- /dev/null
+++ b/ext/intl/tests/timezone_createEnumeration_basic.phpt
@@ -0,0 +1,26 @@
+--TEST--
+IntlTimeZone::createEnumeration(): basic test
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+$tz = IntlTimeZone::createEnumeration();
+var_dump(get_class($tz));
+$count = count(iterator_to_array($tz));
+var_dump($count > 300);
+
+$tz = intltz_create_enumeration();
+var_dump(get_class($tz));
+$count2 = count(iterator_to_array($tz));
+var_dump($count == $count2);
+?>
+==DONE==
+--EXPECT--
+string(12) "IntlIterator"
+bool(true)
+string(12) "IntlIterator"
+bool(true)
+==DONE== \ No newline at end of file
diff --git a/ext/intl/tests/timezone_createEnumeration_error.phpt b/ext/intl/tests/timezone_createEnumeration_error.phpt
new file mode 100644
index 0000000000..e1e7cb9333
--- /dev/null
+++ b/ext/intl/tests/timezone_createEnumeration_error.phpt
@@ -0,0 +1,23 @@
+--TEST--
+IntlTimeZone::createEnumeration(): errors
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+
+var_dump(IntlTimeZone::createEnumeration(array()));
+var_dump(IntlTimeZone::createEnumeration(1, 2));
+
+
+--EXPECTF--
+
+Warning: IntlTimeZone::createEnumeration(): intltz_create_enumeration: invalid argument type in %s on line %d
+bool(false)
+
+Warning: IntlTimeZone::createEnumeration() expects at most 1 parameter, 2 given in %s on line %d
+
+Warning: IntlTimeZone::createEnumeration(): intltz_create_enumeration: bad arguments in %s on line %d
+bool(false)
diff --git a/ext/intl/tests/timezone_createEnumeration_variation1.phpt b/ext/intl/tests/timezone_createEnumeration_variation1.phpt
new file mode 100644
index 0000000000..30fc43660e
--- /dev/null
+++ b/ext/intl/tests/timezone_createEnumeration_variation1.phpt
@@ -0,0 +1,24 @@
+--TEST--
+IntlTimeZone::createEnumeration(): variant with offset
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+$tz = IntlTimeZone::createEnumeration(3600000);
+var_dump(get_class($tz));
+$count = count(iterator_to_array($tz));
+var_dump($count > 20);
+
+$tz->rewind();
+var_dump(in_array('Europe/Amsterdam', iterator_to_array($tz)));
+
+?>
+==DONE==
+--EXPECT--
+string(12) "IntlIterator"
+bool(true)
+bool(true)
+==DONE== \ No newline at end of file
diff --git a/ext/intl/tests/timezone_createEnumeration_variation2.phpt b/ext/intl/tests/timezone_createEnumeration_variation2.phpt
new file mode 100644
index 0000000000..ddf1a6ece1
--- /dev/null
+++ b/ext/intl/tests/timezone_createEnumeration_variation2.phpt
@@ -0,0 +1,24 @@
+--TEST--
+IntlTimeZone::createEnumeration(): variant with country
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+$tz = IntlTimeZone::createEnumeration('NL');
+var_dump(get_class($tz));
+$count = count(iterator_to_array($tz));
+var_dump($count >= 1);
+
+$tz->rewind();
+var_dump(in_array('Europe/Amsterdam', iterator_to_array($tz)));
+
+?>
+==DONE==
+--EXPECT--
+string(12) "IntlIterator"
+bool(true)
+bool(true)
+==DONE== \ No newline at end of file
diff --git a/ext/intl/tests/timezone_createTimeZoneIDEnumeration_basic.phpt b/ext/intl/tests/timezone_createTimeZoneIDEnumeration_basic.phpt
new file mode 100644
index 0000000000..9ceffc5289
--- /dev/null
+++ b/ext/intl/tests/timezone_createTimeZoneIDEnumeration_basic.phpt
@@ -0,0 +1,34 @@
+--TEST--
+IntlTimeZone::createTimeZoneIDEnumeration(): basic test
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+if (version_compare(INTL_ICU_VERSION, '4.8') < 0)
+ die('skip for ICU 4.8+');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+$enum = IntlTimeZone::createTimeZoneIDEnumeration(
+ IntlTimeZone::TYPE_ANY,
+ 'PT',
+ -3600000);
+print_r(iterator_to_array($enum));
+
+$enum = intltz_create_time_zone_id_enumeration(
+ IntlTimeZone::TYPE_ANY,
+ 'PT',
+ -3600000);
+print_r(iterator_to_array($enum));
+?>
+==DONE==
+--EXPECT--
+Array
+(
+ [0] => Atlantic/Azores
+)
+Array
+(
+ [0] => Atlantic/Azores
+)
+==DONE== \ No newline at end of file
diff --git a/ext/intl/tests/timezone_createTimeZoneIDEnumeration_error.phpt b/ext/intl/tests/timezone_createTimeZoneIDEnumeration_error.phpt
new file mode 100644
index 0000000000..2cc2ac48e7
--- /dev/null
+++ b/ext/intl/tests/timezone_createTimeZoneIDEnumeration_error.phpt
@@ -0,0 +1,42 @@
+--TEST--
+IntlTimeZone::createTimeZoneIDEnumeration(): errors
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+if (version_compare(INTL_ICU_VERSION, '4.8') < 0)
+ die('skip for ICU 4.8+');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+
+var_dump(IntlTimeZone::createTimeZoneIDEnumeration());
+var_dump(IntlTimeZone::createTimeZoneIDEnumeration(array()));
+var_dump(IntlTimeZone::createTimeZoneIDEnumeration(-1));
+var_dump(IntlTimeZone::createTimeZoneIDEnumeration(IntlTimeZone::TYPE_ANY, array()));
+var_dump(IntlTimeZone::createTimeZoneIDEnumeration(IntlTimeZone::TYPE_ANY, "PT", "a80"));
+
+--EXPECTF--
+
+Warning: IntlTimeZone::createTimeZoneIDEnumeration() expects at least 1 parameter, 0 given in %s on line %d
+
+Warning: IntlTimeZone::createTimeZoneIDEnumeration(): intltz_create_time_zone_id_enumeration: bad arguments in %s on line %d
+bool(false)
+
+Warning: IntlTimeZone::createTimeZoneIDEnumeration() expects parameter 1 to be long, array given in %s on line %d
+
+Warning: IntlTimeZone::createTimeZoneIDEnumeration(): intltz_create_time_zone_id_enumeration: bad arguments in %s on line %d
+bool(false)
+
+Warning: IntlTimeZone::createTimeZoneIDEnumeration(): intltz_create_time_zone_id_enumeration: bad zone type in %s on line %d
+bool(false)
+
+Warning: IntlTimeZone::createTimeZoneIDEnumeration() expects parameter 2 to be string, array given in %s on line %d
+
+Warning: IntlTimeZone::createTimeZoneIDEnumeration(): intltz_create_time_zone_id_enumeration: bad arguments in %s on line %d
+bool(false)
+
+Warning: IntlTimeZone::createTimeZoneIDEnumeration() expects parameter 3 to be long, string given in %s on line %d
+
+Warning: IntlTimeZone::createTimeZoneIDEnumeration(): intltz_create_time_zone_id_enumeration: bad arguments in %s on line %d
+bool(false)
diff --git a/ext/intl/tests/timezone_createTimeZoneIDEnumeration_variant1.phpt b/ext/intl/tests/timezone_createTimeZoneIDEnumeration_variant1.phpt
new file mode 100644
index 0000000000..d57dfbf42f
--- /dev/null
+++ b/ext/intl/tests/timezone_createTimeZoneIDEnumeration_variant1.phpt
@@ -0,0 +1,32 @@
+--TEST--
+IntlTimeZone::createTimeZoneIDEnumeration(): variant without offset
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+if (version_compare(INTL_ICU_VERSION, '4.8') < 0)
+ die('skip for ICU 4.8+');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+$enum = IntlTimeZone::createTimeZoneIDEnumeration(
+ IntlTimeZone::TYPE_ANY,
+ 'PT');
+$values = iterator_to_array($enum);
+var_dump(in_array('Europe/Lisbon', $values));
+var_dump(in_array('Atlantic/Azores', $values));
+
+$enum = IntlTimeZone::createTimeZoneIDEnumeration(
+ IntlTimeZone::TYPE_ANY,
+ 'PT',
+ null);
+$values2 = iterator_to_array($enum);
+var_dump($values2 == $values);
+
+?>
+==DONE==
+--EXPECT--
+bool(true)
+bool(true)
+bool(true)
+==DONE== \ No newline at end of file
diff --git a/ext/intl/tests/timezone_createTimeZoneIDEnumeration_variant2.phpt b/ext/intl/tests/timezone_createTimeZoneIDEnumeration_variant2.phpt
new file mode 100644
index 0000000000..2afe171c58
--- /dev/null
+++ b/ext/intl/tests/timezone_createTimeZoneIDEnumeration_variant2.phpt
@@ -0,0 +1,52 @@
+--TEST--
+IntlTimeZone::createTimeZoneIDEnumeration(): variant without region
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+if (version_compare(INTL_ICU_VERSION, '4.8') < 0)
+ die('skip for ICU 4.8+');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+$enum = IntlTimeZone::createTimeZoneIDEnumeration(
+ IntlTimeZone::TYPE_ANY);
+$countAny = count(iterator_to_array($enum));
+$enum = IntlTimeZone::createTimeZoneIDEnumeration(
+ IntlTimeZone::TYPE_CANONICAL);
+$countCanonical = count(iterator_to_array($enum));
+$enum = IntlTimeZone::createTimeZoneIDEnumeration(
+ IntlTimeZone::TYPE_CANONICAL_LOCATION);
+$countCanonicalLocation = count(iterator_to_array($enum));
+
+var_dump($countAny > $countCanonical);
+var_dump($countCanonical > $countCanonicalLocation);
+
+$enum = IntlTimeZone::createTimeZoneIDEnumeration(
+ IntlTimeZone::TYPE_ANY, null, null);
+$countAny2 = count(iterator_to_array($enum));
+var_dump($countAny == $countAny2);
+
+$enum = IntlTimeZone::createTimeZoneIDEnumeration(
+ IntlTimeZone::TYPE_ANY, null, -3600000);
+$values = iterator_to_array($enum);
+
+print_r(
+array_values(
+array_intersect($values,
+array('Etc/GMT+1', 'Atlantic/Azores'))
+));
+
+
+?>
+==DONE==
+--EXPECT--
+bool(true)
+bool(true)
+bool(true)
+Array
+(
+ [0] => Atlantic/Azores
+ [1] => Etc/GMT+1
+)
+==DONE== \ No newline at end of file
diff --git a/ext/intl/tests/timezone_createTimeZone_basic.phpt b/ext/intl/tests/timezone_createTimeZone_basic.phpt
new file mode 100644
index 0000000000..e79f5b58ee
--- /dev/null
+++ b/ext/intl/tests/timezone_createTimeZone_basic.phpt
@@ -0,0 +1,33 @@
+--TEST--
+IntlTimeZone::createTimeZone(): basic test
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+if (version_compare(INTL_ICU_VERSION, '4.8') < 0)
+ die('skip for ICU 4.8+');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+$tz = IntlTimeZone::createTimeZone('GMT+01:00');
+print_r($tz);
+$tz = intltz_create_time_zone('GMT+01:00');
+print_r($tz);
+?>
+==DONE==
+--EXPECT--
+IntlTimeZone Object
+(
+ [valid] => 1
+ [id] => GMT+01:00
+ [rawOffset] => 3600000
+ [currentOffset] => 3600000
+)
+IntlTimeZone Object
+(
+ [valid] => 1
+ [id] => GMT+01:00
+ [rawOffset] => 3600000
+ [currentOffset] => 3600000
+)
+==DONE== \ No newline at end of file
diff --git a/ext/intl/tests/timezone_createTimeZone_error.phpt b/ext/intl/tests/timezone_createTimeZone_error.phpt
new file mode 100644
index 0000000000..2be821a67e
--- /dev/null
+++ b/ext/intl/tests/timezone_createTimeZone_error.phpt
@@ -0,0 +1,34 @@
+--TEST--
+IntlTimeZone::createTimeZone(): errors
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+
+var_dump(IntlTimeZone::createTimeZone());
+var_dump(IntlTimeZone::createTimeZone(new stdClass));
+var_dump(IntlTimeZone::createTimeZone("foo bar", 4));
+var_dump(IntlTimeZone::createTimeZone("foo\x80"));
+
+--EXPECTF--
+
+Warning: IntlTimeZone::createTimeZone() expects exactly 1 parameter, 0 given in %s on line %d
+
+Warning: IntlTimeZone::createTimeZone(): intltz_create_time_zone: bad arguments in %s on line %d
+NULL
+
+Warning: IntlTimeZone::createTimeZone() expects parameter 1 to be string, object given in %s on line %d
+
+Warning: IntlTimeZone::createTimeZone(): intltz_create_time_zone: bad arguments in %s on line %d
+NULL
+
+Warning: IntlTimeZone::createTimeZone() expects exactly 1 parameter, 2 given in %s on line %d
+
+Warning: IntlTimeZone::createTimeZone(): intltz_create_time_zone: bad arguments in %s on line %d
+NULL
+
+Warning: IntlTimeZone::createTimeZone(): intltz_create_time_zone: could not convert time zone id to UTF-16 in %s on line %d
+NULL
diff --git a/ext/intl/tests/timezone_equals_basic.phpt b/ext/intl/tests/timezone_equals_basic.phpt
new file mode 100644
index 0000000000..105ae8582f
--- /dev/null
+++ b/ext/intl/tests/timezone_equals_basic.phpt
@@ -0,0 +1,33 @@
+--TEST--
+IntlTimeZone equals handler: basic test
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+
+$tz1 = intltz_create_time_zone('Europe/Lisbon');
+$tz2 = intltz_create_time_zone('Europe/Lisbon');
+echo "Comparison to self:\n";
+var_dump($tz1 == $tz1);
+echo "Comparison to equal instance:\n";
+var_dump($tz1 == $tz2);
+echo "Comparison to equivalent instance:\n";
+var_dump($tz1 == intltz_create_time_zone('Portugal'));
+echo "Comparison to GMT:\n";
+var_dump($tz1 == intltz_get_gmt());
+
+?>
+==DONE==
+--EXPECT--
+Comparison to self:
+bool(true)
+Comparison to equal instance:
+bool(true)
+Comparison to equivalent instance:
+bool(false)
+Comparison to GMT:
+bool(false)
+==DONE== \ No newline at end of file
diff --git a/ext/intl/tests/timezone_equals_error.phpt b/ext/intl/tests/timezone_equals_error.phpt
new file mode 100644
index 0000000000..d8d027a761
--- /dev/null
+++ b/ext/intl/tests/timezone_equals_error.phpt
@@ -0,0 +1,43 @@
+--TEST--
+IntlTimeZone equals handler: error test
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+
+class A extends IntlTimeZone {
+function __construct() {}
+}
+
+$tz = new A();
+$tz2 = intltz_get_gmt();
+var_dump($tz, $tz2);
+try {
+var_dump($tz == $tz2);
+} catch (Exception $e) {
+ var_dump(get_class($e), $e->getMessage());
+}
+
+?>
+==DONE==
+--EXPECT--
+object(A)#1 (1) {
+ ["valid"]=>
+ bool(false)
+}
+object(IntlTimeZone)#2 (4) {
+ ["valid"]=>
+ bool(true)
+ ["id"]=>
+ string(3) "GMT"
+ ["rawOffset"]=>
+ int(0)
+ ["currentOffset"]=>
+ int(0)
+}
+string(9) "Exception"
+string(63) "Comparison with at least one unconstructed IntlTimeZone operand"
+==DONE== \ No newline at end of file
diff --git a/ext/intl/tests/timezone_fromDateTimeZone_basic.phpt b/ext/intl/tests/timezone_fromDateTimeZone_basic.phpt
new file mode 100644
index 0000000000..10e2621ae4
--- /dev/null
+++ b/ext/intl/tests/timezone_fromDateTimeZone_basic.phpt
@@ -0,0 +1,41 @@
+--TEST--
+IntlTimeZone::fromDateTimeZone(): basic test
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+ini_set("intl.default_locale", "nl");
+date_default_timezone_set('Europe/Lisbon');
+
+$tz = IntlTimeZone::fromDateTimeZone(new DateTimeZone('Europe/Amsterdam'));
+var_dump($tz->getID(), $tz->getRawOffset());
+
+
+$dt = new DateTime('2012-01-01 00:00:00 CET');
+$dtz = $dt->getTimeZone();
+/* this is different from new DateTimeZone('CET'),
+ * which gives a Europe/Berlin timezone */
+var_dump($dtz->getName());
+$tz = IntlTimeZone::fromDateTimeZone($dtz);
+var_dump($tz->getID(), $tz->getRawOffset());
+
+
+$dt = new DateTime('2012-01-01 00:00:00 +0340');
+$dtz = $dt->getTimeZone();
+/* I don't think this timezone can be generated without a DateTime object */
+var_dump($dtz->getName());
+$tz = IntlTimeZone::fromDateTimeZone($dtz);
+var_dump($tz->getID(), $tz->getRawOffset() /* (3*60+40)*60000 */);
+
+--EXPECTF--
+string(16) "Europe/Amsterdam"
+int(3600000)
+string(3) "CET"
+string(3) "CET"
+int(3600000)
+string(6) "+03:40"
+string(%d) "GMT+03%s0"
+int(13200000)
diff --git a/ext/intl/tests/timezone_fromDateTimeZone_error.phpt b/ext/intl/tests/timezone_fromDateTimeZone_error.phpt
new file mode 100644
index 0000000000..031882277e
--- /dev/null
+++ b/ext/intl/tests/timezone_fromDateTimeZone_error.phpt
@@ -0,0 +1,50 @@
+--TEST--
+IntlTimeZone::fromDateTimeZone(): argument errors
+--INI--
+date.timezone=Atlantic/Azores
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+
+var_dump(IntlTimeZone::fromDateTimeZone());
+var_dump(IntlTimeZone::fromDateTimeZone(1,2));
+var_dump(IntlTimeZone::fromDateTimeZone('sdfds'));
+var_dump(IntlTimeZone::fromDateTimeZone(new stdclass));
+$dt = new DateTime('2012-08-01 00:00:00 WEST');
+var_dump(IntlTimeZone::fromDateTimeZone($dt->getTimeZone()));
+
+var_dump(intltz_from_date_time_zone());
+
+--EXPECTF--
+
+Warning: IntlTimeZone::fromDateTimeZone() expects exactly 1 parameter, 0 given in %s on line %d
+
+Warning: IntlTimeZone::fromDateTimeZone(): intltz_from_date_time_zone: bad arguments in %s on line %d
+NULL
+
+Warning: IntlTimeZone::fromDateTimeZone() expects exactly 1 parameter, 2 given in %s on line %d
+
+Warning: IntlTimeZone::fromDateTimeZone(): intltz_from_date_time_zone: bad arguments in %s on line %d
+NULL
+
+Warning: IntlTimeZone::fromDateTimeZone() expects parameter 1 to be DateTimeZone, string given in %s on line %d
+
+Warning: IntlTimeZone::fromDateTimeZone(): intltz_from_date_time_zone: bad arguments in %s on line %d
+NULL
+
+Warning: IntlTimeZone::fromDateTimeZone() expects parameter 1 to be DateTimeZone, object given in %s on line %d
+
+Warning: IntlTimeZone::fromDateTimeZone(): intltz_from_date_time_zone: bad arguments in %s on line %d
+NULL
+
+Warning: IntlTimeZone::fromDateTimeZone(): intltz_from_date_time_zone: time zone id 'WEST' extracted from ext/date DateTimeZone not recognized in %s on line %d
+NULL
+
+Warning: intltz_from_date_time_zone() expects exactly 1 parameter, 0 given in %s on line %d
+
+Warning: intltz_from_date_time_zone(): intltz_from_date_time_zone: bad arguments in %s on line %d
+NULL
diff --git a/ext/intl/tests/timezone_getCanonicalID_basic.phpt b/ext/intl/tests/timezone_getCanonicalID_basic.phpt
new file mode 100644
index 0000000000..897e9a9edc
--- /dev/null
+++ b/ext/intl/tests/timezone_getCanonicalID_basic.phpt
@@ -0,0 +1,19 @@
+--TEST--
+IntlTimeZone::getCanonicalID: basic test
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+print_R(IntlTimeZone::getCanonicalID('Portugal'));
+echo "\n";
+print_R(intltz_get_canonical_id('Portugal'));
+echo "\n";
+?>
+==DONE==
+--EXPECT--
+Europe/Lisbon
+Europe/Lisbon
+==DONE== \ No newline at end of file
diff --git a/ext/intl/tests/timezone_getCanonicalID_error.phpt b/ext/intl/tests/timezone_getCanonicalID_error.phpt
new file mode 100644
index 0000000000..c7ffb45b77
--- /dev/null
+++ b/ext/intl/tests/timezone_getCanonicalID_error.phpt
@@ -0,0 +1,32 @@
+--TEST--
+IntlTimeZone::getCanonicalID(): errors
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+
+var_dump(IntlTimeZone::getCanonicalID());
+var_dump(IntlTimeZone::getCanonicalID(array()));
+var_dump(IntlTimeZone::getCanonicalID("foo\x81"));
+var_dump(IntlTimeZone::getCanonicalID('foobar', null));
+
+
+--EXPECTF--
+
+Warning: IntlTimeZone::getCanonicalID() expects at least 1 parameter, 0 given in %s on line %d
+
+Warning: IntlTimeZone::getCanonicalID(): intltz_get_canonical_id: bad arguments in %s on line %d
+bool(false)
+
+Warning: IntlTimeZone::getCanonicalID() expects parameter 1 to be string, array given in %s on line %d
+
+Warning: IntlTimeZone::getCanonicalID(): intltz_get_canonical_id: bad arguments in %s on line %d
+bool(false)
+
+Warning: IntlTimeZone::getCanonicalID(): intltz_get_canonical_id: could not convert time zone id to UTF-16 in %s on line %d
+bool(false)
+
+Fatal error: Cannot pass parameter 2 by reference in %s on line %d
diff --git a/ext/intl/tests/timezone_getCanonicalID_variant1.phpt b/ext/intl/tests/timezone_getCanonicalID_variant1.phpt
new file mode 100644
index 0000000000..92a7f07378
--- /dev/null
+++ b/ext/intl/tests/timezone_getCanonicalID_variant1.phpt
@@ -0,0 +1,24 @@
+--TEST--
+IntlTimeZone::getCanonicalID(): second argument
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+
+var_dump(IntlTimeZone::getCanonicalID('Portugal', $isSystemId));
+var_dump($isSystemId);
+
+var_dump(IntlTimeZone::getCanonicalID('GMT +01:25', $isSystemId));
+var_dump($isSystemId);
+
+?>
+==DONE==
+--EXPECT--
+string(13) "Europe/Lisbon"
+bool(true)
+string(0) ""
+bool(false)
+==DONE== \ No newline at end of file
diff --git a/ext/intl/tests/timezone_getDSTSavings_basic.phpt b/ext/intl/tests/timezone_getDSTSavings_basic.phpt
new file mode 100644
index 0000000000..8dee5b8e94
--- /dev/null
+++ b/ext/intl/tests/timezone_getDSTSavings_basic.phpt
@@ -0,0 +1,21 @@
+--TEST--
+IntlTimeZone::getDSTSavings(): basic test
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+
+$lsb = IntlTimeZone::createTimeZone('Europe/Lisbon');
+var_dump($lsb->getDSTSavings());
+
+var_dump(intltz_get_dst_savings($lsb));
+
+?>
+==DONE==
+--EXPECT--
+int(3600000)
+int(3600000)
+==DONE== \ No newline at end of file
diff --git a/ext/intl/tests/timezone_getDSTSavings_error.phpt b/ext/intl/tests/timezone_getDSTSavings_error.phpt
new file mode 100644
index 0000000000..e1469f4ac6
--- /dev/null
+++ b/ext/intl/tests/timezone_getDSTSavings_error.phpt
@@ -0,0 +1,23 @@
+--TEST--
+IntlTimeZone::getDSTSavings(): errors
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+
+$tz = IntlTimeZone::createTimeZone('Europe/Lisbon');
+var_dump($tz->getDSTSavings(array()));
+
+var_dump(intltz_get_dst_savings(null));
+
+--EXPECTF--
+
+Warning: IntlTimeZone::getDSTSavings() expects exactly 0 parameters, 1 given in %s on line %d
+
+Warning: IntlTimeZone::getDSTSavings(): intltz_get_dst_savings: bad arguments in %s on line %d
+bool(false)
+
+Catchable fatal error: Argument 1 passed to intltz_get_dst_savings() must be an instance of IntlTimeZone, null given in %s on line %d
diff --git a/ext/intl/tests/timezone_getDisplayName_basic.phpt b/ext/intl/tests/timezone_getDisplayName_basic.phpt
new file mode 100644
index 0000000000..e4fc2f37ce
--- /dev/null
+++ b/ext/intl/tests/timezone_getDisplayName_basic.phpt
@@ -0,0 +1,24 @@
+--TEST--
+IntlTimeZone::getDisplayName(): basic test
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+
+$lsb = IntlTimeZone::createTimeZone('Europe/Lisbon');
+
+ini_set('intl.default_locale', 'en_US');
+var_dump($lsb->getDisplayName());
+
+ini_set('intl.default_locale', 'pt_PT');
+var_dump($lsb->getDisplayName());
+
+?>
+==DONE==
+--EXPECTF--
+string(%d) "Western European%sTime"
+string(%d) "Hora%sda Europa Ocidental"
+==DONE== \ No newline at end of file
diff --git a/ext/intl/tests/timezone_getDisplayName_error.phpt b/ext/intl/tests/timezone_getDisplayName_error.phpt
new file mode 100644
index 0000000000..a12f85c855
--- /dev/null
+++ b/ext/intl/tests/timezone_getDisplayName_error.phpt
@@ -0,0 +1,45 @@
+--TEST--
+IntlTimeZone::getDisplayName(): errors
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+
+$tz = IntlTimeZone::createTimeZone('Europe/Lisbon');
+var_dump($tz->getDisplayName(array()));
+var_dump($tz->getDisplayName(false, array()));
+var_dump($tz->getDisplayName(false, -1));
+var_dump($tz->getDisplayName(false, IntlTimeZone::DISPLAY_SHORT, array()));
+var_dump($tz->getDisplayName(false, IntlTimeZone::DISPLAY_SHORT, NULL, NULL));
+
+var_dump(intltz_get_display_name(null, IntlTimeZone::DISPLAY_SHORT, false, 'pt_PT'));
+
+--EXPECTF--
+
+Warning: IntlTimeZone::getDisplayName() expects parameter 1 to be boolean, array given in %s on line %d
+
+Warning: IntlTimeZone::getDisplayName(): intltz_get_display_name: bad arguments in %s on line %d
+bool(false)
+
+Warning: IntlTimeZone::getDisplayName() expects parameter 2 to be long, array given in %s on line %d
+
+Warning: IntlTimeZone::getDisplayName(): intltz_get_display_name: bad arguments in %s on line %d
+bool(false)
+
+Warning: IntlTimeZone::getDisplayName(): intltz_get_display_name: wrong display type in %s on line %d
+bool(false)
+
+Warning: IntlTimeZone::getDisplayName() expects parameter 3 to be string, array given in %s on line %d
+
+Warning: IntlTimeZone::getDisplayName(): intltz_get_display_name: bad arguments in %s on line %d
+bool(false)
+
+Warning: IntlTimeZone::getDisplayName() expects at most 3 parameters, 4 given in %s on line %d
+
+Warning: IntlTimeZone::getDisplayName(): intltz_get_display_name: bad arguments in %s on line %d
+bool(false)
+
+Catchable fatal error: Argument 1 passed to intltz_get_display_name() must be an instance of IntlTimeZone, null given in %s on line %d
diff --git a/ext/intl/tests/timezone_getDisplayName_variant1.phpt b/ext/intl/tests/timezone_getDisplayName_variant1.phpt
new file mode 100644
index 0000000000..83922dd170
--- /dev/null
+++ b/ext/intl/tests/timezone_getDisplayName_variant1.phpt
@@ -0,0 +1,26 @@
+--TEST--
+IntlTimeZone::getDisplayName(): daylight parameter effect
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+ini_set("error_reporting", -1);
+ini_set("display_errors", 1);
+
+$lsb = IntlTimeZone::createTimeZone('Europe/Lisbon');
+
+ini_set('intl.default_locale', 'en_US');
+var_dump($lsb->getDisplayName());
+var_dump($lsb->getDisplayName(false));
+var_dump($lsb->getDisplayName(true));
+
+?>
+==DONE==
+--EXPECTF--
+string(%d) "Western European%sTime"
+string(%d) "Western European%sTime"
+string(28) "Western European Summer Time"
+==DONE== \ No newline at end of file
diff --git a/ext/intl/tests/timezone_getDisplayName_variant2-49+.phpt b/ext/intl/tests/timezone_getDisplayName_variant2-49+.phpt
new file mode 100644
index 0000000000..4ee30aee12
--- /dev/null
+++ b/ext/intl/tests/timezone_getDisplayName_variant2-49+.phpt
@@ -0,0 +1,38 @@
+--TEST--
+IntlTimeZone::getDisplayName(): type parameter (ICU >= 49)
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+if (version_compare(INTL_ICU_VERSION, '49') < 0)
+ die('skip for ICU 49+');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+ini_set("error_reporting", -1);
+ini_set("display_errors", 1);
+
+$lsb = IntlTimeZone::createTimeZone('Europe/Lisbon');
+
+ini_set('intl.default_locale', 'en_US');
+var_dump($lsb->getDisplayName(false, IntlTimeZone::DISPLAY_SHORT));
+var_dump($lsb->getDisplayName(false, IntlTimeZone::DISPLAY_LONG));
+var_dump($lsb->getDisplayName(false, IntlTimeZone::DISPLAY_SHORT_GENERIC));
+var_dump($lsb->getDisplayName(false, IntlTimeZone::DISPLAY_LONG_GENERIC));
+var_dump($lsb->getDisplayName(false, IntlTimeZone::DISPLAY_SHORT_GMT));
+var_dump($lsb->getDisplayName(false, IntlTimeZone::DISPLAY_LONG_GMT));
+var_dump($lsb->getDisplayName(false, IntlTimeZone::DISPLAY_SHORT_COMMONLY_USED));
+var_dump($lsb->getDisplayName(false, IntlTimeZone::DISPLAY_GENERIC_LOCATION));
+
+?>
+==DONE==
+--EXPECT--
+string(3) "GMT"
+string(30) "Western European Standard Time"
+string(22) "Portugal Time (Lisbon)"
+string(21) "Western European Time"
+string(5) "+0000"
+string(3) "GMT"
+string(3) "GMT"
+string(22) "Portugal Time (Lisbon)"
+==DONE== \ No newline at end of file
diff --git a/ext/intl/tests/timezone_getDisplayName_variant2.phpt b/ext/intl/tests/timezone_getDisplayName_variant2.phpt
new file mode 100644
index 0000000000..1ccf68767f
--- /dev/null
+++ b/ext/intl/tests/timezone_getDisplayName_variant2.phpt
@@ -0,0 +1,40 @@
+--TEST--
+IntlTimeZone::getDisplayName(): type parameter (ICU < 49)
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+if (version_compare(INTL_ICU_VERSION, '49') >= 0)
+ die('skip for ICU < 49');
+if (version_compare(INTL_ICU_VERSION, '4.8') < 0)
+ die('skip for ICU 4.8+');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+ini_set("error_reporting", -1);
+ini_set("display_errors", 1);
+
+$lsb = IntlTimeZone::createTimeZone('Europe/Lisbon');
+
+ini_set('intl.default_locale', 'en_US');
+var_dump($lsb->getDisplayName(false, IntlTimeZone::DISPLAY_SHORT));
+var_dump($lsb->getDisplayName(false, IntlTimeZone::DISPLAY_LONG));
+var_dump($lsb->getDisplayName(false, IntlTimeZone::DISPLAY_SHORT_GENERIC));
+var_dump($lsb->getDisplayName(false, IntlTimeZone::DISPLAY_LONG_GENERIC));
+var_dump($lsb->getDisplayName(false, IntlTimeZone::DISPLAY_SHORT_GMT));
+var_dump($lsb->getDisplayName(false, IntlTimeZone::DISPLAY_LONG_GMT));
+var_dump($lsb->getDisplayName(false, IntlTimeZone::DISPLAY_SHORT_COMMONLY_USED));
+var_dump($lsb->getDisplayName(false, IntlTimeZone::DISPLAY_GENERIC_LOCATION));
+
+?>
+==DONE==
+--EXPECT--
+string(3) "WET"
+string(21) "Western European Time"
+string(22) "Portugal Time (Lisbon)"
+string(22) "Portugal Time (Lisbon)"
+string(5) "+0000"
+string(3) "GMT"
+string(3) "GMT"
+string(22) "Portugal Time (Lisbon)"
+==DONE== \ No newline at end of file
diff --git a/ext/intl/tests/timezone_getDisplayName_variant3-49+.phpt b/ext/intl/tests/timezone_getDisplayName_variant3-49+.phpt
new file mode 100644
index 0000000000..e90cc4748c
--- /dev/null
+++ b/ext/intl/tests/timezone_getDisplayName_variant3-49+.phpt
@@ -0,0 +1,28 @@
+--TEST--
+IntlTimeZone::getDisplayName(): locale parameter
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+if (version_compare(INTL_ICU_VERSION, '49') < 0)
+ die('skip for ICU 49+');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+ini_set("error_reporting", -1);
+ini_set("display_errors", 1);
+
+$lsb = IntlTimeZone::createTimeZone('Europe/Lisbon');
+
+ini_set('intl.default_locale', 'en_US');
+var_dump($lsb->getDisplayName(false, IntlTimeZone::DISPLAY_LONG));
+var_dump($lsb->getDisplayName(false, IntlTimeZone::DISPLAY_LONG, NULL));
+var_dump($lsb->getDisplayName(false, IntlTimeZone::DISPLAY_LONG, 'pt_PT'));
+
+?>
+==DONE==
+--EXPECT--
+string(30) "Western European Standard Time"
+string(30) "Western European Standard Time"
+string(32) "Hora Padrão da Europa Ocidental"
+==DONE==
diff --git a/ext/intl/tests/timezone_getDisplayName_variant3.phpt b/ext/intl/tests/timezone_getDisplayName_variant3.phpt
new file mode 100644
index 0000000000..c160777583
--- /dev/null
+++ b/ext/intl/tests/timezone_getDisplayName_variant3.phpt
@@ -0,0 +1,28 @@
+--TEST--
+IntlTimeZone::getDisplayName(): locale parameter
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+if (version_compare(INTL_ICU_VERSION, '49') >= 0)
+ die('skip for ICU <= 4.8');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+ini_set("error_reporting", -1);
+ini_set("display_errors", 1);
+
+$lsb = IntlTimeZone::createTimeZone('Europe/Lisbon');
+
+ini_set('intl.default_locale', 'en_US');
+var_dump($lsb->getDisplayName(false, IntlTimeZone::DISPLAY_LONG));
+var_dump($lsb->getDisplayName(false, IntlTimeZone::DISPLAY_LONG, NULL));
+var_dump($lsb->getDisplayName(false, IntlTimeZone::DISPLAY_LONG, 'pt_PT'));
+
+?>
+==DONE==
+--EXPECT--
+string(21) "Western European Time"
+string(21) "Western European Time"
+string(24) "Hora da Europa Ocidental"
+==DONE== \ No newline at end of file
diff --git a/ext/intl/tests/timezone_getEquivalentID_basic.phpt b/ext/intl/tests/timezone_getEquivalentID_basic.phpt
new file mode 100644
index 0000000000..8af1e20897
--- /dev/null
+++ b/ext/intl/tests/timezone_getEquivalentID_basic.phpt
@@ -0,0 +1,19 @@
+--TEST--
+IntlTimeZone::getEquivalentID(): basic test
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+print_R(IntlTimeZone::getEquivalentID('Europe/Lisbon', "1"));
+echo "\n";
+print_R(intltz_get_equivalent_id('Europe/Lisbon', 1));
+echo "\n";
+?>
+==DONE==
+--EXPECT--
+Portugal
+Portugal
+==DONE== \ No newline at end of file
diff --git a/ext/intl/tests/timezone_getEquivalentID_error.phpt b/ext/intl/tests/timezone_getEquivalentID_error.phpt
new file mode 100644
index 0000000000..b3f344b54d
--- /dev/null
+++ b/ext/intl/tests/timezone_getEquivalentID_error.phpt
@@ -0,0 +1,34 @@
+--TEST--
+IntlTimeZone::getEquivalentID(): errors
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+
+var_dump(IntlTimeZone::getEquivalentID('foo'));
+var_dump(IntlTimeZone::getEquivalentID('foo', 'bar'));
+var_dump(IntlTimeZone::getEquivalentID('Europe/Lisbon', 0, 1));
+var_dump(IntlTimeZone::getEquivalentID("foo\x80", 0));
+
+--EXPECTF--
+
+Warning: IntlTimeZone::getEquivalentID() expects exactly 2 parameters, 1 given in %s on line %d
+
+Warning: IntlTimeZone::getEquivalentID(): intltz_get_equivalent_id: bad arguments in %s on line %d
+bool(false)
+
+Warning: IntlTimeZone::getEquivalentID() expects parameter 2 to be long, string given in %s on line %d
+
+Warning: IntlTimeZone::getEquivalentID(): intltz_get_equivalent_id: bad arguments in %s on line %d
+bool(false)
+
+Warning: IntlTimeZone::getEquivalentID() expects exactly 2 parameters, 3 given in %s on line %d
+
+Warning: IntlTimeZone::getEquivalentID(): intltz_get_equivalent_id: bad arguments in %s on line %d
+bool(false)
+
+Warning: IntlTimeZone::getEquivalentID(): intltz_get_equivalent_id: could not convert time zone id to UTF-16 in %s on line %d
+bool(false)
diff --git a/ext/intl/tests/timezone_getErrorCodeMessage_basic.phpt b/ext/intl/tests/timezone_getErrorCodeMessage_basic.phpt
new file mode 100644
index 0000000000..d3a3dee47d
--- /dev/null
+++ b/ext/intl/tests/timezone_getErrorCodeMessage_basic.phpt
@@ -0,0 +1,31 @@
+--TEST--
+IntlTimeZone::getErrorCode/Message(): basic test
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+
+$lsb = IntlTimeZone::createTimeZone('Europe/Lisbon');
+
+var_dump($lsb->getErrorCode());
+var_dump($lsb->getErrorMessage());
+
+var_dump($lsb->getOffset(INF, 1, $a, $b));
+
+var_dump($lsb->getErrorCode());
+var_dump($lsb->getErrorMessage());
+
+?>
+==DONE==
+--EXPECTF--
+int(0)
+string(12) "U_ZERO_ERROR"
+
+Warning: IntlTimeZone::getOffset(): intltz_get_offset: error obtaining offset in %s on line %d
+bool(false)
+int(1)
+string(67) "intltz_get_offset: error obtaining offset: U_ILLEGAL_ARGUMENT_ERROR"
+==DONE== \ No newline at end of file
diff --git a/ext/intl/tests/timezone_getErrorCode_error.phpt b/ext/intl/tests/timezone_getErrorCode_error.phpt
new file mode 100644
index 0000000000..b56d3b0a48
--- /dev/null
+++ b/ext/intl/tests/timezone_getErrorCode_error.phpt
@@ -0,0 +1,23 @@
+--TEST--
+IntlTimeZone::getErrorCode(): errors
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+
+$tz = IntlTimeZone::createTimeZone('Europe/Lisbon');
+var_dump($tz->getErrorCode(array()));
+
+var_dump(intltz_get_error_code(null));
+
+--EXPECTF--
+
+Warning: IntlTimeZone::getErrorCode() expects exactly 0 parameters, 1 given in %s on line %d
+
+Warning: IntlTimeZone::getErrorCode(): intltz_get_error_code: bad arguments in %s on line %d
+bool(false)
+
+Catchable fatal error: Argument 1 passed to intltz_get_error_code() must be an instance of IntlTimeZone, null given in %s on line %d
diff --git a/ext/intl/tests/timezone_getErrorMessage_error.phpt b/ext/intl/tests/timezone_getErrorMessage_error.phpt
new file mode 100644
index 0000000000..067dcdc13b
--- /dev/null
+++ b/ext/intl/tests/timezone_getErrorMessage_error.phpt
@@ -0,0 +1,23 @@
+--TEST--
+IntlTimeZone::getErrorMessage(): errors
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+
+$tz = IntlTimeZone::createTimeZone('Europe/Lisbon');
+var_dump($tz->getErrorMessage(array()));
+
+var_dump(intltz_get_error_message(null));
+
+--EXPECTF--
+
+Warning: IntlTimeZone::getErrorMessage() expects exactly 0 parameters, 1 given in %s on line %d
+
+Warning: IntlTimeZone::getErrorMessage(): intltz_get_error_message: bad arguments in %s on line %d
+bool(false)
+
+Catchable fatal error: Argument 1 passed to intltz_get_error_message() must be an instance of IntlTimeZone, null given in %s on line %d
diff --git a/ext/intl/tests/timezone_getGMT_basic.phpt b/ext/intl/tests/timezone_getGMT_basic.phpt
new file mode 100644
index 0000000000..99b3fa22ca
--- /dev/null
+++ b/ext/intl/tests/timezone_getGMT_basic.phpt
@@ -0,0 +1,31 @@
+--TEST--
+IntlTimeZone::getGMT(): basic test
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+$tz = IntlTimeZone::getGMT();
+print_r($tz);
+$tz = intltz_get_gmt();
+print_r($tz);
+?>
+==DONE==
+--EXPECT--
+IntlTimeZone Object
+(
+ [valid] => 1
+ [id] => GMT
+ [rawOffset] => 0
+ [currentOffset] => 0
+)
+IntlTimeZone Object
+(
+ [valid] => 1
+ [id] => GMT
+ [rawOffset] => 0
+ [currentOffset] => 0
+)
+==DONE== \ No newline at end of file
diff --git a/ext/intl/tests/timezone_getGMT_error.phpt b/ext/intl/tests/timezone_getGMT_error.phpt
new file mode 100644
index 0000000000..15afb765e4
--- /dev/null
+++ b/ext/intl/tests/timezone_getGMT_error.phpt
@@ -0,0 +1,19 @@
+--TEST--
+IntlTimeZone::getGMT(): errors
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+
+var_dump(IntlTimeZone::getGMT(4));
+
+
+--EXPECTF--
+
+Warning: IntlTimeZone::getGMT() expects exactly 0 parameters, 1 given in %s on line %d
+
+Warning: IntlTimeZone::getGMT(): intltz_get_gmt: bad arguments in %s on line %d
+NULL
diff --git a/ext/intl/tests/timezone_getID_error.phpt b/ext/intl/tests/timezone_getID_error.phpt
new file mode 100644
index 0000000000..b239b3facf
--- /dev/null
+++ b/ext/intl/tests/timezone_getID_error.phpt
@@ -0,0 +1,23 @@
+--TEST--
+IntlTimeZone::getID(): errors
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+
+$tz = IntlTimeZone::createTimeZone('Europe/Lisbon');
+var_dump($tz->getID('foo'));
+intltz_get_id(null);
+
+
+--EXPECTF--
+
+Warning: IntlTimeZone::getID() expects exactly 0 parameters, 1 given in %s on line %d
+
+Warning: IntlTimeZone::getID(): intltz_get_id: bad arguments in %s on line %d
+bool(false)
+
+Catchable fatal error: Argument 1 passed to intltz_get_id() must be an instance of IntlTimeZone, null given in %s on line %d
diff --git a/ext/intl/tests/timezone_getOffset_basic.phpt b/ext/intl/tests/timezone_getOffset_basic.phpt
new file mode 100644
index 0000000000..582d45cad9
--- /dev/null
+++ b/ext/intl/tests/timezone_getOffset_basic.phpt
@@ -0,0 +1,33 @@
+--TEST--
+IntlTimeZone::getOffset(): basic test
+--INI--
+date.timezone=Atlantic/Azores
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+$ams = IntlTimeZone::createTimeZone('Europe/Amsterdam');
+
+$date = strtotime("1 July 2012 +0000");
+
+var_dump($ams->getOffset($date *1000., true, $rawOffset, $dstOffset),
+ $rawOffset, $dstOffset);
+
+$lsb = IntlTimeZone::createTimeZone('Europe/Lisbon');
+
+var_dump(intltz_get_offset($lsb, $date *1000., true, $rawOffset, $dstOffset),
+ $rawOffset, $dstOffset);
+
+?>
+==DONE==
+--EXPECT--
+bool(true)
+int(3600000)
+int(3600000)
+bool(true)
+int(0)
+int(3600000)
+==DONE== \ No newline at end of file
diff --git a/ext/intl/tests/timezone_getOffset_error.phpt b/ext/intl/tests/timezone_getOffset_error.phpt
new file mode 100644
index 0000000000..73555002c0
--- /dev/null
+++ b/ext/intl/tests/timezone_getOffset_error.phpt
@@ -0,0 +1,33 @@
+--TEST--
+IntlTimeZone::getOffset(): errors
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+
+$tz = IntlTimeZone::createTimeZone('Europe/Lisbon');
+var_dump($tz->getOffset(INF, true, $a, $a));
+var_dump($tz->getOffset(time()*1000, true, $a));
+var_dump($tz->getOffset(time()*1000, true, $a, $a, $a));
+
+intltz_get_offset(null, time()*1000, false, $a, $a);
+
+--EXPECTF--
+
+Warning: IntlTimeZone::getOffset(): intltz_get_offset: error obtaining offset in %s on line %d
+bool(false)
+
+Warning: IntlTimeZone::getOffset() expects exactly 4 parameters, 3 given in %s on line %d
+
+Warning: IntlTimeZone::getOffset(): intltz_get_offset: bad arguments in %s on line %d
+bool(false)
+
+Warning: IntlTimeZone::getOffset() expects exactly 4 parameters, 5 given in %s on line %d
+
+Warning: IntlTimeZone::getOffset(): intltz_get_offset: bad arguments in %s on line %d
+bool(false)
+
+Catchable fatal error: Argument 1 passed to intltz_get_offset() must be an instance of IntlTimeZone, null given in %s on line %d
diff --git a/ext/intl/tests/timezone_getRawOffset_basic.phpt b/ext/intl/tests/timezone_getRawOffset_basic.phpt
new file mode 100644
index 0000000000..a2b4debf2b
--- /dev/null
+++ b/ext/intl/tests/timezone_getRawOffset_basic.phpt
@@ -0,0 +1,21 @@
+--TEST--
+IntlTimeZone::getRawOffset(): basic test
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+$ams = IntlTimeZone::createTimeZone('Europe/Amsterdam');
+var_dump($ams->getRawOffset());
+
+$lsb = IntlTimeZone::createTimeZone('Europe/Lisbon');
+var_dump(intltz_get_raw_offset($lsb));
+
+?>
+==DONE==
+--EXPECT--
+int(3600000)
+int(0)
+==DONE== \ No newline at end of file
diff --git a/ext/intl/tests/timezone_getRawOffset_error.phpt b/ext/intl/tests/timezone_getRawOffset_error.phpt
new file mode 100644
index 0000000000..eb6aac02cd
--- /dev/null
+++ b/ext/intl/tests/timezone_getRawOffset_error.phpt
@@ -0,0 +1,23 @@
+--TEST--
+IntlTimeZone::getRawOffset(): errors
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+
+$tz = IntlTimeZone::createTimeZone('Europe/Lisbon');
+var_dump($tz->getRawOffset('foo'));
+
+intltz_get_raw_offset(null);
+
+--EXPECTF--
+
+Warning: IntlTimeZone::getRawOffset() expects exactly 0 parameters, 1 given in %s on line %d
+
+Warning: IntlTimeZone::getRawOffset(): intltz_get_raw_offset: bad arguments in %s on line %d
+bool(false)
+
+Catchable fatal error: Argument 1 passed to intltz_get_raw_offset() must be an instance of IntlTimeZone, null given in %s on line %d
diff --git a/ext/intl/tests/timezone_getRegion_basic.phpt b/ext/intl/tests/timezone_getRegion_basic.phpt
new file mode 100644
index 0000000000..1a41ae8d58
--- /dev/null
+++ b/ext/intl/tests/timezone_getRegion_basic.phpt
@@ -0,0 +1,21 @@
+--TEST--
+IntlTimeZone::getRegion(): basic test
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+if (version_compare(INTL_ICU_VERSION, '4.8') < 0)
+ die('skip for ICU 4.8+');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+print_R(IntlTimeZone::getRegion('Europe/Amsterdam'));
+echo "\n";
+print_R(intltz_get_region('Europe/Amsterdam'));
+echo "\n";
+?>
+==DONE==
+--EXPECT--
+NL
+NL
+==DONE== \ No newline at end of file
diff --git a/ext/intl/tests/timezone_getRegion_error.phpt b/ext/intl/tests/timezone_getRegion_error.phpt
new file mode 100644
index 0000000000..34911d9abc
--- /dev/null
+++ b/ext/intl/tests/timezone_getRegion_error.phpt
@@ -0,0 +1,42 @@
+--TEST--
+IntlTimeZone::getRegion(): errors
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+if (version_compare(INTL_ICU_VERSION, '4.8') < 0)
+ die('skip for ICU 4.8+');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+
+var_dump(IntlTimeZone::getRegion());
+var_dump(IntlTimeZone::getRegion(array()));
+var_dump(IntlTimeZone::getRegion('Europe/Lisbon', 4));
+var_dump(IntlTimeZone::getRegion("foo\x81"));
+var_dump(IntlTimeZone::getRegion("foo"));
+
+
+
+--EXPECTF--
+
+Warning: IntlTimeZone::getRegion() expects exactly 1 parameter, 0 given in %s on line %d
+
+Warning: IntlTimeZone::getRegion(): intltz_get_region: bad arguments in %s on line %d
+bool(false)
+
+Warning: IntlTimeZone::getRegion() expects parameter 1 to be string, array given in %s on line %d
+
+Warning: IntlTimeZone::getRegion(): intltz_get_region: bad arguments in %s on line %d
+bool(false)
+
+Warning: IntlTimeZone::getRegion() expects exactly 1 parameter, 2 given in %s on line %d
+
+Warning: IntlTimeZone::getRegion(): intltz_get_region: bad arguments in %s on line %d
+bool(false)
+
+Warning: IntlTimeZone::getRegion(): intltz_get_region: could not convert time zone id to UTF-16 in %s on line %d
+bool(false)
+
+Warning: IntlTimeZone::getRegion(): intltz_get_region: Error obtaining region in %s on line %d
+bool(false)
diff --git a/ext/intl/tests/timezone_getTZDataVersion_error.phpt b/ext/intl/tests/timezone_getTZDataVersion_error.phpt
new file mode 100644
index 0000000000..258b8807b7
--- /dev/null
+++ b/ext/intl/tests/timezone_getTZDataVersion_error.phpt
@@ -0,0 +1,18 @@
+--TEST--
+IntlTimeZone::getTZDataVersion(): errors
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+
+var_dump(IntlTimeZone::getTZDataVersion('foo'));
+
+--EXPECTF--
+
+Warning: IntlTimeZone::getTZDataVersion() expects exactly 0 parameters, 1 given in %s on line %d
+
+Warning: IntlTimeZone::getTZDataVersion(): intltz_get_tz_data_version: bad arguments in %s on line %d
+bool(false)
diff --git a/ext/intl/tests/timezone_getTZData_basic.phpt b/ext/intl/tests/timezone_getTZData_basic.phpt
new file mode 100644
index 0000000000..dea5b7c4b3
--- /dev/null
+++ b/ext/intl/tests/timezone_getTZData_basic.phpt
@@ -0,0 +1,19 @@
+--TEST--
+IntlTimeZone::getTZDataVersion: basic test
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+print_R(IntlTimeZone::getTZDataVersion());
+echo "\n";
+print_R(intltz_get_tz_data_version());
+echo "\n";
+?>
+==DONE==
+--EXPECTF--
+20%d%s
+20%d%s
+==DONE== \ No newline at end of file
diff --git a/ext/intl/tests/timezone_getUnknown_basic.phpt b/ext/intl/tests/timezone_getUnknown_basic.phpt
new file mode 100644
index 0000000000..aef1a54561
--- /dev/null
+++ b/ext/intl/tests/timezone_getUnknown_basic.phpt
@@ -0,0 +1,35 @@
+--TEST--
+IntlCalendar::getUnknown(): basic test
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+if (version_compare(INTL_ICU_VERSION, '49') < 0)
+ die('skip for ICU 49+');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+ini_set("intl.default_locale", "nl");
+
+$tz = IntlTimeZone::getUnknown();
+print_r($tz);
+$tz = intltz_get_unknown();
+print_r($tz);
+?>
+==DONE==
+--EXPECT--
+IntlTimeZone Object
+(
+ [valid] => 1
+ [id] => Etc/Unknown
+ [rawOffset] => 0
+ [currentOffset] => 0
+)
+IntlTimeZone Object
+(
+ [valid] => 1
+ [id] => Etc/Unknown
+ [rawOffset] => 0
+ [currentOffset] => 0
+)
+==DONE== \ No newline at end of file
diff --git a/ext/intl/tests/timezone_getUnknown_error.phpt b/ext/intl/tests/timezone_getUnknown_error.phpt
new file mode 100644
index 0000000000..704b1b096f
--- /dev/null
+++ b/ext/intl/tests/timezone_getUnknown_error.phpt
@@ -0,0 +1,29 @@
+--TEST--
+IntlCalendar::getUnknown(): bad arguments
+--INI--
+date.timezone=Atlantic/Azores
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+if (version_compare(INTL_ICU_VERSION, '49') < 0)
+ die('skip for ICU 49+');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+
+$c = new IntlGregorianCalendar(NULL, 'pt_PT');
+
+IntlTimeZone::getUnknown(1);
+
+intltz_get_unknown(1);
+
+--EXPECTF--
+
+Warning: IntlTimeZone::getUnknown() expects exactly 0 parameters, 1 given in %s on line %d
+
+Warning: IntlTimeZone::getUnknown(): intltz_get_unknown: bad arguments in %s on line %d
+
+Warning: intltz_get_unknown() expects exactly 0 parameters, 1 given in %s on line %d
+
+Warning: intltz_get_unknown(): intltz_get_unknown: bad arguments in %s on line %d
diff --git a/ext/intl/tests/timezone_hasSameRules_basic.phpt b/ext/intl/tests/timezone_hasSameRules_basic.phpt
new file mode 100644
index 0000000000..55faaf760b
--- /dev/null
+++ b/ext/intl/tests/timezone_hasSameRules_basic.phpt
@@ -0,0 +1,35 @@
+--TEST--
+IntlTimeZone::hasSameRules(): basic test
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+
+$lsb = IntlTimeZone::createTimeZone('Europe/Lisbon');
+$prt = IntlTimeZone::createTimeZone('Portugal');
+$azo = IntlTimeZone::createTimeZone('Atlantic/Azores');
+
+echo "Europe/Lisbon has same rules as itself:\n";
+var_dump($lsb->hasSameRules($lsb));
+
+echo "\nEurope/Lisbon has same rules as Portugal:\n";
+var_dump($lsb->hasSameRules($prt));
+
+echo "\nEurope/Lisbon has same rules as Atlantic/Azores:\n";
+var_dump(intltz_has_same_rules($lsb, $azo));
+
+?>
+==DONE==
+--EXPECT--
+Europe/Lisbon has same rules as itself:
+bool(true)
+
+Europe/Lisbon has same rules as Portugal:
+bool(true)
+
+Europe/Lisbon has same rules as Atlantic/Azores:
+bool(false)
+==DONE== \ No newline at end of file
diff --git a/ext/intl/tests/timezone_hasSameRules_error.phpt b/ext/intl/tests/timezone_hasSameRules_error.phpt
new file mode 100644
index 0000000000..35a29be5db
--- /dev/null
+++ b/ext/intl/tests/timezone_hasSameRules_error.phpt
@@ -0,0 +1,37 @@
+--TEST--
+IntlTimeZone::hasSameRules(): errors
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+
+function error_handler($errno, $errstr, $errfile, $errline)
+{
+ var_dump($errno, $errstr);
+ return true;
+}
+set_error_handler("error_handler");
+
+$tz = IntlTimeZone::createTimeZone('Europe/Lisbon');
+var_dump($tz->hasSameRules('foo'));
+
+var_dump(intltz_has_same_rules(null, $tz));
+
+--EXPECT--
+int(4096)
+string(99) "Argument 1 passed to IntlTimeZone::hasSameRules() must be an instance of IntlTimeZone, string given"
+int(2)
+string(81) "IntlTimeZone::hasSameRules() expects parameter 1 to be IntlTimeZone, string given"
+int(2)
+string(66) "IntlTimeZone::hasSameRules(): intltz_has_same_rules: bad arguments"
+bool(false)
+int(4096)
+string(92) "Argument 1 passed to intltz_has_same_rules() must be an instance of IntlTimeZone, null given"
+int(2)
+string(74) "intltz_has_same_rules() expects parameter 1 to be IntlTimeZone, null given"
+int(2)
+string(61) "intltz_has_same_rules(): intltz_has_same_rules: bad arguments"
+bool(false)
diff --git a/ext/intl/tests/timezone_toDateTimeZone_basic.phpt b/ext/intl/tests/timezone_toDateTimeZone_basic.phpt
new file mode 100644
index 0000000000..d22aa689dc
--- /dev/null
+++ b/ext/intl/tests/timezone_toDateTimeZone_basic.phpt
@@ -0,0 +1,38 @@
+--TEST--
+IntlTimeZone::toDateTimeZone(): basic test
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+ini_set("intl.default_locale", "nl");
+date_default_timezone_set('Europe/Lisbon');
+
+function do_test(IntlTimeZone $tz, $proc = false) {
+ var_dump($tz->getID(), $tz->getRawOffset());
+ if (!$proc)
+ $dtz = $tz->toDateTimeZone();
+ else
+ $dtz = intltz_to_date_time_zone($tz);
+ var_dump($dtz->getName(), $dtz->getOffset(new DateTime('2012-01-01 00:00:00')));
+}
+
+do_test(IntlTimeZone::createTimeZone('CET'));
+do_test(IntlTimeZone::createTimeZone('Europe/Amsterdam'));
+do_test(IntlTimeZone::createTimeZone('GMT+0405'), true);
+
+--EXPECTF--
+string(3) "CET"
+int(3600000)
+string(13) "Europe/Berlin"
+int(3600)
+string(16) "Europe/Amsterdam"
+int(3600000)
+string(16) "Europe/Amsterdam"
+int(3600)
+string(%s) "GMT+04%s5"
+int(14700000)
+string(6) "+04:05"
+int(14700)
diff --git a/ext/intl/tests/timezone_toDateTimeZone_error.phpt b/ext/intl/tests/timezone_toDateTimeZone_error.phpt
new file mode 100644
index 0000000000..e48d7aca92
--- /dev/null
+++ b/ext/intl/tests/timezone_toDateTimeZone_error.phpt
@@ -0,0 +1,38 @@
+--TEST--
+IntlTimeZone::toDateTimeZone(): errors
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+
+$tz = IntlTimeZone::createTimeZone('Etc/Unknown');
+
+var_dump($tz->toDateTimeZone(''));
+try {
+ var_dump($tz->toDateTimeZone());
+} catch (Exception $e) {
+ var_dump($e->getMessage());
+}
+
+var_dump(intltz_to_date_time_zone());
+var_dump(intltz_to_date_time_zone(1));
+
+--EXPECTF--
+
+Warning: IntlTimeZone::toDateTimeZone() expects exactly 0 parameters, 1 given in %s on line %d
+
+Warning: IntlTimeZone::toDateTimeZone(): intltz_to_date_time_zone: bad arguments in %s on line %d
+bool(false)
+
+Warning: IntlTimeZone::toDateTimeZone(): intltz_to_date_time_zone: DateTimeZone constructor threw exception in %s on line %d
+string(66) "DateTimeZone::__construct(): Unknown or bad timezone (Etc/Unknown)"
+
+Warning: intltz_to_date_time_zone() expects exactly 1 parameter, 0 given in %s on line %d
+
+Warning: intltz_to_date_time_zone(): intltz_to_date_time_zone: bad arguments in %s on line %d
+bool(false)
+
+Catchable fatal error: Argument 1 passed to intltz_to_date_time_zone() must be an instance of IntlTimeZone, integer given in %s on line %d
diff --git a/ext/intl/tests/timezone_useDaylightTime_basic.phpt b/ext/intl/tests/timezone_useDaylightTime_basic.phpt
new file mode 100644
index 0000000000..15baf108b3
--- /dev/null
+++ b/ext/intl/tests/timezone_useDaylightTime_basic.phpt
@@ -0,0 +1,25 @@
+--TEST--
+IntlTimeZone::useDaylightTime: basic test
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+$lsb = IntlTimeZone::createTimeZone('Europe/Lisbon');
+$gmt = IntlTimeZone::getGMT();
+
+var_dump($lsb->useDaylightTime());
+var_dump($gmt->useDaylightTime());
+
+var_dump(intltz_use_daylight_time($lsb));
+var_dump(intltz_use_daylight_time($gmt));
+?>
+==DONE==
+--EXPECT--
+bool(true)
+bool(false)
+bool(true)
+bool(false)
+==DONE== \ No newline at end of file
diff --git a/ext/intl/tests/timezone_useDaylightTime_error.phpt b/ext/intl/tests/timezone_useDaylightTime_error.phpt
new file mode 100644
index 0000000000..aa5ca6cfca
--- /dev/null
+++ b/ext/intl/tests/timezone_useDaylightTime_error.phpt
@@ -0,0 +1,22 @@
+--TEST--
+IntlTimeZone::useDaylightTime(): errors
+--SKIPIF--
+<?php
+if (!extension_loaded('intl'))
+ die('skip intl extension not enabled');
+--FILE--
+<?php
+ini_set("intl.error_level", E_WARNING);
+
+$tz = IntlTimeZone::createTimeZone('Europe/Lisbon');
+var_dump($tz->useDaylightTime('foo'));
+intltz_use_daylight_time(null);
+
+--EXPECTF--
+
+Warning: IntlTimeZone::useDaylightTime() expects exactly 0 parameters, 1 given in %s on line %d
+
+Warning: IntlTimeZone::useDaylightTime(): intltz_use_daylight_time: bad arguments in %s on line %d
+bool(false)
+
+Catchable fatal error: Argument 1 passed to intltz_use_daylight_time() must be an instance of IntlTimeZone, null given in %s on line %d
diff --git a/ext/intl/tests/uconverter___construct_error.phpt b/ext/intl/tests/uconverter___construct_error.phpt
new file mode 100644
index 0000000000..1b2480818b
--- /dev/null
+++ b/ext/intl/tests/uconverter___construct_error.phpt
@@ -0,0 +1,14 @@
+--TEST--
+Basic UConverter::convert() usage
+--INI--
+intl.error_level = E_WARNING
+--SKIPIF--
+<?php if( !extension_loaded( 'intl' ) ) print 'skip'; ?>
+--FILE--
+<?php
+$c = new UConverter('utf-8', "\x80");
+var_dump($c);
+--EXPECTF--
+Warning: UConverter::__construct(): ucnv_open() returned error 4: U_FILE_ACCESS_ERROR in %s on line %d
+object(UConverter)#%d (0) {
+}
diff --git a/ext/intl/tests/uconverter_enum.phpt b/ext/intl/tests/uconverter_enum.phpt
new file mode 100644
index 0000000000..67e02c9d75
--- /dev/null
+++ b/ext/intl/tests/uconverter_enum.phpt
@@ -0,0 +1,21 @@
+--TEST--
+UConverter Enumerations
+--SKIPIF--
+<?php if( !extension_loaded( 'intl' ) ) print 'skip'; ?>
+--FILE--
+<?php
+$avail = UConverter::getAvailable();
+var_dump(count($avail) > 100);
+var_dump(in_array('UTF-7', $avail));
+var_dump(in_array('CESU-8', $avail));
+var_dump(in_array('ISO-8859-1', $avail));
+
+$latin1 = UConverter::getAliases('latin1');
+var_dump(in_array('ISO-8859-1', $latin1));
+
+--EXPECT--
+bool(true)
+bool(true)
+bool(true)
+bool(true)
+bool(true)
diff --git a/ext/intl/tests/uconverter_func_basic.phpt b/ext/intl/tests/uconverter_func_basic.phpt
new file mode 100644
index 0000000000..da8956beae
--- /dev/null
+++ b/ext/intl/tests/uconverter_func_basic.phpt
@@ -0,0 +1,17 @@
+--TEST--
+Basic UConverter::transcode() usage
+--SKIPIF--
+<?php if( !extension_loaded( 'intl' ) ) print 'skip'; ?>
+--FILE--
+<?php
+var_dump(UConverter::transcode("This is an ascii string", 'utf-8', 'latin1'));
+// urlencode so that non-ascii shows up parsable in phpt file
+var_dump(urlencode(UConverter::transcode("Espa\xF1ol", 'utf-8', 'latin1')));
+var_dump(urlencode(UConverter::transcode("Stra\xDFa", 'utf-8', 'latin1')));
+
+var_dump(bin2hex(UConverter::transcode("\xE4", 'utf-8', 'koi8-r')));
+--EXPECT--
+string(23) "This is an ascii string"
+string(12) "Espa%C3%B1ol"
+string(11) "Stra%C3%9Fa"
+string(4) "d094"
diff --git a/ext/intl/tests/uconverter_func_subst.phpt b/ext/intl/tests/uconverter_func_subst.phpt
new file mode 100644
index 0000000000..5cac5ce59c
--- /dev/null
+++ b/ext/intl/tests/uconverter_func_subst.phpt
@@ -0,0 +1,31 @@
+--TEST--
+Basic UConverter::convert() w/ Subsitution
+--SKIPIF--
+<?php if( !extension_loaded( 'intl' ) ) print 'skip'; ?>
+--INI--
+intl.use_exceptions=false
+--FILE--
+<?php
+foreach(array('?','','??') as $subst) {
+ $opts = array('to_subst' => $subst);
+ $ret = UConverter::transcode("This is an ascii string", 'ascii', 'utf-8', $opts);
+ if ($ret === FALSE) {
+ echo "Error: ", intl_get_error_message(), "\n";
+ } else {
+ var_dump($ret);
+ }
+ $ret = UConverter::transcode("Snowman: (\xE2\x98\x83)", 'ascii', 'utf-8', $opts);
+ if ($ret === FALSE) {
+ echo "Error: ", intl_get_error_message(), "\n";
+ } else {
+ var_dump($ret);
+ }
+}
+
+--EXPECTF--
+string(23) "This is an ascii string"
+string(12) "Snowman: (?)"
+Error: transcode() returned error 1: U_ILLEGAL_ARGUMENT_ERROR: U_ILLEGAL_ARGUMENT_ERROR
+Error: transcode() returned error 1: U_ILLEGAL_ARGUMENT_ERROR: U_ILLEGAL_ARGUMENT_ERROR
+Error: transcode() returned error 1: U_ILLEGAL_ARGUMENT_ERROR: U_ILLEGAL_ARGUMENT_ERROR
+Error: transcode() returned error 1: U_ILLEGAL_ARGUMENT_ERROR: U_ILLEGAL_ARGUMENT_ERROR
diff --git a/ext/intl/tests/uconverter_oop_algo.phpt b/ext/intl/tests/uconverter_oop_algo.phpt
new file mode 100644
index 0000000000..349182ce32
--- /dev/null
+++ b/ext/intl/tests/uconverter_oop_algo.phpt
@@ -0,0 +1,18 @@
+--TEST--
+UConverter Algorithmic converters
+--SKIPIF--
+<?php if( !extension_loaded( 'intl' ) ) print 'skip'; ?>
+--FILE--
+<?php
+$c = new UConverter('utf-8', 'latin1');
+var_dump(UConverter::LATIN_1 === $c->getSourceType());
+var_dump(UConverter::UTF8 === $c->getDestinationType());
+
+$c = new UConverter('koi8-r', 'utf-32be');
+var_dump(UConverter::UTF32_BigEndian === $c->getSourceType());
+var_dump(UConverter::SBCS === $c->getDestinationType());
+--EXPECT--
+bool(true)
+bool(true)
+bool(true)
+bool(true)
diff --git a/ext/intl/tests/uconverter_oop_basic.phpt b/ext/intl/tests/uconverter_oop_basic.phpt
new file mode 100644
index 0000000000..2b8909ff31
--- /dev/null
+++ b/ext/intl/tests/uconverter_oop_basic.phpt
@@ -0,0 +1,21 @@
+--TEST--
+Basic UConverter::convert() usage
+--SKIPIF--
+<?php if( !extension_loaded( 'intl' ) ) print 'skip'; ?>
+--FILE--
+<?php
+$c = new UConverter('utf-8', 'latin1');
+var_dump($c->convert("This is an ascii string"));
+// urlencode so that non-ascii shows up parsable in phpt file
+var_dump(urlencode($c->convert("Espa\xF1ol"))); // U+00F1 LATIN SMALL LETTER N WITH TILDE
+var_dump(urlencode($c->convert("Stra\xDFa"))); // U+00DF LATIN SMALL LETTER SHARP S
+var_dump(urlencode($c->convert("Stra\xC3\x9Fa", true))); // Reverse prior op
+
+$k = new UConverter('utf-8', 'koi8-r');
+var_dump(bin2hex($k->convert("\xE4"))); // U+0414 CYRILLIC CAPITAL LETTER DE
+--EXPECT--
+string(23) "This is an ascii string"
+string(12) "Espa%C3%B1ol"
+string(11) "Stra%C3%9Fa"
+string(8) "Stra%DFa"
+string(4) "d094"
diff --git a/ext/intl/tests/uconverter_oop_callback.phpt b/ext/intl/tests/uconverter_oop_callback.phpt
new file mode 100644
index 0000000000..47daf43305
--- /dev/null
+++ b/ext/intl/tests/uconverter_oop_callback.phpt
@@ -0,0 +1,52 @@
+--TEST--
+UConverter::convert() w/ Callback Reasons
+--SKIPIF--
+<?php if( !extension_loaded( 'intl' ) ) print 'skip'; ?>
+--FILE--
+<?php
+class MyConverter extends UConverter {
+ /**
+ * Called during conversion from source encoding to internal UChar representation
+ */
+ public function toUCallback($reason, $source, $codeUnits, &$error) {
+ echo "toUCallback(", UConverter::reasonText($reason), ", ...)\n";
+ return parent::toUCallback($reason, $source, $codeUnits, $error);
+ }
+
+ /**
+ * Called during conversion from internal UChar to destination encoding
+ */
+ public function fromUCallback($reason, $source, $codePoint, &$error) {
+ echo "fromUCallback(", UConverter::reasonText($reason), ", ...)\n";
+ return parent::fromUCallback($reason, $source, $codePoint, $error);
+ }
+
+}
+
+$c = new MyConverter('ascii', 'utf-8');
+foreach(array("regular", "irregul\xC1\xA1r", "\xC2\xA1unsupported!") as $word) {
+ $c->convert($word);
+}
+--EXPECT--
+toUCallback(REASON_RESET, ...)
+toUCallback(REASON_RESET, ...)
+fromUCallback(REASON_RESET, ...)
+fromUCallback(REASON_RESET, ...)
+toUCallback(REASON_RESET, ...)
+toUCallback(REASON_ILLEGAL, ...)
+toUCallback(REASON_RESET, ...)
+toUCallback(REASON_ILLEGAL, ...)
+fromUCallback(REASON_RESET, ...)
+fromUCallback(REASON_UNASSIGNED, ...)
+fromUCallback(REASON_RESET, ...)
+fromUCallback(REASON_UNASSIGNED, ...)
+toUCallback(REASON_RESET, ...)
+toUCallback(REASON_RESET, ...)
+fromUCallback(REASON_RESET, ...)
+fromUCallback(REASON_UNASSIGNED, ...)
+fromUCallback(REASON_RESET, ...)
+fromUCallback(REASON_UNASSIGNED, ...)
+toUCallback(REASON_CLOSE, ...)
+fromUCallback(REASON_CLOSE, ...)
+toUCallback(REASON_CLOSE, ...)
+fromUCallback(REASON_CLOSE, ...)
diff --git a/ext/intl/tests/uconverter_oop_callback_return.phpt b/ext/intl/tests/uconverter_oop_callback_return.phpt
new file mode 100644
index 0000000000..cd7e7a5834
--- /dev/null
+++ b/ext/intl/tests/uconverter_oop_callback_return.phpt
@@ -0,0 +1,40 @@
+--TEST--
+UConverter::convert() w/ Callback Return Values
+--SKIPIF--
+<?php if( !extension_loaded( 'intl' ) ) print 'skip'; ?>
+--FILE--
+<?php
+class MyConverter extends UConverter {
+ public function toUCallback($reason, $source, $codeUnits, &$error) {
+ $error = U_ZERO_ERROR;
+ switch ($codeUnits) {
+ case "\x80": return NULL;
+ case "\x81": return 'a';
+ case "\x82": return ord('b');
+ case "\x83": return array('c');
+ }
+ }
+
+ /**
+ * Called during conversion from internal UChar to destination encoding
+ */
+ public function fromUCallback($reason, $source, $codePoint, &$error) {
+ $error = U_ZERO_ERROR;
+ switch ($codePoint) {
+ case 0x00F1: return "A";
+ case 0x00F2: return ord("B");
+ case 0x00F3: return array("C");
+ case 0x00F4: return NULL;
+ }
+ }
+
+}
+
+$c = new MyConverter('ascii', 'utf-8');
+// This line will trigger toUCallback
+var_dump($c->convert("\x80\x81\x82\x83"));
+// This line will trigger fromUCallback
+var_dump($c->convert("\xC3\xB1\xC3\xB2\xC3\xB3\xC3\xB4"));
+--EXPECT--
+string(3) "abc"
+string(3) "ABC"
diff --git a/ext/intl/tests/uconverter_oop_subst.phpt b/ext/intl/tests/uconverter_oop_subst.phpt
new file mode 100644
index 0000000000..d21d95f8d0
--- /dev/null
+++ b/ext/intl/tests/uconverter_oop_subst.phpt
@@ -0,0 +1,24 @@
+--TEST--
+Basic UConverter::convert() w/ Subsitution
+--SKIPIF--
+<?php if( !extension_loaded( 'intl' ) ) print 'skip'; ?>
+--INI--
+intl.use_exceptions=false
+--FILE--
+<?php
+$c = new UConverter('ascii', 'utf-8');
+
+foreach(array('?','','<unknown>') as $subst) {
+ if (!$c->setSubstChars($subst)) {
+ echo "**Disallowed\n";
+ continue;
+ }
+ var_dump($c->convert("This is an ascii string"));
+ var_dump($c->convert("Snowman: (\xE2\x98\x83)"));
+}
+
+--EXPECT--
+string(23) "This is an ascii string"
+string(12) "Snowman: (?)"
+**Disallowed
+**Disallowed
diff --git a/ext/intl/timezone/timezone_class.cpp b/ext/intl/timezone/timezone_class.cpp
new file mode 100644
index 0000000000..374b163851
--- /dev/null
+++ b/ext/intl/timezone/timezone_class.cpp
@@ -0,0 +1,540 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Gustavo Lopes <cataphract@php.net> |
+ +----------------------------------------------------------------------+
+*/
+
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "../intl_cppshims.h"
+
+#include <unicode/timezone.h>
+#include <unicode/calendar.h>
+#include "../intl_convertcpp.h"
+
+#include "../common/common_date.h"
+
+extern "C" {
+#include "../intl_convert.h"
+#define USE_TIMEZONE_POINTER 1
+#include "timezone_class.h"
+#include "timezone_methods.h"
+#include <zend_exceptions.h>
+#include <zend_interfaces.h>
+#include <ext/date/php_date.h>
+}
+
+/* {{{ Global variables */
+U_CDECL_BEGIN
+zend_class_entry *TimeZone_ce_ptr = NULL;
+zend_object_handlers TimeZone_handlers;
+U_CDECL_END
+/* }}} */
+
+/* {{{ timezone_object_construct */
+U_CFUNC void timezone_object_construct(const TimeZone *zone, zval *object, int owned TSRMLS_DC)
+{
+ TimeZone_object *to;
+
+ object_init_ex(object, TimeZone_ce_ptr);
+ TIMEZONE_METHOD_FETCH_OBJECT_NO_CHECK; /* fetch zend object from zval "object" into "to" */
+ to->utimezone = zone;
+ to->should_delete = owned;
+}
+/* }}} */
+
+/* {{{ timezone_convert_to_datetimezone
+ * Convert from TimeZone to DateTimeZone object */
+U_CFUNC zval *timezone_convert_to_datetimezone(const TimeZone *timeZone,
+ intl_error *outside_error,
+ const char *func TSRMLS_DC)
+{
+ zval *ret = NULL;
+ UnicodeString id;
+ char *message = NULL;
+ php_timezone_obj *tzobj;
+ zval arg = zval_used_for_init;
+
+ timeZone->getID(id);
+ if (id.isBogus()) {
+ spprintf(&message, 0, "%s: could not obtain TimeZone id", func);
+ intl_errors_set(outside_error, U_ILLEGAL_ARGUMENT_ERROR,
+ message, 1 TSRMLS_CC);
+ goto error;
+ }
+
+ MAKE_STD_ZVAL(ret);
+ object_init_ex(ret, php_date_get_timezone_ce());
+ tzobj = (php_timezone_obj *)zend_objects_get_address(ret TSRMLS_CC);
+
+ if (id.compare(0, 3, UnicodeString("GMT", sizeof("GMT")-1, US_INV)) == 0) {
+ /* The DateTimeZone constructor doesn't support offset time zones,
+ * so we must mess with DateTimeZone structure ourselves */
+ tzobj->initialized = 1;
+ tzobj->type = TIMELIB_ZONETYPE_OFFSET;
+ //convert offset from milliseconds to minutes
+ tzobj->tzi.utc_offset = -1 * timeZone->getRawOffset() / (60 * 1000);
+ } else {
+ /* Call the constructor! */
+ Z_TYPE(arg) = IS_STRING;
+ if (intl_charFromString(id, &Z_STRVAL(arg), &Z_STRLEN(arg),
+ &INTL_ERROR_CODE(*outside_error)) == FAILURE) {
+ spprintf(&message, 0, "%s: could not convert id to UTF-8", func);
+ intl_errors_set(outside_error, INTL_ERROR_CODE(*outside_error),
+ message, 1 TSRMLS_CC);
+ goto error;
+ }
+ zend_call_method_with_1_params(&ret, NULL, NULL, "__construct",
+ NULL, &arg);
+ if (EG(exception)) {
+ spprintf(&message, 0,
+ "%s: DateTimeZone constructor threw exception", func);
+ intl_errors_set(outside_error, U_ILLEGAL_ARGUMENT_ERROR,
+ message, 1 TSRMLS_CC);
+ zend_object_store_ctor_failed(ret TSRMLS_CC);
+ goto error;
+ }
+ }
+
+ if (0) {
+error:
+ if (ret) {
+ zval_ptr_dtor(&ret);
+ }
+ ret = NULL;
+ }
+
+ if (message) {
+ efree(message);
+ }
+ if (Z_TYPE(arg) == IS_STRING) {
+ zval_dtor(&arg);
+ }
+ return ret;
+}
+/* }}} */
+
+/* {{{ timezone_process_timezone_argument
+ * TimeZone argument processor. outside_error may be NULL (for static functions/constructors) */
+U_CFUNC TimeZone *timezone_process_timezone_argument(zval **zv_timezone,
+ intl_error *outside_error,
+ const char *func TSRMLS_DC)
+{
+ zval local_zv_tz = zval_used_for_init,
+ *local_zv_tz_p = &local_zv_tz;
+ char *message = NULL;
+ TimeZone *timeZone;
+
+ if (zv_timezone == NULL || Z_TYPE_PP(zv_timezone) == IS_NULL) {
+ timelib_tzinfo *tzinfo = get_timezone_info(TSRMLS_C);
+ ZVAL_STRING(&local_zv_tz, tzinfo->name, 0);
+ zv_timezone = &local_zv_tz_p;
+ }
+
+ if (Z_TYPE_PP(zv_timezone) == IS_OBJECT &&
+ instanceof_function(Z_OBJCE_PP(zv_timezone), TimeZone_ce_ptr TSRMLS_CC)) {
+ TimeZone_object *to = (TimeZone_object*)zend_objects_get_address(
+ *zv_timezone TSRMLS_CC);
+ if (to->utimezone == NULL) {
+ spprintf(&message, 0, "%s: passed IntlTimeZone is not "
+ "properly constructed", func);
+ if (message) {
+ intl_errors_set(outside_error, U_ILLEGAL_ARGUMENT_ERROR, message, 1 TSRMLS_CC);
+ efree(message);
+ }
+ return NULL;
+ }
+ timeZone = to->utimezone->clone();
+ if (timeZone == NULL) {
+ spprintf(&message, 0, "%s: could not clone TimeZone", func);
+ if (message) {
+ intl_errors_set(outside_error, U_MEMORY_ALLOCATION_ERROR, message, 1 TSRMLS_CC);
+ efree(message);
+ }
+ return NULL;
+ }
+ } else if (Z_TYPE_PP(zv_timezone) == IS_OBJECT &&
+ instanceof_function(Z_OBJCE_PP(zv_timezone), php_date_get_timezone_ce() TSRMLS_CC)) {
+
+ php_timezone_obj *tzobj = (php_timezone_obj *)zend_objects_get_address(
+ *zv_timezone TSRMLS_CC);
+
+ return timezone_convert_datetimezone(tzobj->type, tzobj, 0,
+ outside_error, func TSRMLS_CC);
+ } else {
+ UnicodeString id,
+ gottenId;
+ UErrorCode status = U_ZERO_ERROR; /* outside_error may be NULL */
+ convert_to_string_ex(zv_timezone);
+ if (intl_stringFromChar(id, Z_STRVAL_PP(zv_timezone), Z_STRLEN_PP(zv_timezone),
+ &status) == FAILURE) {
+ spprintf(&message, 0, "%s: Time zone identifier given is not a "
+ "valid UTF-8 string", func);
+ if (message) {
+ intl_errors_set(outside_error, status, message, 1 TSRMLS_CC);
+ efree(message);
+ }
+ return NULL;
+ }
+ timeZone = TimeZone::createTimeZone(id);
+ if (timeZone == NULL) {
+ spprintf(&message, 0, "%s: could not create time zone", func);
+ if (message) {
+ intl_errors_set(outside_error, U_MEMORY_ALLOCATION_ERROR, message, 1 TSRMLS_CC);
+ efree(message);
+ }
+ return NULL;
+ }
+ if (timeZone->getID(gottenId) != id) {
+ spprintf(&message, 0, "%s: no such time zone: '%s'",
+ func, Z_STRVAL_PP(zv_timezone));
+ if (message) {
+ intl_errors_set(outside_error, U_ILLEGAL_ARGUMENT_ERROR, message, 1 TSRMLS_CC);
+ efree(message);
+ }
+ delete timeZone;
+ return NULL;
+ }
+ }
+
+ return timeZone;
+}
+/* }}} */
+
+/* {{{ clone handler for TimeZone */
+static zend_object_value TimeZone_clone_obj(zval *object TSRMLS_DC)
+{
+ TimeZone_object *to_orig,
+ *to_new;
+ zend_object_value ret_val;
+ intl_error_reset(NULL TSRMLS_CC);
+
+ to_orig = (TimeZone_object*)zend_object_store_get_object(object TSRMLS_CC);
+ intl_error_reset(TIMEZONE_ERROR_P(to_orig) TSRMLS_CC);
+
+ ret_val = TimeZone_ce_ptr->create_object(Z_OBJCE_P(object) TSRMLS_CC);
+ to_new = (TimeZone_object*)zend_object_store_get_object_by_handle(
+ ret_val.handle TSRMLS_CC);
+
+ zend_objects_clone_members(&to_new->zo, ret_val,
+ &to_orig->zo, Z_OBJ_HANDLE_P(object) TSRMLS_CC);
+
+ if (to_orig->utimezone != NULL) {
+ TimeZone *newTimeZone;
+
+ newTimeZone = to_orig->utimezone->clone();
+ to_new->should_delete = 1;
+ if (!newTimeZone) {
+ char *err_msg;
+ intl_errors_set_code(TIMEZONE_ERROR_P(to_orig),
+ U_MEMORY_ALLOCATION_ERROR TSRMLS_CC);
+ intl_errors_set_custom_msg(TIMEZONE_ERROR_P(to_orig),
+ "Could not clone IntlTimeZone", 0 TSRMLS_CC);
+ err_msg = intl_error_get_message(TIMEZONE_ERROR_P(to_orig) TSRMLS_CC);
+ zend_throw_exception(NULL, err_msg, 0 TSRMLS_CC);
+ efree(err_msg);
+ } else {
+ to_new->utimezone = newTimeZone;
+ }
+ } else {
+ zend_throw_exception(NULL, "Cannot clone unconstructed IntlTimeZone", 0 TSRMLS_CC);
+ }
+
+ return ret_val;
+}
+/* }}} */
+
+/* {{{ compare_objects handler for TimeZone
+ * Can't be used for >, >=, <, <= comparisons */
+static int TimeZone_compare_objects(zval *object1, zval *object2 TSRMLS_DC)
+{
+ TimeZone_object *to1,
+ *to2;
+ to1 = (TimeZone_object*)zend_object_store_get_object(object1 TSRMLS_CC);
+ to2 = (TimeZone_object*)zend_object_store_get_object(object2 TSRMLS_CC);
+
+ if (to1->utimezone == NULL || to2->utimezone == NULL) {
+ zend_throw_exception(NULL, "Comparison with at least one unconstructed "
+ "IntlTimeZone operand", 0 TSRMLS_CC);
+ /* intentionally not returning */
+ } else {
+ if (*to1->utimezone == *to2->utimezone) {
+ return 0;
+ }
+ }
+
+ return 1;
+}
+/* }}} */
+
+/* {{{ get_debug_info handler for TimeZone */
+static HashTable *TimeZone_get_debug_info(zval *object, int *is_temp TSRMLS_DC)
+{
+ zval zv = zval_used_for_init;
+ TimeZone_object *to;
+ const TimeZone *tz;
+ UnicodeString ustr;
+ char *str;
+ int str_len;
+ UErrorCode uec = U_ZERO_ERROR;
+
+ *is_temp = 1;
+
+ array_init_size(&zv, 4);
+
+ to = (TimeZone_object*)zend_object_store_get_object(object TSRMLS_CC);
+ tz = to->utimezone;
+
+ if (tz == NULL) {
+ add_assoc_bool_ex(&zv, "valid", sizeof("valid"), 0);
+ return Z_ARRVAL(zv);
+ }
+
+ add_assoc_bool_ex(&zv, "valid", sizeof("valid"), 1);
+
+ tz->getID(ustr);
+ intl_convert_utf16_to_utf8(&str, &str_len,
+ ustr.getBuffer(), ustr.length(), &uec);
+ if (U_FAILURE(uec)) {
+ return Z_ARRVAL(zv);
+ }
+ add_assoc_stringl_ex(&zv, "id", sizeof("id"), str, str_len, 0);
+
+ int32_t rawOffset, dstOffset;
+ UDate now = Calendar::getNow();
+ tz->getOffset(now, FALSE, rawOffset, dstOffset, uec);
+ if (U_FAILURE(uec)) {
+ return Z_ARRVAL(zv);
+ }
+
+ add_assoc_long_ex(&zv, "rawOffset", sizeof("rawOffset"), (long)rawOffset);
+ add_assoc_long_ex(&zv, "currentOffset", sizeof("currentOffset"),
+ (long)(rawOffset + dstOffset));
+
+ return Z_ARRVAL(zv);
+}
+/* }}} */
+
+/* {{{ void TimeZone_object_init(TimeZone_object* to)
+ * Initialize internals of TImeZone_object not specific to zend standard objects.
+ */
+static void TimeZone_object_init(TimeZone_object *to TSRMLS_DC)
+{
+ intl_error_init(TIMEZONE_ERROR_P(to) TSRMLS_CC);
+ to->utimezone = NULL;
+ to->should_delete = 0;
+}
+/* }}} */
+
+/* {{{ TimeZone_objects_dtor */
+static void TimeZone_objects_dtor(zend_object *object,
+ zend_object_handle handle TSRMLS_DC)
+{
+ zend_objects_destroy_object(object, handle TSRMLS_CC);
+}
+/* }}} */
+
+/* {{{ TimeZone_objects_free */
+static void TimeZone_objects_free(zend_object *object TSRMLS_DC)
+{
+ TimeZone_object* to = (TimeZone_object*) object;
+
+ if (to->utimezone && to->should_delete) {
+ delete to->utimezone;
+ to->utimezone = NULL;
+ }
+ intl_error_reset(TIMEZONE_ERROR_P(to) TSRMLS_CC);
+
+ zend_object_std_dtor(&to->zo TSRMLS_CC);
+
+ efree(to);
+}
+/* }}} */
+
+/* {{{ TimeZone_object_create */
+static zend_object_value TimeZone_object_create(zend_class_entry *ce TSRMLS_DC)
+{
+ zend_object_value retval;
+ TimeZone_object* intern;
+
+ intern = (TimeZone_object*)ecalloc(1, sizeof(TimeZone_object));
+
+ zend_object_std_init(&intern->zo, ce TSRMLS_CC);
+#if PHP_VERSION_ID < 50399
+ zend_hash_copy(intern->zo.properties, &(ce->default_properties),
+ (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval*));
+#else
+ object_properties_init((zend_object*) intern, ce);
+#endif
+ TimeZone_object_init(intern TSRMLS_CC);
+
+ retval.handle = zend_objects_store_put(
+ intern,
+ (zend_objects_store_dtor_t) TimeZone_objects_dtor,
+ (zend_objects_free_object_storage_t) TimeZone_objects_free,
+ NULL TSRMLS_CC);
+
+ retval.handlers = &TimeZone_handlers;
+
+ return retval;
+}
+/* }}} */
+
+/* {{{ TimeZone methods arguments info */
+
+ZEND_BEGIN_ARG_INFO_EX(ainfo_tz_idarg, 0, 0, 1)
+ ZEND_ARG_INFO(0, zoneId)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX(ainfo_tz_fromDateTimeZone, 0, 0, 1)
+ ZEND_ARG_OBJ_INFO(0, otherTimeZone, IntlTimeZone, 0)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX(ainfo_tz_createEnumeration, 0, 0, 0)
+ ZEND_ARG_INFO(0, countryOrRawOffset)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX(ainfo_tz_countEquivalentIDs, 0, 0, 1)
+ ZEND_ARG_INFO(0, zoneId)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX(ainfo_tz_createTimeZoneIDEnumeration, 0, 0, 1)
+ ZEND_ARG_INFO(0, zoneType)
+ ZEND_ARG_INFO(0, region)
+ ZEND_ARG_INFO(0, rawOffset)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX(ainfo_tz_getCanonicalID, 0, 0, 1)
+ ZEND_ARG_INFO(0, zoneId)
+ ZEND_ARG_INFO(1, isSystemID)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX(ainfo_tz_getEquivalentID, 0, 0, 2)
+ ZEND_ARG_INFO(0, zoneId)
+ ZEND_ARG_INFO(0, index)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX(ainfo_tz_getOffset, 0, 0, 4)
+ ZEND_ARG_INFO(0, date)
+ ZEND_ARG_INFO(0, local)
+ ZEND_ARG_INFO(1, rawOffset)
+ ZEND_ARG_INFO(1, dstOffset)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX(ainfo_tz_hasSameRules, 0, 0, 1)
+ ZEND_ARG_OBJ_INFO(0, otherTimeZone, IntlTimeZone, 0)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX(ainfo_tz_getDisplayName, 0, 0, 0)
+ ZEND_ARG_INFO(0, isDaylight)
+ ZEND_ARG_INFO(0, style)
+ ZEND_ARG_INFO(0, locale)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX(ainfo_tz_void, 0, 0, 0)
+ZEND_END_ARG_INFO()
+
+/* }}} */
+
+/* {{{ TimeZone_class_functions
+ * Every 'IntlTimeZone' class method has an entry in this table
+ */
+static zend_function_entry TimeZone_class_functions[] = {
+ PHP_ME(IntlTimeZone, __construct, ainfo_tz_void, ZEND_ACC_PRIVATE)
+ PHP_ME_MAPPING(createTimeZone, intltz_create_time_zone, ainfo_tz_idarg, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
+ PHP_ME_MAPPING(fromDateTimeZone, intltz_from_date_time_zone, ainfo_tz_idarg, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
+ PHP_ME_MAPPING(createDefault, intltz_create_default, ainfo_tz_void, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
+ PHP_ME_MAPPING(getGMT, intltz_get_gmt, ainfo_tz_void, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
+#if U_ICU_VERSION_MAJOR_NUM >= 49
+ PHP_ME_MAPPING(getUnknown, intltz_get_unknown, ainfo_tz_void, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
+#endif
+ PHP_ME_MAPPING(createEnumeration, intltz_create_enumeration, ainfo_tz_createEnumeration, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
+ PHP_ME_MAPPING(countEquivalentIDs, intltz_count_equivalent_ids, ainfo_tz_idarg, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
+#if U_ICU_VERSION_MAJOR_NUM * 10 + U_ICU_VERSION_MINOR_NUM >= 48
+ PHP_ME_MAPPING(createTimeZoneIDEnumeration, intltz_create_time_zone_id_enumeration, ainfo_tz_createTimeZoneIDEnumeration, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
+#endif
+ PHP_ME_MAPPING(getCanonicalID, intltz_get_canonical_id, ainfo_tz_getCanonicalID, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
+#if U_ICU_VERSION_MAJOR_NUM * 10 + U_ICU_VERSION_MINOR_NUM >= 48
+ PHP_ME_MAPPING(getRegion, intltz_get_region, ainfo_tz_idarg, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
+#endif
+ PHP_ME_MAPPING(getTZDataVersion, intltz_get_tz_data_version, ainfo_tz_void, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
+ PHP_ME_MAPPING(getEquivalentID, intltz_get_equivalent_id, ainfo_tz_getEquivalentID, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
+
+ PHP_ME_MAPPING(getID, intltz_get_id, ainfo_tz_void, ZEND_ACC_PUBLIC)
+ PHP_ME_MAPPING(useDaylightTime, intltz_use_daylight_time, ainfo_tz_void, ZEND_ACC_PUBLIC)
+ PHP_ME_MAPPING(getOffset, intltz_get_offset, ainfo_tz_getOffset, ZEND_ACC_PUBLIC)
+ PHP_ME_MAPPING(getRawOffset, intltz_get_raw_offset, ainfo_tz_void, ZEND_ACC_PUBLIC)
+ PHP_ME_MAPPING(hasSameRules, intltz_has_same_rules, ainfo_tz_hasSameRules, ZEND_ACC_PUBLIC)
+ PHP_ME_MAPPING(getDisplayName, intltz_get_display_name, ainfo_tz_getDisplayName, ZEND_ACC_PUBLIC)
+ PHP_ME_MAPPING(getDSTSavings, intltz_get_dst_savings, ainfo_tz_void, ZEND_ACC_PUBLIC)
+ PHP_ME_MAPPING(toDateTimeZone, intltz_to_date_time_zone, ainfo_tz_void, ZEND_ACC_PUBLIC)
+ PHP_ME_MAPPING(getErrorCode, intltz_get_error_code, ainfo_tz_void, ZEND_ACC_PUBLIC)
+ PHP_ME_MAPPING(getErrorMessage, intltz_get_error_message, ainfo_tz_void, ZEND_ACC_PUBLIC)
+ PHP_FE_END
+};
+/* }}} */
+
+/* {{{ timezone_register_IntlTimeZone_class
+ * Initialize 'IntlTimeZone' class
+ */
+U_CFUNC void timezone_register_IntlTimeZone_class(TSRMLS_D)
+{
+ zend_class_entry ce;
+
+ /* Create and register 'IntlTimeZone' class. */
+ INIT_CLASS_ENTRY(ce, "IntlTimeZone", TimeZone_class_functions);
+ ce.create_object = TimeZone_object_create;
+ TimeZone_ce_ptr = zend_register_internal_class(&ce TSRMLS_CC);
+ if (!TimeZone_ce_ptr) {
+ //can't happen now without bigger problems before
+ php_error_docref0(NULL TSRMLS_CC, E_ERROR,
+ "IntlTimeZone: class registration has failed.");
+ return;
+ }
+
+ memcpy(&TimeZone_handlers, zend_get_std_object_handlers(),
+ sizeof TimeZone_handlers);
+ TimeZone_handlers.clone_obj = TimeZone_clone_obj;
+ TimeZone_handlers.compare_objects = TimeZone_compare_objects;
+ TimeZone_handlers.get_debug_info = TimeZone_get_debug_info;
+
+ /* Declare 'IntlTimeZone' class constants */
+#define TIMEZONE_DECL_LONG_CONST(name, val) \
+ zend_declare_class_constant_long(TimeZone_ce_ptr, name, sizeof(name) - 1, \
+ val TSRMLS_CC)
+
+ TIMEZONE_DECL_LONG_CONST("DISPLAY_SHORT", TimeZone::SHORT);
+ TIMEZONE_DECL_LONG_CONST("DISPLAY_LONG", TimeZone::LONG);
+
+#if U_ICU_VERSION_MAJOR_NUM * 10 + U_ICU_VERSION_MINOR_NUM >= 44
+ TIMEZONE_DECL_LONG_CONST("DISPLAY_SHORT_GENERIC", TimeZone::SHORT_GENERIC);
+ TIMEZONE_DECL_LONG_CONST("DISPLAY_LONG_GENERIC", TimeZone::LONG_GENERIC);
+ TIMEZONE_DECL_LONG_CONST("DISPLAY_SHORT_GMT", TimeZone::SHORT_GMT);
+ TIMEZONE_DECL_LONG_CONST("DISPLAY_LONG_GMT", TimeZone::LONG_GMT);
+ TIMEZONE_DECL_LONG_CONST("DISPLAY_SHORT_COMMONLY_USED", TimeZone::SHORT_COMMONLY_USED);
+ TIMEZONE_DECL_LONG_CONST("DISPLAY_GENERIC_LOCATION", TimeZone::GENERIC_LOCATION);
+#endif
+
+#if U_ICU_VERSION_MAJOR_NUM * 10 + U_ICU_VERSION_MINOR_NUM >= 48
+ TIMEZONE_DECL_LONG_CONST("TYPE_ANY", UCAL_ZONE_TYPE_ANY);
+ TIMEZONE_DECL_LONG_CONST("TYPE_CANONICAL", UCAL_ZONE_TYPE_CANONICAL);
+ TIMEZONE_DECL_LONG_CONST("TYPE_CANONICAL_LOCATION", UCAL_ZONE_TYPE_CANONICAL_LOCATION);
+#endif
+
+ /* Declare 'IntlTimeZone' class properties */
+
+}
+/* }}} */
diff --git a/ext/intl/timezone/timezone_class.h b/ext/intl/timezone/timezone_class.h
new file mode 100644
index 0000000000..a638f6dbf4
--- /dev/null
+++ b/ext/intl/timezone/timezone_class.h
@@ -0,0 +1,72 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Gustavo Lopes <cataphract@netcabo.pt> |
+ +----------------------------------------------------------------------+
+ */
+
+#ifndef TIMEZONE_CLASS_H
+#define TIMEZONE_CLASS_H
+
+//redefinition of inline in PHP headers causes problems, so include this before
+#include <math.h>
+
+//fixes the build on windows for old versions of ICU
+#include <stdio.h>
+
+#include <php.h>
+#include "intl_error.h"
+#include "intl_data.h"
+
+#ifndef USE_TIMEZONE_POINTER
+typedef void TimeZone;
+#endif
+
+typedef struct {
+ zend_object zo;
+
+ // error handling
+ intl_error err;
+
+ // ICU TimeZone
+ const TimeZone *utimezone;
+
+ //whether to delete the timezone on object free
+ zend_bool should_delete;
+} TimeZone_object;
+
+#define TIMEZONE_ERROR(to) (to)->err
+#define TIMEZONE_ERROR_P(to) &(TIMEZONE_ERROR(to))
+
+#define TIMEZONE_ERROR_CODE(co) INTL_ERROR_CODE(TIMEZONE_ERROR(to))
+#define TIMEZONE_ERROR_CODE_P(co) &(INTL_ERROR_CODE(TIMEZONE_ERROR(to)))
+
+#define TIMEZONE_METHOD_INIT_VARS INTL_METHOD_INIT_VARS(TimeZone, to)
+#define TIMEZONE_METHOD_FETCH_OBJECT_NO_CHECK INTL_METHOD_FETCH_OBJECT(TimeZone, to)
+#define TIMEZONE_METHOD_FETCH_OBJECT\
+ TIMEZONE_METHOD_FETCH_OBJECT_NO_CHECK; \
+ if (to->utimezone == NULL) { \
+ intl_errors_set(&to->err, U_ILLEGAL_ARGUMENT_ERROR, "Found unconstructed IntlTimeZone", 0 TSRMLS_CC); \
+ RETURN_FALSE; \
+ }
+
+zval *timezone_convert_to_datetimezone(const TimeZone *timeZone, intl_error *outside_error, const char *func TSRMLS_DC);
+TimeZone *timezone_process_timezone_argument(zval **zv_timezone, intl_error *error, const char *func TSRMLS_DC);
+
+void timezone_object_construct(const TimeZone *zone, zval *object, int owned TSRMLS_DC);
+
+void timezone_register_IntlTimeZone_class(TSRMLS_D);
+
+extern zend_class_entry *TimeZone_ce_ptr;
+extern zend_object_handlers TimeZone_handlers;
+
+#endif /* #ifndef TIMEZONE_CLASS_H */
diff --git a/ext/intl/timezone/timezone_methods.cpp b/ext/intl/timezone/timezone_methods.cpp
new file mode 100644
index 0000000000..9ca6b44c89
--- /dev/null
+++ b/ext/intl/timezone/timezone_methods.cpp
@@ -0,0 +1,659 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Gustavo Lopes <cataphract@php.net> |
+ +----------------------------------------------------------------------+
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "../intl_cppshims.h"
+
+#include <unicode/locid.h>
+#include <unicode/timezone.h>
+#include <unicode/ustring.h>
+#include "intl_convertcpp.h"
+
+#include "../common/common_date.h"
+
+extern "C" {
+#include "../php_intl.h"
+#define USE_TIMEZONE_POINTER 1
+#include "timezone_class.h"
+#include "intl_convert.h"
+#include <zend_exceptions.h>
+#include <ext/date/php_date.h>
+}
+#include "common/common_enum.h"
+
+U_CFUNC PHP_METHOD(IntlTimeZone, __construct)
+{
+ zend_throw_exception( NULL,
+ "An object of this type cannot be created with the new operator",
+ 0 TSRMLS_CC );
+}
+
+U_CFUNC PHP_FUNCTION(intltz_create_time_zone)
+{
+ char *str_id;
+ int str_id_len;
+ intl_error_reset(NULL TSRMLS_CC);
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s",
+ &str_id, &str_id_len) == FAILURE) {
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "intltz_create_time_zone: bad arguments", 0 TSRMLS_CC);
+ RETURN_NULL();
+ }
+
+ UErrorCode status = UErrorCode();
+ UnicodeString id = UnicodeString();
+ if (intl_stringFromChar(id, str_id, str_id_len, &status) == FAILURE) {
+ intl_error_set(NULL, status,
+ "intltz_create_time_zone: could not convert time zone id to UTF-16", 0 TSRMLS_CC);
+ RETURN_NULL();
+ }
+
+ //guaranteed non-null; GMT if timezone cannot be understood
+ TimeZone *tz = TimeZone::createTimeZone(id);
+ timezone_object_construct(tz, return_value, 1 TSRMLS_CC);
+}
+
+U_CFUNC PHP_FUNCTION(intltz_from_date_time_zone)
+{
+ zval *zv_timezone;
+ TimeZone *tz;
+ php_timezone_obj *tzobj;
+ intl_error_reset(NULL TSRMLS_CC);
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O",
+ &zv_timezone, php_date_get_timezone_ce()) == FAILURE) {
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "intltz_from_date_time_zone: bad arguments", 0 TSRMLS_CC);
+ RETURN_NULL();
+ }
+
+ tzobj = (php_timezone_obj *)zend_objects_get_address(zv_timezone TSRMLS_CC);
+ if (!tzobj->initialized) {
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "intltz_from_date_time_zone: DateTimeZone object is unconstructed",
+ 0 TSRMLS_CC);
+ RETURN_NULL();
+ }
+
+ tz = timezone_convert_datetimezone(tzobj->type, tzobj, FALSE, NULL,
+ "intltz_from_date_time_zone" TSRMLS_CC);
+ if (tz == NULL) {
+ RETURN_NULL();
+ }
+
+ timezone_object_construct(tz, return_value, 1 TSRMLS_CC);
+}
+
+U_CFUNC PHP_FUNCTION(intltz_create_default)
+{
+ intl_error_reset(NULL TSRMLS_CC);
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "intltz_create_default: bad arguments", 0 TSRMLS_CC);
+ RETURN_NULL();
+ }
+
+ TimeZone *tz = TimeZone::createDefault();
+ timezone_object_construct(tz, return_value, 1 TSRMLS_CC);
+}
+
+U_CFUNC PHP_FUNCTION(intltz_get_gmt)
+{
+ intl_error_reset(NULL TSRMLS_CC);
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "intltz_get_gmt: bad arguments", 0 TSRMLS_CC);
+ RETURN_NULL();
+ }
+
+ timezone_object_construct(TimeZone::getGMT(), return_value, 0 TSRMLS_CC);
+}
+
+#if U_ICU_VERSION_MAJOR_NUM >= 49
+U_CFUNC PHP_FUNCTION(intltz_get_unknown)
+{
+ intl_error_reset(NULL TSRMLS_CC);
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "intltz_get_unknown: bad arguments", 0 TSRMLS_CC);
+ RETURN_NULL();
+ }
+
+ timezone_object_construct(&TimeZone::getUnknown(), return_value, 0 TSRMLS_CC);
+}
+#endif
+
+U_CFUNC PHP_FUNCTION(intltz_create_enumeration)
+{
+ zval **arg = NULL;
+ StringEnumeration *se = NULL;
+ intl_error_reset(NULL TSRMLS_CC);
+
+ /* double indirection to have the zend engine destroy the new zval that
+ * results from separation */
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|Z", &arg) == FAILURE) {
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "intltz_create_enumeration: bad arguments", 0 TSRMLS_CC);
+ RETURN_FALSE;
+ }
+
+ if (arg == NULL || Z_TYPE_PP(arg) == IS_NULL) {
+ se = TimeZone::createEnumeration();
+ } else if (Z_TYPE_PP(arg) == IS_LONG) {
+int_offset:
+ if (Z_LVAL_PP(arg) < (long)INT32_MIN ||
+ Z_LVAL_PP(arg) > (long)INT32_MAX) {
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "intltz_create_enumeration: value is out of range", 0 TSRMLS_CC);
+ RETURN_FALSE;
+ } else {
+ se = TimeZone::createEnumeration((int32_t) Z_LVAL_PP(arg));
+ }
+ } else if (Z_TYPE_PP(arg) == IS_DOUBLE) {
+double_offset:
+ convert_to_long_ex(arg);
+ goto int_offset;
+ } else if (Z_TYPE_PP(arg) == IS_OBJECT || Z_TYPE_PP(arg) == IS_STRING) {
+ long lval;
+ double dval;
+ convert_to_string_ex(arg);
+ switch (is_numeric_string(Z_STRVAL_PP(arg), Z_STRLEN_PP(arg), &lval, &dval, 0)) {
+ case IS_DOUBLE:
+ SEPARATE_ZVAL(arg);
+ zval_dtor(*arg);
+ Z_TYPE_PP(arg) = IS_DOUBLE;
+ Z_DVAL_PP(arg) = dval;
+ goto double_offset;
+ case IS_LONG:
+ SEPARATE_ZVAL(arg);
+ zval_dtor(*arg);
+ Z_TYPE_PP(arg) = IS_LONG;
+ Z_LVAL_PP(arg) = lval;
+ goto int_offset;
+ }
+ /* else call string version */
+ se = TimeZone::createEnumeration(Z_STRVAL_PP(arg));
+ } else {
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "intltz_create_enumeration: invalid argument type", 0 TSRMLS_CC);
+ RETURN_FALSE;
+ }
+
+ if (se) {
+ IntlIterator_from_StringEnumeration(se, return_value TSRMLS_CC);
+ } else {
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "intltz_create_enumeration: error obtaining enumeration", 0 TSRMLS_CC);
+ RETVAL_FALSE;
+ }
+}
+
+U_CFUNC PHP_FUNCTION(intltz_count_equivalent_ids)
+{
+ char *str_id;
+ int str_id_len;
+ intl_error_reset(NULL TSRMLS_CC);
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s",
+ &str_id, &str_id_len) == FAILURE) {
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "intltz_count_equivalent_ids: bad arguments", 0 TSRMLS_CC);
+ RETURN_FALSE;
+ }
+
+ UErrorCode status = UErrorCode();
+ UnicodeString id = UnicodeString();
+ if (intl_stringFromChar(id, str_id, str_id_len, &status) == FAILURE) {
+ intl_error_set(NULL, status,
+ "intltz_count_equivalent_ids: could not convert time zone id to UTF-16", 0 TSRMLS_CC);
+ RETURN_FALSE;
+ }
+
+ int32_t result = TimeZone::countEquivalentIDs(id);
+ RETURN_LONG((long)result);
+}
+
+#if U_ICU_VERSION_MAJOR_NUM * 10 + U_ICU_VERSION_MINOR_NUM >= 48
+U_CFUNC PHP_FUNCTION(intltz_create_time_zone_id_enumeration)
+{
+ long zoneType,
+ offset_arg;
+ char *region = NULL;
+ int region_len = 0;
+ int32_t offset,
+ *offsetp = NULL;
+ int arg3isnull = 0;
+ intl_error_reset(NULL TSRMLS_CC);
+
+ /* must come before zpp because zpp would convert the arg in the stack to 0 */
+ if (ZEND_NUM_ARGS() == 3) {
+ zval **dummy, **zvoffset;
+ arg3isnull = zend_get_parameters_ex(3, &dummy, &dummy, &zvoffset)
+ != FAILURE && Z_TYPE_PP(zvoffset) == IS_NULL;
+ }
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l|s!l",
+ &zoneType, &region, &region_len, &offset_arg) == FAILURE) {
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "intltz_create_time_zone_id_enumeration: bad arguments", 0 TSRMLS_CC);
+ RETURN_FALSE;
+ }
+
+ if (zoneType != UCAL_ZONE_TYPE_ANY && zoneType != UCAL_ZONE_TYPE_CANONICAL
+ && zoneType != UCAL_ZONE_TYPE_CANONICAL_LOCATION) {
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "intltz_create_time_zone_id_enumeration: bad zone type", 0 TSRMLS_CC);
+ RETURN_FALSE;
+ }
+
+ if (ZEND_NUM_ARGS() == 3) {
+ if (offset_arg < (long)INT32_MIN || offset_arg > (long)INT32_MAX) {
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "intltz_create_time_zone_id_enumeration: offset out of bounds", 0 TSRMLS_CC);
+ RETURN_FALSE;
+ }
+
+ if (!arg3isnull) {
+ offset = (int32_t)offset_arg;
+ offsetp = &offset;
+ } //else leave offsetp NULL
+ }
+
+ StringEnumeration *se;
+ UErrorCode uec = UErrorCode();
+ se = TimeZone::createTimeZoneIDEnumeration((USystemTimeZoneType)zoneType,
+ region, offsetp, uec);
+ INTL_CHECK_STATUS(uec, "intltz_create_time_zone_id_enumeration: "
+ "Error obtaining time zone id enumeration")
+
+ IntlIterator_from_StringEnumeration(se, return_value TSRMLS_CC);
+}
+#endif
+
+U_CFUNC PHP_FUNCTION(intltz_get_canonical_id)
+{
+ char *str_id;
+ int str_id_len;
+ zval *is_systemid = NULL;
+ intl_error_reset(NULL TSRMLS_CC);
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|z",
+ &str_id, &str_id_len, &is_systemid) == FAILURE) {
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "intltz_get_canonical_id: bad arguments", 0 TSRMLS_CC);
+ RETURN_FALSE;
+ }
+
+ UErrorCode status = UErrorCode();
+ UnicodeString id;
+ if (intl_stringFromChar(id, str_id, str_id_len, &status) == FAILURE) {
+ intl_error_set(NULL, status,
+ "intltz_get_canonical_id: could not convert time zone id to UTF-16", 0 TSRMLS_CC);
+ RETURN_FALSE;
+ }
+
+ UnicodeString result;
+ UBool isSystemID;
+ TimeZone::getCanonicalID(id, result, isSystemID, status);
+ INTL_CHECK_STATUS(status, "intltz_get_canonical_id: error obtaining canonical ID");
+
+ intl_convert_utf16_to_utf8(&Z_STRVAL_P(return_value), &Z_STRLEN_P(return_value),
+ result.getBuffer(), result.length(), &status);
+ INTL_CHECK_STATUS(status,
+ "intltz_get_canonical_id: could not convert time zone id to UTF-16");
+ Z_TYPE_P(return_value) = IS_STRING;
+
+ if (is_systemid) { /* by-ref argument passed */
+ zval_dtor(is_systemid);
+ ZVAL_BOOL(is_systemid, isSystemID);
+ }
+}
+
+#if U_ICU_VERSION_MAJOR_NUM * 10 + U_ICU_VERSION_MINOR_NUM >= 48
+U_CFUNC PHP_FUNCTION(intltz_get_region)
+{
+ char *str_id;
+ int str_id_len;
+ char outbuf[3];
+ intl_error_reset(NULL TSRMLS_CC);
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s",
+ &str_id, &str_id_len) == FAILURE) {
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "intltz_get_region: bad arguments", 0 TSRMLS_CC);
+ RETURN_FALSE;
+ }
+
+ UErrorCode status = UErrorCode();
+ UnicodeString id;
+ if (intl_stringFromChar(id, str_id, str_id_len, &status) == FAILURE) {
+ intl_error_set(NULL, status,
+ "intltz_get_region: could not convert time zone id to UTF-16", 0 TSRMLS_CC);
+ RETURN_FALSE;
+ }
+
+ int32_t region_len = TimeZone::getRegion(id, outbuf, sizeof(outbuf), status);
+ INTL_CHECK_STATUS(status, "intltz_get_region: Error obtaining region");
+
+ RETURN_STRINGL(outbuf, region_len, 1);
+}
+#endif
+
+U_CFUNC PHP_FUNCTION(intltz_get_tz_data_version)
+{
+ intl_error_reset(NULL TSRMLS_CC);
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "intltz_get_tz_data_version: bad arguments", 0 TSRMLS_CC);
+ RETURN_FALSE;
+ }
+
+ UErrorCode status = UErrorCode();
+ const char *res = TimeZone::getTZDataVersion(status);
+ INTL_CHECK_STATUS(status, "intltz_get_tz_data_version: "
+ "Error obtaining time zone data version");
+
+ RETURN_STRING(res, 1);
+}
+
+U_CFUNC PHP_FUNCTION(intltz_get_equivalent_id)
+{
+ char *str_id;
+ int str_id_len;
+ long index;
+ intl_error_reset(NULL TSRMLS_CC);
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sl",
+ &str_id, &str_id_len, &index) == FAILURE ||
+ index < (long)INT32_MIN || index > (long)INT32_MAX) {
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "intltz_get_equivalent_id: bad arguments", 0 TSRMLS_CC);
+ RETURN_FALSE;
+ }
+
+ UErrorCode status = UErrorCode();
+ UnicodeString id;
+ if (intl_stringFromChar(id, str_id, str_id_len, &status) == FAILURE) {
+ intl_error_set(NULL, status,
+ "intltz_get_equivalent_id: could not convert time zone id to UTF-16", 0 TSRMLS_CC);
+ RETURN_FALSE;
+ }
+
+ const UnicodeString result = TimeZone::getEquivalentID(id, (int32_t)index);
+ intl_convert_utf16_to_utf8(&Z_STRVAL_P(return_value), &Z_STRLEN_P(return_value),
+ result.getBuffer(), result.length(), &status);
+ INTL_CHECK_STATUS(status, "intltz_get_equivalent_id: "
+ "could not convert resulting time zone id to UTF-16");
+ Z_TYPE_P(return_value) = IS_STRING;
+}
+
+U_CFUNC PHP_FUNCTION(intltz_get_id)
+{
+ TIMEZONE_METHOD_INIT_VARS;
+
+ if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O",
+ &object, TimeZone_ce_ptr) == FAILURE) {
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "intltz_get_id: bad arguments", 0 TSRMLS_CC);
+ RETURN_FALSE;
+ }
+
+ TIMEZONE_METHOD_FETCH_OBJECT;
+
+ UnicodeString id_us;
+ to->utimezone->getID(id_us);
+
+ char *id = NULL;
+ int id_len = 0;
+
+ intl_convert_utf16_to_utf8(&id, &id_len,
+ id_us.getBuffer(), id_us.length(), TIMEZONE_ERROR_CODE_P(to));
+ INTL_METHOD_CHECK_STATUS(to, "intltz_get_id: Could not convert id to UTF-8");
+
+ RETURN_STRINGL(id, id_len, 0);
+}
+
+U_CFUNC PHP_FUNCTION(intltz_use_daylight_time)
+{
+ TIMEZONE_METHOD_INIT_VARS;
+
+ if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O",
+ &object, TimeZone_ce_ptr) == FAILURE) {
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "intltz_use_daylight_time: bad arguments", 0 TSRMLS_CC);
+ RETURN_FALSE;
+ }
+
+ TIMEZONE_METHOD_FETCH_OBJECT;
+
+ RETURN_BOOL(to->utimezone->useDaylightTime());
+}
+
+U_CFUNC PHP_FUNCTION(intltz_get_offset)
+{
+ UDate date;
+ zend_bool local;
+ zval *rawOffsetArg,
+ *dstOffsetArg;
+ int32_t rawOffset,
+ dstOffset;
+ TIMEZONE_METHOD_INIT_VARS;
+
+ if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(),
+ "Odbzz", &object, TimeZone_ce_ptr, &date, &local, &rawOffsetArg,
+ &dstOffsetArg) == FAILURE) {
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "intltz_get_offset: bad arguments", 0 TSRMLS_CC);
+ RETURN_FALSE;
+ }
+
+ TIMEZONE_METHOD_FETCH_OBJECT;
+
+ to->utimezone->getOffset(date, (UBool) local, rawOffset, dstOffset,
+ TIMEZONE_ERROR_CODE(to));
+
+ INTL_METHOD_CHECK_STATUS(to, "intltz_get_offset: error obtaining offset");
+
+ zval_dtor(rawOffsetArg);
+ ZVAL_LONG(rawOffsetArg, rawOffset);
+ zval_dtor(dstOffsetArg);
+ ZVAL_LONG(dstOffsetArg, dstOffset);
+
+ RETURN_TRUE;
+}
+
+U_CFUNC PHP_FUNCTION(intltz_get_raw_offset)
+{
+ TIMEZONE_METHOD_INIT_VARS;
+
+ if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(),
+ "O", &object, TimeZone_ce_ptr) == FAILURE) {
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "intltz_get_raw_offset: bad arguments", 0 TSRMLS_CC);
+ RETURN_FALSE;
+ }
+
+ TIMEZONE_METHOD_FETCH_OBJECT;
+
+ RETURN_LONG(to->utimezone->getRawOffset());
+}
+
+U_CFUNC PHP_FUNCTION(intltz_has_same_rules)
+{
+ zval *other_object;
+ TimeZone_object *other_to;
+ TIMEZONE_METHOD_INIT_VARS;
+
+ if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(),
+ "OO", &object, TimeZone_ce_ptr, &other_object, TimeZone_ce_ptr)
+ == FAILURE) {
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "intltz_has_same_rules: bad arguments", 0 TSRMLS_CC);
+ RETURN_FALSE;
+ }
+ TIMEZONE_METHOD_FETCH_OBJECT;
+ other_to = (TimeZone_object *) zend_object_store_get_object(other_object TSRMLS_CC);
+ if (other_to->utimezone == NULL) {
+ intl_errors_set(&to->err, U_ILLEGAL_ARGUMENT_ERROR,
+ "intltz_has_same_rules: The second IntlTimeZone is unconstructed", 0 TSRMLS_CC);
+ RETURN_FALSE;
+ }
+
+ RETURN_BOOL(to->utimezone->hasSameRules(*other_to->utimezone));
+}
+
+static const TimeZone::EDisplayType display_types[] = {
+ TimeZone::SHORT, TimeZone::LONG,
+#if U_ICU_VERSION_MAJOR_NUM * 10 + U_ICU_VERSION_MINOR_NUM >= 44
+ TimeZone::SHORT_GENERIC, TimeZone::LONG_GENERIC,
+ TimeZone::SHORT_GMT, TimeZone::LONG_GMT,
+ TimeZone::SHORT_COMMONLY_USED, TimeZone::GENERIC_LOCATION
+#endif
+};
+
+U_CFUNC PHP_FUNCTION(intltz_get_display_name)
+{
+ zend_bool daylight = 0;
+ long display_type = TimeZone::LONG;
+ const char *locale_str = NULL;
+ int dummy = 0;
+ TIMEZONE_METHOD_INIT_VARS;
+
+ if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(),
+ "O|bls!", &object, TimeZone_ce_ptr, &daylight, &display_type,
+ &locale_str, &dummy) == FAILURE) {
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "intltz_get_display_name: bad arguments", 0 TSRMLS_CC);
+ RETURN_FALSE;
+ }
+
+ bool found = false;
+ for (int i = 0; !found && i < sizeof(display_types)/sizeof(*display_types); i++) {
+ if (display_types[i] == display_type)
+ found = true;
+ }
+ if (!found) {
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "intltz_get_display_name: wrong display type", 0 TSRMLS_CC);
+ RETURN_FALSE;
+ }
+
+ if (!locale_str) {
+ locale_str = intl_locale_get_default(TSRMLS_C);
+ }
+
+ TIMEZONE_METHOD_FETCH_OBJECT;
+
+ UnicodeString result;
+ to->utimezone->getDisplayName((UBool)daylight, (TimeZone::EDisplayType)display_type,
+ Locale::createFromName(locale_str), result);
+
+ intl_convert_utf16_to_utf8(&Z_STRVAL_P(return_value), &Z_STRLEN_P(return_value),
+ result.getBuffer(), result.length(), TIMEZONE_ERROR_CODE_P(to));
+ INTL_METHOD_CHECK_STATUS(to, "intltz_get_display_name: "
+ "could not convert resulting time zone id to UTF-16");
+
+ Z_TYPE_P(return_value) = IS_STRING;
+}
+
+U_CFUNC PHP_FUNCTION(intltz_get_dst_savings)
+{
+ TIMEZONE_METHOD_INIT_VARS;
+
+ if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(),
+ "O", &object, TimeZone_ce_ptr) == FAILURE) {
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "intltz_get_dst_savings: bad arguments", 0 TSRMLS_CC);
+ RETURN_FALSE;
+ }
+
+ TIMEZONE_METHOD_FETCH_OBJECT;
+
+ RETURN_LONG((long)to->utimezone->getDSTSavings());
+}
+
+U_CFUNC PHP_FUNCTION(intltz_to_date_time_zone)
+{
+ TIMEZONE_METHOD_INIT_VARS;
+
+ if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(),
+ "O", &object, TimeZone_ce_ptr) == FAILURE) {
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "intltz_to_date_time_zone: bad arguments", 0 TSRMLS_CC);
+ RETURN_FALSE;
+ }
+
+ TIMEZONE_METHOD_FETCH_OBJECT;
+
+ zval *ret = timezone_convert_to_datetimezone(to->utimezone,
+ &TIMEZONE_ERROR(to), "intltz_to_date_time_zone" TSRMLS_CC);
+
+ if (ret) {
+ RETURN_ZVAL(ret, 1, 1);
+ } else {
+ RETURN_FALSE;
+ }
+}
+
+U_CFUNC PHP_FUNCTION(intltz_get_error_code)
+{
+ TIMEZONE_METHOD_INIT_VARS
+
+ if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O",
+ &object, TimeZone_ce_ptr) == FAILURE) {
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "intltz_get_error_code: bad arguments", 0 TSRMLS_CC);
+ RETURN_FALSE;
+ }
+
+ /* Fetch the object (without resetting its last error code ). */
+ to = (TimeZone_object*)zend_object_store_get_object(object TSRMLS_CC);
+ if (to == NULL)
+ RETURN_FALSE;
+
+ RETURN_LONG((long)TIMEZONE_ERROR_CODE(to));
+}
+
+U_CFUNC PHP_FUNCTION(intltz_get_error_message)
+{
+ const char* message = NULL;
+ TIMEZONE_METHOD_INIT_VARS
+
+ if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O",
+ &object, TimeZone_ce_ptr) == FAILURE) {
+ intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "intltz_get_error_message: bad arguments", 0 TSRMLS_CC );
+ RETURN_FALSE;
+ }
+
+
+ /* Fetch the object (without resetting its last error code ). */
+ to = (TimeZone_object*)zend_object_store_get_object(object TSRMLS_CC);
+ if (to == NULL)
+ RETURN_FALSE;
+
+ /* Return last error message. */
+ message = intl_error_get_message(TIMEZONE_ERROR_P(to) TSRMLS_CC);
+ RETURN_STRING(message, 0);
+}
diff --git a/ext/intl/timezone/timezone_methods.h b/ext/intl/timezone/timezone_methods.h
new file mode 100644
index 0000000000..28c39f4fd7
--- /dev/null
+++ b/ext/intl/timezone/timezone_methods.h
@@ -0,0 +1,68 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Gustavo Lopes <cataphract@netcabo.pt> |
+ +----------------------------------------------------------------------+
+ */
+
+#ifndef TIMEZONE_METHODS_H
+#define TIMEZONE_METHODS_H
+
+#include <php.h>
+
+PHP_METHOD(IntlTimeZone, __construct);
+
+PHP_FUNCTION(intltz_create_time_zone);
+
+PHP_FUNCTION(intltz_from_date_time_zone);
+
+PHP_FUNCTION(intltz_create_default);
+
+PHP_FUNCTION(intltz_get_id);
+
+PHP_FUNCTION(intltz_get_gmt);
+
+PHP_FUNCTION(intltz_get_unknown);
+
+PHP_FUNCTION(intltz_create_enumeration);
+
+PHP_FUNCTION(intltz_count_equivalent_ids);
+
+PHP_FUNCTION(intltz_create_time_zone_id_enumeration);
+
+PHP_FUNCTION(intltz_get_canonical_id);
+
+PHP_FUNCTION(intltz_get_region);
+
+PHP_FUNCTION(intltz_get_tz_data_version);
+
+PHP_FUNCTION(intltz_get_equivalent_id);
+
+PHP_FUNCTION(intltz_use_daylight_time);
+
+PHP_FUNCTION(intltz_get_offset);
+
+PHP_FUNCTION(intltz_get_raw_offset);
+
+PHP_FUNCTION(intltz_has_same_rules);
+
+PHP_FUNCTION(intltz_get_display_name);
+
+PHP_FUNCTION(intltz_get_dst_savings);
+
+PHP_FUNCTION(intltz_to_date_time_zone);
+
+PHP_FUNCTION(intltz_get_error_code);
+
+PHP_FUNCTION(intltz_get_error_message);
+
+#endif /* #ifndef TIMEZONE_METHODS_H */
diff --git a/ext/intl/transliterator/transliterator.c b/ext/intl/transliterator/transliterator.c
index 75c9eaabda..8ee49e1e51 100644
--- a/ext/intl/transliterator/transliterator.c
+++ b/ext/intl/transliterator/transliterator.c
@@ -49,85 +49,6 @@ void transliterator_register_constants( INIT_FUNC_ARGS )
}
/* }}} */
-/* {{{ transliterator_parse_error_to_string
- * Transforms parse errors in strings.
- */
-smart_str transliterator_parse_error_to_string( UParseError* pe )
-{
- smart_str ret = {0};
- char *buf;
- int u8len;
- UErrorCode status;
- int any = 0;
-
- assert( pe != NULL );
-
- smart_str_appends( &ret, "parse error " );
- if( pe->line > 0 )
- {
- smart_str_appends( &ret, "on line " );
- smart_str_append_long( &ret, (long ) pe->line );
- any = 1;
- }
- if( pe->offset >= 0 ) {
- if( any )
- smart_str_appends( &ret, ", " );
- else
- smart_str_appends( &ret, "at " );
-
- smart_str_appends( &ret, "offset " );
- smart_str_append_long( &ret, (long ) pe->offset );
- any = 1;
- }
-
- if (pe->preContext[0] != 0 ) {
- if( any )
- smart_str_appends( &ret, ", " );
-
- smart_str_appends( &ret, "after \"" );
- intl_convert_utf16_to_utf8( &buf, &u8len, pe->preContext, -1, &status );
- if( U_FAILURE( status ) )
- {
- smart_str_appends( &ret, "(could not convert parser error pre-context to UTF-8)" );
- }
- else {
- smart_str_appendl( &ret, buf, u8len );
- efree( buf );
- }
- smart_str_appends( &ret, "\"" );
- any = 1;
- }
-
- if( pe->postContext[0] != 0 )
- {
- if( any )
- smart_str_appends( &ret, ", " );
-
- smart_str_appends( &ret, "before or at \"" );
- intl_convert_utf16_to_utf8( &buf, &u8len, pe->postContext, -1, &status );
- if( U_FAILURE( status ) )
- {
- smart_str_appends( &ret, "(could not convert parser error post-context to UTF-8)" );
- }
- else
- {
- smart_str_appendl( &ret, buf, u8len );
- efree( buf );
- }
- smart_str_appends( &ret, "\"" );
- any = 1;
- }
-
- if( !any )
- {
- smart_str_free( &ret );
- smart_str_appends( &ret, "no parse error" );
- }
-
- smart_str_0( &ret );
- return ret;
-}
-
/*
* Local variables:
* tab-width: 4
diff --git a/ext/intl/transliterator/transliterator_class.c b/ext/intl/transliterator/transliterator_class.c
index 5ef80fb482..9891b35f4c 100644
--- a/ext/intl/transliterator/transliterator_class.c
+++ b/ext/intl/transliterator/transliterator_class.c
@@ -39,7 +39,7 @@ int transliterator_object_construct( zval *object,
char *str_id;
int str_id_len;
Transliterator_object *to;
-
+
TRANSLITERATOR_METHOD_FETCH_OBJECT_NO_CHECK;
assert( to->utrans == NULL );
@@ -54,7 +54,7 @@ int transliterator_object_construct( zval *object,
{
return FAILURE;
}
-
+
zend_update_property_stringl( Transliterator_ce_ptr, object,
"id", sizeof( "id" ) - 1, str_id, str_id_len TSRMLS_CC );
efree( str_id );
@@ -126,7 +126,7 @@ static zend_object_value Transliterator_object_create(
Transliterator_object* intern;
intern = ecalloc( 1, sizeof( Transliterator_object ) );
-
+
zend_object_std_init( &intern->zo, ce TSRMLS_CC );
#if PHP_VERSION_ID < 50399
zend_hash_copy( intern->zo.properties, &(ce->default_properties ),
@@ -247,7 +247,7 @@ err:
#if PHP_VERSION_ID < 50399
static zval **Transliterator_get_property_ptr_ptr( zval *object, zval *member TSRMLS_DC )
#else
-static zval **Transliterator_get_property_ptr_ptr( zval *object, zval *member,
+static zval **Transliterator_get_property_ptr_ptr( zval *object, zval *member, int type,
const struct _zend_literal *key TSRMLS_DC )
#endif
{
@@ -265,7 +265,7 @@ static zval **Transliterator_get_property_ptr_ptr( zval *object, zval *member,
#if PHP_VERSION_ID < 50399
retval = std_object_handlers.get_property_ptr_ptr( object, member TSRMLS_CC );
#else
- retval = std_object_handlers.get_property_ptr_ptr( object, member, key TSRMLS_CC );
+ retval = std_object_handlers.get_property_ptr_ptr( object, member, type, key TSRMLS_CC );
#endif
}
diff --git a/ext/intl/transliterator/transliterator_methods.c b/ext/intl/transliterator/transliterator_methods.c
index d0cfb9790d..1aa39c54b9 100644
--- a/ext/intl/transliterator/transliterator_methods.c
+++ b/ext/intl/transliterator/transliterator_methods.c
@@ -183,7 +183,7 @@ PHP_FUNCTION( transliterator_create_from_rules )
{
char *msg = NULL;
smart_str parse_error_str;
- parse_error_str = transliterator_parse_error_to_string( &parse_error );
+ parse_error_str = intl_parse_error_to_string( &parse_error );
spprintf( &msg, 0, "transliterator_create_from_rules: unable to "
"create ICU transliterator from rules (%s)", parse_error_str.c );
smart_str_free( &parse_error_str );