mirror of
https://github.com/php/php-src.git
synced 2025-08-15 21:48:51 +02:00

The following changes were made: * The IntlDateFormatter constructor now accepts the usual values for its $timezone argument. This includes timezone identifiers, IntlTimeZone objects, DateTimeZone objects and NULL. An empty string is not accepted. An invalid time zone is no longer accepted (it used to use UTC in this case). * When NULL is passed to IntlDateFormatter, the time zone specified in date.timezone is used instead of the ICU default. * The IntlDateFormatter $calendar argument now accepts also an IntlCalendar. In this case, IntlDateFormatter::getCalendar() will return false. * The time zone passed to the IntlDateFormatter is ignored if it is NULL and if the calendar passed is an IntlCalendar object -- in this case, the IntlCalendar time zone will be used instead. Otherwise, the time zone specified in the $timezone argument is used instead. * Added IntlDateFormatter::getCalendarObject(), which always returns the IntlCalendar object that backs the DateFormat, even if a constant was passed to the constructor, i.e., if an IntlCalendar was not passed to the constructor. * Added IntlDateFormatter::setTimeZone(). It accepts the usual values for time zone arguments. If NULL is passed, the time zone of the IntlDateFormatter WILL be overridden with the default time zone, even if an IntlCalendar object was passed to the constructor. * Added IntlDateFormatter::getTimeZone(), which returns the time zone that's associated with the DateFormat. * Depreacated IntlDateFormatter::setTimeZoneId() and made it an alias for IntlDateFormatter::setTimeZone(), as the new ::setTimeZone() also accepts plain identifiers, besides other types. IntlDateFormatter::getTimeZoneId() is not deprecated however. * IntlDateFormatter::setCalendar() with a constant passed should now work correctly. This requires saving the requested locale to the constructor. * Centralized the hacks required to avoid compilation disasters on Windows due to some headers being included inside and outside of extern "C" blocks.
385 lines
12 KiB
C++
385 lines
12 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 "../intl_cppshims.h"
|
|
|
|
// Fix build on Windows/old versions of ICU
|
|
#include <stdio.h>
|
|
|
|
#include "common_enum.h"
|
|
|
|
extern "C" {
|
|
#include "intl_error.h"
|
|
#include "intl_data.h"
|
|
#include <zend_interfaces.h>
|
|
#include <zend_exceptions.h>
|
|
}
|
|
|
|
static zend_class_entry *IntlIterator_ce_ptr;
|
|
static zend_object_handlers IntlIterator_handlers;
|
|
|
|
typedef struct {
|
|
zend_object zo;
|
|
intl_error err;
|
|
zend_object_iterator *iterator;
|
|
} IntlIterator_object;
|
|
|
|
#define INTLITERATOR_ERROR(ii) (ii)->err
|
|
#define INTLITERATOR_ERROR_P(ii) &(INTLITERATOR_ERROR(ii))
|
|
|
|
#define INTLITERATOR_ERROR_CODE(ii) INTL_ERROR_CODE(INTLITERATOR_ERROR(ii))
|
|
#define INTLITERATOR_ERROR_CODE_P(ii) &(INTL_ERROR_CODE(INTLITERATOR_ERROR(ii)))
|
|
|
|
#define INTLITERATOR_METHOD_INIT_VARS INTL_METHOD_INIT_VARS(IntlIterator, ii)
|
|
#define INTLITERATOR_METHOD_FETCH_OBJECT_NO_CHECK INTL_METHOD_FETCH_OBJECT(IntlIterator, ii)
|
|
#define INTLITERATOR_METHOD_FETCH_OBJECT\
|
|
object = getThis(); \
|
|
INTLITERATOR_METHOD_FETCH_OBJECT_NO_CHECK; \
|
|
if (ii->iterator == NULL) { \
|
|
intl_errors_set(&ii->err, U_ILLEGAL_ARGUMENT_ERROR, "Found unconstructed IntlIterator", 0 TSRMLS_CC); \
|
|
RETURN_FALSE; \
|
|
}
|
|
|
|
typedef struct {
|
|
zend_object_iterator zoi;
|
|
zval *current;
|
|
zval *wrapping_obj;
|
|
void (*destroy_free_it)(zend_object_iterator *iterator TSRMLS_DC);
|
|
} zoi_with_current;
|
|
|
|
static void zoi_with_current_dtor(zend_object_iterator *iter TSRMLS_DC)
|
|
{
|
|
zoi_with_current *zoiwc = (zoi_with_current*)iter;
|
|
|
|
if (zoiwc->wrapping_obj) {
|
|
/* we have to copy the pointer because zoiwc->wrapping_obj may be
|
|
* changed midway the execution of zval_ptr_dtor() */
|
|
zval *zwo = zoiwc->wrapping_obj;
|
|
|
|
/* object is still here, we can rely on it to call this again and
|
|
* destroy this object */
|
|
zval_ptr_dtor(&zwo);
|
|
} else {
|
|
/* Object not here anymore (we've been called by the object free handler)
|
|
* Note that the iterator wrapper objects (that also depend on this
|
|
* structure) call this function earlier, in the destruction phase, which
|
|
* precedes the object free phase. Therefore there's no risk on this
|
|
* function being called by the iterator wrapper destructor function and
|
|
* not finding the memory of this iterator allocated anymore. */
|
|
iter->funcs->invalidate_current(iter TSRMLS_CC);
|
|
zoiwc->destroy_free_it(iter TSRMLS_CC);
|
|
efree(iter);
|
|
}
|
|
}
|
|
|
|
static int zoi_with_current_valid(zend_object_iterator *iter TSRMLS_DC)
|
|
{
|
|
return ((zoi_with_current*)iter)->current != NULL ? SUCCESS : FAILURE;
|
|
}
|
|
|
|
static void zoi_with_current_get_current_data(zend_object_iterator *iter, zval ***data TSRMLS_DC)
|
|
{
|
|
*data = &((zoi_with_current*)iter)->current;
|
|
}
|
|
|
|
static void zoi_with_current_invalidate_current(zend_object_iterator *iter TSRMLS_DC)
|
|
{
|
|
zoi_with_current *zoi_iter = (zoi_with_current*)iter;
|
|
if (zoi_iter->current) {
|
|
zval_ptr_dtor(&zoi_iter->current);
|
|
zoi_iter->current = NULL; //valid would return FAILURE now
|
|
}
|
|
}
|
|
|
|
static void string_enum_current_move_forward(zend_object_iterator *iter TSRMLS_DC)
|
|
{
|
|
zoi_with_current *zoi_iter = (zoi_with_current*)iter;
|
|
INTLITERATOR_METHOD_INIT_VARS;
|
|
|
|
iter->funcs->invalidate_current(iter TSRMLS_CC);
|
|
|
|
object = zoi_iter->wrapping_obj;
|
|
INTLITERATOR_METHOD_FETCH_OBJECT_NO_CHECK;
|
|
|
|
int32_t result_length;
|
|
const char *result = ((StringEnumeration*)iter->data)->next(
|
|
&result_length, INTLITERATOR_ERROR_CODE(ii));
|
|
|
|
intl_error_set_code(NULL, INTLITERATOR_ERROR_CODE(ii) TSRMLS_CC);
|
|
if (U_FAILURE(INTLITERATOR_ERROR_CODE(ii))) {
|
|
intl_errors_set_custom_msg(INTL_DATA_ERROR_P(ii),
|
|
"Error fetching next iteration element", 0 TSRMLS_CC);
|
|
} else if (result) {
|
|
MAKE_STD_ZVAL(zoi_iter->current);
|
|
ZVAL_STRINGL(zoi_iter->current, result, result_length, 1);
|
|
} //else we've reached the end of the enum, nothing more is required
|
|
}
|
|
|
|
static void string_enum_rewind(zend_object_iterator *iter TSRMLS_DC)
|
|
{
|
|
zoi_with_current *zoi_iter = (zoi_with_current*)iter;
|
|
INTLITERATOR_METHOD_INIT_VARS;
|
|
|
|
if (zoi_iter->current) {
|
|
iter->funcs->invalidate_current(iter TSRMLS_CC);
|
|
}
|
|
|
|
object = zoi_iter->wrapping_obj;
|
|
INTLITERATOR_METHOD_FETCH_OBJECT_NO_CHECK;
|
|
|
|
((StringEnumeration*)iter->data)->reset(INTLITERATOR_ERROR_CODE(ii));
|
|
|
|
intl_error_set_code(NULL, INTLITERATOR_ERROR_CODE(ii) TSRMLS_CC);
|
|
if (U_FAILURE(INTLITERATOR_ERROR_CODE(ii))) {
|
|
intl_errors_set_custom_msg(INTL_DATA_ERROR_P(ii),
|
|
"Error resetting enumeration", 0 TSRMLS_CC);
|
|
} else {
|
|
iter->funcs->move_forward(iter TSRMLS_CC);
|
|
}
|
|
}
|
|
|
|
static void string_enum_destroy_free_it(zend_object_iterator *iter TSRMLS_DC)
|
|
{
|
|
delete (StringEnumeration*)iter->data;
|
|
}
|
|
|
|
static zend_object_iterator_funcs string_enum_object_iterator_funcs = {
|
|
zoi_with_current_dtor,
|
|
zoi_with_current_valid,
|
|
zoi_with_current_get_current_data,
|
|
NULL,
|
|
string_enum_current_move_forward,
|
|
string_enum_rewind,
|
|
zoi_with_current_invalidate_current
|
|
};
|
|
|
|
U_CFUNC void IntlIterator_from_StringEnumeration(StringEnumeration *se, zval *object TSRMLS_DC)
|
|
{
|
|
IntlIterator_object *ii;
|
|
object_init_ex(object, IntlIterator_ce_ptr);
|
|
ii = (IntlIterator_object*)zend_object_store_get_object(object TSRMLS_CC);
|
|
ii->iterator = (zend_object_iterator*)emalloc(sizeof(zoi_with_current));
|
|
ii->iterator->data = (void*)se;
|
|
ii->iterator->funcs = &string_enum_object_iterator_funcs;
|
|
ii->iterator->index = 0;
|
|
((zoi_with_current*)ii->iterator)->destroy_free_it = string_enum_destroy_free_it;
|
|
((zoi_with_current*)ii->iterator)->wrapping_obj = object;
|
|
((zoi_with_current*)ii->iterator)->current = NULL;
|
|
}
|
|
|
|
static void IntlIterator_objects_free(zend_object *object TSRMLS_DC)
|
|
{
|
|
IntlIterator_object *ii = (IntlIterator_object*) object;
|
|
|
|
if (ii->iterator) {
|
|
zval **wrapping_objp = &((zoi_with_current*)ii->iterator)->wrapping_obj;
|
|
*wrapping_objp = NULL;
|
|
ii->iterator->funcs->dtor(ii->iterator TSRMLS_CC);
|
|
}
|
|
intl_error_reset(INTLITERATOR_ERROR_P(ii) TSRMLS_CC);
|
|
|
|
zend_object_std_dtor(&ii->zo TSRMLS_CC);
|
|
|
|
efree(ii);
|
|
}
|
|
|
|
static zend_object_iterator *IntlIterator_get_iterator(
|
|
zend_class_entry *ce, zval *object, int by_ref TSRMLS_DC)
|
|
{
|
|
if (by_ref) {
|
|
zend_throw_exception(NULL,
|
|
"Iteration by reference is not supported", 0 TSRMLS_CC);
|
|
return NULL;
|
|
}
|
|
|
|
IntlIterator_object *ii = (IntlIterator_object*)
|
|
zend_object_store_get_object(object TSRMLS_CC);
|
|
|
|
if (ii->iterator == NULL) {
|
|
zend_throw_exception(NULL,
|
|
"The IntlIterator is not properly constructed", 0 TSRMLS_CC);
|
|
return NULL;
|
|
}
|
|
|
|
zval_add_ref(&object);
|
|
|
|
return ii->iterator;
|
|
}
|
|
|
|
static zend_object_value IntlIterator_object_create(zend_class_entry *ce TSRMLS_DC)
|
|
{
|
|
zend_object_value retval;
|
|
IntlIterator_object *intern;
|
|
|
|
intern = (IntlIterator_object*)ecalloc(1, sizeof(IntlIterator_object));
|
|
|
|
zend_object_std_init(&intern->zo, ce TSRMLS_CC);
|
|
#if PHP_VERSION_ID < 50399
|
|
zend_hash_copy(intern->zo.properties, &(ce->default_properties),
|
|
(copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval*));
|
|
#else
|
|
object_properties_init((zend_object*) intern, ce);
|
|
#endif
|
|
intl_error_init(INTLITERATOR_ERROR_P(intern) TSRMLS_CC);
|
|
intern->iterator = NULL;
|
|
|
|
retval.handle = zend_objects_store_put(
|
|
intern,
|
|
(zend_objects_store_dtor_t)zend_objects_destroy_object,
|
|
(zend_objects_free_object_storage_t)IntlIterator_objects_free,
|
|
NULL TSRMLS_CC);
|
|
|
|
retval.handlers = &IntlIterator_handlers;
|
|
|
|
return retval;
|
|
}
|
|
|
|
static PHP_METHOD(IntlIterator, current)
|
|
{
|
|
zval **data;
|
|
INTLITERATOR_METHOD_INIT_VARS;
|
|
|
|
if (zend_parse_parameters_none() == FAILURE) {
|
|
intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
|
|
"IntlIterator::current: bad arguments", 0 TSRMLS_CC);
|
|
return;
|
|
}
|
|
|
|
INTLITERATOR_METHOD_FETCH_OBJECT;
|
|
ii->iterator->funcs->get_current_data(ii->iterator, &data TSRMLS_CC);
|
|
if (data && *data) {
|
|
RETURN_ZVAL(*data, 1, 0);
|
|
}
|
|
}
|
|
|
|
static PHP_METHOD(IntlIterator, key)
|
|
{
|
|
INTLITERATOR_METHOD_INIT_VARS;
|
|
|
|
if (zend_parse_parameters_none() == FAILURE) {
|
|
intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
|
|
"IntlIterator::key: bad arguments", 0 TSRMLS_CC);
|
|
return;
|
|
}
|
|
|
|
INTLITERATOR_METHOD_FETCH_OBJECT;
|
|
|
|
if (ii->iterator->funcs->get_current_key) {
|
|
char *str_key;
|
|
uint str_key_len;
|
|
ulong int_key;
|
|
|
|
switch (ii->iterator->funcs->get_current_key(
|
|
ii->iterator, &str_key, &str_key_len, &int_key TSRMLS_CC)) {
|
|
case HASH_KEY_IS_LONG:
|
|
RETURN_LONG(int_key);
|
|
break;
|
|
case HASH_KEY_IS_STRING:
|
|
RETURN_STRINGL(str_key, str_key_len-1, 0);
|
|
break;
|
|
}
|
|
} else {
|
|
RETURN_LONG(ii->iterator->index);
|
|
}
|
|
}
|
|
|
|
static PHP_METHOD(IntlIterator, next)
|
|
{
|
|
INTLITERATOR_METHOD_INIT_VARS;
|
|
|
|
if (zend_parse_parameters_none() == FAILURE) {
|
|
intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
|
|
"IntlIterator::next: bad arguments", 0 TSRMLS_CC);
|
|
return;
|
|
}
|
|
|
|
INTLITERATOR_METHOD_FETCH_OBJECT;
|
|
ii->iterator->funcs->move_forward(ii->iterator TSRMLS_CC);
|
|
/* foreach also advances the index after the last iteration,
|
|
* so I see no problem in incrementing the index here unconditionally */
|
|
ii->iterator->index++;
|
|
}
|
|
|
|
static PHP_METHOD(IntlIterator, rewind)
|
|
{
|
|
INTLITERATOR_METHOD_INIT_VARS;
|
|
|
|
if (zend_parse_parameters_none() == FAILURE) {
|
|
intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
|
|
"IntlIterator::rewind: bad arguments", 0 TSRMLS_CC);
|
|
return;
|
|
}
|
|
|
|
INTLITERATOR_METHOD_FETCH_OBJECT;
|
|
if (ii->iterator->funcs->rewind) {
|
|
ii->iterator->funcs->rewind(ii->iterator TSRMLS_CC);
|
|
} else {
|
|
intl_error_set(NULL, U_UNSUPPORTED_ERROR,
|
|
"IntlIterator::rewind: rewind not supported", 0 TSRMLS_CC);
|
|
}
|
|
}
|
|
|
|
static PHP_METHOD(IntlIterator, valid)
|
|
{
|
|
INTLITERATOR_METHOD_INIT_VARS;
|
|
|
|
if (zend_parse_parameters_none() == FAILURE) {
|
|
intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
|
|
"IntlIterator::valid: bad arguments", 0 TSRMLS_CC);
|
|
return;
|
|
}
|
|
|
|
INTLITERATOR_METHOD_FETCH_OBJECT;
|
|
RETURN_BOOL(ii->iterator->funcs->valid(ii->iterator TSRMLS_CC) == SUCCESS);
|
|
}
|
|
|
|
ZEND_BEGIN_ARG_INFO_EX(ainfo_se_void, 0, 0, 0)
|
|
ZEND_END_ARG_INFO()
|
|
|
|
static zend_function_entry IntlIterator_class_functions[] = {
|
|
PHP_ME(IntlIterator, current, ainfo_se_void, ZEND_ACC_PUBLIC)
|
|
PHP_ME(IntlIterator, key, ainfo_se_void, ZEND_ACC_PUBLIC)
|
|
PHP_ME(IntlIterator, next, ainfo_se_void, ZEND_ACC_PUBLIC)
|
|
PHP_ME(IntlIterator, rewind, ainfo_se_void, ZEND_ACC_PUBLIC)
|
|
PHP_ME(IntlIterator, valid, ainfo_se_void, ZEND_ACC_PUBLIC)
|
|
PHP_FE_END
|
|
};
|
|
|
|
|
|
/* {{{ intl_register_IntlIterator_class
|
|
* Initialize 'IntlIterator' class
|
|
*/
|
|
U_CFUNC void intl_register_IntlIterator_class(TSRMLS_D)
|
|
{
|
|
zend_class_entry ce;
|
|
|
|
/* Create and register 'IntlIterator' class. */
|
|
INIT_CLASS_ENTRY(ce, "IntlIterator", IntlIterator_class_functions);
|
|
ce.create_object = IntlIterator_object_create;
|
|
IntlIterator_ce_ptr = zend_register_internal_class(&ce TSRMLS_CC);
|
|
IntlIterator_ce_ptr->get_iterator = IntlIterator_get_iterator;
|
|
zend_class_implements(IntlIterator_ce_ptr TSRMLS_CC, 1,
|
|
zend_ce_iterator);
|
|
|
|
memcpy(&IntlIterator_handlers, zend_get_std_object_handlers(),
|
|
sizeof IntlIterator_handlers);
|
|
IntlIterator_handlers.clone_obj = NULL;
|
|
|
|
}
|