1 /*
2 +----------------------------------------------------------------------+
3 | PHP Version 5 |
4 +----------------------------------------------------------------------+
5 | This source file is subject to version 3.01 of the PHP license, |
6 | that is bundled with this package in the file LICENSE, and is |
7 | available through the world-wide-web at the following url: |
8 | http://www.php.net/license/3_01.txt |
9 | If you did not receive a copy of the PHP license and are unable to |
10 | obtain it through the world-wide-web, please send a note to |
11 | license@php.net so we can mail you a copy immediately. |
12 +----------------------------------------------------------------------+
13 | Authors: Gustavo Lopes <cataphract@php.net> |
14 +----------------------------------------------------------------------+
15 */
16
17 #ifdef HAVE_CONFIG_H
18 #include "config.h"
19 #endif
20
21 #include "../intl_cppshims.h"
22
23 #include <unicode/locid.h>
24 #include <unicode/calendar.h>
25 #include <unicode/gregocal.h>
26 extern "C" {
27 #include "../php_intl.h"
28 #define USE_TIMEZONE_POINTER 1
29 #include "../timezone/timezone_class.h"
30 #define USE_CALENDAR_POINTER 1
31 #include "calendar_class.h"
32 #include <ext/date/php_date.h>
33 }
34
fetch_greg(Calendar_object * co)35 static inline GregorianCalendar *fetch_greg(Calendar_object *co) {
36 return (GregorianCalendar*)co->ucal;
37 }
38
_php_intlgregcal_constructor_body(INTERNAL_FUNCTION_PARAMETERS)39 static void _php_intlgregcal_constructor_body(INTERNAL_FUNCTION_PARAMETERS)
40 {
41 zval **tz_object = NULL;
42 zval **args_a[6] = {0},
43 ***args = &args_a[0];
44 char *locale = NULL;
45 int locale_len;
46 long largs[6];
47 UErrorCode status = U_ZERO_ERROR;
48 int variant;
49 intl_error_reset(NULL TSRMLS_CC);
50
51 // parameter number validation / variant determination
52 if (ZEND_NUM_ARGS() > 6 ||
53 zend_get_parameters_array_ex(ZEND_NUM_ARGS(), args) == FAILURE) {
54 intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
55 "intlgregcal_create_instance: too many arguments", 0 TSRMLS_CC);
56 RETURN_NULL();
57 }
58 for (variant = ZEND_NUM_ARGS();
59 variant > 0 && Z_TYPE_PP(args[variant - 1]) == IS_NULL;
60 variant--) {}
61 if (variant == 4) {
62 intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
63 "intlgregcal_create_instance: no variant with 4 arguments "
64 "(excluding trailing NULLs)", 0 TSRMLS_CC);
65 RETURN_NULL();
66 }
67
68 // argument parsing
69 if (variant <= 2) {
70 if (zend_parse_parameters(MIN(ZEND_NUM_ARGS(), 2) TSRMLS_CC,
71 "|Z!s!", &tz_object, &locale, &locale_len) == FAILURE) {
72 intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
73 "intlgregcal_create_instance: bad arguments", 0 TSRMLS_CC);
74 RETURN_NULL();
75 }
76 }
77 if (variant > 2 && zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,
78 "lll|lll", &largs[0], &largs[1], &largs[2], &largs[3], &largs[4],
79 &largs[5]) == FAILURE) {
80 intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
81 "intlgregcal_create_instance: bad arguments", 0 TSRMLS_CC);
82 RETURN_NULL();
83 }
84
85 // instantion of ICU object
86 GregorianCalendar *gcal = NULL;
87
88 if (variant <= 2) {
89 // From timezone and locale (0 to 2 arguments)
90 TimeZone *tz = timezone_process_timezone_argument(tz_object, NULL,
91 "intlgregcal_create_instance" TSRMLS_CC);
92 if (tz == NULL) {
93 RETURN_NULL();
94 }
95 if (!locale) {
96 locale = const_cast<char*>(intl_locale_get_default(TSRMLS_C));
97 }
98
99 gcal = new GregorianCalendar(tz, Locale::createFromName(locale),
100 status);
101 if (U_FAILURE(status)) {
102 intl_error_set(NULL, status, "intlgregcal_create_instance: error "
103 "creating ICU GregorianCalendar from time zone and locale", 0 TSRMLS_CC);
104 if (gcal) {
105 delete gcal;
106 }
107 delete tz;
108 RETURN_NULL();
109 }
110 } else {
111 // From date/time (3, 5 or 6 arguments)
112 for (int i = 0; i < variant; i++) {
113 if (largs[i] < INT32_MIN || largs[i] > INT32_MAX) {
114 intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
115 "intlgregcal_create_instance: at least one of the arguments"
116 " has an absolute value that is too large", 0 TSRMLS_CC);
117 RETURN_NULL();
118 }
119 }
120
121 if (variant == 3) {
122 gcal = new GregorianCalendar((int32_t)largs[0], (int32_t)largs[1],
123 (int32_t)largs[2], status);
124 } else if (variant == 5) {
125 gcal = new GregorianCalendar((int32_t)largs[0], (int32_t)largs[1],
126 (int32_t)largs[2], (int32_t)largs[3], (int32_t)largs[4], status);
127 } else if (variant == 6) {
128 gcal = new GregorianCalendar((int32_t)largs[0], (int32_t)largs[1],
129 (int32_t)largs[2], (int32_t)largs[3], (int32_t)largs[4], (int32_t)largs[5],
130 status);
131 }
132 if (U_FAILURE(status)) {
133 intl_error_set(NULL, status, "intlgregcal_create_instance: error "
134 "creating ICU GregorianCalendar from date", 0 TSRMLS_CC);
135 if (gcal) {
136 delete gcal;
137 }
138 RETURN_NULL();
139 }
140
141 timelib_tzinfo *tzinfo = get_timezone_info(TSRMLS_C);
142 #if U_ICU_VERSION_MAJOR_NUM * 10 + U_ICU_VERSION_MINOR_NUM >= 42
143 UnicodeString tzstr = UnicodeString::fromUTF8(StringPiece(tzinfo->name));
144 #else
145 UnicodeString tzstr = UnicodeString(tzinfo->name,
146 strlen(tzinfo->name), US_INV);
147 #endif
148 if (tzstr.isBogus()) {
149 intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
150 "intlgregcal_create_instance: could not create UTF-8 string "
151 "from PHP's default timezone name (see date_default_timezone_get())",
152 0 TSRMLS_CC);
153 delete gcal;
154 RETURN_NULL();
155 }
156
157 TimeZone *tz = TimeZone::createTimeZone(tzstr);
158 gcal->adoptTimeZone(tz);
159 }
160
161 Calendar_object *co = (Calendar_object*)zend_object_store_get_object(
162 return_value TSRMLS_CC);
163 co->ucal = gcal;
164 }
165
PHP_FUNCTION(intlgregcal_create_instance)166 U_CFUNC PHP_FUNCTION(intlgregcal_create_instance)
167 {
168 zval orig;
169 intl_error_reset(NULL TSRMLS_CC);
170
171 object_init_ex(return_value, GregorianCalendar_ce_ptr);
172 orig = *return_value;
173
174 _php_intlgregcal_constructor_body(INTERNAL_FUNCTION_PARAM_PASSTHRU);
175
176 if (Z_TYPE_P(return_value) == IS_NULL) {
177 zend_object_store_ctor_failed(&orig TSRMLS_CC);
178 zval_dtor(&orig);
179 }
180 }
181
PHP_METHOD(IntlGregorianCalendar,__construct)182 U_CFUNC PHP_METHOD(IntlGregorianCalendar, __construct)
183 {
184 zval orig_this = *getThis();
185 intl_error_reset(NULL TSRMLS_CC);
186
187 return_value = getThis();
188 //changes this to IS_NULL (without first destroying) if there's an error
189 _php_intlgregcal_constructor_body(INTERNAL_FUNCTION_PARAM_PASSTHRU);
190
191 if (Z_TYPE_P(return_value) == IS_NULL) {
192 zend_object_store_ctor_failed(&orig_this TSRMLS_CC);
193 zval_dtor(&orig_this);
194 }
195 }
196
PHP_FUNCTION(intlgregcal_set_gregorian_change)197 U_CFUNC PHP_FUNCTION(intlgregcal_set_gregorian_change)
198 {
199 double date;
200 CALENDAR_METHOD_INIT_VARS;
201
202 if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(),
203 "Od", &object, GregorianCalendar_ce_ptr, &date) == FAILURE) {
204 intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
205 "intlgregcal_set_gregorian_change: bad arguments", 0 TSRMLS_CC);
206 RETURN_FALSE;
207 }
208
209 CALENDAR_METHOD_FETCH_OBJECT;
210
211 fetch_greg(co)->setGregorianChange(date, CALENDAR_ERROR_CODE(co));
212 INTL_METHOD_CHECK_STATUS(co, "intlgregcal_set_gregorian_change: error "
213 "calling ICU method");
214
215 RETURN_TRUE;
216 }
217
PHP_FUNCTION(intlgregcal_get_gregorian_change)218 U_CFUNC PHP_FUNCTION(intlgregcal_get_gregorian_change)
219 {
220 CALENDAR_METHOD_INIT_VARS;
221
222 if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(),
223 "O", &object, GregorianCalendar_ce_ptr) == FAILURE) {
224 intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
225 "intlgregcal_get_gregorian_change: bad arguments", 0 TSRMLS_CC);
226 RETURN_FALSE;
227 }
228
229 CALENDAR_METHOD_FETCH_OBJECT;
230
231 RETURN_DOUBLE((double)fetch_greg(co)->getGregorianChange());
232 }
233
PHP_FUNCTION(intlgregcal_is_leap_year)234 U_CFUNC PHP_FUNCTION(intlgregcal_is_leap_year)
235 {
236 long year;
237 CALENDAR_METHOD_INIT_VARS;
238
239 if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(),
240 "Ol", &object, GregorianCalendar_ce_ptr, &year) == FAILURE) {
241 intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
242 "intlgregcal_is_leap_year: bad arguments", 0 TSRMLS_CC);
243 RETURN_FALSE;
244 }
245
246 if (year < INT32_MIN || year > INT32_MAX) {
247 intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
248 "intlgregcal_is_leap_year: year out of bounds", 0 TSRMLS_CC);
249 RETURN_FALSE;
250 }
251
252 CALENDAR_METHOD_FETCH_OBJECT;
253
254 RETURN_BOOL((int)fetch_greg(co)->isLeapYear((int32_t)year));
255 }
256