gregoriancalendar_methods.cpp 7.8 KB

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