summaryrefslogtreecommitdiff
path: root/ext/intl/resourcebundle/resourcebundle_iterator.c
blob: cf38c6b676cd8b8733ba5ff4a9424d5d41f68af3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
/*
   +----------------------------------------------------------------------+
   | PHP Version 7                                                        |
   +----------------------------------------------------------------------+
   | 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 ) );
		}
		resourcebundle_extract_value( &iterator->current, rb TSRMLS_CC );
	}
	else {
		// zend_throw_exception( spl_ce_OutOfRangeException, "Running past end of ResourceBundle", 0 TSRMLS_CC);
		ZVAL_UNDEF(&iterator->current);
	}
}
/* }}} */

/* {{{ resourcebundle_iterator_invalidate */
static void resourcebundle_iterator_invalidate( zend_object_iterator *iter TSRMLS_DC ) 
{
	ResourceBundle_iterator *iterator = (ResourceBundle_iterator *) iter;

	if (!Z_ISUNDEF(iterator->current)) {
		zval_ptr_dtor( &iterator->current );
		ZVAL_UNDEF(&iterator->current);
	}
	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 = &iterator->intern.data;

	resourcebundle_iterator_invalidate( iter TSRMLS_CC );

	zval_ptr_dtor(object);
}
/* }}} */

/* {{{ 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 zval *resourcebundle_iterator_current( zend_object_iterator *iter TSRMLS_DC )
{
	ResourceBundle_iterator *iterator = (ResourceBundle_iterator *) iter;
	if (Z_ISUNDEF(iterator->current)) {
		resourcebundle_iterator_read( iterator TSRMLS_CC);
	}
	return &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 (Z_ISUNDEF(iterator->current)) {
		resourcebundle_iterator_read( iterator TSRMLS_CC);
	}

	if (iterator->is_table) {
		ZVAL_STRING(key, iterator->currentkey);
	} else {
		ZVAL_LONG(key, iterator->i);
	}
}
/* }}} */

/* {{{ resourcebundle_iterator_step */
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 = Z_INTL_RESOURCEBUNDLE_P(object );
	ResourceBundle_iterator *iterator = emalloc( sizeof( ResourceBundle_iterator ) );

	if (byref) {
	     php_error( E_ERROR, "ResourceBundle does not support writable iterators" );
	}

	zend_iterator_init(&iterator->intern TSRMLS_CC);
	ZVAL_COPY(&iterator->intern.data, 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 );

	ZVAL_UNDEF(&iterator->current);
	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
 */