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    | http://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 {
119 		return uenum_count(uenum, &status);
120 	}
121 
snext(UErrorCode & status)122 	virtual const UnicodeString* snext(UErrorCode& status)
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 	virtual const char* next(int32_t *resultLength, UErrorCode &status)
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)
148 	{
149 		uenum_reset(uenum, &status);
150 	}
151 
152 	virtual UClassID getDynamicClassID() const;
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 	zend_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 	// TODO Make void?
409 	RETURN_TRUE;
410 }
411 
PHP_FUNCTION(intlcal_roll)412 U_CFUNC PHP_FUNCTION(intlcal_roll)
413 {
414 	zval *zvalue;
415 	zend_long field, value;
416 	CALENDAR_METHOD_INIT_VARS;
417 
418 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Olz", &object, Calendar_ce_ptr, &field, &zvalue) == FAILURE) {
419 		RETURN_THROWS();
420 	}
421 
422 	CALENDAR_METHOD_FETCH_OBJECT;
423 
424 	ZEND_VALUE_ERROR_INVALID_FIELD(field, 2);
425 
426 	if (Z_TYPE_P(zvalue) == IS_FALSE || Z_TYPE_P(zvalue) == IS_TRUE) {
427 		value = Z_TYPE_P(zvalue) == IS_TRUE ? 1 : -1;
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 	zend_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");
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 	zend_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 	zend_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 	// TODO Return void?
914 	RETURN_TRUE;
915 }
916 
PHP_FUNCTION(intlcal_set_skipped_wall_time_option)917 U_CFUNC PHP_FUNCTION(intlcal_set_skipped_wall_time_option)
918 {
919 	zend_long	option;
920 	CALENDAR_METHOD_INIT_VARS;
921 
922 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(),
923 			"Ol", &object, Calendar_ce_ptr, &option) == FAILURE) {
924 		RETURN_THROWS();
925 	}
926 
927 	if (option != UCAL_WALLTIME_FIRST && option != UCAL_WALLTIME_LAST
928 			&& option != UCAL_WALLTIME_NEXT_VALID) {
929 		zend_argument_value_error(getThis() ? 1 : 2, "must be one of IntlCalendar::WALLTIME_FIRST, "
930 			"IntlCalendar::WALLTIME_LAST, or IntlCalendar::WALLTIME_NEXT_VALID");
931 		RETURN_THROWS();
932 	}
933 
934 	CALENDAR_METHOD_FETCH_OBJECT;
935 
936 	co->ucal->setSkippedWallTimeOption((UCalendarWallTimeOption)option);
937 
938 	// TODO Return void?
939 	RETURN_TRUE;
940 }
941 
PHP_FUNCTION(intlcal_from_date_time)942 U_CFUNC PHP_FUNCTION(intlcal_from_date_time)
943 {
944 	zend_object     *date_obj;
945 	zend_string     *date_str;
946 	zval			zv_tmp, zv_arg, zv_timestamp;
947 	php_date_obj	*datetime;
948 	char			*locale_str = NULL;
949 	size_t				locale_str_len;
950 	TimeZone		*timeZone;
951 	UErrorCode		status = U_ZERO_ERROR;
952 	Calendar        *cal;
953 	intl_error_reset(NULL);
954 
955 	ZEND_PARSE_PARAMETERS_START(1, 2)
956 		Z_PARAM_OBJ_OF_CLASS_OR_STR(date_obj, php_date_get_date_ce(), date_str)
957 		Z_PARAM_OPTIONAL
958 		Z_PARAM_STRING_OR_NULL(locale_str, locale_str_len)
959 	ZEND_PARSE_PARAMETERS_END();
960 
961 	if (date_str) {
962 		object_init_ex(&zv_tmp, php_date_get_date_ce());
963 		ZVAL_STR(&zv_arg, date_str);
964 		zend_call_known_instance_method_with_1_params(Z_OBJCE(zv_tmp)->constructor, Z_OBJ(zv_tmp), NULL, &zv_arg);
965 		date_obj = Z_OBJ(zv_tmp);
966 		if (EG(exception)) {
967 			zend_object_store_ctor_failed(Z_OBJ(zv_tmp));
968 			goto error;
969 		}
970 	}
971 
972 	datetime = php_date_obj_from_obj(date_obj);
973 	if (!datetime->time) {
974 		intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
975 			"intlcal_from_date_time: DateTime object is unconstructed",
976 			0);
977 		goto error;
978 	}
979 
980 	zend_call_method_with_0_params(date_obj, php_date_get_date_ce(), NULL, "gettimestamp", &zv_timestamp);
981 	if (Z_TYPE(zv_timestamp) != IS_LONG) {
982 		intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
983 			"intlcal_from_date_time: bad DateTime; call to "
984 			"DateTime::getTimestamp() failed", 0);
985 		zval_ptr_dtor(&zv_timestamp);
986 		goto error;
987 	}
988 
989 	if (!datetime->time->is_localtime) {
990 		timeZone = TimeZone::getGMT()->clone();
991 	} else {
992 		timeZone = timezone_convert_datetimezone(datetime->time->zone_type,
993 			datetime, 1, NULL, "intlcal_from_date_time");
994 		if (timeZone == NULL) {
995 			goto error;
996 		}
997 	}
998 
999 	if (!locale_str) {
1000 		locale_str = const_cast<char*>(intl_locale_get_default());
1001 	}
1002 
1003 	cal = Calendar::createInstance(timeZone,
1004 		Locale::createFromName(locale_str), status);
1005 	if (cal == NULL) {
1006 		delete timeZone;
1007 		intl_error_set(NULL, status, "intlcal_from_date_time: "
1008 				"error creating ICU Calendar object", 0);
1009 		goto error;
1010 	}
1011 	cal->setTime(((UDate)Z_LVAL(zv_timestamp)) * 1000., status);
1012     if (U_FAILURE(status)) {
1013 		/* time zone was adopted by cal; should not be deleted here */
1014 		delete cal;
1015 		intl_error_set(NULL, status, "intlcal_from_date_time: "
1016 				"error creating ICU Calendar::setTime()", 0);
1017         goto error;
1018     }
1019 
1020 	calendar_object_create(return_value, cal);
1021 
1022 error:
1023 	if (date_str) {
1024 		OBJ_RELEASE(date_obj);
1025 	}
1026 }
1027 
PHP_FUNCTION(intlcal_to_date_time)1028 U_CFUNC PHP_FUNCTION(intlcal_to_date_time)
1029 {
1030 	zval retval;
1031 	CALENDAR_METHOD_INIT_VARS;
1032 
1033 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O",
1034 			&object, Calendar_ce_ptr) == FAILURE) {
1035 		RETURN_THROWS();
1036 	}
1037 
1038 	CALENDAR_METHOD_FETCH_OBJECT;
1039 
1040 	/* There are no exported functions in ext/date to this
1041 	 * in a more native fashion */
1042 	double	date = co->ucal->getTime(CALENDAR_ERROR_CODE(co)) / 1000.;
1043 	int64_t	ts;
1044 	char	ts_str[sizeof("@-9223372036854775808")];
1045 	int		ts_str_len;
1046 	zval	ts_zval, tmp;
1047 
1048 	INTL_METHOD_CHECK_STATUS(co, "Call to ICU method has failed");
1049 
1050 	if (date > (double)U_INT64_MAX || date < (double)U_INT64_MIN) {
1051 		intl_errors_set(CALENDAR_ERROR_P(co), U_ILLEGAL_ARGUMENT_ERROR,
1052 			"intlcal_to_date_time: The calendar date is out of the "
1053 			"range for a 64-bit integer", 0);
1054 		RETURN_FALSE;
1055 	}
1056 
1057 	ZVAL_UNDEF(&retval);
1058 	ts = (int64_t)date;
1059 
1060 	ts_str_len = slprintf(ts_str, sizeof(ts_str), "@%" PRIi64, ts);
1061 	ZVAL_STRINGL(&ts_zval, ts_str, ts_str_len);
1062 
1063 	/* Now get the time zone */
1064 	const TimeZone& tz = co->ucal->getTimeZone();
1065 	zval *timezone_zval = timezone_convert_to_datetimezone(
1066 		&tz, CALENDAR_ERROR_P(co), "intlcal_to_date_time", &tmp);
1067 	if (timezone_zval == NULL) {
1068 		zval_ptr_dtor(&ts_zval);
1069 		RETURN_FALSE;
1070 	}
1071 
1072 	/* resources allocated from now on */
1073 
1074 	/* Finally, instantiate object and call constructor */
1075 	object_init_ex(return_value, php_date_get_date_ce());
1076 	zend_call_known_instance_method_with_2_params(
1077 		Z_OBJCE_P(return_value)->constructor, Z_OBJ_P(return_value), NULL, &ts_zval, timezone_zval);
1078 	if (EG(exception)) {
1079 		zend_object_store_ctor_failed(Z_OBJ_P(return_value));
1080 		zval_ptr_dtor(return_value);
1081 		zval_ptr_dtor(&ts_zval);
1082 
1083 		RETVAL_FALSE;
1084 		goto error;
1085 	}
1086 	zval_ptr_dtor(&ts_zval);
1087 
1088 	/* due to bug #40743, we have to set the time zone again */
1089 	zend_call_method_with_1_params(Z_OBJ_P(return_value), NULL, NULL, "settimezone",
1090 			&retval, timezone_zval);
1091 	if (Z_ISUNDEF(retval) || Z_TYPE(retval) == IS_FALSE) {
1092 		intl_errors_set(CALENDAR_ERROR_P(co), U_ILLEGAL_ARGUMENT_ERROR,
1093 			"intlcal_to_date_time: call to DateTime::setTimeZone has failed",
1094 			1);
1095 		zval_ptr_dtor(return_value);
1096 		RETVAL_FALSE;
1097 		goto error;
1098 	}
1099 
1100 error:
1101 	zval_ptr_dtor(timezone_zval);
1102 	zval_ptr_dtor(&retval);
1103 }
1104 
PHP_FUNCTION(intlcal_get_error_code)1105 U_CFUNC PHP_FUNCTION(intlcal_get_error_code)
1106 {
1107 	CALENDAR_METHOD_INIT_VARS;
1108 
1109 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O",
1110 			&object, Calendar_ce_ptr) == FAILURE) {
1111 		RETURN_THROWS();
1112 	}
1113 
1114 	/* Fetch the object (without resetting its last error code ). */
1115 	co = Z_INTL_CALENDAR_P(object);
1116 	if (co == NULL)
1117 		RETURN_FALSE;
1118 
1119 	RETURN_LONG((zend_long)CALENDAR_ERROR_CODE(co));
1120 }
1121 
PHP_FUNCTION(intlcal_get_error_message)1122 U_CFUNC PHP_FUNCTION(intlcal_get_error_message)
1123 {
1124 	zend_string* message = NULL;
1125 	CALENDAR_METHOD_INIT_VARS;
1126 
1127 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O",
1128 			&object, Calendar_ce_ptr) == FAILURE) {
1129 		RETURN_THROWS();
1130 	}
1131 
1132 
1133 	/* Fetch the object (without resetting its last error code ). */
1134 	co = Z_INTL_CALENDAR_P(object);
1135 	if (co == NULL)
1136 		RETURN_FALSE;
1137 
1138 	/* Return last error message. */
1139 	message = intl_error_get_message(CALENDAR_ERROR_P(co));
1140 	RETURN_STR(message);
1141 }
1142