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 #ifdef HAVE_CONFIG_H
18 #include "config.h"
19 #endif
20 
21 #include "../intl_cppshims.h"
22 
23 #include <unicode/locid.h>
24 #include <unicode/calendar.h>
25 #include <unicode/ustring.h>
26 
27 #include "../intl_convertcpp.h"
28 #include "../common/common_date.h"
29 
30 extern "C" {
31 #include "../php_intl.h"
32 #define USE_TIMEZONE_POINTER 1
33 #include "../timezone/timezone_class.h"
34 #define USE_CALENDAR_POINTER 1
35 #include "calendar_class.h"
36 #include "../intl_convert.h"
37 #include <zend_exceptions.h>
38 #include <zend_interfaces.h>
39 #include <ext/date/php_date.h>
40 }
41 #include "../common/common_enum.h"
42 
PHP_METHOD(IntlCalendar,__construct)43 U_CFUNC PHP_METHOD(IntlCalendar, __construct)
44 {
45 	zend_throw_exception( NULL,
46 		"An object of this type cannot be created with the new operator",
47 		0 TSRMLS_CC );
48 }
49 
PHP_FUNCTION(intlcal_create_instance)50 U_CFUNC PHP_FUNCTION(intlcal_create_instance)
51 {
52 	zval		**zv_timezone	= NULL;
53 	const char	*locale_str		= NULL;
54 	int			dummy;
55 	TimeZone	*timeZone;
56 	UErrorCode	status			= U_ZERO_ERROR;
57 	intl_error_reset(NULL TSRMLS_CC);
58 
59 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|Zs!",
60 			&zv_timezone, &locale_str, &dummy) == FAILURE) {
61 		intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
62 			"intlcal_create_calendar: bad arguments", 0 TSRMLS_CC);
63 		RETURN_NULL();
64 	}
65 
66 	timeZone = timezone_process_timezone_argument(zv_timezone, NULL,
67 		"intlcal_create_instance" TSRMLS_CC);
68 	if (timeZone == NULL) {
69 		RETURN_NULL();
70 	}
71 
72 	if (!locale_str) {
73 		locale_str = intl_locale_get_default(TSRMLS_C);
74 	}
75 
76 	Calendar *cal = Calendar::createInstance(timeZone,
77 		Locale::createFromName(locale_str), status);
78 	if (cal == NULL) {
79 		delete timeZone;
80 		intl_error_set(NULL, status, "Error creating ICU Calendar object", 0 TSRMLS_CC);
81 		RETURN_NULL();
82 	}
83 
84 	calendar_object_create(return_value, cal TSRMLS_CC);
85 }
86 
87 #if U_ICU_VERSION_MAJOR_NUM * 10 + U_ICU_VERSION_MINOR_NUM >= 42
88 class BugStringCharEnumeration : public StringEnumeration
89 {
90 public:
BugStringCharEnumeration(UEnumeration * _uenum)91 	BugStringCharEnumeration(UEnumeration* _uenum) : uenum(_uenum) {}
92 
~BugStringCharEnumeration()93 	~BugStringCharEnumeration()
94 	{
95 		uenum_close(uenum);
96 	}
97 
count(UErrorCode & status) const98 	int32_t count(UErrorCode& status) const {
99 		return uenum_count(uenum, &status);
100 	}
101 
snext(UErrorCode & status)102 	virtual const UnicodeString* snext(UErrorCode& status)
103 	{
104 		int32_t length;
105 		const UChar* str = uenum_unext(uenum, &length, &status);
106 		if (str == 0 || U_FAILURE(status)) {
107 			return 0;
108 		}
109 		return &unistr.setTo(str, length);
110 	}
111 
next(int32_t * resultLength,UErrorCode & status)112 	virtual const char* next(int32_t *resultLength, UErrorCode &status)
113 	{
114 		int32_t length = -1;
115 		const char* str = uenum_next(uenum, &length, &status);
116 		if (str == 0 || U_FAILURE(status)) {
117 			return 0;
118 		}
119 		if (resultLength) {
120 			//the bug is that uenum_next doesn't set the length
121 			*resultLength = (length == -1) ? strlen(str) : length;
122 		}
123 
124 		return str;
125 	}
126 
reset(UErrorCode & status)127 	void reset(UErrorCode& status)
128 	{
129 		uenum_reset(uenum, &status);
130 	}
131 
132 	virtual UClassID getDynamicClassID() const;
133 
134 	static UClassID U_EXPORT2 getStaticClassID();
135 
136 private:
137 	UEnumeration *uenum;
138 };
UOBJECT_DEFINE_RTTI_IMPLEMENTATION(BugStringCharEnumeration)139 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(BugStringCharEnumeration)
140 
141 U_CFUNC PHP_FUNCTION(intlcal_get_keyword_values_for_locale)
142 {
143 	UErrorCode	status = U_ZERO_ERROR;
144 	char		*key,
145 				*locale;
146 	int			key_len,
147 				locale_len;
148 	zend_bool	commonly_used;
149 	intl_error_reset(NULL TSRMLS_CC);
150 
151 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ssb",
152 			&key, &key_len, &locale, &locale_len, &commonly_used) == FAILURE) {
153 		intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
154 			"intlcal_get_keyword_values_for_locale: bad arguments", 0 TSRMLS_CC);
155 		RETURN_FALSE;
156 	}
157 
158 	//does not work; see ICU bug 9194
159 #if 0
160 	StringEnumeration *se = Calendar::getKeywordValuesForLocale(key,
161 		Locale::createFromName(locale), (UBool)commonly_used,
162 		status);
163 	if (se == NULL) {
164 		intl_error_set(NULL, status, "intlcal_get_keyword_values_for_locale: "
165 			"error calling underlying method", 0 TSRMLS_CC);
166 		RETURN_FALSE;
167 	}
168 #else
169     UEnumeration *uenum = ucal_getKeywordValuesForLocale(
170 		key, locale, !!commonly_used, &status);
171     if (U_FAILURE(status)) {
172         uenum_close(uenum);
173 		intl_error_set(NULL, status, "intlcal_get_keyword_values_for_locale: "
174 			"error calling underlying method", 0 TSRMLS_CC);
175         RETURN_FALSE;
176     }
177 
178     StringEnumeration *se = new BugStringCharEnumeration(uenum);
179 #endif
180 
181 	IntlIterator_from_StringEnumeration(se, return_value TSRMLS_CC);
182 }
183 #endif //ICU 4.2 only
184 
PHP_FUNCTION(intlcal_get_now)185 U_CFUNC PHP_FUNCTION(intlcal_get_now)
186 {
187 	intl_error_reset(NULL TSRMLS_CC);
188 
189 	if (zend_parse_parameters_none() == FAILURE) {
190 		intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
191 			"intlcal_get_now: bad arguments", 0 TSRMLS_CC);
192 		RETURN_FALSE;
193 	}
194 
195 	RETURN_DOUBLE((double)Calendar::getNow());
196 }
197 
PHP_FUNCTION(intlcal_get_available_locales)198 U_CFUNC PHP_FUNCTION(intlcal_get_available_locales)
199 {
200 	intl_error_reset(NULL TSRMLS_CC);
201 
202 	if (zend_parse_parameters_none() == FAILURE) {
203 		intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
204 			"intlcal_get_available_locales: bad arguments", 0 TSRMLS_CC);
205 		RETURN_FALSE;
206 	}
207 
208 	int32_t count;
209 	const Locale *availLocales = Calendar::getAvailableLocales(count);
210 	array_init(return_value);
211 	for (int i = 0; i < count; i++) {
212 		Locale locale = availLocales[i];
213 		add_next_index_string(return_value, locale.getName(), 1);
214 	}
215 }
216 
_php_intlcal_field_uec_ret_in32t_method(int32_t (Calendar::* func)(UCalendarDateFields,UErrorCode &)const,const char * method_name,INTERNAL_FUNCTION_PARAMETERS)217 static void _php_intlcal_field_uec_ret_in32t_method(
218 		int32_t (Calendar::*func)(UCalendarDateFields, UErrorCode&) const,
219 		const char *method_name,
220 		INTERNAL_FUNCTION_PARAMETERS)
221 {
222 	long	field;
223 	char	*message;
224 	CALENDAR_METHOD_INIT_VARS;
225 
226 	if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(),
227 			"Ol", &object, Calendar_ce_ptr, &field) == FAILURE) {
228 		spprintf(&message, 0, "%s: bad arguments", method_name);
229 		intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, message, 1 TSRMLS_CC);
230 		efree(message);
231 		RETURN_FALSE;
232 	}
233 
234 	if (field < 0 || field >= UCAL_FIELD_COUNT) {
235 		spprintf(&message, 0, "%s: invalid field", method_name);
236 		intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, message, 1 TSRMLS_CC);
237 		efree(message);
238 		RETURN_FALSE;
239 	}
240 
241 	CALENDAR_METHOD_FETCH_OBJECT;
242 
243 	int32_t result = (co->ucal->*func)(
244 		(UCalendarDateFields)field, CALENDAR_ERROR_CODE(co));
245 	INTL_METHOD_CHECK_STATUS(co, "Call to ICU method has failed");
246 
247 	RETURN_LONG((long)result);
248 }
249 
PHP_FUNCTION(intlcal_get)250 U_CFUNC PHP_FUNCTION(intlcal_get)
251 {
252 	_php_intlcal_field_uec_ret_in32t_method(&Calendar::get,
253 		"intlcal_get", INTERNAL_FUNCTION_PARAM_PASSTHRU);
254 }
255 
PHP_FUNCTION(intlcal_get_time)256 U_CFUNC PHP_FUNCTION(intlcal_get_time)
257 {
258 	CALENDAR_METHOD_INIT_VARS;
259 
260 	if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O",
261 			&object, Calendar_ce_ptr) == FAILURE) {
262 		intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
263 			"intlcal_get_time: bad arguments", 0 TSRMLS_CC);
264 		RETURN_FALSE;
265 	}
266 
267 	CALENDAR_METHOD_FETCH_OBJECT;
268 
269 	UDate result = co->ucal->getTime(CALENDAR_ERROR_CODE(co));
270 	INTL_METHOD_CHECK_STATUS(co,
271 		"intlcal_get_time: error calling ICU Calendar::getTime");
272 
273 	RETURN_DOUBLE((double)result);
274 }
275 
PHP_FUNCTION(intlcal_set_time)276 U_CFUNC PHP_FUNCTION(intlcal_set_time)
277 {
278 	double	time_arg;
279 	CALENDAR_METHOD_INIT_VARS;
280 
281 	if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Od",
282 			&object, Calendar_ce_ptr, &time_arg) == FAILURE) {
283 		intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
284 			"intlcal_set_time: bad arguments", 0 TSRMLS_CC);
285 		RETURN_FALSE;
286 	}
287 
288 	CALENDAR_METHOD_FETCH_OBJECT;
289 
290 	co->ucal->setTime((UDate)time_arg, CALENDAR_ERROR_CODE(co));
291 	INTL_METHOD_CHECK_STATUS(co, "Call to underlying method failed");
292 
293 	RETURN_TRUE;
294 }
295 
PHP_FUNCTION(intlcal_add)296 U_CFUNC PHP_FUNCTION(intlcal_add)
297 {
298 	long	field,
299 			amount;
300 	CALENDAR_METHOD_INIT_VARS;
301 
302 	if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(),
303 			"Oll", &object, Calendar_ce_ptr, &field, &amount) == FAILURE) {
304 		intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
305 			"intlcal_add: bad arguments", 0 TSRMLS_CC);
306 		RETURN_FALSE;
307 	}
308 
309 	if (field < 0 || field >= UCAL_FIELD_COUNT) {
310 		intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
311 			"intlcal_add: invalid field", 0 TSRMLS_CC);
312 		RETURN_FALSE;
313 	}
314 	if (amount < INT32_MIN || amount > INT32_MAX) {
315 		intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
316 			"intlcal_add: amount out of bounds", 0 TSRMLS_CC);
317 		RETURN_FALSE;
318 	}
319 
320 	CALENDAR_METHOD_FETCH_OBJECT;
321 
322 	co->ucal->add((UCalendarDateFields)field, (int32_t)amount, CALENDAR_ERROR_CODE(co));
323 	INTL_METHOD_CHECK_STATUS(co, "intlcal_add: Call to underlying method failed");
324 
325 	RETURN_TRUE;
326 }
327 
PHP_FUNCTION(intlcal_set_time_zone)328 U_CFUNC PHP_FUNCTION(intlcal_set_time_zone)
329 {
330 	zval			*zv_timezone;
331 	TimeZone		*timeZone;
332 	CALENDAR_METHOD_INIT_VARS;
333 
334 	if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(),
335 			"Oz!", &object, Calendar_ce_ptr, &zv_timezone) == FAILURE) {
336 		intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
337 			"intlcal_set_time_zone: bad arguments", 0 TSRMLS_CC);
338 		RETURN_FALSE;
339 	}
340 
341 	CALENDAR_METHOD_FETCH_OBJECT;
342 
343 	if (zv_timezone == NULL) {
344 		RETURN_TRUE; /* the method does nothing if passed null */
345 	}
346 
347 	timeZone = timezone_process_timezone_argument(&zv_timezone,
348 		CALENDAR_ERROR_P(co), "intlcal_set_time_zone" TSRMLS_CC);
349 	if (timeZone == NULL) {
350 		RETURN_FALSE;
351 	}
352 
353 	co->ucal->adoptTimeZone(timeZone);
354 
355 	RETURN_TRUE;
356 }
357 
358 
_php_intlcal_before_after(UBool (Calendar::* func)(const Calendar &,UErrorCode &)const,INTERNAL_FUNCTION_PARAMETERS)359 static void _php_intlcal_before_after(
360 		UBool (Calendar::*func)(const Calendar&, UErrorCode&) const,
361 		INTERNAL_FUNCTION_PARAMETERS)
362 {
363 	zval			*when_object;
364 	Calendar_object	*when_co;
365 	CALENDAR_METHOD_INIT_VARS;
366 
367 	if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(),
368 			"OO", &object, Calendar_ce_ptr, &when_object, Calendar_ce_ptr)
369 			== FAILURE) {
370 		intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
371 			"intlcal_before/after: bad arguments", 0 TSRMLS_CC);
372 		RETURN_FALSE;
373 	}
374 
375 	CALENDAR_METHOD_FETCH_OBJECT;
376 
377 	when_co = static_cast<Calendar_object*>(
378 		zend_object_store_get_object(when_object TSRMLS_CC));
379 	if (when_co->ucal == NULL) {
380 		intl_errors_set(&co->err, U_ILLEGAL_ARGUMENT_ERROR,
381 			"intlcal_before/after: Other IntlCalendar was unconstructed", 0 TSRMLS_CC);
382 		RETURN_FALSE;
383 	}
384 
385 	UBool res = (co->ucal->*func)(*when_co->ucal, CALENDAR_ERROR_CODE(co));
386 	INTL_METHOD_CHECK_STATUS(co, "intlcal_before/after: Error calling ICU method");
387 
388 	RETURN_BOOL((int)res);
389 }
390 
PHP_FUNCTION(intlcal_after)391 U_CFUNC PHP_FUNCTION(intlcal_after)
392 {
393 	_php_intlcal_before_after(&Calendar::after, INTERNAL_FUNCTION_PARAM_PASSTHRU);
394 }
395 
PHP_FUNCTION(intlcal_before)396 U_CFUNC PHP_FUNCTION(intlcal_before)
397 {
398 	_php_intlcal_before_after(&Calendar::before, INTERNAL_FUNCTION_PARAM_PASSTHRU);
399 }
400 
PHP_FUNCTION(intlcal_set)401 U_CFUNC PHP_FUNCTION(intlcal_set)
402 {
403 	long	arg1, arg2, arg3, arg4, arg5, arg6;
404 	zval	**args_a[7] = {0},
405 			***args		= &args_a[0];
406 	int		i;
407 	int		variant; /* number of args of the set() overload */
408 	CALENDAR_METHOD_INIT_VARS;
409 
410 	/* must come before zpp because zpp would convert the args in the stack to 0 */
411 	if (ZEND_NUM_ARGS() > (getThis() ? 6 : 7) ||
412 				zend_get_parameters_array_ex(ZEND_NUM_ARGS(), args) == FAILURE) {
413 		intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
414 			"intlcal_set: too many arguments", 0 TSRMLS_CC);
415 		RETURN_FALSE;
416 	}
417 	if (!getThis()) {
418 		args++;
419 	}
420 	variant = ZEND_NUM_ARGS() - (getThis() ? 0 : 1);
421 	while (variant > 2 && Z_TYPE_PP(args[variant - 1]) == IS_NULL) {
422 		variant--;
423 	}
424 
425 	if (variant == 4 ||
426 			zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(),
427 			"Oll|llll",	&object, Calendar_ce_ptr, &arg1, &arg2, &arg3, &arg4,
428 			&arg5, &arg6) == FAILURE) {
429 		intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
430 			"intlcal_set: bad arguments", 0 TSRMLS_CC);
431 		RETURN_FALSE;
432 	}
433 
434 	for (i = 0; i < variant; i++) {
435 		if (Z_LVAL_PP(args[i]) < INT32_MIN || Z_LVAL_PP(args[i]) > INT32_MAX) {
436 			intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
437 				"intlcal_set: at least one of the arguments has an absolute "
438 				"value that is too large", 0 TSRMLS_CC);
439 			RETURN_FALSE;
440 		}
441 	}
442 
443 	if (variant == 2 && (arg1 < 0 || arg1 >= UCAL_FIELD_COUNT)) {
444 		intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
445 			"intlcal_set: invalid field", 0 TSRMLS_CC);
446 		RETURN_FALSE;
447 	}
448 
449 	CALENDAR_METHOD_FETCH_OBJECT;
450 
451 	if (variant == 2) {
452 		co->ucal->set((UCalendarDateFields)arg1, (int32_t)arg2);
453 	} else if (variant == 3) {
454 		co->ucal->set((int32_t)arg1, (int32_t)arg2, (int32_t)arg3);
455 	} else if (variant == 5) {
456 		co->ucal->set((int32_t)arg1, (int32_t)arg2, (int32_t)arg3, (int32_t)arg4, (int32_t)arg5);
457 	} else if (variant == 6) {
458 		co->ucal->set((int32_t)arg1, (int32_t)arg2, (int32_t)arg3, (int32_t)arg4, (int32_t)arg5, (int32_t)arg6);
459 	}
460 
461 	RETURN_TRUE;
462 }
463 
PHP_FUNCTION(intlcal_roll)464 U_CFUNC PHP_FUNCTION(intlcal_roll)
465 {
466 	long		field,
467 				value;
468 	zval		**args_a[3]		 = {0},
469 				***args			 = &args_a[0];
470 	zend_bool	bool_variant_val = (zend_bool)-1;
471 	CALENDAR_METHOD_INIT_VARS;
472 
473 	if (ZEND_NUM_ARGS() > (getThis() ? 2 :3) ||
474 			zend_get_parameters_array_ex(ZEND_NUM_ARGS(), args) == FAILURE) {
475 		intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
476 			"intlcal_set: too many arguments", 0 TSRMLS_CC);
477 		RETURN_FALSE;
478 	}
479 	if (!getThis()) {
480 		args++;
481 	}
482 	if (args[1] != NULL && Z_TYPE_PP(args[1]) == IS_BOOL) {
483 		if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(),
484 				"Olb", &object, Calendar_ce_ptr, &field, &bool_variant_val)
485 				== FAILURE) {
486 			intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
487 				"intlcal_roll: bad arguments", 0 TSRMLS_CC);
488 			RETURN_FALSE;
489 		}
490 		bool_variant_val = Z_BVAL_PP(args[1]);
491 	} else if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(),
492 			"Oll", &object, Calendar_ce_ptr, &field, &value) == FAILURE) {
493 		intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
494 			"intlcal_roll: bad arguments", 0 TSRMLS_CC);
495 		RETURN_FALSE;
496 	}
497 
498 	if (field < 0 || field >= UCAL_FIELD_COUNT) {
499 		intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
500 			"intlcal_roll: invalid field", 0 TSRMLS_CC);
501 		RETURN_FALSE;
502 	}
503 	if (bool_variant_val == (zend_bool)-1 &&
504 			(value < INT32_MIN || value > INT32_MAX)) {
505 		intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
506 			"intlcal_roll: value out of bounds", 0 TSRMLS_CC);
507 		RETURN_FALSE;
508 	}
509 
510 	CALENDAR_METHOD_FETCH_OBJECT;
511 
512 	if (bool_variant_val != (zend_bool)-1) {
513 		co->ucal->roll((UCalendarDateFields)field, (UBool)bool_variant_val,
514 			CALENDAR_ERROR_CODE(co));
515 	} else {
516 		co->ucal->roll((UCalendarDateFields)field, (int32_t)value,
517 			CALENDAR_ERROR_CODE(co));
518 	}
519 	INTL_METHOD_CHECK_STATUS(co, "intlcal_roll: Error calling ICU Calendar::roll");
520 
521 	RETURN_TRUE;
522 }
523 
PHP_FUNCTION(intlcal_clear)524 U_CFUNC PHP_FUNCTION(intlcal_clear)
525 {
526 	zval	**args_a[2] = {0},
527 			***args		= &args_a[0];
528 	long	field;
529 	int		variant;
530 	CALENDAR_METHOD_INIT_VARS;
531 
532 	if (ZEND_NUM_ARGS() > (getThis() ? 1 : 2) ||
533 			zend_get_parameters_array_ex(ZEND_NUM_ARGS(), args) == FAILURE) {
534 		intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
535 			"intlcal_clear: too many arguments", 0 TSRMLS_CC);
536 		RETURN_FALSE;
537 	}
538 	if (!getThis()) {
539 		args++;
540 	}
541 	if (args[0] == NULL || Z_TYPE_PP(args[0]) == IS_NULL) {
542 		zval *dummy; /* we know it's null */
543 		if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC,
544 				getThis(), "O|z", &object, Calendar_ce_ptr, &dummy) == FAILURE) {
545 			intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
546 				"intlcal_clear: bad arguments", 0 TSRMLS_CC);
547 			RETURN_FALSE;
548 		}
549 		variant = 0;
550 	} else if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC,
551 			getThis(), "Ol", &object, Calendar_ce_ptr, &field) == FAILURE) {
552 		intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
553 			"intlcal_clear: bad arguments", 0 TSRMLS_CC);
554 		RETURN_FALSE;
555 	} else if (field < 0 || field >= UCAL_FIELD_COUNT) {
556 		intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
557 			"intlcal_clear: invalid field", 0 TSRMLS_CC);
558 		RETURN_FALSE;
559 	} else {
560 		variant = 1;
561 	}
562 
563 	CALENDAR_METHOD_FETCH_OBJECT;
564 
565 	if (variant == 0) {
566 		co->ucal->clear();
567 	} else {
568 		co->ucal->clear((UCalendarDateFields)field);
569 	}
570 
571 	RETURN_TRUE;
572 }
573 
PHP_FUNCTION(intlcal_field_difference)574 U_CFUNC PHP_FUNCTION(intlcal_field_difference)
575 {
576 	long	field;
577 	double	when;
578 	CALENDAR_METHOD_INIT_VARS;
579 
580 	if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(),
581 			"Odl", &object, Calendar_ce_ptr, &when, &field)	== FAILURE) {
582 		intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
583 			"intlcal_field_difference: bad arguments", 0 TSRMLS_CC);
584 		RETURN_FALSE;
585 	}
586 
587 	if (field < 0 || field >= UCAL_FIELD_COUNT) {
588 		intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
589 			"intlcal_field_difference: invalid field", 0 TSRMLS_CC);
590 		RETURN_FALSE;
591 	}
592 
593 	CALENDAR_METHOD_FETCH_OBJECT;
594 
595 	int32_t result = co->ucal->fieldDifference((UDate)when,
596 		(UCalendarDateFields)field, CALENDAR_ERROR_CODE(co));
597 	INTL_METHOD_CHECK_STATUS(co,
598 		"intlcal_field_difference: Call to ICU method has failed");
599 
600 	RETURN_LONG((long)result);
601 }
602 
PHP_FUNCTION(intlcal_get_actual_maximum)603 U_CFUNC PHP_FUNCTION(intlcal_get_actual_maximum)
604 {
605 	_php_intlcal_field_uec_ret_in32t_method(&Calendar::getActualMaximum,
606 		"intlcal_get_actual_maximum", INTERNAL_FUNCTION_PARAM_PASSTHRU);
607 }
608 
PHP_FUNCTION(intlcal_get_actual_minimum)609 U_CFUNC PHP_FUNCTION(intlcal_get_actual_minimum)
610 {
611 	_php_intlcal_field_uec_ret_in32t_method(&Calendar::getActualMinimum,
612 		"intlcal_get_actual_minimum", INTERNAL_FUNCTION_PARAM_PASSTHRU);
613 }
614 
615 #if U_ICU_VERSION_MAJOR_NUM * 10 + U_ICU_VERSION_MINOR_NUM >= 44
PHP_FUNCTION(intlcal_get_day_of_week_type)616 U_CFUNC PHP_FUNCTION(intlcal_get_day_of_week_type)
617 {
618 	long	dow;
619 	CALENDAR_METHOD_INIT_VARS;
620 
621 	if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(),
622 			"Ol", &object, Calendar_ce_ptr, &dow) == FAILURE) {
623 		intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
624 			"intlcal_get_day_of_week_type: bad arguments", 0 TSRMLS_CC);
625 		RETURN_FALSE;
626 	}
627 
628 	if (dow < UCAL_SUNDAY || dow > UCAL_SATURDAY) {
629 		intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
630 			"intlcal_get_day_of_week_type: invalid day of week", 0 TSRMLS_CC);
631 		RETURN_FALSE;
632 	}
633 
634 	CALENDAR_METHOD_FETCH_OBJECT;
635 
636 	int32_t result = co->ucal->getDayOfWeekType(
637 		(UCalendarDaysOfWeek)dow, CALENDAR_ERROR_CODE(co));
638 	INTL_METHOD_CHECK_STATUS(co,
639 		"intlcal_get_day_of_week_type: Call to ICU method has failed");
640 
641 	RETURN_LONG((long)result);
642 }
643 #endif
644 
PHP_FUNCTION(intlcal_get_first_day_of_week)645 U_CFUNC PHP_FUNCTION(intlcal_get_first_day_of_week)
646 {
647 	CALENDAR_METHOD_INIT_VARS;
648 
649 	if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(),
650 			"O", &object, Calendar_ce_ptr) == FAILURE) {
651 		intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
652 			"intlcal_get_first_day_of_week: bad arguments", 0 TSRMLS_CC);
653 		RETURN_FALSE;
654 	}
655 
656 	CALENDAR_METHOD_FETCH_OBJECT;
657 
658 	int32_t result = co->ucal->getFirstDayOfWeek(CALENDAR_ERROR_CODE(co));
659 	INTL_METHOD_CHECK_STATUS(co,
660 		"intlcal_get_first_day_of_week: Call to ICU method has failed");
661 
662 	RETURN_LONG((long)result);
663 }
664 
_php_intlcal_field_ret_in32t_method(int32_t (Calendar::* func)(UCalendarDateFields)const,const char * method_name,INTERNAL_FUNCTION_PARAMETERS)665 static void _php_intlcal_field_ret_in32t_method(
666 		int32_t (Calendar::*func)(UCalendarDateFields) const,
667 		const char *method_name,
668 		INTERNAL_FUNCTION_PARAMETERS)
669 {
670 	long	field;
671 	char	*message;
672 	CALENDAR_METHOD_INIT_VARS;
673 
674 	if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(),
675 			"Ol", &object, Calendar_ce_ptr, &field) == FAILURE) {
676 		spprintf(&message, 0, "%s: bad arguments", method_name);
677 		intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, message, 1 TSRMLS_CC);
678 		efree(message);
679 		RETURN_FALSE;
680 	}
681 
682 	if (field < 0 || field >= UCAL_FIELD_COUNT) {
683 		spprintf(&message, 0, "%s: invalid field", method_name);
684 		intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, message, 1 TSRMLS_CC);
685 		efree(message);
686 		RETURN_FALSE;
687 	}
688 
689 	CALENDAR_METHOD_FETCH_OBJECT;
690 
691 	int32_t result = (co->ucal->*func)((UCalendarDateFields)field);
692 	INTL_METHOD_CHECK_STATUS(co, "Call to ICU method has failed");
693 
694 	RETURN_LONG((long)result);
695 }
696 
PHP_FUNCTION(intlcal_get_greatest_minimum)697 U_CFUNC PHP_FUNCTION(intlcal_get_greatest_minimum)
698 {
699 	_php_intlcal_field_ret_in32t_method(&Calendar::getGreatestMinimum,
700 		"intlcal_get_greatest_minimum", INTERNAL_FUNCTION_PARAM_PASSTHRU);
701 }
702 
PHP_FUNCTION(intlcal_get_least_maximum)703 U_CFUNC PHP_FUNCTION(intlcal_get_least_maximum)
704 {
705 	_php_intlcal_field_ret_in32t_method(&Calendar::getLeastMaximum,
706 		"intlcal_get_least_maximum", INTERNAL_FUNCTION_PARAM_PASSTHRU);
707 }
708 
PHP_FUNCTION(intlcal_get_locale)709 U_CFUNC PHP_FUNCTION(intlcal_get_locale)
710 {
711 	long	locale_type;
712 	CALENDAR_METHOD_INIT_VARS;
713 
714 	if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(),
715 			"Ol", &object, Calendar_ce_ptr, &locale_type) == FAILURE) {
716 		intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
717 			"intlcal_get_locale: bad arguments", 0 TSRMLS_CC);
718 		RETURN_FALSE;
719 	}
720 
721 	if (locale_type != ULOC_ACTUAL_LOCALE && locale_type != ULOC_VALID_LOCALE) {
722 		intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
723 			"intlcal_get_locale: invalid locale type", 0 TSRMLS_CC);
724 		RETURN_FALSE;
725 	}
726 
727 	CALENDAR_METHOD_FETCH_OBJECT;
728 
729 	Locale locale = co->ucal->getLocale((ULocDataLocaleType)locale_type,
730 		CALENDAR_ERROR_CODE(co));
731 	INTL_METHOD_CHECK_STATUS(co,
732 		"intlcal_get_locale: Call to ICU method has failed");
733 
734 	RETURN_STRING(locale.getName(), 1);
735 }
736 
PHP_FUNCTION(intlcal_get_maximum)737 U_CFUNC PHP_FUNCTION(intlcal_get_maximum)
738 {
739 	_php_intlcal_field_ret_in32t_method(&Calendar::getMaximum,
740 		"intlcal_get_maximum", INTERNAL_FUNCTION_PARAM_PASSTHRU);
741 }
742 
PHP_FUNCTION(intlcal_get_minimal_days_in_first_week)743 U_CFUNC PHP_FUNCTION(intlcal_get_minimal_days_in_first_week)
744 {
745 	CALENDAR_METHOD_INIT_VARS;
746 
747 	if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(),
748 			"O", &object, Calendar_ce_ptr) == FAILURE) {
749 		intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
750 			"intlcal_get_minimal_days_in_first_week: bad arguments", 0 TSRMLS_CC);
751 		RETURN_FALSE;
752 	}
753 
754 	CALENDAR_METHOD_FETCH_OBJECT;
755 
756 	uint8_t result = co->ucal->getMinimalDaysInFirstWeek();
757 	INTL_METHOD_CHECK_STATUS(co,
758 		"intlcal_get_first_day_of_week: Call to ICU method has failed");
759 
760 	RETURN_LONG((long)result);
761 }
762 
PHP_FUNCTION(intlcal_get_minimum)763 U_CFUNC PHP_FUNCTION(intlcal_get_minimum)
764 {
765 	_php_intlcal_field_ret_in32t_method(&Calendar::getMinimum,
766 		"intlcal_get_minimum", INTERNAL_FUNCTION_PARAM_PASSTHRU);
767 }
768 
PHP_FUNCTION(intlcal_get_time_zone)769 U_CFUNC PHP_FUNCTION(intlcal_get_time_zone)
770 {
771 	CALENDAR_METHOD_INIT_VARS;
772 
773 	if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(),
774 			"O", &object, Calendar_ce_ptr) == FAILURE) {
775 		intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
776 			"intlcal_get_time_zone: bad arguments", 0 TSRMLS_CC);
777 		RETURN_FALSE;
778 	}
779 
780 	CALENDAR_METHOD_FETCH_OBJECT;
781 
782 	TimeZone *tz = co->ucal->getTimeZone().clone();
783 	if (tz == NULL) {
784 		intl_errors_set(CALENDAR_ERROR_P(co), U_MEMORY_ALLOCATION_ERROR,
785 			"intlcal_get_time_zone: could not clone TimeZone", 0 TSRMLS_CC);
786 		RETURN_FALSE;
787 	}
788 
789 	timezone_object_construct(tz, return_value, 1 TSRMLS_CC);
790 }
791 
PHP_FUNCTION(intlcal_get_type)792 U_CFUNC PHP_FUNCTION(intlcal_get_type)
793 {
794 	CALENDAR_METHOD_INIT_VARS;
795 
796 	if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(),
797 			"O", &object, Calendar_ce_ptr) == FAILURE) {
798 		intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
799 			"intlcal_get_type: bad arguments", 0 TSRMLS_CC);
800 		RETURN_FALSE;
801 	}
802 
803 	CALENDAR_METHOD_FETCH_OBJECT;
804 
805 	RETURN_STRING(co->ucal->getType(), 1);
806 }
807 
808 #if U_ICU_VERSION_MAJOR_NUM * 10 + U_ICU_VERSION_MINOR_NUM >= 44
PHP_FUNCTION(intlcal_get_weekend_transition)809 U_CFUNC PHP_FUNCTION(intlcal_get_weekend_transition)
810 {
811 	long	dow;
812 	CALENDAR_METHOD_INIT_VARS;
813 
814 	if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(),
815 			"Ol", &object, Calendar_ce_ptr, &dow) == FAILURE) {
816 		intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
817 			"intlcal_get_weekend_transition: bad arguments", 0 TSRMLS_CC);
818 		RETURN_FALSE;
819 	}
820 
821 	if (dow < UCAL_SUNDAY || dow > UCAL_SATURDAY) {
822 		intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
823 			"intlcal_get_weekend_transition: invalid day of week", 0 TSRMLS_CC);
824 		RETURN_FALSE;
825 	}
826 
827 	CALENDAR_METHOD_FETCH_OBJECT;
828 
829 	int32_t res = co->ucal->getWeekendTransition((UCalendarDaysOfWeek)dow,
830 		CALENDAR_ERROR_CODE(co));
831 	INTL_METHOD_CHECK_STATUS(co, "intlcal_get_weekend_transition: "
832 		"Error calling ICU method");
833 
834 	RETURN_LONG((long)res);
835 }
836 #endif
837 
PHP_FUNCTION(intlcal_in_daylight_time)838 U_CFUNC PHP_FUNCTION(intlcal_in_daylight_time)
839 {
840 	CALENDAR_METHOD_INIT_VARS;
841 
842 	if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(),
843 			"O", &object, Calendar_ce_ptr) == FAILURE) {
844 		intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
845 			"intlcal_in_daylight_time: bad arguments", 0 TSRMLS_CC);
846 		RETURN_FALSE;
847 	}
848 
849 	CALENDAR_METHOD_FETCH_OBJECT;
850 
851 	UBool ret = co->ucal->inDaylightTime(CALENDAR_ERROR_CODE(co));
852 	INTL_METHOD_CHECK_STATUS(co, "intlcal_in_daylight_time: "
853 		"Error calling ICU method");
854 
855 	RETURN_BOOL((int)ret);
856 }
857 
PHP_FUNCTION(intlcal_is_equivalent_to)858 U_CFUNC PHP_FUNCTION(intlcal_is_equivalent_to)
859 {
860 	zval			*other_object;
861 	Calendar_object *other_co;
862 	CALENDAR_METHOD_INIT_VARS;
863 
864 	if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(),
865 			"OO", &object, Calendar_ce_ptr, &other_object, Calendar_ce_ptr)
866 			== FAILURE) {
867 		intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
868 			"intlcal_is_equivalent_to: bad arguments", 0 TSRMLS_CC);
869 		RETURN_FALSE;
870 	}
871 
872 	other_co = (Calendar_object*)zend_object_store_get_object(other_object TSRMLS_CC);
873 	if (other_co->ucal == NULL) {
874 		intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, "intlcal_is_equivalent_to:"
875 			" Other IntlCalendar is unconstructed", 0 TSRMLS_CC);
876 		RETURN_FALSE;
877 	}
878 
879 	CALENDAR_METHOD_FETCH_OBJECT;
880 
881 	RETURN_BOOL((int)co->ucal->isEquivalentTo(*other_co->ucal));
882 }
883 
PHP_FUNCTION(intlcal_is_lenient)884 U_CFUNC PHP_FUNCTION(intlcal_is_lenient)
885 {
886 	CALENDAR_METHOD_INIT_VARS;
887 
888 	if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(),
889 			"O", &object, Calendar_ce_ptr) == FAILURE) {
890 		intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
891 			"intlcal_is_lenient: bad arguments", 0 TSRMLS_CC);
892 		RETURN_FALSE;
893 	}
894 
895 	CALENDAR_METHOD_FETCH_OBJECT;
896 
897 	RETURN_BOOL((int)co->ucal->isLenient());
898 }
899 
PHP_FUNCTION(intlcal_is_set)900 U_CFUNC PHP_FUNCTION(intlcal_is_set)
901 {
902 	long field;
903 	CALENDAR_METHOD_INIT_VARS;
904 
905 	if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(),
906 			"Ol", &object, Calendar_ce_ptr, &field) == FAILURE) {
907 		intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
908 			"intlcal_is_set: bad arguments", 0 TSRMLS_CC);
909 		RETURN_FALSE;
910 	}
911 
912 	if (field < 0 || field >= UCAL_FIELD_COUNT) {
913 		intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
914 			"intlcal_is_set: invalid field", 0 TSRMLS_CC);
915 		RETURN_FALSE;
916 	}
917 
918 	CALENDAR_METHOD_FETCH_OBJECT;
919 
920 	RETURN_BOOL((int)co->ucal->isSet((UCalendarDateFields)field));
921 }
922 
923 #if U_ICU_VERSION_MAJOR_NUM * 10 + U_ICU_VERSION_MINOR_NUM >= 44
PHP_FUNCTION(intlcal_is_weekend)924 U_CFUNC PHP_FUNCTION(intlcal_is_weekend)
925 {
926 	double date;
927 	zval *rawDate = NULL;
928 	CALENDAR_METHOD_INIT_VARS;
929 
930 	if (zend_parse_method_parameters_ex(ZEND_PARSE_PARAMS_QUIET,
931 			ZEND_NUM_ARGS() TSRMLS_CC, getThis(),
932 			"O|z!", &object, Calendar_ce_ptr, &rawDate) == FAILURE
933 			|| (rawDate != NULL &&
934 				zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(),
935 				"O|d", &object, Calendar_ce_ptr, &date) == FAILURE)) {
936 		intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
937 			"intlcal_is_weekend: bad arguments", 0 TSRMLS_CC);
938 		RETURN_FALSE;
939 	}
940 
941 	CALENDAR_METHOD_FETCH_OBJECT;
942 
943 	if (rawDate == NULL) {
944 		RETURN_BOOL((int)co->ucal->isWeekend());
945 	} else {
946 		UBool ret = co->ucal->isWeekend((UDate)date, CALENDAR_ERROR_CODE(co));
947 		INTL_METHOD_CHECK_STATUS(co, "intlcal_is_weekend: "
948 			"Error calling ICU method");
949 		RETURN_BOOL((int)ret);
950 	}
951 }
952 #endif
953 
954 
PHP_FUNCTION(intlcal_set_first_day_of_week)955 U_CFUNC PHP_FUNCTION(intlcal_set_first_day_of_week)
956 {
957 	long	dow;
958 	CALENDAR_METHOD_INIT_VARS;
959 
960 	if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(),
961 			"Ol", &object, Calendar_ce_ptr, &dow) == FAILURE) {
962 		intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
963 			"intlcal_set_first_day_of_week: bad arguments", 0 TSRMLS_CC);
964 		RETURN_FALSE;
965 	}
966 
967 	if (dow < UCAL_SUNDAY || dow > UCAL_SATURDAY) {
968 		intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
969 			"intlcal_set_first_day_of_week: invalid day of week", 0 TSRMLS_CC);
970 		RETURN_FALSE;
971 	}
972 
973 	CALENDAR_METHOD_FETCH_OBJECT;
974 
975 	co->ucal->setFirstDayOfWeek((UCalendarDaysOfWeek)dow);
976 
977 	RETURN_TRUE;
978 }
979 
PHP_FUNCTION(intlcal_set_lenient)980 U_CFUNC PHP_FUNCTION(intlcal_set_lenient)
981 {
982 	zend_bool is_lenient;
983 	CALENDAR_METHOD_INIT_VARS;
984 
985 	if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(),
986 			"Ob", &object, Calendar_ce_ptr, &is_lenient) == FAILURE) {
987 		intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
988 			"intlcal_set_lenient: bad arguments", 0 TSRMLS_CC);
989 		RETURN_FALSE;
990 	}
991 
992 	CALENDAR_METHOD_FETCH_OBJECT;
993 
994 	co->ucal->setLenient((UBool) is_lenient);
995 
996 	RETURN_TRUE;
997 }
998 
PHP_FUNCTION(intlcal_set_minimal_days_in_first_week)999 U_CFUNC PHP_FUNCTION(intlcal_set_minimal_days_in_first_week)
1000 {
1001 	long	num_days;
1002 	CALENDAR_METHOD_INIT_VARS;
1003 
1004 	if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(),
1005 			"Ol", &object, Calendar_ce_ptr, &num_days) == FAILURE) {
1006 		intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
1007 			"intlcal_set_minimal_days_in_first_week: bad arguments", 0 TSRMLS_CC);
1008 		RETURN_FALSE;
1009 	}
1010 
1011 	if (num_days < 1 || num_days > 7) {
1012 		intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
1013 			"intlcal_set_minimal_days_in_first_week: invalid number of days; "
1014 			"must be between 1 and 7", 0 TSRMLS_CC);
1015 		RETURN_FALSE;
1016 	}
1017 
1018 	CALENDAR_METHOD_FETCH_OBJECT;
1019 
1020 	co->ucal->setMinimalDaysInFirstWeek((uint8_t)num_days);
1021 
1022 	RETURN_TRUE;
1023 }
1024 
PHP_FUNCTION(intlcal_equals)1025 U_CFUNC PHP_FUNCTION(intlcal_equals)
1026 {
1027 	zval			*other_object;
1028 	Calendar_object	*other_co;
1029 	CALENDAR_METHOD_INIT_VARS;
1030 
1031 	if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(),
1032 			"OO", &object, Calendar_ce_ptr, &other_object, Calendar_ce_ptr)
1033 			== FAILURE) {
1034 		intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
1035 			"intlcal_equals: bad arguments", 0 TSRMLS_CC);
1036 		RETURN_FALSE;
1037 	}
1038 
1039 	CALENDAR_METHOD_FETCH_OBJECT;
1040 	other_co = (Calendar_object *) zend_object_store_get_object(other_object TSRMLS_CC);
1041 	if (other_co->ucal == NULL) {
1042 		intl_errors_set(&co->err, U_ILLEGAL_ARGUMENT_ERROR,
1043 			"intlcal_equals: The second IntlCalendar is unconstructed", 0 TSRMLS_CC);
1044 		RETURN_FALSE;
1045 	}
1046 
1047 	UBool result = co->ucal->equals(*other_co->ucal, CALENDAR_ERROR_CODE(co));
1048 	INTL_METHOD_CHECK_STATUS(co, "intlcal_equals: error calling ICU Calendar::equals");
1049 
1050 	RETURN_BOOL((int)result);
1051 }
1052 
1053 #if U_ICU_VERSION_MAJOR_NUM >= 49
1054 
PHP_FUNCTION(intlcal_get_repeated_wall_time_option)1055 U_CFUNC PHP_FUNCTION(intlcal_get_repeated_wall_time_option)
1056 {
1057 	CALENDAR_METHOD_INIT_VARS;
1058 
1059 	if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(),
1060 			"O", &object, Calendar_ce_ptr) == FAILURE) {
1061 		intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
1062 			"intlcal_get_repeated_wall_time_option: bad arguments", 0 TSRMLS_CC);
1063 		RETURN_FALSE;
1064 	}
1065 
1066 	CALENDAR_METHOD_FETCH_OBJECT;
1067 
1068 	RETURN_LONG(co->ucal->getRepeatedWallTimeOption());
1069 }
1070 
PHP_FUNCTION(intlcal_get_skipped_wall_time_option)1071 U_CFUNC PHP_FUNCTION(intlcal_get_skipped_wall_time_option)
1072 {
1073 	CALENDAR_METHOD_INIT_VARS;
1074 
1075 	if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(),
1076 			"O", &object, Calendar_ce_ptr) == FAILURE) {
1077 		intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
1078 			"intlcal_get_skipped_wall_time_option: bad arguments", 0 TSRMLS_CC);
1079 		RETURN_FALSE;
1080 	}
1081 
1082 	CALENDAR_METHOD_FETCH_OBJECT;
1083 
1084 	RETURN_LONG(co->ucal->getSkippedWallTimeOption());
1085 }
1086 
PHP_FUNCTION(intlcal_set_repeated_wall_time_option)1087 U_CFUNC PHP_FUNCTION(intlcal_set_repeated_wall_time_option)
1088 {
1089 	long	option;
1090 	CALENDAR_METHOD_INIT_VARS;
1091 
1092 	if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(),
1093 			"Ol", &object, Calendar_ce_ptr, &option) == FAILURE) {
1094 		intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
1095 			"intlcal_set_repeated_wall_time_option: bad arguments", 0 TSRMLS_CC);
1096 		RETURN_FALSE;
1097 	}
1098 
1099 	if (option != UCAL_WALLTIME_FIRST && option != UCAL_WALLTIME_LAST) {
1100 		intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
1101 			"intlcal_set_repeated_wall_time_option: invalid option", 0 TSRMLS_CC);
1102 		RETURN_FALSE;
1103 	}
1104 
1105 	CALENDAR_METHOD_FETCH_OBJECT;
1106 
1107 	co->ucal->setRepeatedWallTimeOption((UCalendarWallTimeOption)option);
1108 
1109 	RETURN_TRUE;
1110 }
1111 
PHP_FUNCTION(intlcal_set_skipped_wall_time_option)1112 U_CFUNC PHP_FUNCTION(intlcal_set_skipped_wall_time_option)
1113 {
1114 	long	option;
1115 	CALENDAR_METHOD_INIT_VARS;
1116 
1117 	if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(),
1118 			"Ol", &object, Calendar_ce_ptr, &option) == FAILURE) {
1119 		intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
1120 			"intlcal_set_skipped_wall_time_option: bad arguments", 0 TSRMLS_CC);
1121 		RETURN_FALSE;
1122 	}
1123 
1124 	if (option != UCAL_WALLTIME_FIRST && option != UCAL_WALLTIME_LAST
1125 			&& option != UCAL_WALLTIME_NEXT_VALID) {
1126 		intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
1127 			"intlcal_set_skipped_wall_time_option: invalid option", 0 TSRMLS_CC);
1128 		RETURN_FALSE;
1129 	}
1130 
1131 	CALENDAR_METHOD_FETCH_OBJECT;
1132 
1133 	co->ucal->setSkippedWallTimeOption((UCalendarWallTimeOption)option);
1134 
1135 	RETURN_TRUE;
1136 }
1137 
1138 #endif
1139 
PHP_FUNCTION(intlcal_from_date_time)1140 U_CFUNC PHP_FUNCTION(intlcal_from_date_time)
1141 {
1142 	zval			**zv_arg,
1143 					*zv_datetime		= NULL,
1144 					*zv_timestamp		= NULL;
1145 	php_date_obj	*datetime;
1146 	char			*locale_str			= NULL;
1147 	int				locale_str_len;
1148 	TimeZone		*timeZone;
1149 	UErrorCode		status				= U_ZERO_ERROR;
1150 	Calendar        *cal;
1151 	intl_error_reset(NULL TSRMLS_CC);
1152 
1153 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z|s!",
1154 			&zv_arg, &locale_str, &locale_str_len) == FAILURE) {
1155 		intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
1156 			"intlcal_from_date_time: bad arguments", 0 TSRMLS_CC);
1157 		RETURN_NULL();
1158 	}
1159 
1160 	if (!(Z_TYPE_PP(zv_arg) == IS_OBJECT && instanceof_function(
1161 			Z_OBJCE_PP(zv_arg), php_date_get_date_ce() TSRMLS_CC))) {
1162 		ALLOC_INIT_ZVAL(zv_datetime);
1163 		object_init_ex(zv_datetime, php_date_get_date_ce());
1164 		zend_call_method_with_1_params(&zv_datetime, NULL, NULL, "__construct",
1165 			NULL, *zv_arg);
1166 		if (EG(exception)) {
1167 			zend_object_store_ctor_failed(zv_datetime TSRMLS_CC);
1168 			goto error;
1169 		}
1170 	} else {
1171 		zv_datetime = *zv_arg;
1172 	}
1173 
1174 	datetime = (php_date_obj*)zend_object_store_get_object(zv_datetime TSRMLS_CC);
1175 	if (!datetime->time) {
1176 		intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
1177 			"intlcal_from_date_time: DateTime object is unconstructed",
1178 			0 TSRMLS_CC);
1179 		goto error;
1180 	}
1181 
1182 	zend_call_method_with_0_params(&zv_datetime, php_date_get_date_ce(),
1183 		NULL, "gettimestamp", &zv_timestamp);
1184 	if (!zv_timestamp || Z_TYPE_P(zv_timestamp) != IS_LONG) {
1185 		intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
1186 			"intlcal_from_date_time: bad DateTime; call to "
1187 			"DateTime::getTimestamp() failed", 0 TSRMLS_CC);
1188 		goto error;
1189 	}
1190 
1191 	if (!datetime->time->is_localtime) {
1192 		timeZone = TimeZone::getGMT()->clone();
1193 	} else {
1194 		timeZone = timezone_convert_datetimezone(datetime->time->zone_type,
1195 			datetime, 1, NULL, "intlcal_from_date_time" TSRMLS_CC);
1196 		if (timeZone == NULL) {
1197 			goto error;
1198 		}
1199 	}
1200 
1201 	if (!locale_str) {
1202 		locale_str = const_cast<char*>(intl_locale_get_default(TSRMLS_C));
1203 	}
1204 
1205 	cal = Calendar::createInstance(timeZone,
1206 		Locale::createFromName(locale_str), status);
1207 	if (cal == NULL) {
1208 		delete timeZone;
1209 		intl_error_set(NULL, status, "intlcal_from_date_time: "
1210 				"error creating ICU Calendar object", 0 TSRMLS_CC);
1211 		goto error;
1212 	}
1213 	cal->setTime(((UDate)Z_LVAL_P(zv_timestamp)) * 1000., status);
1214     if (U_FAILURE(status)) {
1215 		/* time zone was adopted by cal; should not be deleted here */
1216 		delete cal;
1217 		intl_error_set(NULL, status, "intlcal_from_date_time: "
1218 				"error creating ICU Calendar::setTime()", 0 TSRMLS_CC);
1219         goto error;
1220     }
1221 
1222 	calendar_object_create(return_value, cal TSRMLS_CC);
1223 
1224 error:
1225 	if (zv_datetime != *zv_arg) {
1226 		zval_ptr_dtor(&zv_datetime);
1227 	}
1228 	if (zv_timestamp) {
1229 		zval_ptr_dtor(&zv_timestamp);
1230 	}
1231 }
1232 
PHP_FUNCTION(intlcal_to_date_time)1233 U_CFUNC PHP_FUNCTION(intlcal_to_date_time)
1234 {
1235 	zval *retval = NULL;
1236 	CALENDAR_METHOD_INIT_VARS;
1237 
1238 	if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O",
1239 			&object, Calendar_ce_ptr) == FAILURE) {
1240 		intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
1241 			"intlcal_to_date_time: bad arguments", 0 TSRMLS_CC);
1242 		RETURN_FALSE;
1243 	}
1244 
1245 	CALENDAR_METHOD_FETCH_OBJECT;
1246 
1247 	/* There are no exported functions in ext/date to this
1248 	 * in a more native fashion */
1249 	double	date = co->ucal->getTime(CALENDAR_ERROR_CODE(co)) / 1000.;
1250 	int64_t	ts;
1251 	char	ts_str[sizeof("@-9223372036854775808")];
1252 	int		ts_str_len;
1253 	zval	ts_zval = zval_used_for_init;
1254 
1255 	INTL_METHOD_CHECK_STATUS(co, "Call to ICU method has failed");
1256 
1257 	if (date > (double)U_INT64_MAX || date < (double)U_INT64_MIN) {
1258 		intl_errors_set(CALENDAR_ERROR_P(co), U_ILLEGAL_ARGUMENT_ERROR,
1259 			"intlcal_to_date_time: The calendar date is out of the "
1260 			"range for a 64-bit integer", 0 TSRMLS_CC);
1261 		RETURN_FALSE;
1262 	}
1263 
1264 	ts = (int64_t)date;
1265 
1266 	ts_str_len = slprintf(ts_str, sizeof(ts_str), "@%I64d", ts);
1267 	ZVAL_STRINGL(&ts_zval, ts_str, ts_str_len, 0);
1268 
1269 	/* Now get the time zone */
1270 	const TimeZone& tz = co->ucal->getTimeZone();
1271 	zval *timezone_zval = timezone_convert_to_datetimezone(
1272 		&tz, CALENDAR_ERROR_P(co), "intlcal_to_date_time" TSRMLS_CC);
1273 	if (timezone_zval == NULL) {
1274 		RETURN_FALSE;
1275 	}
1276 
1277 	/* resources allocated from now on */
1278 
1279 	/* Finally, instantiate object and call constructor */
1280 	object_init_ex(return_value, php_date_get_date_ce());
1281 	zend_call_method_with_2_params(&return_value, NULL, NULL, "__construct",
1282 			NULL, &ts_zval, timezone_zval);
1283 	if (EG(exception)) {
1284 		intl_errors_set(CALENDAR_ERROR_P(co), U_ILLEGAL_ARGUMENT_ERROR,
1285 			"intlcal_to_date_time: DateTime constructor has thrown exception",
1286 			1 TSRMLS_CC);
1287 		zend_object_store_ctor_failed(return_value TSRMLS_CC);
1288 		zval_ptr_dtor(&return_value);
1289 
1290 		RETVAL_FALSE;
1291 		goto error;
1292 	}
1293 
1294 	/* due to bug #40743, we have to set the time zone again */
1295 	zend_call_method_with_1_params(&return_value, NULL, NULL, "settimezone",
1296 			&retval, timezone_zval);
1297 	if (retval == NULL || Z_TYPE_P(retval) == IS_BOOL) {
1298 		intl_errors_set(CALENDAR_ERROR_P(co), U_ILLEGAL_ARGUMENT_ERROR,
1299 			"intlcal_to_date_time: call to DateTime::setTimeZone has failed",
1300 			1 TSRMLS_CC);
1301 		zval_ptr_dtor(&return_value);
1302 		RETVAL_FALSE;
1303 		goto error;
1304 	}
1305 
1306 error:
1307 	zval_ptr_dtor(&timezone_zval);
1308 	if (retval != NULL) {
1309 		zval_ptr_dtor(&retval);
1310 	}
1311 }
1312 
PHP_FUNCTION(intlcal_get_error_code)1313 U_CFUNC PHP_FUNCTION(intlcal_get_error_code)
1314 {
1315 	CALENDAR_METHOD_INIT_VARS;
1316 
1317 	if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O",
1318 			&object, Calendar_ce_ptr) == FAILURE) {
1319 		intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
1320 			"intlcal_get_error_code: bad arguments", 0 TSRMLS_CC);
1321 		RETURN_FALSE;
1322 	}
1323 
1324 	/* Fetch the object (without resetting its last error code ). */
1325 	co = (Calendar_object*)zend_object_store_get_object(object TSRMLS_CC);
1326 	if (co == NULL)
1327 		RETURN_FALSE;
1328 
1329 	RETURN_LONG((long)CALENDAR_ERROR_CODE(co));
1330 }
1331 
PHP_FUNCTION(intlcal_get_error_message)1332 U_CFUNC PHP_FUNCTION(intlcal_get_error_message)
1333 {
1334 	const char* message = NULL;
1335 	CALENDAR_METHOD_INIT_VARS;
1336 
1337 	if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O",
1338 			&object, Calendar_ce_ptr) == FAILURE) {
1339 		intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,
1340 			"intlcal_get_error_message: bad arguments", 0 TSRMLS_CC );
1341 		RETURN_FALSE;
1342 	}
1343 
1344 
1345 	/* Fetch the object (without resetting its last error code ). */
1346 	co = (Calendar_object*)zend_object_store_get_object(object TSRMLS_CC);
1347 	if (co == NULL)
1348 		RETURN_FALSE;
1349 
1350 	/* Return last error message. */
1351 	message = intl_error_get_message(CALENDAR_ERROR_P(co) TSRMLS_CC);
1352 	RETURN_STRING(message, 0);
1353 }
1354