1 /*
2    +----------------------------------------------------------------------+
3    | This source file is subject to version 3.01 of the PHP license,      |
4    | that is bundled with this package in the file LICENSE, and is        |
5    | available through the world-wide-web at the following url:           |
6    | https://www.php.net/license/3_01.txt                                 |
7    | If you did not receive a copy of the PHP license and are unable to   |
8    | obtain it through the world-wide-web, please send a note to          |
9    | license@php.net so we can mail you a copy immediately.               |
10    +----------------------------------------------------------------------+
11    | Authors: Gustavo Lopes <cataphract@php.net>                          |
12    +----------------------------------------------------------------------+
13 */
14 
15 #ifdef HAVE_CONFIG_H
16 #include "config.h"
17 #endif
18 
19 #include <inttypes.h>
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 
43 using icu::Locale;
44 
45 #define ZEND_VALUE_ERROR_INVALID_FIELD(argument, zpp_arg_position) \
46 	if (argument < 0 || argument >= UCAL_FIELD_COUNT) { \
47 		zend_argument_value_error(getThis() ? ((zpp_arg_position)-1) : zpp_arg_position, \
48 			"must be a valid field"); \
49 		RETURN_THROWS(); \
50 	}
51 
52 #define ZEND_VALUE_ERROR_OUT_OF_BOUND_VALUE(argument, zpp_arg_position) \
53 	if (argument < INT32_MIN || argument > INT32_MAX) { \
54 		zend_argument_value_error(getThis() ? ((zpp_arg_position)-1) : zpp_arg_position, \
55 			"must be between %d and %d", INT32_MIN, INT32_MAX); \
56 		RETURN_THROWS(); \
57 	}
58 
59 #define ZEND_VALUE_ERROR_INVALID_DAY_OF_WEEK(argument, zpp_arg_position) \
60 	if (argument < UCAL_SUNDAY || argument > UCAL_SATURDAY) { \
61 		zend_argument_value_error(getThis() ? ((zpp_arg_position)-1) : zpp_arg_position, \
62 			"must be a valid day of the week"); \
63 		RETURN_THROWS(); \
64 	}
65 
PHP_METHOD(IntlCalendar,__construct)66 U_CFUNC PHP_METHOD(IntlCalendar, __construct)
67 {
68 	zend_throw_exception( NULL,
69 		"An object of this type cannot be created with the new operator",
70 		0 );
71 }
72 
PHP_FUNCTION(intlcal_create_instance)73 U_CFUNC PHP_FUNCTION(intlcal_create_instance)
74 {
75 	zval		*zv_timezone	= NULL;
76 	const char	*locale_str		= NULL;
77 	size_t			dummy;
78 	TimeZone	*timeZone;
79 	UErrorCode	status			= U_ZERO_ERROR;
80 	intl_error_reset(NULL);
81 
82 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "|zs!",
83 			&zv_timezone, &locale_str, &dummy) == FAILURE) {
84 		RETURN_THROWS();
85 	}
86 
87 	timeZone = timezone_process_timezone_argument(zv_timezone, NULL,
88 		"intlcal_create_instance");
89 	if (timeZone == NULL) {
90 		RETURN_NULL();
91 	}
92 
93 	if (!locale_str) {
94 		locale_str = intl_locale_get_default();
95 	}
96 
97 	Calendar *cal = Calendar::createInstance(timeZone,
98 		Locale::createFromName(locale_str), status);
99 	if (cal == NULL) {
100 		delete timeZone;
101 		intl_error_set(NULL, status, "Error creating ICU Calendar object", 0);
102 		RETURN_NULL();
103 	}
104 
105 	calendar_object_create(return_value, cal);
106 }
107 
108 class BugStringCharEnumeration : public StringEnumeration
109 {
110 public:
BugStringCharEnumeration(UEnumeration * _uenum)111 	explicit BugStringCharEnumeration(UEnumeration* _uenum) : uenum(_uenum) {}
112 
~BugStringCharEnumeration()113 	~BugStringCharEnumeration()
114 	{
115 		uenum_close(uenum);
116 	}
117 
count(UErrorCode & status) const118 	int32_t count(UErrorCode& status) const override {
119 		return uenum_count(uenum, &status);
120 	}
121 
snext(UErrorCode & status)122 	const UnicodeString* snext(UErrorCode& status) override
123 	{
124 		int32_t length;
125 		const UChar* str = uenum_unext(uenum, &length, &status);
126 		if (str == 0 || U_FAILURE(status)) {
127 			return 0;
128 		}
129 		return &unistr.setTo(str, length);
130 	}
131 
next(int32_t * resultLength,UErrorCode & status)132 	const char* next(int32_t *resultLength, UErrorCode &status) override
133 	{
134 		int32_t length = -1;
135 		const char* str = uenum_next(uenum, &length, &status);
136 		if (str == 0 || U_FAILURE(status)) {
137 			return 0;
138 		}
139 		if (resultLength) {
140 			//the bug is that uenum_next doesn't set the length
141 			*resultLength = (length == -1) ? (int32_t)strlen(str) : length;
142 		}
143 
144 		return str;
145 	}
146 
reset(UErrorCode & status)147 	void reset(UErrorCode& status) override
148 	{
149 		uenum_reset(uenum, &status);
150 	}
151 
152 	UClassID getDynamicClassID() const override;
153 
154 	static UClassID U_EXPORT2 getStaticClassID();
155 
156 private:
157 	UEnumeration *uenum;
158 };
UOBJECT_DEFINE_RTTI_IMPLEMENTATION(BugStringCharEnumeration)159 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(BugStringCharEnumeration)
160 
161 U_CFUNC PHP_FUNCTION(intlcal_get_keyword_values_for_locale)
162 {
163 	UErrorCode	status = U_ZERO_ERROR;
164 	char		*key,
165 				*locale;
166 	size_t			key_len,
167 				locale_len;
168 	bool	commonly_used;
169 	intl_error_reset(NULL);
170 
171 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "ssb",
172 			&key, &key_len, &locale, &locale_len, &commonly_used) == FAILURE) {
173 		RETURN_THROWS();
174 	}
175 
176 	StringEnumeration *se = Calendar::getKeywordValuesForLocale(key,
177 		Locale::createFromName(locale), (UBool)commonly_used,
178 		status);
179 	if (se == NULL) {
180 		intl_error_set(NULL, status, "intlcal_get_keyword_values_for_locale: "
181 			"error calling underlying method", 0);
182 		RETURN_FALSE;
183 	}
184 
185 	IntlIterator_from_StringEnumeration(se, return_value);
186 }
187 
PHP_FUNCTION(intlcal_get_now)188 U_CFUNC PHP_FUNCTION(intlcal_get_now)
189 {
190 	intl_error_reset(NULL);
191 
192 	if (zend_parse_parameters_none() == FAILURE) {
193 		RETURN_THROWS();
194 	}
195 
196 	RETURN_DOUBLE((double)Calendar::getNow());
197 }
198 
PHP_FUNCTION(intlcal_get_available_locales)199 U_CFUNC PHP_FUNCTION(intlcal_get_available_locales)
200 {
201 	intl_error_reset(NULL);
202 
203 	if (zend_parse_parameters_none() == FAILURE) {
204 		RETURN_THROWS();
205 	}
206 
207 	int32_t count;
208 	const Locale *availLocales = Calendar::getAvailableLocales(count);
209 	array_init(return_value);
210 	for (int i = 0; i < count; i++) {
211 		Locale locale = availLocales[i];
212 		add_next_index_string(return_value, locale.getName());
213 	}
214 }
215 
_php_intlcal_field_uec_ret_in32t_method(int32_t (Calendar::* func)(UCalendarDateFields,UErrorCode &)const,INTERNAL_FUNCTION_PARAMETERS)216 static void _php_intlcal_field_uec_ret_in32t_method(
217 		int32_t (Calendar::*func)(UCalendarDateFields, UErrorCode&) const,
218 		INTERNAL_FUNCTION_PARAMETERS)
219 {
220 	zend_long	field;
221 	CALENDAR_METHOD_INIT_VARS;
222 
223 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(),
224 			"Ol", &object, Calendar_ce_ptr, &field) == FAILURE) {
225 		RETURN_THROWS();
226 	}
227 
228 	ZEND_VALUE_ERROR_INVALID_FIELD(field, 2);
229 
230 	CALENDAR_METHOD_FETCH_OBJECT;
231 
232 	int32_t result = (co->ucal->*func)(
233 		(UCalendarDateFields)field, CALENDAR_ERROR_CODE(co));
234 	INTL_METHOD_CHECK_STATUS(co, "Call to ICU method has failed");
235 
236 	RETURN_LONG((zend_long)result);
237 }
238 
PHP_FUNCTION(intlcal_get)239 U_CFUNC PHP_FUNCTION(intlcal_get)
240 {
241 	_php_intlcal_field_uec_ret_in32t_method(&Calendar::get,
242 		INTERNAL_FUNCTION_PARAM_PASSTHRU);
243 }
244 
PHP_FUNCTION(intlcal_get_time)245 U_CFUNC PHP_FUNCTION(intlcal_get_time)
246 {
247 	CALENDAR_METHOD_INIT_VARS;
248 
249 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O",
250 			&object, Calendar_ce_ptr) == FAILURE) {
251 		RETURN_THROWS();
252 	}
253 
254 	CALENDAR_METHOD_FETCH_OBJECT;
255 
256 	UDate result = co->ucal->getTime(CALENDAR_ERROR_CODE(co));
257 	INTL_METHOD_CHECK_STATUS(co,
258 		"intlcal_get_time: error calling ICU Calendar::getTime");
259 
260 	RETURN_DOUBLE((double)result);
261 }
262 
PHP_FUNCTION(intlcal_set_time)263 U_CFUNC PHP_FUNCTION(intlcal_set_time)
264 {
265 	double	time_arg;
266 	CALENDAR_METHOD_INIT_VARS;
267 
268 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Od",
269 			&object, Calendar_ce_ptr, &time_arg) == FAILURE) {
270 		RETURN_THROWS();
271 	}
272 
273 	CALENDAR_METHOD_FETCH_OBJECT;
274 
275 	co->ucal->setTime((UDate)time_arg, CALENDAR_ERROR_CODE(co));
276 	INTL_METHOD_CHECK_STATUS(co, "Call to underlying method failed");
277 
278 	RETURN_TRUE;
279 }
280 
PHP_FUNCTION(intlcal_add)281 U_CFUNC PHP_FUNCTION(intlcal_add)
282 {
283 	zend_long	field,
284 			amount;
285 	CALENDAR_METHOD_INIT_VARS;
286 
287 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(),
288 			"Oll", &object, Calendar_ce_ptr, &field, &amount) == FAILURE) {
289 		RETURN_THROWS();
290 	}
291 
292 	ZEND_VALUE_ERROR_INVALID_FIELD(field, 2);
293 	ZEND_VALUE_ERROR_OUT_OF_BOUND_VALUE(amount, 3);
294 
295 	CALENDAR_METHOD_FETCH_OBJECT;
296 
297 	co->ucal->add((UCalendarDateFields)field, (int32_t)amount, CALENDAR_ERROR_CODE(co));
298 	INTL_METHOD_CHECK_STATUS(co, "intlcal_add: Call to underlying method failed");
299 
300 	RETURN_TRUE;
301 }
302 
PHP_FUNCTION(intlcal_set_time_zone)303 U_CFUNC PHP_FUNCTION(intlcal_set_time_zone)
304 {
305 	zval			*zv_timezone;
306 	TimeZone		*timeZone;
307 	CALENDAR_METHOD_INIT_VARS;
308 
309 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(),
310 			"Oz!", &object, Calendar_ce_ptr, &zv_timezone) == FAILURE) {
311 		RETURN_THROWS();
312 	}
313 
314 	CALENDAR_METHOD_FETCH_OBJECT;
315 
316 	if (zv_timezone == NULL) {
317 		RETURN_TRUE; /* the method does nothing if passed null */
318 	}
319 
320 	timeZone = timezone_process_timezone_argument(zv_timezone,
321 			CALENDAR_ERROR_P(co), "intlcal_set_time_zone");
322 	if (timeZone == NULL) {
323 		RETURN_FALSE;
324 	}
325 
326 	co->ucal->adoptTimeZone(timeZone);
327 
328 	RETURN_TRUE;
329 }
330 
331 
_php_intlcal_before_after(UBool (Calendar::* func)(const Calendar &,UErrorCode &)const,INTERNAL_FUNCTION_PARAMETERS)332 static void _php_intlcal_before_after(
333 		UBool (Calendar::*func)(const Calendar&, UErrorCode&) const,
334 		INTERNAL_FUNCTION_PARAMETERS)
335 {
336 	zval			*when_object;
337 	Calendar_object	*when_co;
338 	CALENDAR_METHOD_INIT_VARS;
339 
340 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(),
341 			"OO", &object, Calendar_ce_ptr, &when_object, Calendar_ce_ptr)
342 			== FAILURE) {
343 		RETURN_THROWS();
344 	}
345 
346 	CALENDAR_METHOD_FETCH_OBJECT;
347 
348 	when_co = Z_INTL_CALENDAR_P(when_object);
349 	if (when_co->ucal == NULL) {
350 		zend_argument_error(NULL, 2, "is uninitialized");
351 		RETURN_THROWS();
352 	}
353 
354 	UBool res = (co->ucal->*func)(*when_co->ucal, CALENDAR_ERROR_CODE(co));
355 	INTL_METHOD_CHECK_STATUS(co, "intlcal_before/after: Error calling ICU method");
356 
357 	RETURN_BOOL((int)res);
358 }
359 
PHP_FUNCTION(intlcal_after)360 U_CFUNC PHP_FUNCTION(intlcal_after)
361 {
362 	_php_intlcal_before_after(&Calendar::after, INTERNAL_FUNCTION_PARAM_PASSTHRU);
363 }
364 
PHP_FUNCTION(intlcal_before)365 U_CFUNC PHP_FUNCTION(intlcal_before)
366 {
367 	_php_intlcal_before_after(&Calendar::before, INTERNAL_FUNCTION_PARAM_PASSTHRU);
368 }
369 
PHP_FUNCTION(intlcal_set)370 U_CFUNC PHP_FUNCTION(intlcal_set)
371 {
372 	zend_long args[6];
373 
374 	CALENDAR_METHOD_INIT_VARS;
375 
376 	object = getThis();
377 
378 	int arg_num = ZEND_NUM_ARGS() - (object ? 0 : 1);
379 
380 	if (zend_parse_method_parameters(
381 		ZEND_NUM_ARGS(), object, "Oll|llll",
382 		&object, Calendar_ce_ptr, &args[0], &args[1], &args[2], &args[3], &args[4], &args[5]
383 	) == FAILURE) {
384 		RETURN_THROWS();
385 	}
386 
387 	for (int i = 0; i < arg_num; i++) {
388 		/* Arguments start at 1 */
389 		ZEND_VALUE_ERROR_OUT_OF_BOUND_VALUE(args[i], i + 1);
390 	}
391 
392 	CALENDAR_METHOD_FETCH_OBJECT;
393 
394 	if (arg_num == 2) {
395 		ZEND_VALUE_ERROR_INVALID_FIELD(args[0], 2);
396 		co->ucal->set((UCalendarDateFields)args[0], (int32_t)args[1]);
397 	} else if (arg_num == 3) {
398 		co->ucal->set((int32_t)args[0], (int32_t)args[1], (int32_t)args[2]);
399 	} else if (arg_num == 4) {
400 		zend_argument_count_error("IntlCalendar::set() has no variant with exactly 4 parameters");
401 		RETURN_THROWS();
402 	} else if (arg_num == 5) {
403 		co->ucal->set((int32_t)args[0], (int32_t)args[1], (int32_t)args[2], (int32_t)args[3], (int32_t)args[4]);
404 	} else {
405 		co->ucal->set((int32_t)args[0], (int32_t)args[1], (int32_t)args[2], (int32_t)args[3], (int32_t)args[4], (int32_t)args[5]);
406 	}
407 
408 	RETURN_TRUE;
409 }
410 
PHP_FUNCTION(intlcal_roll)411 U_CFUNC PHP_FUNCTION(intlcal_roll)
412 {
413 	zval *zvalue;
414 	zend_long field, value;
415 	CALENDAR_METHOD_INIT_VARS;
416 
417 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Olz", &object, Calendar_ce_ptr, &field, &zvalue) == FAILURE) {
418 		RETURN_THROWS();
419 	}
420 
421 	CALENDAR_METHOD_FETCH_OBJECT;
422 
423 	ZEND_VALUE_ERROR_INVALID_FIELD(field, 2);
424 
425 	if (Z_TYPE_P(zvalue) == IS_FALSE || Z_TYPE_P(zvalue) == IS_TRUE) {
426 		value = Z_TYPE_P(zvalue) == IS_TRUE ? 1 : -1;
427 		php_error_docref(NULL, E_DEPRECATED, "Passing bool is deprecated, use 1 or -1 instead");
428 	} else {
429 		value = zval_get_long(zvalue);
430 		ZEND_VALUE_ERROR_OUT_OF_BOUND_VALUE(value, 3);
431 	}
432 
433 	co->ucal->roll((UCalendarDateFields)field, (int32_t)value, CALENDAR_ERROR_CODE(co));
434 
435 	INTL_METHOD_CHECK_STATUS(co, "intlcal_roll: Error calling ICU Calendar::roll");
436 
437 	RETURN_TRUE;
438 }
439 
PHP_FUNCTION(intlcal_clear)440 U_CFUNC PHP_FUNCTION(intlcal_clear)
441 {
442 	zend_long field;
443 	bool field_is_null = 1;
444 	CALENDAR_METHOD_INIT_VARS;
445 
446 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(),
447 			getThis(), "O|l!", &object, Calendar_ce_ptr, &field, &field_is_null) == FAILURE) {
448 		RETURN_THROWS();
449 	}
450 
451 	CALENDAR_METHOD_FETCH_OBJECT;
452 
453 	if (field_is_null) {
454 		co->ucal->clear();
455 	} else {
456 		ZEND_VALUE_ERROR_INVALID_FIELD(field, 2);
457 
458 		co->ucal->clear((UCalendarDateFields)field);
459 	}
460 
461 	RETURN_TRUE;
462 }
463 
PHP_FUNCTION(intlcal_field_difference)464 U_CFUNC PHP_FUNCTION(intlcal_field_difference)
465 {
466 	zend_long	field;
467 	double	when;
468 	CALENDAR_METHOD_INIT_VARS;
469 
470 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(),
471 			"Odl", &object, Calendar_ce_ptr, &when, &field)	== FAILURE) {
472 		RETURN_THROWS();
473 	}
474 
475 	ZEND_VALUE_ERROR_INVALID_FIELD(field, 3);
476 
477 	CALENDAR_METHOD_FETCH_OBJECT;
478 
479 	int32_t result = co->ucal->fieldDifference((UDate)when,
480 		(UCalendarDateFields)field, CALENDAR_ERROR_CODE(co));
481 	INTL_METHOD_CHECK_STATUS(co,
482 		"intlcal_field_difference: Call to ICU method has failed");
483 
484 	RETURN_LONG((zend_long)result);
485 }
486 
PHP_FUNCTION(intlcal_get_actual_maximum)487 U_CFUNC PHP_FUNCTION(intlcal_get_actual_maximum)
488 {
489 	_php_intlcal_field_uec_ret_in32t_method(&Calendar::getActualMaximum,
490 		INTERNAL_FUNCTION_PARAM_PASSTHRU);
491 }
492 
PHP_FUNCTION(intlcal_get_actual_minimum)493 U_CFUNC PHP_FUNCTION(intlcal_get_actual_minimum)
494 {
495 	_php_intlcal_field_uec_ret_in32t_method(&Calendar::getActualMinimum,
496 		INTERNAL_FUNCTION_PARAM_PASSTHRU);
497 }
498 
PHP_FUNCTION(intlcal_get_day_of_week_type)499 U_CFUNC PHP_FUNCTION(intlcal_get_day_of_week_type)
500 {
501 	zend_long	dow;
502 	CALENDAR_METHOD_INIT_VARS;
503 
504 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(),
505 			"Ol", &object, Calendar_ce_ptr, &dow) == FAILURE) {
506 		RETURN_THROWS();
507 	}
508 
509 	ZEND_VALUE_ERROR_INVALID_DAY_OF_WEEK(dow, 2);
510 
511 	CALENDAR_METHOD_FETCH_OBJECT;
512 
513 	int32_t result = co->ucal->getDayOfWeekType(
514 		(UCalendarDaysOfWeek)dow, CALENDAR_ERROR_CODE(co));
515 	INTL_METHOD_CHECK_STATUS(co,
516 		"intlcal_get_day_of_week_type: Call to ICU method has failed");
517 
518 	RETURN_LONG((zend_long)result);
519 }
520 
PHP_FUNCTION(intlcal_get_first_day_of_week)521 U_CFUNC PHP_FUNCTION(intlcal_get_first_day_of_week)
522 {
523 	CALENDAR_METHOD_INIT_VARS;
524 
525 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(),
526 			"O", &object, Calendar_ce_ptr) == FAILURE) {
527 		RETURN_THROWS();
528 	}
529 
530 	CALENDAR_METHOD_FETCH_OBJECT;
531 
532 	int32_t result = co->ucal->getFirstDayOfWeek(CALENDAR_ERROR_CODE(co));
533 	INTL_METHOD_CHECK_STATUS(co,
534 		"intlcal_get_first_day_of_week: Call to ICU method has failed");
535 
536 	RETURN_LONG((zend_long)result);
537 }
538 
_php_intlcal_field_ret_in32t_method(int32_t (Calendar::* func)(UCalendarDateFields)const,INTERNAL_FUNCTION_PARAMETERS)539 static void _php_intlcal_field_ret_in32t_method(
540 		int32_t (Calendar::*func)(UCalendarDateFields) const,
541 		INTERNAL_FUNCTION_PARAMETERS)
542 {
543 	zend_long	field;
544 	CALENDAR_METHOD_INIT_VARS;
545 
546 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(),
547 			"Ol", &object, Calendar_ce_ptr, &field) == FAILURE) {
548 		RETURN_THROWS();
549 	}
550 
551 	ZEND_VALUE_ERROR_INVALID_FIELD(field, 2);
552 
553 	CALENDAR_METHOD_FETCH_OBJECT;
554 
555 	int32_t result = (co->ucal->*func)((UCalendarDateFields)field);
556 	INTL_METHOD_CHECK_STATUS(co, "Call to ICU method has failed");
557 
558 	RETURN_LONG((zend_long)result);
559 }
560 
PHP_FUNCTION(intlcal_get_greatest_minimum)561 U_CFUNC PHP_FUNCTION(intlcal_get_greatest_minimum)
562 {
563 	_php_intlcal_field_ret_in32t_method(&Calendar::getGreatestMinimum,
564 		INTERNAL_FUNCTION_PARAM_PASSTHRU);
565 }
566 
PHP_FUNCTION(intlcal_get_least_maximum)567 U_CFUNC PHP_FUNCTION(intlcal_get_least_maximum)
568 {
569 	_php_intlcal_field_ret_in32t_method(&Calendar::getLeastMaximum,
570 		INTERNAL_FUNCTION_PARAM_PASSTHRU);
571 }
572 
PHP_FUNCTION(intlcal_get_locale)573 U_CFUNC PHP_FUNCTION(intlcal_get_locale)
574 {
575 	zend_long	locale_type;
576 	CALENDAR_METHOD_INIT_VARS;
577 
578 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(),
579 			"Ol", &object, Calendar_ce_ptr, &locale_type) == FAILURE) {
580 		RETURN_THROWS();
581 	}
582 
583 	if (locale_type != ULOC_ACTUAL_LOCALE && locale_type != ULOC_VALID_LOCALE) {
584 		zend_argument_value_error(getThis() ? 1 : 2, "must be either Locale::ACTUAL_LOCALE or Locale::VALID_LOCALE");
585 		RETURN_THROWS();
586 	}
587 
588 	CALENDAR_METHOD_FETCH_OBJECT;
589 
590 	Locale locale = co->ucal->getLocale((ULocDataLocaleType)locale_type,
591 		CALENDAR_ERROR_CODE(co));
592 	INTL_METHOD_CHECK_STATUS(co,
593 		"intlcal_get_locale: Call to ICU method has failed");
594 
595 	RETURN_STRING(locale.getName());
596 }
597 
PHP_FUNCTION(intlcal_get_maximum)598 U_CFUNC PHP_FUNCTION(intlcal_get_maximum)
599 {
600 	_php_intlcal_field_ret_in32t_method(&Calendar::getMaximum,
601 		INTERNAL_FUNCTION_PARAM_PASSTHRU);
602 }
603 
PHP_FUNCTION(intlcal_get_minimal_days_in_first_week)604 U_CFUNC PHP_FUNCTION(intlcal_get_minimal_days_in_first_week)
605 {
606 	CALENDAR_METHOD_INIT_VARS;
607 
608 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(),
609 			"O", &object, Calendar_ce_ptr) == FAILURE) {
610 		RETURN_THROWS();
611 	}
612 
613 	CALENDAR_METHOD_FETCH_OBJECT;
614 
615 	uint8_t result = co->ucal->getMinimalDaysInFirstWeek();
616 	INTL_METHOD_CHECK_STATUS(co,
617 		"intlcal_get_first_day_of_week: Call to ICU method has failed"); /* TODO Is it really a failure? */
618 
619 	RETURN_LONG((zend_long)result);
620 }
621 
PHP_FUNCTION(intlcal_get_minimum)622 U_CFUNC PHP_FUNCTION(intlcal_get_minimum)
623 {
624 	_php_intlcal_field_ret_in32t_method(&Calendar::getMinimum,
625 		INTERNAL_FUNCTION_PARAM_PASSTHRU);
626 }
627 
PHP_FUNCTION(intlcal_get_time_zone)628 U_CFUNC PHP_FUNCTION(intlcal_get_time_zone)
629 {
630 	CALENDAR_METHOD_INIT_VARS;
631 
632 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(),
633 			"O", &object, Calendar_ce_ptr) == FAILURE) {
634 		RETURN_THROWS();
635 	}
636 
637 	CALENDAR_METHOD_FETCH_OBJECT;
638 
639 	TimeZone *tz = co->ucal->getTimeZone().clone();
640 	if (tz == NULL) {
641 		intl_errors_set(CALENDAR_ERROR_P(co), U_MEMORY_ALLOCATION_ERROR,
642 			"intlcal_get_time_zone: could not clone TimeZone", 0);
643 		RETURN_FALSE;
644 	}
645 
646 	timezone_object_construct(tz, return_value, 1);
647 }
648 
PHP_FUNCTION(intlcal_get_type)649 U_CFUNC PHP_FUNCTION(intlcal_get_type)
650 {
651 	CALENDAR_METHOD_INIT_VARS;
652 
653 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(),
654 			"O", &object, Calendar_ce_ptr) == FAILURE) {
655 		RETURN_THROWS();
656 	}
657 
658 	CALENDAR_METHOD_FETCH_OBJECT;
659 
660 	RETURN_STRING(co->ucal->getType());
661 }
662 
PHP_FUNCTION(intlcal_get_weekend_transition)663 U_CFUNC PHP_FUNCTION(intlcal_get_weekend_transition)
664 {
665 	zend_long	dow;
666 	CALENDAR_METHOD_INIT_VARS;
667 
668 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(),
669 			"Ol", &object, Calendar_ce_ptr, &dow) == FAILURE) {
670 		RETURN_THROWS();
671 	}
672 
673 	ZEND_VALUE_ERROR_INVALID_DAY_OF_WEEK(dow, 2);
674 
675 	CALENDAR_METHOD_FETCH_OBJECT;
676 
677 	int32_t res = co->ucal->getWeekendTransition((UCalendarDaysOfWeek)dow,
678 		CALENDAR_ERROR_CODE(co));
679 	INTL_METHOD_CHECK_STATUS(co, "intlcal_get_weekend_transition: "
680 		"Error calling ICU method");
681 
682 	RETURN_LONG((zend_long)res);
683 }
684 
PHP_FUNCTION(intlcal_in_daylight_time)685 U_CFUNC PHP_FUNCTION(intlcal_in_daylight_time)
686 {
687 	CALENDAR_METHOD_INIT_VARS;
688 
689 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(),
690 			"O", &object, Calendar_ce_ptr) == FAILURE) {
691 		RETURN_THROWS();
692 	}
693 
694 	CALENDAR_METHOD_FETCH_OBJECT;
695 
696 	UBool ret = co->ucal->inDaylightTime(CALENDAR_ERROR_CODE(co));
697 	INTL_METHOD_CHECK_STATUS(co, "intlcal_in_daylight_time: "
698 		"Error calling ICU method");
699 
700 	RETURN_BOOL((int)ret);
701 }
702 
PHP_FUNCTION(intlcal_is_equivalent_to)703 U_CFUNC PHP_FUNCTION(intlcal_is_equivalent_to)
704 {
705 	zval			*other_object;
706 	Calendar_object *other_co;
707 	CALENDAR_METHOD_INIT_VARS;
708 
709 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(),
710 			"OO", &object, Calendar_ce_ptr, &other_object, Calendar_ce_ptr)
711 			== FAILURE) {
712 		RETURN_THROWS();
713 	}
714 
715 	other_co = Z_INTL_CALENDAR_P(other_object);
716 	if (other_co->ucal == NULL) {
717 		zend_argument_error(NULL, 2, "is uninitialized");
718 		RETURN_THROWS();
719 	}
720 
721 	CALENDAR_METHOD_FETCH_OBJECT;
722 
723 	RETURN_BOOL((int)co->ucal->isEquivalentTo(*other_co->ucal));
724 }
725 
PHP_FUNCTION(intlcal_is_lenient)726 U_CFUNC PHP_FUNCTION(intlcal_is_lenient)
727 {
728 	CALENDAR_METHOD_INIT_VARS;
729 
730 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(),
731 			"O", &object, Calendar_ce_ptr) == FAILURE) {
732 		RETURN_THROWS();
733 	}
734 
735 	CALENDAR_METHOD_FETCH_OBJECT;
736 
737 	RETURN_BOOL((int)co->ucal->isLenient());
738 }
739 
PHP_FUNCTION(intlcal_is_set)740 U_CFUNC PHP_FUNCTION(intlcal_is_set)
741 {
742 	zend_long field;
743 	CALENDAR_METHOD_INIT_VARS;
744 
745 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(),
746 			"Ol", &object, Calendar_ce_ptr, &field) == FAILURE) {
747 		RETURN_THROWS();
748 	}
749 
750 	ZEND_VALUE_ERROR_INVALID_FIELD(field, 2);
751 
752 	CALENDAR_METHOD_FETCH_OBJECT;
753 
754 	RETURN_BOOL((int)co->ucal->isSet((UCalendarDateFields)field));
755 }
756 
PHP_FUNCTION(intlcal_is_weekend)757 U_CFUNC PHP_FUNCTION(intlcal_is_weekend)
758 {
759 	double date;
760 	bool date_is_null = 1;
761 	CALENDAR_METHOD_INIT_VARS;
762 
763 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(),
764 				"O|d!", &object, Calendar_ce_ptr, &date, &date_is_null) == FAILURE) {
765 		RETURN_THROWS();
766 	}
767 
768 	CALENDAR_METHOD_FETCH_OBJECT;
769 
770 	if (date_is_null) {
771 		RETURN_BOOL((int)co->ucal->isWeekend());
772 	} else {
773 		UBool ret = co->ucal->isWeekend((UDate)date, CALENDAR_ERROR_CODE(co));
774 		INTL_METHOD_CHECK_STATUS(co, "intlcal_is_weekend: "
775 			"Error calling ICU method");
776 		RETURN_BOOL((int)ret);
777 	}
778 }
779 
780 
PHP_FUNCTION(intlcal_set_first_day_of_week)781 U_CFUNC PHP_FUNCTION(intlcal_set_first_day_of_week)
782 {
783 	zend_long	dow;
784 	CALENDAR_METHOD_INIT_VARS;
785 
786 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(),
787 			"Ol", &object, Calendar_ce_ptr, &dow) == FAILURE) {
788 		RETURN_THROWS();
789 	}
790 
791 	ZEND_VALUE_ERROR_INVALID_DAY_OF_WEEK(dow, 2);
792 
793 	CALENDAR_METHOD_FETCH_OBJECT;
794 
795 	co->ucal->setFirstDayOfWeek((UCalendarDaysOfWeek)dow);
796 
797 	RETURN_TRUE;
798 }
799 
PHP_FUNCTION(intlcal_set_lenient)800 U_CFUNC PHP_FUNCTION(intlcal_set_lenient)
801 {
802 	bool is_lenient;
803 	CALENDAR_METHOD_INIT_VARS;
804 
805 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(),
806 			"Ob", &object, Calendar_ce_ptr, &is_lenient) == FAILURE) {
807 		RETURN_THROWS();
808 	}
809 
810 	CALENDAR_METHOD_FETCH_OBJECT;
811 
812 	co->ucal->setLenient((UBool) is_lenient);
813 
814 	RETURN_TRUE;
815 }
816 
PHP_FUNCTION(intlcal_set_minimal_days_in_first_week)817 U_CFUNC PHP_FUNCTION(intlcal_set_minimal_days_in_first_week)
818 {
819 	zend_long	num_days;
820 	CALENDAR_METHOD_INIT_VARS;
821 
822 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(),
823 			"Ol", &object, Calendar_ce_ptr, &num_days) == FAILURE) {
824 		RETURN_THROWS();
825 	}
826 
827 	// Use ZEND_VALUE_ERROR_INVALID_DAY_OF_WEEK ?
828 	if (num_days < 1 || num_days > 7) {
829 		zend_argument_value_error(getThis() ? 1 : 2, "must be between 1 and 7");
830 		RETURN_THROWS();
831 	}
832 
833 	CALENDAR_METHOD_FETCH_OBJECT;
834 
835 	co->ucal->setMinimalDaysInFirstWeek((uint8_t)num_days);
836 
837 	RETURN_TRUE;
838 }
839 
PHP_FUNCTION(intlcal_equals)840 U_CFUNC PHP_FUNCTION(intlcal_equals)
841 {
842 	zval			*other_object;
843 	Calendar_object	*other_co;
844 	CALENDAR_METHOD_INIT_VARS;
845 
846 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(),
847 			"OO", &object, Calendar_ce_ptr, &other_object, Calendar_ce_ptr)
848 			== FAILURE) {
849 		RETURN_THROWS();
850 	}
851 
852 	CALENDAR_METHOD_FETCH_OBJECT;
853 	other_co = Z_INTL_CALENDAR_P(other_object);
854 	if (other_co->ucal == NULL) {
855 		zend_argument_error(NULL, 2, "is uninitialized");
856 		RETURN_THROWS();
857 	}
858 
859 	UBool result = co->ucal->equals(*other_co->ucal, CALENDAR_ERROR_CODE(co));
860 	INTL_METHOD_CHECK_STATUS(co, "intlcal_equals: error calling ICU Calendar::equals");
861 
862 	RETURN_BOOL((int)result);
863 }
864 
PHP_FUNCTION(intlcal_get_repeated_wall_time_option)865 U_CFUNC PHP_FUNCTION(intlcal_get_repeated_wall_time_option)
866 {
867 	CALENDAR_METHOD_INIT_VARS;
868 
869 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(),
870 			"O", &object, Calendar_ce_ptr) == FAILURE) {
871 		RETURN_THROWS();
872 	}
873 
874 	CALENDAR_METHOD_FETCH_OBJECT;
875 
876 	RETURN_LONG(co->ucal->getRepeatedWallTimeOption());
877 }
878 
PHP_FUNCTION(intlcal_get_skipped_wall_time_option)879 U_CFUNC PHP_FUNCTION(intlcal_get_skipped_wall_time_option)
880 {
881 	CALENDAR_METHOD_INIT_VARS;
882 
883 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(),
884 			"O", &object, Calendar_ce_ptr) == FAILURE) {
885 		RETURN_THROWS();
886 	}
887 
888 	CALENDAR_METHOD_FETCH_OBJECT;
889 
890 	RETURN_LONG(co->ucal->getSkippedWallTimeOption());
891 }
892 
PHP_FUNCTION(intlcal_set_repeated_wall_time_option)893 U_CFUNC PHP_FUNCTION(intlcal_set_repeated_wall_time_option)
894 {
895 	zend_long	option;
896 	CALENDAR_METHOD_INIT_VARS;
897 
898 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(),
899 			"Ol", &object, Calendar_ce_ptr, &option) == FAILURE) {
900 		RETURN_THROWS();
901 	}
902 
903 	if (option != UCAL_WALLTIME_FIRST && option != UCAL_WALLTIME_LAST) {
904 		zend_argument_value_error(getThis() ? 1 : 2, "must be either IntlCalendar::WALLTIME_FIRST or "
905 			"IntlCalendar::WALLTIME_LAST");
906 		RETURN_THROWS();
907 	}
908 
909 	CALENDAR_METHOD_FETCH_OBJECT;
910 
911 	co->ucal->setRepeatedWallTimeOption((UCalendarWallTimeOption)option);
912 
913 	RETURN_TRUE;
914 }
915 
PHP_FUNCTION(intlcal_set_skipped_wall_time_option)916 U_CFUNC PHP_FUNCTION(intlcal_set_skipped_wall_time_option)
917 {
918 	zend_long	option;
919 	CALENDAR_METHOD_INIT_VARS;
920 
921 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(),
922 			"Ol", &object, Calendar_ce_ptr, &option) == FAILURE) {
923 		RETURN_THROWS();
924 	}
925 
926 	if (option != UCAL_WALLTIME_FIRST && option != UCAL_WALLTIME_LAST
927 			&& option != UCAL_WALLTIME_NEXT_VALID) {
928 		zend_argument_value_error(getThis() ? 1 : 2, "must be one of IntlCalendar::WALLTIME_FIRST, "
929 			"IntlCalendar::WALLTIME_LAST, or IntlCalendar::WALLTIME_NEXT_VALID");
930 		RETURN_THROWS();
931 	}
932 
933 	CALENDAR_METHOD_FETCH_OBJECT;
934 
935 	co->ucal->setSkippedWallTimeOption((UCalendarWallTimeOption)option);
936 
937 	RETURN_TRUE;
938 }
939 
PHP_FUNCTION(intlcal_from_date_time)940 U_CFUNC PHP_FUNCTION(intlcal_from_date_time)
941 {
942 	zend_object     *date_obj;
943 	zend_string     *date_str;
944 	zval			zv_tmp, zv_arg, zv_timestamp;
945 	php_date_obj	*datetime;
946 	char			*locale_str = NULL;
947 	size_t				locale_str_len;
948 	TimeZone		*timeZone;
949 	UErrorCode		status = U_ZERO_ERROR;
950 	Calendar        *cal;
951 	intl_error_reset(NULL);
952 
953 	ZEND_PARSE_PARAMETERS_START(1, 2)
954 		Z_PARAM_OBJ_OF_CLASS_OR_STR(date_obj, php_date_get_date_ce(), date_str)
955 		Z_PARAM_OPTIONAL
956 		Z_PARAM_STRING_OR_NULL(locale_str, locale_str_len)
957 	ZEND_PARSE_PARAMETERS_END();
958 
959 	if (date_str) {
960 		object_init_ex(&zv_tmp, php_date_get_date_ce());
961 		ZVAL_STR(&zv_arg, date_str);
962 		zend_call_known_instance_method_with_1_params(Z_OBJCE(zv_tmp)->constructor, Z_OBJ(zv_tmp), NULL, &zv_arg);
963 		date_obj = Z_OBJ(zv_tmp);
964 		if (EG(exception)) {
965 			zend_object_store_ctor_failed(Z_OBJ(zv_tmp));
966 			goto error;
967 		}
968 	}
969 
970 	datetime = php_date_obj_from_obj(date_obj);
971 	if (!datetime->time) {
972 		intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
973 			"intlcal_from_date_time: DateTime object is unconstructed",
974 			0);
975 		goto error;
976 	}
977 
978 	zend_call_method_with_0_params(date_obj, php_date_get_date_ce(), NULL, "gettimestamp", &zv_timestamp);
979 	if (Z_TYPE(zv_timestamp) != IS_LONG) {
980 		intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
981 			"intlcal_from_date_time: bad DateTime; call to "
982 			"DateTime::getTimestamp() failed", 0);
983 		zval_ptr_dtor(&zv_timestamp);
984 		goto error;
985 	}
986 
987 	if (!datetime->time->is_localtime) {
988 		timeZone = TimeZone::getGMT()->clone();
989 	} else {
990 		timeZone = timezone_convert_datetimezone(datetime->time->zone_type,
991 			datetime, 1, NULL, "intlcal_from_date_time");
992 		if (timeZone == NULL) {
993 			goto error;
994 		}
995 	}
996 
997 	if (!locale_str) {
998 		locale_str = const_cast<char*>(intl_locale_get_default());
999 	}
1000 
1001 	cal = Calendar::createInstance(timeZone,
1002 		Locale::createFromName(locale_str), status);
1003 	if (cal == NULL) {
1004 		delete timeZone;
1005 		intl_error_set(NULL, status, "intlcal_from_date_time: "
1006 				"error creating ICU Calendar object", 0);
1007 		goto error;
1008 	}
1009 	cal->setTime(((UDate)Z_LVAL(zv_timestamp)) * 1000., status);
1010     if (U_FAILURE(status)) {
1011 		/* time zone was adopted by cal; should not be deleted here */
1012 		delete cal;
1013 		intl_error_set(NULL, status, "intlcal_from_date_time: "
1014 				"error creating ICU Calendar::setTime()", 0);
1015         goto error;
1016     }
1017 
1018 	calendar_object_create(return_value, cal);
1019 
1020 error:
1021 	if (date_str) {
1022 		OBJ_RELEASE(date_obj);
1023 	}
1024 }
1025 
PHP_FUNCTION(intlcal_to_date_time)1026 U_CFUNC PHP_FUNCTION(intlcal_to_date_time)
1027 {
1028 	zval retval;
1029 	CALENDAR_METHOD_INIT_VARS;
1030 
1031 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O",
1032 			&object, Calendar_ce_ptr) == FAILURE) {
1033 		RETURN_THROWS();
1034 	}
1035 
1036 	CALENDAR_METHOD_FETCH_OBJECT;
1037 
1038 	/* There are no exported functions in ext/date to this
1039 	 * in a more native fashion */
1040 	double	date = co->ucal->getTime(CALENDAR_ERROR_CODE(co)) / 1000.;
1041 	int64_t	ts;
1042 	char	ts_str[sizeof("@-9223372036854775808")];
1043 	int		ts_str_len;
1044 	zval	ts_zval, tmp;
1045 
1046 	INTL_METHOD_CHECK_STATUS(co, "Call to ICU method has failed");
1047 
1048 	if (date > (double)U_INT64_MAX || date < (double)U_INT64_MIN) {
1049 		intl_errors_set(CALENDAR_ERROR_P(co), U_ILLEGAL_ARGUMENT_ERROR,
1050 			"intlcal_to_date_time: The calendar date is out of the "
1051 			"range for a 64-bit integer", 0);
1052 		RETURN_FALSE;
1053 	}
1054 
1055 	ZVAL_UNDEF(&retval);
1056 	ts = (int64_t)date;
1057 
1058 	ts_str_len = slprintf(ts_str, sizeof(ts_str), "@%" PRIi64, ts);
1059 	ZVAL_STRINGL(&ts_zval, ts_str, ts_str_len);
1060 
1061 	/* Now get the time zone */
1062 	const TimeZone& tz = co->ucal->getTimeZone();
1063 	zval *timezone_zval = timezone_convert_to_datetimezone(
1064 		&tz, CALENDAR_ERROR_P(co), "intlcal_to_date_time", &tmp);
1065 	if (timezone_zval == NULL) {
1066 		zval_ptr_dtor(&ts_zval);
1067 		RETURN_FALSE;
1068 	}
1069 
1070 	/* resources allocated from now on */
1071 
1072 	/* Finally, instantiate object and call constructor */
1073 	object_init_ex(return_value, php_date_get_date_ce());
1074 	zend_call_known_instance_method_with_2_params(
1075 		Z_OBJCE_P(return_value)->constructor, Z_OBJ_P(return_value), NULL, &ts_zval, timezone_zval);
1076 	if (EG(exception)) {
1077 		zend_object_store_ctor_failed(Z_OBJ_P(return_value));
1078 		zval_ptr_dtor(return_value);
1079 		zval_ptr_dtor(&ts_zval);
1080 
1081 		RETVAL_FALSE;
1082 		goto error;
1083 	}
1084 	zval_ptr_dtor(&ts_zval);
1085 
1086 	/* due to bug #40743, we have to set the time zone again */
1087 	zend_call_method_with_1_params(Z_OBJ_P(return_value), NULL, NULL, "settimezone",
1088 			&retval, timezone_zval);
1089 	if (Z_ISUNDEF(retval) || Z_TYPE(retval) == IS_FALSE) {
1090 		intl_errors_set(CALENDAR_ERROR_P(co), U_ILLEGAL_ARGUMENT_ERROR,
1091 			"intlcal_to_date_time: call to DateTime::setTimeZone has failed",
1092 			1);
1093 		zval_ptr_dtor(return_value);
1094 		RETVAL_FALSE;
1095 		goto error;
1096 	}
1097 
1098 error:
1099 	zval_ptr_dtor(timezone_zval);
1100 	zval_ptr_dtor(&retval);
1101 }
1102 
PHP_FUNCTION(intlcal_get_error_code)1103 U_CFUNC PHP_FUNCTION(intlcal_get_error_code)
1104 {
1105 	CALENDAR_METHOD_INIT_VARS;
1106 
1107 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O",
1108 			&object, Calendar_ce_ptr) == FAILURE) {
1109 		RETURN_THROWS();
1110 	}
1111 
1112 	/* Fetch the object (without resetting its last error code ). */
1113 	co = Z_INTL_CALENDAR_P(object);
1114 	if (co == NULL)
1115 		RETURN_FALSE;
1116 
1117 	RETURN_LONG((zend_long)CALENDAR_ERROR_CODE(co));
1118 }
1119 
PHP_FUNCTION(intlcal_get_error_message)1120 U_CFUNC PHP_FUNCTION(intlcal_get_error_message)
1121 {
1122 	zend_string* message = NULL;
1123 	CALENDAR_METHOD_INIT_VARS;
1124 
1125 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O",
1126 			&object, Calendar_ce_ptr) == FAILURE) {
1127 		RETURN_THROWS();
1128 	}
1129 
1130 
1131 	/* Fetch the object (without resetting its last error code ). */
1132 	co = Z_INTL_CALENDAR_P(object);
1133 	if (co == NULL)
1134 		RETURN_FALSE;
1135 
1136 	/* Return last error message. */
1137 	message = intl_error_get_message(CALENDAR_ERROR_P(co));
1138 	RETURN_STR(message);
1139 }
1140