text: /*
     +----------------------------------------------------------------------+
     | 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: Hans-Peter Oeri (University of St.Gallen) <hp@oeri.ch>      |
     +----------------------------------------------------------------------+
   */
  
  #include <php.h>
  #include <zend.h>
  #include <zend_API.h>
  
  #include "resourcebundle/resourcebundle.h"
  #include "resourcebundle/resourcebundle_class.h"
  #include "resourcebundle/resourcebundle_iterator.h"
  
  /*
   * Although libicu offers iterator functions, they are not used here: libicu does iterate
   * irrespective of array indices. Those cannot be recreated afterwards. Arrays as well as tables
   * can however be accessed by numerical index, with table keys readable ex post.
   */
  
  /* {{{ resourcebundle_iterator_read */
  static void resourcebundle_iterator_read( ResourceBundle_iterator *iterator TSRMLS_DC ) 
  {
  	UErrorCode icuerror = U_ZERO_ERROR;
  	ResourceBundle_object *rb = iterator->subject;
  
  	rb->child = ures_getByIndex( rb->me, iterator->i, rb->child, &icuerror );
  
  	if (U_SUCCESS(icuerror)) {
  		/* ATTN: key extraction must be the first thing to do... rb->child might be reset in read! */
  		if (iterator->is_table) {
  			iterator->currentkey = estrdup( ures_getKey( rb->child ) );
  		}
  		MAKE_STD_ZVAL( iterator->current );
  		resourcebundle_extract_value( iterator->current, rb TSRMLS_CC );
  	}
  	else {
  		// zend_throw_exception( spl_ce_OutOfRangeException, "Running past end of ResourceBundle", 0 TSRMLS_CC);
  		iterator->current = NULL;
  	}
  }
  /* }}} */
  
  /* {{{ resourcebundle_iterator_invalidate */
  static void resourcebundle_iterator_invalidate( zend_object_iterator *iter TSRMLS_DC ) 
  {
  	ResourceBundle_iterator *iterator = (ResourceBundle_iterator *) iter;
  
  	if (iterator->current) {
  		zval_ptr_dtor( &iterator->current );
  		iterator->current = NULL;
  	}
  	if (iterator->currentkey) {
  		efree( iterator->currentkey );
  		iterator->currentkey = NULL;
  	}
  }
  /* }}} */
  
  /* {{{ resourcebundle_iterator_dtor */
  static void resourcebundle_iterator_dtor( zend_object_iterator *iter TSRMLS_DC )
  {
  	ResourceBundle_iterator *iterator = (ResourceBundle_iterator *) iter;
  	zval                    *object = (zval *)iterator->intern.data;
  
  	resourcebundle_iterator_invalidate( iter TSRMLS_CC );
  
  	Z_DELREF_P(object);
  
  	efree(iterator);
  }
  /* }}} */
  
  /* {{{ resourcebundle_iterator_has_more */
  static int resourcebundle_iterator_has_more( zend_object_iterator *iter TSRMLS_DC )
  {
  	ResourceBundle_iterator *iterator = (ResourceBundle_iterator *) iter;
  	return (iterator->i < iterator->length) ? SUCCESS : FAILURE;
  }
  /* }}} */
  
  /* {{{ resourcebundle_iterator_current */
  static void resourcebundle_iterator_current( zend_object_iterator *iter, zval ***data TSRMLS_DC )
  {
  	ResourceBundle_iterator *iterator = (ResourceBundle_iterator *) iter;
  	if (!iterator->current) {
  		resourcebundle_iterator_read( iterator TSRMLS_CC);
  	}
  	*data = &iterator->current;
  }
  /* }}} */
  
  /* {{{ resourcebundle_iterator_key */
  static void resourcebundle_iterator_key( zend_object_iterator *iter, zval *key TSRMLS_DC )
  {
  	ResourceBundle_iterator *iterator = (ResourceBundle_iterator *) iter;
  
  	if (!iterator->current) {
  		resourcebundle_iterator_read( iterator TSRMLS_CC);
  	}
  
  	if (iterator->is_table) {
  		ZVAL_STRING(key, iterator->currentkey, 1);
  	} else {
  		ZVAL_LONG(key, iterator->i);
  	}
  }
  /* }}} */
  
  /* {{{ resourcebundle_iterator_has_more */
  static void resourcebundle_iterator_step( zend_object_iterator *iter TSRMLS_DC )
  {
  	ResourceBundle_iterator *iterator = (ResourceBundle_iterator *) iter;
  
  	iterator->i++;
  	resourcebundle_iterator_invalidate( iter TSRMLS_CC );
  }
  /* }}} */
  
  /* {{{ resourcebundle_iterator_has_reset */
  static void resourcebundle_iterator_reset( zend_object_iterator *iter TSRMLS_DC )
  {
  	ResourceBundle_iterator *iterator = (ResourceBundle_iterator *) iter;
  
  	iterator->i = 0;
  	resourcebundle_iterator_invalidate( iter TSRMLS_CC );
  }
  /* }}} */
  
  /* {{{ resourcebundle_iterator_funcs */
  static zend_object_iterator_funcs resourcebundle_iterator_funcs = {
  	resourcebundle_iterator_dtor,
  	resourcebundle_iterator_has_more,
  	resourcebundle_iterator_current,
  	resourcebundle_iterator_key,
  	resourcebundle_iterator_step,
  	resourcebundle_iterator_reset,
  	resourcebundle_iterator_invalidate
  };
  /* }}} */
  
  /* {{{ resourcebundle_get_iterator */
  zend_object_iterator *resourcebundle_get_iterator( zend_class_entry *ce, zval *object, int byref TSRMLS_DC )
  {
  	ResourceBundle_object   *rb = (ResourceBundle_object *) zend_object_store_get_object( object TSRMLS_CC );
  	ResourceBundle_iterator *iterator = emalloc( sizeof( ResourceBundle_iterator ) );
  
  	if (byref) {
  	     php_error( E_ERROR, "ResourceBundle does not support writable iterators" );
  	}
  
  	Z_ADDREF_P(object);
  	iterator->intern.data = (void *) object;
  	iterator->intern.funcs = &resourcebundle_iterator_funcs;
  
  	iterator->subject = rb;
  
  	/* The iterated rb can only be either URES_TABLE or URES_ARRAY
  	 * All other types are returned as php primitives!
  	 */
  	iterator->is_table = (ures_getType( rb->me ) == URES_TABLE);
  	iterator->length = ures_getSize( rb->me );
  
  	iterator->current = NULL;
  	iterator->currentkey = NULL;
  	iterator->i = 0;
  
  	return (zend_object_iterator *) iterator;
  }
  /* }}} */
  
  /*
   * Local variables:
   * tab-width: 4
   * c-basic-offset: 4
   * End:
   * vim600: noet sw=4 ts=4 fdm=marker
   * vim<600: noet sw=4 ts=4
   */
  