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: 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 );
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 	size_t			dummy;
55 	TimeZone	*timeZone;
56 	UErrorCode	status			= U_ZERO_ERROR;
57 	intl_error_reset(NULL);
58 
59 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "|zs!",
60 			&zv_timezone, &locale_str, &dummy) == FAILURE) {
61 		intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
62 			"intlcal_create_calendar: bad arguments", 0);
63 		RETURN_NULL();
64 	}
65 
66 	timeZone = timezone_process_timezone_argument(zv_timezone, NULL,
67 		"intlcal_create_instance");
68 	if (timeZone == NULL) {
69 		RETURN_NULL();
70 	}
71 
72 	if (!locale_str) {
73 		locale_str = intl_locale_get_default();
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);
81 		RETURN_NULL();
82 	}
83 
84 	calendar_object_create(return_value, cal);
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 	size_t			key_len,
147 				locale_len;
148 	zend_bool	commonly_used;
149 	intl_error_reset(NULL);
150 
151 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "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);
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);
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);
175         RETURN_FALSE;
176     }
177 
178     StringEnumeration *se = new BugStringCharEnumeration(uenum);
179 #endif
180 
181 	IntlIterator_from_StringEnumeration(se, return_value);
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);
188 
189 	if (zend_parse_parameters_none() == FAILURE) {
190 		intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
191 			"intlcal_get_now: bad arguments", 0);
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);
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);
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());
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 	zend_long	field;
223 	char	*message;
224 	CALENDAR_METHOD_INIT_VARS;
225 
226 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), 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);
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);
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((zend_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(), getThis(), "O",
261 			&object, Calendar_ce_ptr) == FAILURE) {
262 		intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
263 			"intlcal_get_time: bad arguments", 0);
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(), 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);
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 	zend_long	field,
299 			amount;
300 	CALENDAR_METHOD_INIT_VARS;
301 
302 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), 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);
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);
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);
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(), 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);
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");
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(), 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);
372 		RETURN_FALSE;
373 	}
374 
375 	CALENDAR_METHOD_FETCH_OBJECT;
376 
377 	when_co = Z_INTL_CALENDAR_P(when_object);
378 	if (when_co->ucal == NULL) {
379 		intl_errors_set(&co->err, U_ILLEGAL_ARGUMENT_ERROR,
380 			"intlcal_before/after: Other IntlCalendar was unconstructed", 0);
381 		RETURN_FALSE;
382 	}
383 
384 	UBool res = (co->ucal->*func)(*when_co->ucal, CALENDAR_ERROR_CODE(co));
385 	INTL_METHOD_CHECK_STATUS(co, "intlcal_before/after: Error calling ICU method");
386 
387 	RETURN_BOOL((int)res);
388 }
389 
PHP_FUNCTION(intlcal_after)390 U_CFUNC PHP_FUNCTION(intlcal_after)
391 {
392 	_php_intlcal_before_after(&Calendar::after, INTERNAL_FUNCTION_PARAM_PASSTHRU);
393 }
394 
PHP_FUNCTION(intlcal_before)395 U_CFUNC PHP_FUNCTION(intlcal_before)
396 {
397 	_php_intlcal_before_after(&Calendar::before, INTERNAL_FUNCTION_PARAM_PASSTHRU);
398 }
399 
PHP_FUNCTION(intlcal_set)400 U_CFUNC PHP_FUNCTION(intlcal_set)
401 {
402 	zend_long	arg1, arg2, arg3, arg4, arg5, arg6;
403 	zval	args_a[7] = {0},
404 			*args = args_a;
405 	int		i;
406 	int		variant; /* number of args of the set() overload */
407 	CALENDAR_METHOD_INIT_VARS;
408 
409 	/* must come before zpp because zpp would convert the args in the stack to 0 */
410 	if (ZEND_NUM_ARGS() > (getThis() ? 6 : 7) ||
411 				zend_get_parameters_array_ex(ZEND_NUM_ARGS(), args) == FAILURE) {
412 		intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
413 			"intlcal_set: too many arguments", 0);
414 		RETURN_FALSE;
415 	}
416 	if (!getThis()) {
417 		args++;
418 	}
419 	variant = ZEND_NUM_ARGS() - (getThis() ? 0 : 1);
420 	while (variant > 2 && Z_TYPE(args[variant - 1]) == IS_NULL) {
421 		variant--;
422 	}
423 
424 	if (variant == 4 ||
425 			zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(),
426 			"Oll|llll",	&object, Calendar_ce_ptr, &arg1, &arg2, &arg3, &arg4,
427 			&arg5, &arg6) == FAILURE) {
428 		intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
429 			"intlcal_set: bad arguments", 0);
430 		RETURN_FALSE;
431 	}
432 
433 	for (i = 0; i < variant; i++) {
434 		if (Z_LVAL(args[i]) < INT32_MIN || Z_LVAL(args[i]) > INT32_MAX) {
435 			intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
436 				"intlcal_set: at least one of the arguments has an absolute "
437 				"value that is too large", 0);
438 			RETURN_FALSE;
439 		}
440 	}
441 
442 	if (variant == 2 && (arg1 < 0 || arg1 >= UCAL_FIELD_COUNT)) {
443 		intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
444 			"intlcal_set: invalid field", 0);
445 		RETURN_FALSE;
446 	}
447 
448 	CALENDAR_METHOD_FETCH_OBJECT;
449 
450 	if (variant == 2) {
451 		co->ucal->set((UCalendarDateFields)arg1, (int32_t)arg2);
452 	} else if (variant == 3) {
453 		co->ucal->set((int32_t)arg1, (int32_t)arg2, (int32_t)arg3);
454 	} else if (variant == 5) {
455 		co->ucal->set((int32_t)arg1, (int32_t)arg2, (int32_t)arg3, (int32_t)arg4, (int32_t)arg5);
456 	} else if (variant == 6) {
457 		co->ucal->set((int32_t)arg1, (int32_t)arg2, (int32_t)arg3, (int32_t)arg4, (int32_t)arg5, (int32_t)arg6);
458 	}
459 
460 	RETURN_TRUE;
461 }
462 
PHP_FUNCTION(intlcal_roll)463 U_CFUNC PHP_FUNCTION(intlcal_roll)
464 {
465 	zend_long		field,
466 				value;
467 	zval		args_a[3]		 = {0},
468 				*args			 = args_a;
469 	zend_bool	bool_variant_val = (zend_bool)-1;
470 	CALENDAR_METHOD_INIT_VARS;
471 
472 	if (ZEND_NUM_ARGS() > (getThis() ? 2 :3) ||
473 			zend_get_parameters_array_ex(ZEND_NUM_ARGS(), args) == FAILURE) {
474 		intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
475 			"intlcal_set: too many arguments", 0);
476 		RETURN_FALSE;
477 	}
478 	if (!getThis()) {
479 		args++;
480 	}
481 	if (!Z_ISUNDEF(args[1]) && (Z_TYPE(args[1]) == IS_TRUE || Z_TYPE(args[1]) == IS_FALSE)) {
482 		if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(),
483 				"Olb", &object, Calendar_ce_ptr, &field, &bool_variant_val)
484 				== FAILURE) {
485 			intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
486 				"intlcal_roll: bad arguments", 0);
487 			RETURN_FALSE;
488 		}
489 		bool_variant_val = Z_TYPE(args[1]) == IS_TRUE? 1 : 0;
490 	} else if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(),
491 			"Oll", &object, Calendar_ce_ptr, &field, &value) == FAILURE) {
492 		intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
493 			"intlcal_roll: bad arguments", 0);
494 		RETURN_FALSE;
495 	}
496 
497 	if (field < 0 || field >= UCAL_FIELD_COUNT) {
498 		intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
499 			"intlcal_roll: invalid field", 0);
500 		RETURN_FALSE;
501 	}
502 	if (bool_variant_val == (zend_bool)-1 &&
503 			(value < INT32_MIN || value > INT32_MAX)) {
504 		intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
505 			"intlcal_roll: value out of bounds", 0);
506 		RETURN_FALSE;
507 	}
508 
509 	CALENDAR_METHOD_FETCH_OBJECT;
510 
511 	if (bool_variant_val != (zend_bool)-1) {
512 		co->ucal->roll((UCalendarDateFields)field, (UBool)bool_variant_val,
513 			CALENDAR_ERROR_CODE(co));
514 	} else {
515 		co->ucal->roll((UCalendarDateFields)field, (int32_t)value,
516 			CALENDAR_ERROR_CODE(co));
517 	}
518 	INTL_METHOD_CHECK_STATUS(co, "intlcal_roll: Error calling ICU Calendar::roll");
519 
520 	RETURN_TRUE;
521 }
522 
PHP_FUNCTION(intlcal_clear)523 U_CFUNC PHP_FUNCTION(intlcal_clear)
524 {
525 	zend_long field;
526 	zend_bool field_is_null = 1;
527 	CALENDAR_METHOD_INIT_VARS;
528 
529 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(),
530 			getThis(), "O|l!", &object, Calendar_ce_ptr, &field, &field_is_null) == FAILURE) {
531 		intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
532 			"intlcal_clear: bad arguments", 0);
533 		RETURN_FALSE;
534 	}
535 
536 	CALENDAR_METHOD_FETCH_OBJECT;
537 
538 	if (field_is_null) {
539 		co->ucal->clear();
540 	} else {
541 		if (field < 0 || field >= UCAL_FIELD_COUNT) {
542 			intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
543 				"intlcal_clear: invalid field", 0);
544 			RETURN_FALSE;
545 		}
546 
547 		co->ucal->clear((UCalendarDateFields)field);
548 	}
549 
550 	RETURN_TRUE;
551 }
552 
PHP_FUNCTION(intlcal_field_difference)553 U_CFUNC PHP_FUNCTION(intlcal_field_difference)
554 {
555 	zend_long	field;
556 	double	when;
557 	CALENDAR_METHOD_INIT_VARS;
558 
559 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(),
560 			"Odl", &object, Calendar_ce_ptr, &when, &field)	== FAILURE) {
561 		intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
562 			"intlcal_field_difference: bad arguments", 0);
563 		RETURN_FALSE;
564 	}
565 
566 	if (field < 0 || field >= UCAL_FIELD_COUNT) {
567 		intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
568 			"intlcal_field_difference: invalid field", 0);
569 		RETURN_FALSE;
570 	}
571 
572 	CALENDAR_METHOD_FETCH_OBJECT;
573 
574 	int32_t result = co->ucal->fieldDifference((UDate)when,
575 		(UCalendarDateFields)field, CALENDAR_ERROR_CODE(co));
576 	INTL_METHOD_CHECK_STATUS(co,
577 		"intlcal_field_difference: Call to ICU method has failed");
578 
579 	RETURN_LONG((zend_long)result);
580 }
581 
PHP_FUNCTION(intlcal_get_actual_maximum)582 U_CFUNC PHP_FUNCTION(intlcal_get_actual_maximum)
583 {
584 	_php_intlcal_field_uec_ret_in32t_method(&Calendar::getActualMaximum,
585 		"intlcal_get_actual_maximum", INTERNAL_FUNCTION_PARAM_PASSTHRU);
586 }
587 
PHP_FUNCTION(intlcal_get_actual_minimum)588 U_CFUNC PHP_FUNCTION(intlcal_get_actual_minimum)
589 {
590 	_php_intlcal_field_uec_ret_in32t_method(&Calendar::getActualMinimum,
591 		"intlcal_get_actual_minimum", INTERNAL_FUNCTION_PARAM_PASSTHRU);
592 }
593 
594 #if U_ICU_VERSION_MAJOR_NUM * 10 + U_ICU_VERSION_MINOR_NUM >= 44
PHP_FUNCTION(intlcal_get_day_of_week_type)595 U_CFUNC PHP_FUNCTION(intlcal_get_day_of_week_type)
596 {
597 	zend_long	dow;
598 	CALENDAR_METHOD_INIT_VARS;
599 
600 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(),
601 			"Ol", &object, Calendar_ce_ptr, &dow) == FAILURE) {
602 		intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
603 			"intlcal_get_day_of_week_type: bad arguments", 0);
604 		RETURN_FALSE;
605 	}
606 
607 	if (dow < UCAL_SUNDAY || dow > UCAL_SATURDAY) {
608 		intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
609 			"intlcal_get_day_of_week_type: invalid day of week", 0);
610 		RETURN_FALSE;
611 	}
612 
613 	CALENDAR_METHOD_FETCH_OBJECT;
614 
615 	int32_t result = co->ucal->getDayOfWeekType(
616 		(UCalendarDaysOfWeek)dow, CALENDAR_ERROR_CODE(co));
617 	INTL_METHOD_CHECK_STATUS(co,
618 		"intlcal_get_day_of_week_type: Call to ICU method has failed");
619 
620 	RETURN_LONG((zend_long)result);
621 }
622 #endif
623 
PHP_FUNCTION(intlcal_get_first_day_of_week)624 U_CFUNC PHP_FUNCTION(intlcal_get_first_day_of_week)
625 {
626 	CALENDAR_METHOD_INIT_VARS;
627 
628 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(),
629 			"O", &object, Calendar_ce_ptr) == FAILURE) {
630 		intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
631 			"intlcal_get_first_day_of_week: bad arguments", 0);
632 		RETURN_FALSE;
633 	}
634 
635 	CALENDAR_METHOD_FETCH_OBJECT;
636 
637 	int32_t result = co->ucal->getFirstDayOfWeek(CALENDAR_ERROR_CODE(co));
638 	INTL_METHOD_CHECK_STATUS(co,
639 		"intlcal_get_first_day_of_week: Call to ICU method has failed");
640 
641 	RETURN_LONG((zend_long)result);
642 }
643 
_php_intlcal_field_ret_in32t_method(int32_t (Calendar::* func)(UCalendarDateFields)const,const char * method_name,INTERNAL_FUNCTION_PARAMETERS)644 static void _php_intlcal_field_ret_in32t_method(
645 		int32_t (Calendar::*func)(UCalendarDateFields) const,
646 		const char *method_name,
647 		INTERNAL_FUNCTION_PARAMETERS)
648 {
649 	zend_long	field;
650 	char	*message;
651 	CALENDAR_METHOD_INIT_VARS;
652 
653 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(),
654 			"Ol", &object, Calendar_ce_ptr, &field) == FAILURE) {
655 		spprintf(&message, 0, "%s: bad arguments", method_name);
656 		intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, message, 1);
657 		efree(message);
658 		RETURN_FALSE;
659 	}
660 
661 	if (field < 0 || field >= UCAL_FIELD_COUNT) {
662 		spprintf(&message, 0, "%s: invalid field", method_name);
663 		intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, message, 1);
664 		efree(message);
665 		RETURN_FALSE;
666 	}
667 
668 	CALENDAR_METHOD_FETCH_OBJECT;
669 
670 	int32_t result = (co->ucal->*func)((UCalendarDateFields)field);
671 	INTL_METHOD_CHECK_STATUS(co, "Call to ICU method has failed");
672 
673 	RETURN_LONG((zend_long)result);
674 }
675 
PHP_FUNCTION(intlcal_get_greatest_minimum)676 U_CFUNC PHP_FUNCTION(intlcal_get_greatest_minimum)
677 {
678 	_php_intlcal_field_ret_in32t_method(&Calendar::getGreatestMinimum,
679 		"intlcal_get_greatest_minimum", INTERNAL_FUNCTION_PARAM_PASSTHRU);
680 }
681 
PHP_FUNCTION(intlcal_get_least_maximum)682 U_CFUNC PHP_FUNCTION(intlcal_get_least_maximum)
683 {
684 	_php_intlcal_field_ret_in32t_method(&Calendar::getLeastMaximum,
685 		"intlcal_get_least_maximum", INTERNAL_FUNCTION_PARAM_PASSTHRU);
686 }
687 
PHP_FUNCTION(intlcal_get_locale)688 U_CFUNC PHP_FUNCTION(intlcal_get_locale)
689 {
690 	zend_long	locale_type;
691 	CALENDAR_METHOD_INIT_VARS;
692 
693 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(),
694 			"Ol", &object, Calendar_ce_ptr, &locale_type) == FAILURE) {
695 		intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
696 			"intlcal_get_locale: bad arguments", 0);
697 		RETURN_FALSE;
698 	}
699 
700 	if (locale_type != ULOC_ACTUAL_LOCALE && locale_type != ULOC_VALID_LOCALE) {
701 		intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
702 			"intlcal_get_locale: invalid locale type", 0);
703 		RETURN_FALSE;
704 	}
705 
706 	CALENDAR_METHOD_FETCH_OBJECT;
707 
708 	Locale locale = co->ucal->getLocale((ULocDataLocaleType)locale_type,
709 		CALENDAR_ERROR_CODE(co));
710 	INTL_METHOD_CHECK_STATUS(co,
711 		"intlcal_get_locale: Call to ICU method has failed");
712 
713 	RETURN_STRING(locale.getName());
714 }
715 
PHP_FUNCTION(intlcal_get_maximum)716 U_CFUNC PHP_FUNCTION(intlcal_get_maximum)
717 {
718 	_php_intlcal_field_ret_in32t_method(&Calendar::getMaximum,
719 		"intlcal_get_maximum", INTERNAL_FUNCTION_PARAM_PASSTHRU);
720 }
721 
PHP_FUNCTION(intlcal_get_minimal_days_in_first_week)722 U_CFUNC PHP_FUNCTION(intlcal_get_minimal_days_in_first_week)
723 {
724 	CALENDAR_METHOD_INIT_VARS;
725 
726 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(),
727 			"O", &object, Calendar_ce_ptr) == FAILURE) {
728 		intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
729 			"intlcal_get_minimal_days_in_first_week: bad arguments", 0);
730 		RETURN_FALSE;
731 	}
732 
733 	CALENDAR_METHOD_FETCH_OBJECT;
734 
735 	uint8_t result = co->ucal->getMinimalDaysInFirstWeek();
736 	INTL_METHOD_CHECK_STATUS(co,
737 		"intlcal_get_first_day_of_week: Call to ICU method has failed");
738 
739 	RETURN_LONG((zend_long)result);
740 }
741 
PHP_FUNCTION(intlcal_get_minimum)742 U_CFUNC PHP_FUNCTION(intlcal_get_minimum)
743 {
744 	_php_intlcal_field_ret_in32t_method(&Calendar::getMinimum,
745 		"intlcal_get_minimum", INTERNAL_FUNCTION_PARAM_PASSTHRU);
746 }
747 
PHP_FUNCTION(intlcal_get_time_zone)748 U_CFUNC PHP_FUNCTION(intlcal_get_time_zone)
749 {
750 	CALENDAR_METHOD_INIT_VARS;
751 
752 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(),
753 			"O", &object, Calendar_ce_ptr) == FAILURE) {
754 		intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
755 			"intlcal_get_time_zone: bad arguments", 0);
756 		RETURN_FALSE;
757 	}
758 
759 	CALENDAR_METHOD_FETCH_OBJECT;
760 
761 	TimeZone *tz = co->ucal->getTimeZone().clone();
762 	if (tz == NULL) {
763 		intl_errors_set(CALENDAR_ERROR_P(co), U_MEMORY_ALLOCATION_ERROR,
764 			"intlcal_get_time_zone: could not clone TimeZone", 0);
765 		RETURN_FALSE;
766 	}
767 
768 	timezone_object_construct(tz, return_value, 1);
769 }
770 
PHP_FUNCTION(intlcal_get_type)771 U_CFUNC PHP_FUNCTION(intlcal_get_type)
772 {
773 	CALENDAR_METHOD_INIT_VARS;
774 
775 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(),
776 			"O", &object, Calendar_ce_ptr) == FAILURE) {
777 		intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
778 			"intlcal_get_type: bad arguments", 0);
779 		RETURN_FALSE;
780 	}
781 
782 	CALENDAR_METHOD_FETCH_OBJECT;
783 
784 	RETURN_STRING(co->ucal->getType());
785 }
786 
787 #if U_ICU_VERSION_MAJOR_NUM * 10 + U_ICU_VERSION_MINOR_NUM >= 44
PHP_FUNCTION(intlcal_get_weekend_transition)788 U_CFUNC PHP_FUNCTION(intlcal_get_weekend_transition)
789 {
790 	zend_long	dow;
791 	CALENDAR_METHOD_INIT_VARS;
792 
793 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(),
794 			"Ol", &object, Calendar_ce_ptr, &dow) == FAILURE) {
795 		intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
796 			"intlcal_get_weekend_transition: bad arguments", 0);
797 		RETURN_FALSE;
798 	}
799 
800 	if (dow < UCAL_SUNDAY || dow > UCAL_SATURDAY) {
801 		intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
802 			"intlcal_get_weekend_transition: invalid day of week", 0);
803 		RETURN_FALSE;
804 	}
805 
806 	CALENDAR_METHOD_FETCH_OBJECT;
807 
808 	int32_t res = co->ucal->getWeekendTransition((UCalendarDaysOfWeek)dow,
809 		CALENDAR_ERROR_CODE(co));
810 	INTL_METHOD_CHECK_STATUS(co, "intlcal_get_weekend_transition: "
811 		"Error calling ICU method");
812 
813 	RETURN_LONG((zend_long)res);
814 }
815 #endif
816 
PHP_FUNCTION(intlcal_in_daylight_time)817 U_CFUNC PHP_FUNCTION(intlcal_in_daylight_time)
818 {
819 	CALENDAR_METHOD_INIT_VARS;
820 
821 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(),
822 			"O", &object, Calendar_ce_ptr) == FAILURE) {
823 		intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
824 			"intlcal_in_daylight_time: bad arguments", 0);
825 		RETURN_FALSE;
826 	}
827 
828 	CALENDAR_METHOD_FETCH_OBJECT;
829 
830 	UBool ret = co->ucal->inDaylightTime(CALENDAR_ERROR_CODE(co));
831 	INTL_METHOD_CHECK_STATUS(co, "intlcal_in_daylight_time: "
832 		"Error calling ICU method");
833 
834 	RETURN_BOOL((int)ret);
835 }
836 
PHP_FUNCTION(intlcal_is_equivalent_to)837 U_CFUNC PHP_FUNCTION(intlcal_is_equivalent_to)
838 {
839 	zval			*other_object;
840 	Calendar_object *other_co;
841 	CALENDAR_METHOD_INIT_VARS;
842 
843 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(),
844 			"OO", &object, Calendar_ce_ptr, &other_object, Calendar_ce_ptr)
845 			== FAILURE) {
846 		intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
847 			"intlcal_is_equivalent_to: bad arguments", 0);
848 		RETURN_FALSE;
849 	}
850 
851 	other_co = Z_INTL_CALENDAR_P(other_object);
852 	if (other_co->ucal == NULL) {
853 		intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, "intlcal_is_equivalent_to:"
854 			" Other IntlCalendar is unconstructed", 0);
855 		RETURN_FALSE;
856 	}
857 
858 	CALENDAR_METHOD_FETCH_OBJECT;
859 
860 	RETURN_BOOL((int)co->ucal->isEquivalentTo(*other_co->ucal));
861 }
862 
PHP_FUNCTION(intlcal_is_lenient)863 U_CFUNC PHP_FUNCTION(intlcal_is_lenient)
864 {
865 	CALENDAR_METHOD_INIT_VARS;
866 
867 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(),
868 			"O", &object, Calendar_ce_ptr) == FAILURE) {
869 		intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
870 			"intlcal_is_lenient: bad arguments", 0);
871 		RETURN_FALSE;
872 	}
873 
874 	CALENDAR_METHOD_FETCH_OBJECT;
875 
876 	RETURN_BOOL((int)co->ucal->isLenient());
877 }
878 
PHP_FUNCTION(intlcal_is_set)879 U_CFUNC PHP_FUNCTION(intlcal_is_set)
880 {
881 	zend_long field;
882 	CALENDAR_METHOD_INIT_VARS;
883 
884 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(),
885 			"Ol", &object, Calendar_ce_ptr, &field) == FAILURE) {
886 		intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
887 			"intlcal_is_set: bad arguments", 0);
888 		RETURN_FALSE;
889 	}
890 
891 	if (field < 0 || field >= UCAL_FIELD_COUNT) {
892 		intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
893 			"intlcal_is_set: invalid field", 0);
894 		RETURN_FALSE;
895 	}
896 
897 	CALENDAR_METHOD_FETCH_OBJECT;
898 
899 	RETURN_BOOL((int)co->ucal->isSet((UCalendarDateFields)field));
900 }
901 
902 #if U_ICU_VERSION_MAJOR_NUM * 10 + U_ICU_VERSION_MINOR_NUM >= 44
PHP_FUNCTION(intlcal_is_weekend)903 U_CFUNC PHP_FUNCTION(intlcal_is_weekend)
904 {
905 	double date;
906 	zend_bool date_is_null = 1;
907 	CALENDAR_METHOD_INIT_VARS;
908 
909 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(),
910 				"O|d!", &object, Calendar_ce_ptr, &date, &date_is_null) == FAILURE) {
911 		intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
912 			"intlcal_is_weekend: bad arguments", 0);
913 		RETURN_FALSE;
914 	}
915 
916 	CALENDAR_METHOD_FETCH_OBJECT;
917 
918 	if (date_is_null) {
919 		RETURN_BOOL((int)co->ucal->isWeekend());
920 	} else {
921 		UBool ret = co->ucal->isWeekend((UDate)date, CALENDAR_ERROR_CODE(co));
922 		INTL_METHOD_CHECK_STATUS(co, "intlcal_is_weekend: "
923 			"Error calling ICU method");
924 		RETURN_BOOL((int)ret);
925 	}
926 }
927 #endif
928 
929 
PHP_FUNCTION(intlcal_set_first_day_of_week)930 U_CFUNC PHP_FUNCTION(intlcal_set_first_day_of_week)
931 {
932 	zend_long	dow;
933 	CALENDAR_METHOD_INIT_VARS;
934 
935 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(),
936 			"Ol", &object, Calendar_ce_ptr, &dow) == FAILURE) {
937 		intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
938 			"intlcal_set_first_day_of_week: bad arguments", 0);
939 		RETURN_FALSE;
940 	}
941 
942 	if (dow < UCAL_SUNDAY || dow > UCAL_SATURDAY) {
943 		intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
944 			"intlcal_set_first_day_of_week: invalid day of week", 0);
945 		RETURN_FALSE;
946 	}
947 
948 	CALENDAR_METHOD_FETCH_OBJECT;
949 
950 	co->ucal->setFirstDayOfWeek((UCalendarDaysOfWeek)dow);
951 
952 	RETURN_TRUE;
953 }
954 
PHP_FUNCTION(intlcal_set_lenient)955 U_CFUNC PHP_FUNCTION(intlcal_set_lenient)
956 {
957 	zend_bool is_lenient;
958 	CALENDAR_METHOD_INIT_VARS;
959 
960 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(),
961 			"Ob", &object, Calendar_ce_ptr, &is_lenient) == FAILURE) {
962 		intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
963 			"intlcal_set_lenient: bad arguments", 0);
964 		RETURN_FALSE;
965 	}
966 
967 	CALENDAR_METHOD_FETCH_OBJECT;
968 
969 	co->ucal->setLenient((UBool) is_lenient);
970 
971 	RETURN_TRUE;
972 }
973 
PHP_FUNCTION(intlcal_set_minimal_days_in_first_week)974 U_CFUNC PHP_FUNCTION(intlcal_set_minimal_days_in_first_week)
975 {
976 	zend_long	num_days;
977 	CALENDAR_METHOD_INIT_VARS;
978 
979 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(),
980 			"Ol", &object, Calendar_ce_ptr, &num_days) == FAILURE) {
981 		intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
982 			"intlcal_set_minimal_days_in_first_week: bad arguments", 0);
983 		RETURN_FALSE;
984 	}
985 
986 	if (num_days < 1 || num_days > 7) {
987 		intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
988 			"intlcal_set_minimal_days_in_first_week: invalid number of days; "
989 			"must be between 1 and 7", 0);
990 		RETURN_FALSE;
991 	}
992 
993 	CALENDAR_METHOD_FETCH_OBJECT;
994 
995 	co->ucal->setMinimalDaysInFirstWeek((uint8_t)num_days);
996 
997 	RETURN_TRUE;
998 }
999 
PHP_FUNCTION(intlcal_equals)1000 U_CFUNC PHP_FUNCTION(intlcal_equals)
1001 {
1002 	zval			*other_object;
1003 	Calendar_object	*other_co;
1004 	CALENDAR_METHOD_INIT_VARS;
1005 
1006 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(),
1007 			"OO", &object, Calendar_ce_ptr, &other_object, Calendar_ce_ptr)
1008 			== FAILURE) {
1009 		intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
1010 			"intlcal_equals: bad arguments", 0);
1011 		RETURN_FALSE;
1012 	}
1013 
1014 	CALENDAR_METHOD_FETCH_OBJECT;
1015 	other_co = Z_INTL_CALENDAR_P(other_object);
1016 	if (other_co->ucal == NULL) {
1017 		intl_errors_set(&co->err, U_ILLEGAL_ARGUMENT_ERROR,
1018 			"intlcal_equals: The second IntlCalendar is unconstructed", 0);
1019 		RETURN_FALSE;
1020 	}
1021 
1022 	UBool result = co->ucal->equals(*other_co->ucal, CALENDAR_ERROR_CODE(co));
1023 	INTL_METHOD_CHECK_STATUS(co, "intlcal_equals: error calling ICU Calendar::equals");
1024 
1025 	RETURN_BOOL((int)result);
1026 }
1027 
1028 #if U_ICU_VERSION_MAJOR_NUM >= 49
1029 
PHP_FUNCTION(intlcal_get_repeated_wall_time_option)1030 U_CFUNC PHP_FUNCTION(intlcal_get_repeated_wall_time_option)
1031 {
1032 	CALENDAR_METHOD_INIT_VARS;
1033 
1034 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(),
1035 			"O", &object, Calendar_ce_ptr) == FAILURE) {
1036 		intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
1037 			"intlcal_get_repeated_wall_time_option: bad arguments", 0);
1038 		RETURN_FALSE;
1039 	}
1040 
1041 	CALENDAR_METHOD_FETCH_OBJECT;
1042 
1043 	RETURN_LONG(co->ucal->getRepeatedWallTimeOption());
1044 }
1045 
PHP_FUNCTION(intlcal_get_skipped_wall_time_option)1046 U_CFUNC PHP_FUNCTION(intlcal_get_skipped_wall_time_option)
1047 {
1048 	CALENDAR_METHOD_INIT_VARS;
1049 
1050 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(),
1051 			"O", &object, Calendar_ce_ptr) == FAILURE) {
1052 		intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
1053 			"intlcal_get_skipped_wall_time_option: bad arguments", 0);
1054 		RETURN_FALSE;
1055 	}
1056 
1057 	CALENDAR_METHOD_FETCH_OBJECT;
1058 
1059 	RETURN_LONG(co->ucal->getSkippedWallTimeOption());
1060 }
1061 
PHP_FUNCTION(intlcal_set_repeated_wall_time_option)1062 U_CFUNC PHP_FUNCTION(intlcal_set_repeated_wall_time_option)
1063 {
1064 	zend_long	option;
1065 	CALENDAR_METHOD_INIT_VARS;
1066 
1067 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(),
1068 			"Ol", &object, Calendar_ce_ptr, &option) == FAILURE) {
1069 		intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
1070 			"intlcal_set_repeated_wall_time_option: bad arguments", 0);
1071 		RETURN_FALSE;
1072 	}
1073 
1074 	if (option != UCAL_WALLTIME_FIRST && option != UCAL_WALLTIME_LAST) {
1075 		intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
1076 			"intlcal_set_repeated_wall_time_option: invalid option", 0);
1077 		RETURN_FALSE;
1078 	}
1079 
1080 	CALENDAR_METHOD_FETCH_OBJECT;
1081 
1082 	co->ucal->setRepeatedWallTimeOption((UCalendarWallTimeOption)option);
1083 
1084 	RETURN_TRUE;
1085 }
1086 
PHP_FUNCTION(intlcal_set_skipped_wall_time_option)1087 U_CFUNC PHP_FUNCTION(intlcal_set_skipped_wall_time_option)
1088 {
1089 	zend_long	option;
1090 	CALENDAR_METHOD_INIT_VARS;
1091 
1092 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(),
1093 			"Ol", &object, Calendar_ce_ptr, &option) == FAILURE) {
1094 		intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
1095 			"intlcal_set_skipped_wall_time_option: bad arguments", 0);
1096 		RETURN_FALSE;
1097 	}
1098 
1099 	if (option != UCAL_WALLTIME_FIRST && option != UCAL_WALLTIME_LAST
1100 			&& option != UCAL_WALLTIME_NEXT_VALID) {
1101 		intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
1102 			"intlcal_set_skipped_wall_time_option: invalid option", 0);
1103 		RETURN_FALSE;
1104 	}
1105 
1106 	CALENDAR_METHOD_FETCH_OBJECT;
1107 
1108 	co->ucal->setSkippedWallTimeOption((UCalendarWallTimeOption)option);
1109 
1110 	RETURN_TRUE;
1111 }
1112 
1113 #endif
1114 
PHP_FUNCTION(intlcal_from_date_time)1115 U_CFUNC PHP_FUNCTION(intlcal_from_date_time)
1116 {
1117 	zval			*zv_arg,
1118 					zv_tmp,
1119 					*zv_datetime  		= NULL,
1120 					zv_timestamp;
1121 	php_date_obj	*datetime;
1122 	char			*locale_str			= NULL;
1123 	size_t				locale_str_len;
1124 	TimeZone		*timeZone;
1125 	UErrorCode		status				= U_ZERO_ERROR;
1126 	Calendar        *cal;
1127 	intl_error_reset(NULL);
1128 
1129 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "z|s!",
1130 			&zv_arg, &locale_str, &locale_str_len) == FAILURE) {
1131 		intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
1132 			"intlcal_from_date_time: bad arguments", 0);
1133 		RETURN_NULL();
1134 	}
1135 
1136 	if (!(Z_TYPE_P(zv_arg) == IS_OBJECT && instanceof_function(
1137 			Z_OBJCE_P(zv_arg), php_date_get_date_ce()))) {
1138 		object_init_ex(&zv_tmp, php_date_get_date_ce());
1139 		zend_call_method_with_1_params(&zv_tmp, NULL, NULL, "__construct", NULL, zv_arg);
1140 		zv_datetime = &zv_tmp;
1141 		if (EG(exception)) {
1142 			zend_object_store_ctor_failed(Z_OBJ(zv_tmp));
1143 			goto error;
1144 		}
1145 	} else {
1146 		zv_datetime = zv_arg;
1147 	}
1148 
1149 	datetime = Z_PHPDATE_P(zv_datetime);
1150 	if (!datetime->time) {
1151 		intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
1152 			"intlcal_from_date_time: DateTime object is unconstructed",
1153 			0);
1154 		goto error;
1155 	}
1156 
1157 	zend_call_method_with_0_params(zv_datetime, php_date_get_date_ce(), NULL, "gettimestamp", &zv_timestamp);
1158 	if (Z_TYPE(zv_timestamp) != IS_LONG) {
1159 		intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
1160 			"intlcal_from_date_time: bad DateTime; call to "
1161 			"DateTime::getTimestamp() failed", 0);
1162 		zval_ptr_dtor(&zv_timestamp);
1163 		goto error;
1164 	}
1165 
1166 	if (!datetime->time->is_localtime) {
1167 		timeZone = TimeZone::getGMT()->clone();
1168 	} else {
1169 		timeZone = timezone_convert_datetimezone(datetime->time->zone_type,
1170 			datetime, 1, NULL, "intlcal_from_date_time");
1171 		if (timeZone == NULL) {
1172 			goto error;
1173 		}
1174 	}
1175 
1176 	if (!locale_str) {
1177 		locale_str = const_cast<char*>(intl_locale_get_default());
1178 	}
1179 
1180 	cal = Calendar::createInstance(timeZone,
1181 		Locale::createFromName(locale_str), status);
1182 	if (cal == NULL) {
1183 		delete timeZone;
1184 		intl_error_set(NULL, status, "intlcal_from_date_time: "
1185 				"error creating ICU Calendar object", 0);
1186 		goto error;
1187 	}
1188 	cal->setTime(((UDate)Z_LVAL(zv_timestamp)) * 1000., status);
1189     if (U_FAILURE(status)) {
1190 		/* time zone was adopted by cal; should not be deleted here */
1191 		delete cal;
1192 		intl_error_set(NULL, status, "intlcal_from_date_time: "
1193 				"error creating ICU Calendar::setTime()", 0);
1194         goto error;
1195     }
1196 
1197 	calendar_object_create(return_value, cal);
1198 
1199 error:
1200 	if (zv_datetime && zv_datetime != zv_arg) {
1201 		zval_ptr_dtor(zv_datetime);
1202 	}
1203 }
1204 
PHP_FUNCTION(intlcal_to_date_time)1205 U_CFUNC PHP_FUNCTION(intlcal_to_date_time)
1206 {
1207 	zval retval;
1208 	CALENDAR_METHOD_INIT_VARS;
1209 
1210 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O",
1211 			&object, Calendar_ce_ptr) == FAILURE) {
1212 		intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
1213 			"intlcal_to_date_time: bad arguments", 0);
1214 		RETURN_FALSE;
1215 	}
1216 
1217 	CALENDAR_METHOD_FETCH_OBJECT;
1218 
1219 	/* There are no exported functions in ext/date to this
1220 	 * in a more native fashion */
1221 	double	date = co->ucal->getTime(CALENDAR_ERROR_CODE(co)) / 1000.;
1222 	int64_t	ts;
1223 	char	ts_str[sizeof("@-9223372036854775808")];
1224 	int		ts_str_len;
1225 	zval	ts_zval, tmp;
1226 
1227 	INTL_METHOD_CHECK_STATUS(co, "Call to ICU method has failed");
1228 
1229 	if (date > (double)U_INT64_MAX || date < (double)U_INT64_MIN) {
1230 		intl_errors_set(CALENDAR_ERROR_P(co), U_ILLEGAL_ARGUMENT_ERROR,
1231 			"intlcal_to_date_time: The calendar date is out of the "
1232 			"range for a 64-bit integer", 0);
1233 		RETURN_FALSE;
1234 	}
1235 
1236 	ZVAL_UNDEF(&retval);
1237 	ts = (int64_t)date;
1238 
1239 	ts_str_len = slprintf(ts_str, sizeof(ts_str), "@%I64d", ts);
1240 	ZVAL_STRINGL(&ts_zval, ts_str, ts_str_len);
1241 
1242 	/* Now get the time zone */
1243 	const TimeZone& tz = co->ucal->getTimeZone();
1244 	zval *timezone_zval = timezone_convert_to_datetimezone(
1245 		&tz, CALENDAR_ERROR_P(co), "intlcal_to_date_time", &tmp);
1246 	if (timezone_zval == NULL) {
1247 		zval_ptr_dtor(&ts_zval);
1248 		RETURN_FALSE;
1249 	}
1250 
1251 	/* resources allocated from now on */
1252 
1253 	/* Finally, instantiate object and call constructor */
1254 	object_init_ex(return_value, php_date_get_date_ce());
1255 	zend_call_method_with_2_params(return_value, NULL, NULL, "__construct", NULL, &ts_zval, timezone_zval);
1256 	if (EG(exception)) {
1257 		intl_errors_set(CALENDAR_ERROR_P(co), U_ILLEGAL_ARGUMENT_ERROR,
1258 			"intlcal_to_date_time: DateTime constructor has thrown exception",
1259 			1);
1260 		zend_object_store_ctor_failed(Z_OBJ_P(return_value));
1261 		zval_ptr_dtor(return_value);
1262 		zval_ptr_dtor(&ts_zval);
1263 
1264 		RETVAL_FALSE;
1265 		goto error;
1266 	}
1267 	zval_ptr_dtor(&ts_zval);
1268 
1269 	/* due to bug #40743, we have to set the time zone again */
1270 	zend_call_method_with_1_params(return_value, NULL, NULL, "settimezone",
1271 			&retval, timezone_zval);
1272 	if (Z_ISUNDEF(retval) || Z_TYPE(retval) == IS_FALSE) {
1273 		intl_errors_set(CALENDAR_ERROR_P(co), U_ILLEGAL_ARGUMENT_ERROR,
1274 			"intlcal_to_date_time: call to DateTime::setTimeZone has failed",
1275 			1);
1276 		zval_ptr_dtor(return_value);
1277 		RETVAL_FALSE;
1278 		goto error;
1279 	}
1280 
1281 error:
1282 	zval_ptr_dtor(timezone_zval);
1283 	zval_ptr_dtor(&retval);
1284 }
1285 
PHP_FUNCTION(intlcal_get_error_code)1286 U_CFUNC PHP_FUNCTION(intlcal_get_error_code)
1287 {
1288 	CALENDAR_METHOD_INIT_VARS;
1289 
1290 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O",
1291 			&object, Calendar_ce_ptr) == FAILURE) {
1292 		intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
1293 			"intlcal_get_error_code: bad arguments", 0);
1294 		RETURN_FALSE;
1295 	}
1296 
1297 	/* Fetch the object (without resetting its last error code ). */
1298 	co = Z_INTL_CALENDAR_P(object);
1299 	if (co == NULL)
1300 		RETURN_FALSE;
1301 
1302 	RETURN_LONG((zend_long)CALENDAR_ERROR_CODE(co));
1303 }
1304 
PHP_FUNCTION(intlcal_get_error_message)1305 U_CFUNC PHP_FUNCTION(intlcal_get_error_message)
1306 {
1307 	zend_string* message = NULL;
1308 	CALENDAR_METHOD_INIT_VARS;
1309 
1310 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O",
1311 			&object, Calendar_ce_ptr) == FAILURE) {
1312 		intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,
1313 			"intlcal_get_error_message: bad arguments", 0 );
1314 		RETURN_FALSE;
1315 	}
1316 
1317 
1318 	/* Fetch the object (without resetting its last error code ). */
1319 	co = Z_INTL_CALENDAR_P(object);
1320 	if (co == NULL)
1321 		RETURN_FALSE;
1322 
1323 	/* Return last error message. */
1324 	message = intl_error_get_message(CALENDAR_ERROR_P(co));
1325 	RETURN_STR(message);
1326 }
1327