1 /*
2    +----------------------------------------------------------------------+
3    | PHP Version 5                                                        |
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: Gustavo Lopes <cataphract@php.net>                          |
14    +----------------------------------------------------------------------+
15 */
16 
17 #include "../intl_cppshims.h"
18 
19 #include <unicode/timezone.h>
20 #include <unicode/calendar.h>
21 #include <unicode/datefmt.h>
22 
23 extern "C" {
24 #include "../php_intl.h"
25 #include "dateformat_class.h"
26 #include "dateformat_attrcpp.h"
27 #define USE_TIMEZONE_POINTER 1
28 #include "../timezone/timezone_class.h"
29 #define USE_CALENDAR_POINTER 1
30 #include "../calendar/calendar_class.h"
31 }
32 
33 #include "../intl_convertcpp.h"
34 #include "dateformat_helpers.h"
35 
fetch_datefmt(IntlDateFormatter_object * dfo)36 static inline DateFormat *fetch_datefmt(IntlDateFormatter_object *dfo) {
37 	return (DateFormat *)dfo->datef_data.udatf;
38 }
39 
40 /* {{{ proto string IntlDateFormatter::getTimeZoneId()
41  * Get formatter timezone_id. }}} */
42 /* {{{ proto string datefmt_get_timezone_id(IntlDateFormatter $mf)
43  * Get formatter timezone_id.
44  */
PHP_FUNCTION(datefmt_get_timezone_id)45 U_CFUNC PHP_FUNCTION(datefmt_get_timezone_id)
46 {
47 	DATE_FORMAT_METHOD_INIT_VARS;
48 
49 	if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O",
50 			&object, IntlDateFormatter_ce_ptr ) == FAILURE) {
51 		intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,	"datefmt_get_timezone_"
52 				"id: unable to parse input params", 0 TSRMLS_CC);
53 		RETURN_FALSE;
54 	}
55 
56 	DATE_FORMAT_METHOD_FETCH_OBJECT;
57 
58 	UnicodeString res = UnicodeString();
59 	fetch_datefmt(dfo)->getTimeZone().getID(res);
60 	intl_charFromString(res, &Z_STRVAL_P(return_value),
61 			&Z_STRLEN_P(return_value), &INTL_DATA_ERROR_CODE(dfo));
62 	INTL_METHOD_CHECK_STATUS(dfo, "Could not convert time zone id to UTF-8");
63 
64 	Z_TYPE_P(return_value) = IS_STRING;
65 }
66 
67 /* {{{ proto IntlTimeZone IntlDateFormatter::getTimeZone()
68  * Get formatter timezone. }}} */
69 /* {{{ proto IntlTimeZone datefmt_get_timezone(IntlDateFormatter $mf)
70  * Get formatter timezone.
71  */
PHP_FUNCTION(datefmt_get_timezone)72 U_CFUNC PHP_FUNCTION(datefmt_get_timezone)
73 {
74 	DATE_FORMAT_METHOD_INIT_VARS;
75 
76 	if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O",
77 			&object, IntlDateFormatter_ce_ptr ) == FAILURE) {
78 		intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,
79 			"datefmt_get_timezone: unable to parse input params", 0 TSRMLS_CC );
80 		RETURN_FALSE;
81 	}
82 
83 	DATE_FORMAT_METHOD_FETCH_OBJECT;
84 
85 	const TimeZone& tz = fetch_datefmt(dfo)->getTimeZone();
86 	TimeZone *tz_clone = tz.clone();
87 	if (tz_clone == NULL) {
88 		intl_errors_set(INTL_DATA_ERROR_P(dfo), U_MEMORY_ALLOCATION_ERROR,
89 				"datefmt_get_timezone: Out of memory when cloning time zone",
90 				0 TSRMLS_CC);
91 		RETURN_FALSE;
92 	}
93 
94 	object_init_ex(return_value, TimeZone_ce_ptr);
95 	timezone_object_construct(tz_clone, return_value, 1 TSRMLS_CC);
96 }
97 
PHP_FUNCTION(datefmt_set_timezone_id)98 U_CFUNC PHP_FUNCTION(datefmt_set_timezone_id)
99 {
100 	php_error_docref0(NULL TSRMLS_CC, E_DEPRECATED,
101 			"Use datefmt_set_timezone() instead, which also accepts a plain "
102 			"time zone identifier and for which this function is now an "
103 			"alias");
104 	PHP_FN(datefmt_set_timezone)(INTERNAL_FUNCTION_PARAM_PASSTHRU);
105 }
106 
107 /* {{{ proto boolean IntlDateFormatter::setTimeZone(mixed $timezone)
108  * Set formatter's timezone. }}} */
109 /* {{{ proto boolean datefmt_set_timezone_id(IntlDateFormatter $mf, $timezone_id)
110  * Set formatter timezone_id.
111  */
PHP_FUNCTION(datefmt_set_timezone)112 U_CFUNC PHP_FUNCTION(datefmt_set_timezone)
113 {
114 	zval		**timezone_zv;
115 	TimeZone	*timezone;
116 
117 	DATE_FORMAT_METHOD_INIT_VARS;
118 
119 	if ( zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(),
120 			"OZ", &object, IntlDateFormatter_ce_ptr, &timezone_zv) == FAILURE) {
121 		intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, "datefmt_set_timezone: "
122 				"unable to parse input params", 0 TSRMLS_CC);
123 		RETURN_FALSE;
124 	}
125 
126 	DATE_FORMAT_METHOD_FETCH_OBJECT;
127 
128 	timezone = timezone_process_timezone_argument(timezone_zv,
129 			INTL_DATA_ERROR_P(dfo), "datefmt_set_timezone" TSRMLS_CC);
130 	if (timezone == NULL) {
131 		RETURN_FALSE;
132 	}
133 
134 	fetch_datefmt(dfo)->adoptTimeZone(timezone);
135 }
136 
137 /* {{{ proto int IntlDateFormatter::getCalendar( )
138  * Get formatter calendar type. }}} */
139 /* {{{ proto int datefmt_get_calendar(IntlDateFormatter $mf)
140  * Get formatter calendar type.
141  */
PHP_FUNCTION(datefmt_get_calendar)142 U_CFUNC PHP_FUNCTION(datefmt_get_calendar)
143 {
144 	DATE_FORMAT_METHOD_INIT_VARS;
145 
146 	if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O",
147 			&object, IntlDateFormatter_ce_ptr ) == FAILURE) {
148 		intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
149 			"datefmt_get_calendar: unable to parse input params", 0 TSRMLS_CC);
150 		RETURN_FALSE;
151 	}
152 
153 	DATE_FORMAT_METHOD_FETCH_OBJECT;
154 
155 	if (dfo->calendar == -1) {
156 		/* an IntlCalendar was provided to the constructor */
157 		RETURN_FALSE;
158 	}
159 
160 	RETURN_LONG(dfo->calendar);
161 }
162 /* }}} */
163 
164 /* {{{ proto IntlCalendar IntlDateFormatter::getCalendarObject()
165  * Get formatter calendar. }}} */
166 /* {{{ proto IntlCalendar datefmt_get_calendar_object(IntlDateFormatter $mf)
167  * Get formatter calendar.
168  */
PHP_FUNCTION(datefmt_get_calendar_object)169 U_CFUNC PHP_FUNCTION(datefmt_get_calendar_object)
170 {
171 	DATE_FORMAT_METHOD_INIT_VARS;
172 
173 	if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O",
174 			&object, IntlDateFormatter_ce_ptr ) == FAILURE) {
175 		intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
176 				"datefmt_get_calendar_object: unable to parse input params",
177 				0 TSRMLS_CC);
178 		RETURN_FALSE;
179 	}
180 
181 	DATE_FORMAT_METHOD_FETCH_OBJECT;
182 
183 	const Calendar *cal = fetch_datefmt(dfo)->getCalendar();
184 	if (cal == NULL) {
185 		RETURN_NULL();
186 	}
187 
188 	Calendar *cal_clone = cal->clone();
189 	if (cal_clone == NULL) {
190 		intl_errors_set(INTL_DATA_ERROR_P(dfo), U_MEMORY_ALLOCATION_ERROR,
191 				"datefmt_get_calendar_object: Out of memory when cloning "
192 				"calendar", 0 TSRMLS_CC);
193 		RETURN_FALSE;
194 	}
195 
196 	calendar_object_create(return_value, cal_clone TSRMLS_CC);
197 }
198 /* }}} */
199 
200 /* {{{ proto bool IntlDateFormatter::setCalendar(mixed $calendar)
201  * Set formatter's calendar. }}} */
202 /* {{{ proto bool datefmt_set_calendar(IntlDateFormatter $mf, mixed $calendar)
203  * Set formatter's calendar.
204  */
PHP_FUNCTION(datefmt_set_calendar)205 U_CFUNC PHP_FUNCTION(datefmt_set_calendar)
206 {
207 	zval	*calendar_zv;
208 	DATE_FORMAT_METHOD_INIT_VARS;
209 
210 	if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Oz",
211 			&object, IntlDateFormatter_ce_ptr, &calendar_zv) == FAILURE) {
212 		intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
213 			"datefmt_set_calendar: unable to parse input params", 0 TSRMLS_CC);
214 		RETURN_FALSE;
215 	}
216 
217 	DATE_FORMAT_METHOD_FETCH_OBJECT;
218 
219 	Calendar	*cal;
220 	long		cal_type;
221 	bool		cal_owned;
222 	Locale		locale = Locale::createFromName(dfo->requested_locale);
223 	// getting the actual locale from the DateFormat is not enough
224 	// because we would have lost modifiers such as @calendar. We
225 	// must store the requested locale on object creation
226 
227 	if (datefmt_process_calendar_arg(calendar_zv, locale,
228 			"datefmt_set_calendar",	INTL_DATA_ERROR_P(dfo), cal, cal_type,
229 			cal_owned TSRMLS_CC) == FAILURE) {
230 		RETURN_FALSE;
231 	}
232 
233 	if (cal_owned) {
234 		/* a non IntlCalendar was specified, we want to keep the timezone */
235 		TimeZone *old_timezone = fetch_datefmt(dfo)->getTimeZone().clone();
236 		if (old_timezone == NULL) {
237 			intl_errors_set(INTL_DATA_ERROR_P(dfo), U_MEMORY_ALLOCATION_ERROR,
238 					"datefmt_set_calendar: Out of memory when cloning calendar",
239 					0 TSRMLS_CC);
240 			delete cal;
241 			RETURN_FALSE;
242 		}
243 		cal->adoptTimeZone(old_timezone);
244 	} else {
245 		cal = cal->clone();
246 		if (cal == NULL) {
247 			intl_errors_set(INTL_DATA_ERROR_P(dfo), U_MEMORY_ALLOCATION_ERROR,
248 					"datefmt_set_calendar: Out of memory when cloning calendar",
249 					0 TSRMLS_CC);
250 			RETURN_FALSE;
251 		}
252 	}
253 
254 	fetch_datefmt(dfo)->adoptCalendar(cal);
255 
256 	dfo->calendar = cal_type;
257 
258 	RETURN_TRUE;
259 }
260 /* }}} */
261 
262