mirror of
https://github.com/php/php-src.git
synced 2025-01-05 02:14:08 +08:00
9a35d45a5b
Also unified timezone handling in IntlCalendar::setTimeZone() to that in the IntlCalendar and IntlGregorianCalendar constructors.
257 lines
7.9 KiB
C++
257 lines
7.9 KiB
C++
/*
|
|
+----------------------------------------------------------------------+
|
|
| PHP Version 5 |
|
|
+----------------------------------------------------------------------+
|
|
| This source file is subject to version 3.01 of the PHP license, |
|
|
| that is bundled with this package in the file LICENSE, and is |
|
|
| available through the world-wide-web at the following url: |
|
|
| http://www.php.net/license/3_01.txt |
|
|
| If you did not receive a copy of the PHP license and are unable to |
|
|
| obtain it through the world-wide-web, please send a note to |
|
|
| license@php.net so we can mail you a copy immediately. |
|
|
+----------------------------------------------------------------------+
|
|
| Authors: Gustavo Lopes <cataphract@php.net> |
|
|
+----------------------------------------------------------------------+
|
|
*/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include "config.h"
|
|
#endif
|
|
|
|
#include <unicode/locid.h>
|
|
#include <unicode/calendar.h>
|
|
#include <unicode/gregocal.h>
|
|
extern "C" {
|
|
#define USE_TIMEZONE_POINTER 1
|
|
#include "../timezone/timezone_class.h"
|
|
#define USE_CALENDAR_POINTER 1
|
|
#include "calendar_class.h"
|
|
#include "../locale/locale.h"
|
|
/* avoid redefinition of int8_t, already defined in unicode/pwin32.h */
|
|
#define _MSC_STDINT_H_ 1
|
|
#include <ext/date/php_date.h>
|
|
}
|
|
|
|
static inline GregorianCalendar *fetch_greg(Calendar_object *co) {
|
|
return (GregorianCalendar*)co->ucal;
|
|
}
|
|
|
|
static void _php_intlgregcal_constructor_body(INTERNAL_FUNCTION_PARAMETERS)
|
|
{
|
|
zval *object = getThis();
|
|
zval **tz_object = NULL;
|
|
zval **args_a[6] = {0},
|
|
***args = &args_a[0];
|
|
char *locale = NULL;
|
|
int locale_len;
|
|
long largs[6];
|
|
UErrorCode status = U_ZERO_ERROR;
|
|
int variant;
|
|
intl_error_reset(NULL TSRMLS_CC);
|
|
|
|
// parameter number validation / variant determination
|
|
if (ZEND_NUM_ARGS() > 6 ||
|
|
zend_get_parameters_array_ex(ZEND_NUM_ARGS(), args) == FAILURE) {
|
|
intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
|
|
"intlgregcal_create_instance: too many arguments", 0 TSRMLS_CC);
|
|
RETURN_NULL();
|
|
}
|
|
for (variant = ZEND_NUM_ARGS();
|
|
variant > 0 && Z_TYPE_PP(args[variant - 1]) == IS_NULL;
|
|
variant--) {}
|
|
if (variant == 4) {
|
|
intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
|
|
"intlgregcal_create_instance: no variant with 4 arguments "
|
|
"(excluding trailing NULLs)", 0 TSRMLS_CC);
|
|
RETURN_NULL();
|
|
}
|
|
|
|
// argument parsing
|
|
if (variant <= 2) {
|
|
if (zend_parse_parameters(MIN(ZEND_NUM_ARGS(), 2) TSRMLS_CC,
|
|
"|Z!s!", &tz_object, &locale, &locale_len) == FAILURE) {
|
|
intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
|
|
"intlgregcal_create_instance: bad arguments", 0 TSRMLS_CC);
|
|
RETURN_NULL();
|
|
}
|
|
}
|
|
if (variant > 2 && zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,
|
|
"lll|lll", &largs[0], &largs[1], &largs[2], &largs[3], &largs[4],
|
|
&largs[5]) == FAILURE) {
|
|
intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
|
|
"intlgregcal_create_instance: bad arguments", 0 TSRMLS_CC);
|
|
RETURN_NULL();
|
|
}
|
|
|
|
// instantion of ICU object
|
|
GregorianCalendar *gcal;
|
|
|
|
if (variant <= 2) {
|
|
// From timezone and locale (0 to 2 arguments)
|
|
TimeZone *tz = timezone_process_timezone_argument(tz_object, NULL,
|
|
"intlgregcal_create_instance" TSRMLS_CC);
|
|
if (tz == NULL) {
|
|
RETURN_NULL();
|
|
}
|
|
if (!locale) {
|
|
locale = const_cast<char*>(intl_locale_get_default(TSRMLS_C));
|
|
}
|
|
|
|
gcal = new GregorianCalendar(tz, Locale::createFromName(locale),
|
|
status);
|
|
if (U_FAILURE(status)) {
|
|
intl_error_set(NULL, status, "intlgregcal_create_instance: error "
|
|
"creating ICU GregorianCalendar from time zone and locale", 0 TSRMLS_CC);
|
|
if (gcal) {
|
|
delete gcal;
|
|
}
|
|
delete tz;
|
|
RETURN_NULL();
|
|
}
|
|
} else {
|
|
// From date/time (3, 5 or 6 arguments)
|
|
for (int i = 0; i < variant; i++) {
|
|
if (largs[i] < INT32_MIN || largs[i] > INT32_MAX) {
|
|
intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
|
|
"intlgregcal_create_instance: at least one of the arguments"
|
|
" has an absolute value that is too large", 0 TSRMLS_CC);
|
|
RETURN_NULL();
|
|
}
|
|
}
|
|
|
|
if (variant == 3) {
|
|
gcal = new GregorianCalendar((int32_t)largs[0], (int32_t)largs[1],
|
|
(int32_t)largs[2], status);
|
|
} else if (variant == 5) {
|
|
gcal = new GregorianCalendar((int32_t)largs[0], (int32_t)largs[1],
|
|
(int32_t)largs[2], (int32_t)largs[3], (int32_t)largs[4], status);
|
|
} else if (variant == 6) {
|
|
gcal = new GregorianCalendar((int32_t)largs[0], (int32_t)largs[1],
|
|
(int32_t)largs[2], (int32_t)largs[3], (int32_t)largs[4], (int32_t)largs[5],
|
|
status);
|
|
}
|
|
if (U_FAILURE(status)) {
|
|
intl_error_set(NULL, status, "intlgregcal_create_instance: error "
|
|
"creating ICU GregorianCalendar from date", 0 TSRMLS_CC);
|
|
if (gcal) {
|
|
delete gcal;
|
|
}
|
|
RETURN_NULL();
|
|
}
|
|
|
|
timelib_tzinfo *tzinfo = get_timezone_info(TSRMLS_C);
|
|
#if U_ICU_VERSION_MAJOR_NUM * 10 + U_ICU_VERSION_MINOR_NUM >= 42
|
|
UnicodeString tzstr = UnicodeString::fromUTF8(StringPiece(tzinfo->name));
|
|
#else
|
|
UnicodeString tzstr = UnicodeString(tzinfo->name,
|
|
strlen(tzinfo->name), US_INV);
|
|
#endif
|
|
if (tzstr.isBogus()) {
|
|
intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
|
|
"intlgregcal_create_instance: could not create UTF-8 string "
|
|
"from PHP's default timezone name (see date_default_timezone_get())",
|
|
0 TSRMLS_CC);
|
|
delete gcal;
|
|
RETURN_NULL();
|
|
}
|
|
|
|
TimeZone *tz = TimeZone::createTimeZone(tzstr);
|
|
gcal->adoptTimeZone(tz);
|
|
}
|
|
|
|
Calendar_object *co = (Calendar_object*)zend_object_store_get_object(
|
|
return_value TSRMLS_CC);
|
|
co->ucal = gcal;
|
|
}
|
|
|
|
U_CFUNC PHP_FUNCTION(intlgregcal_create_instance)
|
|
{
|
|
zval orig;
|
|
intl_error_reset(NULL TSRMLS_CC);
|
|
|
|
object_init_ex(return_value, GregorianCalendar_ce_ptr);
|
|
orig = *return_value;
|
|
|
|
_php_intlgregcal_constructor_body(INTERNAL_FUNCTION_PARAM_PASSTHRU);
|
|
|
|
if (Z_TYPE_P(return_value) == IS_NULL) {
|
|
zend_object_store_ctor_failed(&orig TSRMLS_CC);
|
|
zval_dtor(&orig);
|
|
}
|
|
}
|
|
|
|
U_CFUNC PHP_METHOD(IntlGregorianCalendar, __construct)
|
|
{
|
|
zval orig_this = *getThis();
|
|
intl_error_reset(NULL TSRMLS_CC);
|
|
|
|
return_value = getThis();
|
|
//changes this to IS_NULL (without first destroying) if there's an error
|
|
_php_intlgregcal_constructor_body(INTERNAL_FUNCTION_PARAM_PASSTHRU);
|
|
|
|
if (Z_TYPE_P(return_value) == IS_NULL) {
|
|
zend_object_store_ctor_failed(&orig_this TSRMLS_CC);
|
|
zval_dtor(&orig_this);
|
|
}
|
|
}
|
|
|
|
U_CFUNC PHP_FUNCTION(intlgregcal_set_gregorian_change)
|
|
{
|
|
double date;
|
|
CALENDAR_METHOD_INIT_VARS;
|
|
|
|
if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(),
|
|
"Od", &object, GregorianCalendar_ce_ptr, &date) == FAILURE) {
|
|
intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
|
|
"intlgregcal_set_gregorian_change: bad arguments", 0 TSRMLS_CC);
|
|
RETURN_FALSE;
|
|
}
|
|
|
|
CALENDAR_METHOD_FETCH_OBJECT;
|
|
|
|
fetch_greg(co)->setGregorianChange(date, CALENDAR_ERROR_CODE(co));
|
|
INTL_METHOD_CHECK_STATUS(co, "intlgregcal_set_gregorian_change: error "
|
|
"calling ICU method");
|
|
|
|
RETURN_TRUE;
|
|
}
|
|
|
|
U_CFUNC PHP_FUNCTION(intlgregcal_get_gregorian_change)
|
|
{
|
|
CALENDAR_METHOD_INIT_VARS;
|
|
|
|
if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(),
|
|
"O", &object, GregorianCalendar_ce_ptr) == FAILURE) {
|
|
intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
|
|
"intlgregcal_get_gregorian_change: bad arguments", 0 TSRMLS_CC);
|
|
RETURN_FALSE;
|
|
}
|
|
|
|
CALENDAR_METHOD_FETCH_OBJECT;
|
|
|
|
RETURN_DOUBLE((double)fetch_greg(co)->getGregorianChange());
|
|
}
|
|
|
|
U_CFUNC PHP_FUNCTION(intlgregcal_is_leap_year)
|
|
{
|
|
long year;
|
|
CALENDAR_METHOD_INIT_VARS;
|
|
|
|
if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(),
|
|
"Ol", &object, GregorianCalendar_ce_ptr, &year) == FAILURE) {
|
|
intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
|
|
"intlgregcal_is_leap_year: bad arguments", 0 TSRMLS_CC);
|
|
RETURN_FALSE;
|
|
}
|
|
|
|
if (year < INT32_MIN || year > INT32_MAX) {
|
|
intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
|
|
"intlgregcal_is_leap_year: year out of bounds", 0 TSRMLS_CC);
|
|
RETURN_FALSE;
|
|
}
|
|
|
|
CALENDAR_METHOD_FETCH_OBJECT;
|
|
|
|
RETURN_BOOL((int)fetch_greg(co)->isLeapYear((int32_t)year));
|
|
}
|