1 /*
2 +----------------------------------------------------------------------+
3 | PHP Version 7 |
4 +----------------------------------------------------------------------+
5 | This source file is subject to version 3.01 of the PHP license, |
6 | that is bundled with this package in the file LICENSE, and is |
7 | available through the world-wide-web at the following url: |
8 | http://www.php.net/license/3_01.txt |
9 | If you did not receive a copy of the PHP license and are unable to |
10 | obtain it through the world-wide-web, please send a note to |
11 | license@php.net so we can mail you a copy immediately. |
12 +----------------------------------------------------------------------+
13 | Authors: Kirti Velankar <kirtig@yahoo-inc.com> |
14 | Gustavo Lopes <cataphract@php.net> |
15 +----------------------------------------------------------------------+
16 */
17
18 #include "../intl_cppshims.h"
19
20 #include <unicode/timezone.h>
21 #include <unicode/calendar.h>
22 #include <unicode/datefmt.h>
23
24 extern "C" {
25 #include <unicode/ustring.h>
26 #include <unicode/udat.h>
27
28 #include "php_intl.h"
29 #include "dateformat_create.h"
30 #include "dateformat_class.h"
31 #define USE_TIMEZONE_POINTER 1
32 #include "../timezone/timezone_class.h"
33 #include "../intl_convert.h"
34 }
35
36 #include "dateformat_helpers.h"
37 #include "zend_exceptions.h"
38
39 #if U_ICU_VERSION_MAJOR_NUM < 50
40 #define UDAT_PATTERN 0
41 #endif
42
43 #define INTL_UDATE_FMT_OK(i) \
44 (UDAT_FULL == (i) || UDAT_LONG == (i) || \
45 UDAT_MEDIUM == (i) || UDAT_SHORT == (i) || \
46 UDAT_RELATIVE == (i) || UDAT_FULL_RELATIVE == (i) || \
47 UDAT_LONG_RELATIVE == (i) || UDAT_MEDIUM_RELATIVE == (i) || \
48 UDAT_SHORT_RELATIVE == (i) || UDAT_NONE == (i) || \
49 UDAT_PATTERN == (i))
50
51 /* {{{ */
datefmt_ctor(INTERNAL_FUNCTION_PARAMETERS,zend_bool is_constructor)52 static int datefmt_ctor(INTERNAL_FUNCTION_PARAMETERS, zend_bool is_constructor)
53 {
54 zval *object;
55 const char *locale_str;
56 size_t locale_len = 0;
57 Locale locale;
58 zend_long date_type = 0;
59 zend_long time_type = 0;
60 zval *calendar_zv = NULL;
61 Calendar *calendar = NULL;
62 zend_long calendar_type;
63 bool calendar_owned;
64 zval *timezone_zv = NULL;
65 TimeZone *timezone = NULL;
66 bool explicit_tz;
67 char* pattern_str = NULL;
68 size_t pattern_str_len = 0;
69 UChar* svalue = NULL; /* UTF-16 pattern_str */
70 int32_t slength = 0;
71 IntlDateFormatter_object* dfo;
72 int zpp_flags = is_constructor ? ZEND_PARSE_PARAMS_THROW : 0;
73
74 intl_error_reset(NULL);
75 object = return_value;
76 /* Parse parameters. */
77 if (zend_parse_parameters_ex(zpp_flags, ZEND_NUM_ARGS(), "s!ll|zzs",
78 &locale_str, &locale_len, &date_type, &time_type, &timezone_zv,
79 &calendar_zv, &pattern_str, &pattern_str_len) == FAILURE) {
80 intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR, "datefmt_create: "
81 "unable to parse input parameters", 0);
82 return FAILURE;
83 }
84
85 DATE_FORMAT_METHOD_FETCH_OBJECT_NO_CHECK;
86
87 if (DATE_FORMAT_OBJECT(dfo) != NULL) {
88 intl_errors_set(INTL_DATA_ERROR_P(dfo), U_ILLEGAL_ARGUMENT_ERROR,
89 "datefmt_create: cannot call constructor twice", 0);
90 return FAILURE;
91 }
92
93 if (!INTL_UDATE_FMT_OK(date_type)) {
94 intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, "datefmt_create: invalid date format style", 0);
95 return FAILURE;
96 }
97 if (!INTL_UDATE_FMT_OK(time_type)) {
98 intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, "datefmt_create: invalid time format style", 0);
99 return FAILURE;
100 }
101
102 INTL_CHECK_LOCALE_LEN_OR_FAILURE(locale_len);
103 if (locale_len == 0) {
104 locale_str = intl_locale_get_default();
105 }
106 locale = Locale::createFromName(locale_str);
107
108 /* process calendar */
109 if (datefmt_process_calendar_arg(calendar_zv, locale, "datefmt_create",
110 INTL_DATA_ERROR_P(dfo), calendar, calendar_type,
111 calendar_owned)
112 == FAILURE) {
113 goto error;
114 }
115
116 /* process timezone */
117 explicit_tz = timezone_zv != NULL && Z_TYPE_P(timezone_zv) != IS_NULL;
118
119 if (explicit_tz || calendar_owned ) {
120 //we have an explicit time zone or a non-object calendar
121 timezone = timezone_process_timezone_argument(timezone_zv,
122 INTL_DATA_ERROR_P(dfo), "datefmt_create");
123 if (timezone == NULL) {
124 goto error;
125 }
126 }
127
128 /* Convert pattern (if specified) to UTF-16. */
129 if (pattern_str && pattern_str_len > 0) {
130 intl_convert_utf8_to_utf16(&svalue, &slength,
131 pattern_str, pattern_str_len, &INTL_DATA_ERROR_CODE(dfo));
132 if (U_FAILURE(INTL_DATA_ERROR_CODE(dfo))) {
133 /* object construction -> only set global error */
134 intl_error_set(NULL, INTL_DATA_ERROR_CODE(dfo), "datefmt_create: "
135 "error converting pattern to UTF-16", 0);
136 goto error;
137 }
138 }
139
140 DATE_FORMAT_OBJECT(dfo) = udat_open((UDateFormatStyle)time_type,
141 (UDateFormatStyle)date_type, locale_str, NULL, 0, svalue,
142 slength, &INTL_DATA_ERROR_CODE(dfo));
143
144 if (pattern_str && pattern_str_len > 0) {
145 udat_applyPattern(DATE_FORMAT_OBJECT(dfo), true, svalue, slength);
146 if (U_FAILURE(INTL_DATA_ERROR_CODE(dfo))) {
147 intl_error_set(NULL, INTL_DATA_ERROR_CODE(dfo), "datefmt_create: error applying pattern", 0);
148 goto error;
149 }
150 }
151
152 if (!U_FAILURE(INTL_DATA_ERROR_CODE(dfo))) {
153 DateFormat *df = (DateFormat*)DATE_FORMAT_OBJECT(dfo);
154 if (calendar_owned) {
155 df->adoptCalendar(calendar);
156 calendar_owned = false;
157 } else {
158 df->setCalendar(*calendar);
159 }
160
161 if (timezone != NULL) {
162 df->adoptTimeZone(timezone);
163 }
164 } else {
165 intl_error_set(NULL, INTL_DATA_ERROR_CODE(dfo), "datefmt_create: date "
166 "formatter creation failed", 0);
167 goto error;
168 }
169
170 /* Set the class variables */
171 dfo->date_type = date_type;
172 dfo->time_type = time_type;
173 dfo->calendar = calendar_type;
174 dfo->requested_locale = estrdup(locale_str);
175
176 error:
177 if (svalue) {
178 efree(svalue);
179 }
180 if (timezone != NULL && DATE_FORMAT_OBJECT(dfo) == NULL) {
181 delete timezone;
182 }
183 if (calendar != NULL && calendar_owned) {
184 delete calendar;
185 }
186
187 return U_FAILURE(intl_error_get_code(NULL)) ? FAILURE : SUCCESS;
188 }
189 /* }}} */
190
191 /* {{{ proto IntlDateFormatter IntlDateFormatter::create(string $locale, long date_type, long time_type[, string $timezone_str, long $calendar, string $pattern] )
192 * Create formatter. }}} */
193 /* {{{ proto IntlDateFormatter datefmt_create(string $locale, long date_type, long time_type[, string $timezone_str, long $calendar, string $pattern)
194 * Create formatter.
195 */
PHP_FUNCTION(datefmt_create)196 U_CFUNC PHP_FUNCTION( datefmt_create )
197 {
198 object_init_ex( return_value, IntlDateFormatter_ce_ptr );
199 if (datefmt_ctor(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0) == FAILURE) {
200 zval_ptr_dtor(return_value);
201 RETURN_NULL();
202 }
203 }
204 /* }}} */
205
206 /* {{{ proto void IntlDateFormatter::__construct(string $locale, long date_type, long time_type[, string $timezone_str, long $calendar, string $pattern])
207 * IntlDateFormatter object constructor.
208 */
PHP_METHOD(IntlDateFormatter,__construct)209 U_CFUNC PHP_METHOD( IntlDateFormatter, __construct )
210 {
211 zend_error_handling error_handling;
212
213 zend_replace_error_handling(EH_THROW, IntlException_ce_ptr, &error_handling);
214 /* return_value param is being changed, therefore we will always return
215 * NULL here */
216 return_value = getThis();
217 if (datefmt_ctor(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1) == FAILURE) {
218 if (!EG(exception)) {
219 zend_string *err = intl_error_get_message(NULL);
220 zend_throw_exception(IntlException_ce_ptr, ZSTR_VAL(err), intl_error_get_code(NULL));
221 zend_string_release_ex(err, 0);
222 }
223 }
224 zend_restore_error_handling(&error_handling);
225 }
226 /* }}} */
227