root/ext/intl/common/common_enum.cpp

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. zoi_with_current_dtor
  2. zoi_with_current_valid
  3. zoi_with_current_get_current_data
  4. zoi_with_current_invalidate_current
  5. string_enum_current_move_forward
  6. string_enum_rewind
  7. string_enum_destroy_it
  8. IntlIterator_from_StringEnumeration
  9. IntlIterator_objects_free
  10. IntlIterator_get_iterator
  11. IntlIterator_object_create
  12. PHP_METHOD
  13. PHP_METHOD
  14. PHP_METHOD
  15. PHP_METHOD
  16. PHP_METHOD
  17. intl_register_IntlIterator_class

/*
   +----------------------------------------------------------------------+
   | 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 <zend_interfaces.h>
#include <zend_exceptions.h>
}

zend_class_entry *IntlIterator_ce_ptr;
zend_object_handlers IntlIterator_handlers;

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_it(iter TSRMLS_CC);
                efree(iter);
        }
}

U_CFUNC int zoi_with_current_valid(zend_object_iterator *iter TSRMLS_DC)
{
        return ((zoi_with_current*)iter)->current != NULL ? SUCCESS : FAILURE;
}

U_CFUNC void zoi_with_current_get_current_data(zend_object_iterator *iter, zval ***data TSRMLS_DC)
{
        *data = &((zoi_with_current*)iter)->current;
}

U_CFUNC 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_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_it = string_enum_destroy_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) {
                ii->iterator->funcs->get_current_key(ii->iterator, return_value TSRMLS_CC);
        } 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_errors_set(INTLITERATOR_ERROR_P(ii), 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;

}

/* [<][>][^][v][top][bottom][index][help] */