diff options
author | Gustavo André dos Santos Lopes <cataphract@php.net> | 2012-04-01 11:11:40 +0200 |
---|---|---|
committer | Gustavo André dos Santos Lopes <cataphract@php.net> | 2012-04-01 23:28:00 +0100 |
commit | 5e65205a8f52d25635bb4e7619a4b0216aefa4b8 (patch) | |
tree | 5c9984f097fe230ad52dbd48ad8895056c108960 /ext/intl/common/common_enum.cpp | |
parent | 6c891f33d73afc50c3d79e982c5752fc3f5df85f (diff) | |
download | php-git-5e65205a8f52d25635bb4e7619a4b0216aefa4b8.tar.gz |
Initial checkin of calendar/timezone code.
Diffstat (limited to 'ext/intl/common/common_enum.cpp')
-rw-r--r-- | ext/intl/common/common_enum.cpp | 380 |
1 files changed, 380 insertions, 0 deletions
diff --git a/ext/intl/common/common_enum.cpp b/ext/intl/common/common_enum.cpp new file mode 100644 index 0000000000..08f6c858cb --- /dev/null +++ b/ext/intl/common/common_enum.cpp @@ -0,0 +1,380 @@ +/* + +----------------------------------------------------------------------+ + | 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 "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; + +} |