1 : /*
2 : +----------------------------------------------------------------------+
3 : | PHP Version 5 |
4 : +----------------------------------------------------------------------+
5 : | Copyright (c) 1997-2007 The PHP Group |
6 : +----------------------------------------------------------------------+
7 : | This source file is subject to version 3.01 of the PHP license, |
8 : | that is bundled with this package in the file LICENSE, and is |
9 : | available through the world-wide-web at the following url: |
10 : | http://www.php.net/license/3_01.txt |
11 : | If you did not receive a copy of the PHP license and are unable to |
12 : | obtain it through the world-wide-web, please send a note to |
13 : | license@php.net so we can mail you a copy immediately. |
14 : +----------------------------------------------------------------------+
15 : | Authors: Marcus Boerger <helly@php.net> |
16 : +----------------------------------------------------------------------+
17 : */
18 :
19 : /* $Id: spl_iterators.c,v 1.73.2.30.2.27 2007/03/04 14:01:06 helly Exp $ */
20 :
21 : #ifdef HAVE_CONFIG_H
22 : # include "config.h"
23 : #endif
24 :
25 : #include "php.h"
26 : #include "php_ini.h"
27 : #include "ext/standard/info.h"
28 : #include "zend_exceptions.h"
29 : #include "zend_interfaces.h"
30 :
31 : #include "php_spl.h"
32 : #include "spl_functions.h"
33 : #include "spl_engine.h"
34 : #include "spl_iterators.h"
35 : #include "spl_directory.h"
36 : #include "spl_array.h"
37 : #include "spl_exceptions.h"
38 :
39 : #ifdef accept
40 : #undef accept
41 : #endif
42 :
43 : PHPAPI zend_class_entry *spl_ce_RecursiveIterator;
44 : PHPAPI zend_class_entry *spl_ce_RecursiveIteratorIterator;
45 : PHPAPI zend_class_entry *spl_ce_FilterIterator;
46 : PHPAPI zend_class_entry *spl_ce_RecursiveFilterIterator;
47 : PHPAPI zend_class_entry *spl_ce_ParentIterator;
48 : PHPAPI zend_class_entry *spl_ce_SeekableIterator;
49 : PHPAPI zend_class_entry *spl_ce_LimitIterator;
50 : PHPAPI zend_class_entry *spl_ce_CachingIterator;
51 : PHPAPI zend_class_entry *spl_ce_RecursiveCachingIterator;
52 : PHPAPI zend_class_entry *spl_ce_OuterIterator;
53 : PHPAPI zend_class_entry *spl_ce_IteratorIterator;
54 : PHPAPI zend_class_entry *spl_ce_NoRewindIterator;
55 : PHPAPI zend_class_entry *spl_ce_InfiniteIterator;
56 : PHPAPI zend_class_entry *spl_ce_EmptyIterator;
57 : PHPAPI zend_class_entry *spl_ce_AppendIterator;
58 : PHPAPI zend_class_entry *spl_ce_RegexIterator;
59 : PHPAPI zend_class_entry *spl_ce_RecursiveRegexIterator;
60 : PHPAPI zend_class_entry *spl_ce_Countable;
61 :
62 : zend_function_entry spl_funcs_RecursiveIterator[] = {
63 : SPL_ABSTRACT_ME(RecursiveIterator, hasChildren, NULL)
64 : SPL_ABSTRACT_ME(RecursiveIterator, getChildren, NULL)
65 : {NULL, NULL, NULL}
66 : };
67 :
68 : typedef enum {
69 : RIT_LEAVES_ONLY = 0,
70 : RIT_SELF_FIRST = 1,
71 : RIT_CHILD_FIRST = 2
72 : } RecursiveIteratorMode;
73 :
74 : #define RIT_CATCH_GET_CHILD CIT_CATCH_GET_CHILD
75 :
76 : typedef enum {
77 : RS_NEXT = 0,
78 : RS_TEST = 1,
79 : RS_SELF = 2,
80 : RS_CHILD = 3,
81 : RS_START = 4
82 : } RecursiveIteratorState;
83 :
84 : typedef struct _spl_sub_iterator {
85 : zend_object_iterator *iterator;
86 : zval *zobject;
87 : zend_class_entry *ce;
88 : RecursiveIteratorState state;
89 : } spl_sub_iterator;
90 :
91 : typedef struct _spl_recursive_it_object {
92 : zend_object std;
93 : spl_sub_iterator *iterators;
94 : int level;
95 : RecursiveIteratorMode mode;
96 : int flags;
97 : int max_depth;
98 : zend_bool in_iteration;
99 : zend_function *beginIteration;
100 : zend_function *endIteration;
101 : zend_function *callHasChildren;
102 : zend_function *callGetChildren;
103 : zend_function *beginChildren;
104 : zend_function *endChildren;
105 : zend_function *nextElement;
106 : zend_class_entry *ce;
107 : } spl_recursive_it_object;
108 :
109 : typedef struct _spl_recursive_it_iterator {
110 : zend_object_iterator intern;
111 : zval *zobject;
112 : } spl_recursive_it_iterator;
113 :
114 : static zend_object_handlers spl_handlers_rec_it_it;
115 : static zend_object_handlers spl_handlers_dual_it;
116 :
117 : static void spl_recursive_it_dtor(zend_object_iterator *_iter TSRMLS_DC)
118 0 : {
119 0 : spl_recursive_it_iterator *iter = (spl_recursive_it_iterator*)_iter;
120 0 : spl_recursive_it_object *object = (spl_recursive_it_object*)_iter->data;
121 : zend_object_iterator *sub_iter;
122 :
123 0 : while (object->level) {
124 0 : sub_iter = object->iterators[object->level].iterator;
125 0 : sub_iter->funcs->dtor(sub_iter TSRMLS_CC);
126 0 : zval_ptr_dtor(&object->iterators[object->level--].zobject);
127 : }
128 0 : object->iterators = erealloc(object->iterators, sizeof(spl_sub_iterator));
129 0 : object->level = 0;
130 :
131 0 : zval_ptr_dtor(&iter->zobject);
132 0 : efree(iter);
133 0 : }
134 :
135 : static int spl_recursive_it_valid_ex(spl_recursive_it_object *object, zval *zthis TSRMLS_DC)
136 0 : {
137 : zend_object_iterator *sub_iter;
138 0 : int level = object->level;
139 :
140 0 : while (level >=0) {
141 0 : sub_iter = object->iterators[level].iterator;
142 0 : if (sub_iter->funcs->valid(sub_iter TSRMLS_CC) == SUCCESS) {
143 0 : return SUCCESS;
144 : }
145 0 : level--;
146 : }
147 0 : if (object->endIteration && object->in_iteration) {
148 0 : zend_call_method_with_0_params(&zthis, object->ce, &object->endIteration, "endIteration", NULL);
149 : }
150 0 : object->in_iteration = 0;
151 0 : return FAILURE;
152 : }
153 :
154 : static int spl_recursive_it_valid(zend_object_iterator *iter TSRMLS_DC)
155 0 : {
156 0 : spl_recursive_it_object *object = (spl_recursive_it_object*)iter->data;
157 :
158 0 : return spl_recursive_it_valid_ex(object, ((spl_recursive_it_iterator*)iter)->zobject TSRMLS_CC);
159 : }
160 :
161 : static void spl_recursive_it_get_current_data(zend_object_iterator *iter, zval ***data TSRMLS_DC)
162 0 : {
163 0 : spl_recursive_it_object *object = (spl_recursive_it_object*)iter->data;
164 0 : zend_object_iterator *sub_iter = object->iterators[object->level].iterator;
165 :
166 0 : sub_iter->funcs->get_current_data(sub_iter, data TSRMLS_CC);
167 0 : }
168 :
169 : static int spl_recursive_it_get_current_key(zend_object_iterator *iter, char **str_key, uint *str_key_len, ulong *int_key TSRMLS_DC)
170 0 : {
171 0 : spl_recursive_it_object *object = (spl_recursive_it_object*)iter->data;
172 0 : zend_object_iterator *sub_iter = object->iterators[object->level].iterator;
173 :
174 0 : if (sub_iter->funcs->get_current_key) {
175 0 : return sub_iter->funcs->get_current_key(sub_iter, str_key, str_key_len, int_key TSRMLS_CC);
176 : } else {
177 0 : *int_key = iter->index;
178 0 : return HASH_KEY_IS_LONG;
179 : }
180 : }
181 :
182 : static void spl_recursive_it_move_forward_ex(spl_recursive_it_object *object, zval *zthis TSRMLS_DC)
183 0 : {
184 : zend_object_iterator *iterator;
185 : zval *zobject;
186 : zend_class_entry *ce;
187 : zval *retval, *child;
188 : zend_object_iterator *sub_iter;
189 : int has_children;
190 :
191 0 : while (!EG(exception)) {
192 0 : next_step:
193 0 : iterator = object->iterators[object->level].iterator;
194 0 : switch (object->iterators[object->level].state) {
195 : case RS_NEXT:
196 0 : iterator->funcs->move_forward(iterator TSRMLS_CC);
197 0 : if (EG(exception)) {
198 0 : if (!(object->flags & RIT_CATCH_GET_CHILD)) {
199 0 : return;
200 : } else {
201 0 : zend_clear_exception(TSRMLS_C);
202 : }
203 : }
204 : case RS_START:
205 0 : if (iterator->funcs->valid(iterator TSRMLS_CC) == FAILURE) {
206 0 : break;
207 : }
208 0 : object->iterators[object->level].state = RS_TEST;
209 : /* break; */
210 : case RS_TEST:
211 0 : ce = object->iterators[object->level].ce;
212 0 : zobject = object->iterators[object->level].zobject;
213 0 : if (object->callHasChildren) {
214 0 : zend_call_method_with_0_params(&zthis, object->ce, &object->callHasChildren, "callHasChildren", &retval);
215 : } else {
216 0 : zend_call_method_with_0_params(&zobject, ce, NULL, "haschildren", &retval);
217 : }
218 0 : if (EG(exception)) {
219 0 : if (!(object->flags & RIT_CATCH_GET_CHILD)) {
220 0 : object->iterators[object->level].state = RS_NEXT;
221 0 : return;
222 : } else {
223 0 : zend_clear_exception(TSRMLS_C);
224 : }
225 : }
226 0 : if (retval) {
227 0 : has_children = zend_is_true(retval);
228 0 : zval_ptr_dtor(&retval);
229 0 : if (has_children) {
230 0 : if (object->max_depth == -1 || object->max_depth > object->level) {
231 0 : switch (object->mode) {
232 : case RIT_LEAVES_ONLY:
233 : case RIT_CHILD_FIRST:
234 0 : object->iterators[object->level].state = RS_CHILD;
235 0 : goto next_step;
236 : case RIT_SELF_FIRST:
237 0 : object->iterators[object->level].state = RS_SELF;
238 0 : goto next_step;
239 : }
240 : } else {
241 : /* do not recurse into */
242 0 : if (object->mode == RIT_LEAVES_ONLY) {
243 : /* this is not a leave, so skip it */
244 0 : object->iterators[object->level].state = RS_NEXT;
245 0 : goto next_step;
246 : }
247 : }
248 : }
249 : }
250 0 : if (object->nextElement) {
251 0 : zend_call_method_with_0_params(&zthis, object->ce, &object->nextElement, "nextelement", NULL);
252 : }
253 0 : object->iterators[object->level].state = RS_NEXT;
254 0 : if (EG(exception)) {
255 0 : if (!(object->flags & RIT_CATCH_GET_CHILD)) {
256 0 : return;
257 : } else {
258 0 : zend_clear_exception(TSRMLS_C);
259 : }
260 : }
261 0 : return /* self */;
262 : case RS_SELF:
263 0 : if (object->nextElement && (object->mode == RIT_SELF_FIRST || object->mode == RIT_CHILD_FIRST)) {
264 0 : zend_call_method_with_0_params(&zthis, object->ce, &object->nextElement, "nextelement", NULL);
265 : }
266 0 : if (object->mode == RIT_SELF_FIRST) {
267 0 : object->iterators[object->level].state = RS_CHILD;
268 : } else {
269 0 : object->iterators[object->level].state = RS_NEXT;
270 : }
271 0 : return /* self */;
272 : case RS_CHILD:
273 0 : ce = object->iterators[object->level].ce;
274 0 : zobject = object->iterators[object->level].zobject;
275 0 : if (object->callGetChildren) {
276 0 : zend_call_method_with_0_params(&zthis, object->ce, &object->callGetChildren, "callGetChildren", &child);
277 : } else {
278 0 : zend_call_method_with_0_params(&zobject, ce, NULL, "getchildren", &child);
279 : }
280 :
281 0 : if (EG(exception)) {
282 0 : if (!(object->flags & RIT_CATCH_GET_CHILD)) {
283 0 : return;
284 : } else {
285 0 : zend_clear_exception(TSRMLS_C);
286 0 : if (child) {
287 0 : zval_ptr_dtor(&child);
288 : }
289 0 : object->iterators[object->level].state = RS_NEXT;
290 0 : goto next_step;
291 : }
292 : }
293 :
294 0 : ce = child && Z_TYPE_P(child) == IS_OBJECT ? Z_OBJCE_P(child) : NULL;
295 0 : if (!ce || !instanceof_function(ce, spl_ce_RecursiveIterator TSRMLS_CC)) {
296 0 : if (child) {
297 0 : zval_ptr_dtor(&child);
298 : }
299 0 : zend_throw_exception(spl_ce_UnexpectedValueException, "Objects returned by RecursiveIterator::getChildren() must implement RecursiveIterator", 0 TSRMLS_CC);
300 0 : return;
301 : }
302 0 : if (object->mode == RIT_CHILD_FIRST) {
303 0 : object->iterators[object->level].state = RS_SELF;
304 : } else {
305 0 : object->iterators[object->level].state = RS_NEXT;
306 : }
307 0 : object->iterators = erealloc(object->iterators, sizeof(spl_sub_iterator) * (++object->level+1));
308 0 : sub_iter = ce->get_iterator(ce, child, 0 TSRMLS_CC);
309 0 : object->iterators[object->level].iterator = sub_iter;
310 0 : object->iterators[object->level].zobject = child;
311 0 : object->iterators[object->level].ce = ce;
312 0 : object->iterators[object->level].state = RS_START;
313 0 : if (sub_iter->funcs->rewind) {
314 0 : sub_iter->funcs->rewind(sub_iter TSRMLS_CC);
315 : }
316 0 : if (object->beginChildren) {
317 0 : zend_call_method_with_0_params(&zthis, object->ce, &object->beginChildren, "beginchildren", NULL);
318 0 : if (EG(exception)) {
319 0 : if (!(object->flags & RIT_CATCH_GET_CHILD)) {
320 0 : return;
321 : } else {
322 0 : zend_clear_exception(TSRMLS_C);
323 : }
324 : }
325 : }
326 0 : goto next_step;
327 : }
328 : /* no more elements */
329 0 : if (object->level > 0) {
330 0 : if (object->endChildren) {
331 0 : zend_call_method_with_0_params(&zthis, object->ce, &object->endChildren, "endchildren", NULL);
332 0 : if (EG(exception)) {
333 0 : if (!(object->flags & RIT_CATCH_GET_CHILD)) {
334 0 : return;
335 : } else {
336 0 : zend_clear_exception(TSRMLS_C);
337 : }
338 : }
339 : }
340 0 : iterator->funcs->dtor(iterator TSRMLS_CC);
341 0 : zval_ptr_dtor(&object->iterators[object->level].zobject);
342 0 : object->level--;
343 : } else {
344 0 : return; /* done completeley */
345 : }
346 : }
347 : }
348 :
349 : static void spl_recursive_it_rewind_ex(spl_recursive_it_object *object, zval *zthis TSRMLS_DC)
350 0 : {
351 : zend_object_iterator *sub_iter;
352 :
353 0 : while (object->level) {
354 0 : sub_iter = object->iterators[object->level].iterator;
355 0 : sub_iter->funcs->dtor(sub_iter TSRMLS_CC);
356 0 : zval_ptr_dtor(&object->iterators[object->level--].zobject);
357 0 : if (!EG(exception) && (!object->endChildren || object->endChildren->common.scope != spl_ce_RecursiveIteratorIterator)) {
358 0 : zend_call_method_with_0_params(&zthis, object->ce, &object->endChildren, "endchildren", NULL);
359 : }
360 : }
361 0 : object->iterators = erealloc(object->iterators, sizeof(spl_sub_iterator));
362 0 : object->iterators[0].state = RS_START;
363 0 : sub_iter = object->iterators[0].iterator;
364 0 : if (sub_iter->funcs->rewind) {
365 0 : sub_iter->funcs->rewind(sub_iter TSRMLS_CC);
366 : }
367 0 : if (!EG(exception) && object->beginIteration && !object->in_iteration) {
368 0 : zend_call_method_with_0_params(&zthis, object->ce, &object->beginIteration, "beginIteration", NULL);
369 : }
370 0 : object->in_iteration = 1;
371 0 : spl_recursive_it_move_forward_ex(object, zthis TSRMLS_CC);
372 0 : }
373 :
374 : static void spl_recursive_it_move_forward(zend_object_iterator *iter TSRMLS_DC)
375 0 : {
376 0 : spl_recursive_it_move_forward_ex((spl_recursive_it_object*)iter->data, ((spl_recursive_it_iterator*)iter)->zobject TSRMLS_CC);
377 0 : }
378 :
379 : static void spl_recursive_it_rewind(zend_object_iterator *iter TSRMLS_DC)
380 0 : {
381 0 : spl_recursive_it_rewind_ex((spl_recursive_it_object*)iter->data, ((spl_recursive_it_iterator*)iter)->zobject TSRMLS_CC);
382 0 : }
383 :
384 : static zend_object_iterator *spl_recursive_it_get_iterator(zend_class_entry *ce, zval *zobject, int by_ref TSRMLS_DC)
385 0 : {
386 : spl_recursive_it_iterator *iterator;
387 : spl_recursive_it_object *object;
388 :
389 0 : if (by_ref) {
390 0 : zend_error(E_ERROR, "An iterator cannot be used with foreach by reference");
391 : }
392 0 : iterator = emalloc(sizeof(spl_recursive_it_iterator));
393 0 : object = (spl_recursive_it_object*)zend_object_store_get_object(zobject TSRMLS_CC);
394 :
395 0 : zobject->refcount++;
396 0 : iterator->intern.data = (void*)object;
397 0 : iterator->intern.funcs = ce->iterator_funcs.funcs;
398 0 : iterator->zobject = zobject;
399 0 : return (zend_object_iterator*)iterator;
400 : }
401 :
402 : zend_object_iterator_funcs spl_recursive_it_iterator_funcs = {
403 : spl_recursive_it_dtor,
404 : spl_recursive_it_valid,
405 : spl_recursive_it_get_current_data,
406 : spl_recursive_it_get_current_key,
407 : spl_recursive_it_move_forward,
408 : spl_recursive_it_rewind
409 : };
410 :
411 : /* {{{ proto void RecursiveIteratorIterator::__construct(RecursiveIterator|IteratorAggregate it [, int mode = RIT_LEAVES_ONLY [, int flags = 0]]) throws InvalidArgumentException
412 : Creates a RecursiveIteratorIterator from a RecursiveIterator. */
413 : SPL_METHOD(RecursiveIteratorIterator, __construct)
414 0 : {
415 0 : zval *object = getThis();
416 : spl_recursive_it_object *intern;
417 : zval *iterator;
418 : zend_class_entry *ce_iterator;
419 0 : long mode = RIT_LEAVES_ONLY, flags = 0;
420 0 : int inc_refcount = 1;
421 :
422 0 : php_set_error_handling(EH_THROW, spl_ce_InvalidArgumentException TSRMLS_CC);
423 :
424 0 : if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "o|ll", &iterator, &mode, &flags) == SUCCESS) {
425 0 : if (instanceof_function(Z_OBJCE_P(iterator), zend_ce_aggregate TSRMLS_CC)) {
426 0 : zval *aggregate = iterator;
427 0 : zend_call_method_with_0_params(&aggregate, Z_OBJCE_P(aggregate), &Z_OBJCE_P(aggregate)->iterator_funcs.zf_new_iterator, "getiterator", &iterator);
428 0 : inc_refcount = 0;
429 : }
430 : } else {
431 0 : iterator = NULL;
432 : }
433 0 : if (!iterator || !instanceof_function(Z_OBJCE_P(iterator), spl_ce_RecursiveIterator TSRMLS_CC)) {
434 0 : if (iterator && !inc_refcount) {
435 0 : zval_ptr_dtor(&iterator);
436 : }
437 0 : php_set_error_handling(EH_NORMAL, NULL TSRMLS_CC);
438 0 : zend_throw_exception(spl_ce_InvalidArgumentException, "An instance of RecursiveIterator or IteratorAggregate creating it is required", 0 TSRMLS_CC);
439 0 : return;
440 : }
441 :
442 0 : intern = (spl_recursive_it_object*)zend_object_store_get_object(object TSRMLS_CC);
443 0 : intern->iterators = emalloc(sizeof(spl_sub_iterator));
444 0 : intern->level = 0;
445 0 : intern->mode = mode;
446 0 : intern->flags = flags;
447 0 : intern->max_depth = -1;
448 0 : intern->in_iteration = 0;
449 0 : intern->ce = Z_OBJCE_P(object);
450 :
451 0 : zend_hash_find(&intern->ce->function_table, "beginiteration", sizeof("beginiteration"), (void **) &intern->beginIteration);
452 0 : if (intern->beginIteration->common.scope == spl_ce_RecursiveIteratorIterator) {
453 0 : intern->beginIteration = NULL;
454 : }
455 0 : zend_hash_find(&intern->ce->function_table, "enditeration", sizeof("enditeration"), (void **) &intern->endIteration);
456 0 : if (intern->endIteration->common.scope == spl_ce_RecursiveIteratorIterator) {
457 0 : intern->endIteration = NULL;
458 : }
459 0 : zend_hash_find(&intern->ce->function_table, "callhaschildren", sizeof("callHasChildren"), (void **) &intern->callHasChildren);
460 0 : if (intern->callHasChildren->common.scope == spl_ce_RecursiveIteratorIterator) {
461 0 : intern->callHasChildren = NULL;
462 : }
463 0 : zend_hash_find(&intern->ce->function_table, "callgetchildren", sizeof("callGetChildren"), (void **) &intern->callGetChildren);
464 0 : if (intern->callGetChildren->common.scope == spl_ce_RecursiveIteratorIterator) {
465 0 : intern->callGetChildren = NULL;
466 : }
467 0 : zend_hash_find(&intern->ce->function_table, "beginchildren", sizeof("beginchildren"), (void **) &intern->beginChildren);
468 0 : if (intern->beginChildren->common.scope == spl_ce_RecursiveIteratorIterator) {
469 0 : intern->beginChildren = NULL;
470 : }
471 0 : zend_hash_find(&intern->ce->function_table, "endchildren", sizeof("endchildren"), (void **) &intern->endChildren);
472 0 : if (intern->endChildren->common.scope == spl_ce_RecursiveIteratorIterator) {
473 0 : intern->endChildren = NULL;
474 : }
475 0 : zend_hash_find(&intern->ce->function_table, "nextelement", sizeof("nextElement"), (void **) &intern->nextElement);
476 0 : if (intern->nextElement->common.scope == spl_ce_RecursiveIteratorIterator) {
477 0 : intern->nextElement = NULL;
478 : }
479 0 : ce_iterator = Z_OBJCE_P(iterator); /* respect inheritance, don't use spl_ce_RecursiveIterator */
480 0 : intern->iterators[0].iterator = ce_iterator->get_iterator(ce_iterator, iterator, 0 TSRMLS_CC);
481 0 : if (inc_refcount) {
482 0 : iterator->refcount++;
483 : }
484 0 : intern->iterators[0].zobject = iterator;
485 0 : intern->iterators[0].ce = ce_iterator;
486 0 : intern->iterators[0].state = RS_START;
487 :
488 0 : php_set_error_handling(EH_NORMAL, NULL TSRMLS_CC);
489 : } /* }}} */
490 :
491 : /* {{{ proto void RecursiveIteratorIterator::rewind()
492 : Rewind the iterator to the first element of the top level inner iterator. */
493 : SPL_METHOD(RecursiveIteratorIterator, rewind)
494 0 : {
495 0 : spl_recursive_it_object *object = (spl_recursive_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
496 :
497 0 : spl_recursive_it_rewind_ex(object, getThis() TSRMLS_CC);
498 0 : } /* }}} */
499 :
500 : /* {{{ proto bool RecursiveIteratorIterator::valid()
501 : Check whether the current position is valid */
502 : SPL_METHOD(RecursiveIteratorIterator, valid)
503 0 : {
504 0 : spl_recursive_it_object *object = (spl_recursive_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
505 :
506 0 : RETURN_BOOL(spl_recursive_it_valid_ex(object, getThis() TSRMLS_CC) == SUCCESS);
507 : } /* }}} */
508 :
509 : /* {{{ proto mixed RecursiveIteratorIterator::key()
510 : Access the current key */
511 : SPL_METHOD(RecursiveIteratorIterator, key)
512 0 : {
513 0 : spl_recursive_it_object *object = (spl_recursive_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
514 0 : zend_object_iterator *iterator = object->iterators[object->level].iterator;
515 :
516 0 : if (iterator->funcs->get_current_key) {
517 : char *str_key;
518 : uint str_key_len;
519 : ulong int_key;
520 0 : if (iterator->funcs->get_current_key(iterator, &str_key, &str_key_len, &int_key TSRMLS_CC) == HASH_KEY_IS_LONG) {
521 0 : RETURN_LONG(int_key);
522 : } else {
523 0 : RETURN_STRINGL(str_key, str_key_len-1, 0);
524 : }
525 : } else {
526 0 : RETURN_NULL();
527 : }
528 : } /* }}} */
529 :
530 : /* {{{ proto mixed RecursiveIteratorIterator::current()
531 : Access the current element value */
532 : SPL_METHOD(RecursiveIteratorIterator, current)
533 0 : {
534 0 : spl_recursive_it_object *object = (spl_recursive_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
535 0 : zend_object_iterator *iterator = object->iterators[object->level].iterator;
536 : zval **data;
537 :
538 0 : iterator->funcs->get_current_data(iterator, &data TSRMLS_CC);
539 0 : RETURN_ZVAL(*data, 1, 0);
540 : } /* }}} */
541 :
542 : /* {{{ proto void RecursiveIteratorIterator::next()
543 : Move forward to the next element */
544 : SPL_METHOD(RecursiveIteratorIterator, next)
545 0 : {
546 0 : spl_recursive_it_object *object = (spl_recursive_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
547 :
548 0 : spl_recursive_it_move_forward_ex(object, getThis() TSRMLS_CC);
549 0 : } /* }}} */
550 :
551 : /* {{{ proto int RecursiveIteratorIterator::getDepth()
552 : Get the current depth of the recursive iteration */
553 : SPL_METHOD(RecursiveIteratorIterator, getDepth)
554 0 : {
555 0 : spl_recursive_it_object *object = (spl_recursive_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
556 :
557 0 : RETURN_LONG(object->level);
558 : } /* }}} */
559 :
560 : /* {{{ proto RecursiveIterator RecursiveIteratorIterator::getSubIterator([int level])
561 : The current active sub iterator or the iterator at specified level */
562 : SPL_METHOD(RecursiveIteratorIterator, getSubIterator)
563 0 : {
564 0 : spl_recursive_it_object *object = (spl_recursive_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
565 0 : long level = object->level;
566 :
567 0 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &level) == FAILURE) {
568 0 : return;
569 : }
570 0 : if (level < 0 || level > object->level) {
571 0 : RETURN_NULL();
572 : }
573 0 : RETURN_ZVAL(object->iterators[level].zobject, 1, 0);
574 : } /* }}} */
575 :
576 : /* {{{ proto RecursiveIterator RecursiveIteratorIterator::getInnerIterator()
577 : The current active sub iterator */
578 : SPL_METHOD(RecursiveIteratorIterator, getInnerIterator)
579 0 : {
580 0 : spl_recursive_it_object *object = (spl_recursive_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
581 0 : long level = object->level;
582 :
583 0 : RETURN_ZVAL(object->iterators[level].zobject, 1, 0);
584 : } /* }}} */
585 :
586 : /* {{{ proto RecursiveIterator RecursiveIteratorIterator::beginIteration()
587 : Called when iteration begins (after first rewind() call) */
588 : SPL_METHOD(RecursiveIteratorIterator, beginIteration)
589 0 : {
590 : /* nothing to do */
591 0 : } /* }}} */
592 :
593 : /* {{{ proto RecursiveIterator RecursiveIteratorIterator::endIteration()
594 : Called when iteration ends (when valid() first returns false */
595 : SPL_METHOD(RecursiveIteratorIterator, endIteration)
596 0 : {
597 : /* nothing to do */
598 0 : } /* }}} */
599 :
600 : /* {{{ proto bool RecursiveIteratorIterator::callHasChildren()
601 : Called for each element to test whether it has children */
602 : SPL_METHOD(RecursiveIteratorIterator, callHasChildren)
603 0 : {
604 0 : spl_recursive_it_object *object = (spl_recursive_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
605 0 : zend_class_entry *ce = object->iterators[object->level].ce;
606 : zval *retval, *zobject;
607 :
608 0 : zobject = object->iterators[object->level].zobject;
609 0 : if (!zobject) {
610 0 : RETURN_FALSE;
611 : } else {
612 0 : zend_call_method_with_0_params(&zobject, ce, NULL, "haschildren", &retval);
613 0 : if (retval) {
614 0 : RETURN_ZVAL(retval, 0, 1);
615 : } else {
616 0 : RETURN_FALSE;
617 : }
618 : }
619 : } /* }}} */
620 :
621 : /* {{{ proto RecursiveIterator RecursiveIteratorIterator::callGetChildren()
622 : Return children of current element */
623 : SPL_METHOD(RecursiveIteratorIterator, callGetChildren)
624 0 : {
625 0 : spl_recursive_it_object *object = (spl_recursive_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
626 0 : zend_class_entry *ce = object->iterators[object->level].ce;
627 : zval *retval, *zobject;
628 :
629 0 : zobject = object->iterators[object->level].zobject;
630 0 : if (!zobject) {
631 0 : return;
632 : } else {
633 0 : zend_call_method_with_0_params(&zobject, ce, NULL, "getchildren", &retval);
634 0 : if (retval) {
635 0 : RETURN_ZVAL(retval, 0, 1);
636 : }
637 : }
638 : } /* }}} */
639 :
640 : /* {{{ proto void RecursiveIteratorIterator::beginChildren()
641 : Called when recursing one level down */
642 : SPL_METHOD(RecursiveIteratorIterator, beginChildren)
643 0 : {
644 : /* nothing to do */
645 0 : } /* }}} */
646 :
647 : /* {{{ proto void RecursiveIteratorIterator::endChildren()
648 : Called when end recursing one level */
649 : SPL_METHOD(RecursiveIteratorIterator, endChildren)
650 0 : {
651 : /* nothing to do */
652 0 : } /* }}} */
653 :
654 : /* {{{ proto void RecursiveIteratorIterator::nextElement()
655 : Called when the next element is available */
656 : SPL_METHOD(RecursiveIteratorIterator, nextElement)
657 0 : {
658 : /* nothing to do */
659 0 : } /* }}} */
660 :
661 : /* {{{ proto void RecursiveIteratorIterator::setMaxDepth([$max_depth = -1])
662 : Set the maximum allowed depth (or any depth if pmax_depth = -1] */
663 : SPL_METHOD(RecursiveIteratorIterator, setMaxDepth)
664 0 : {
665 0 : spl_recursive_it_object *object = (spl_recursive_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
666 0 : long max_depth = -1;
667 :
668 0 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &max_depth) == FAILURE) {
669 0 : return;
670 : }
671 0 : if (max_depth < -1) {
672 0 : zend_throw_exception(spl_ce_OutOfRangeException, "Parameter max_depth must be >= -1", 0 TSRMLS_CC);
673 0 : return;
674 : }
675 0 : object->max_depth = max_depth;
676 : } /* }}} */
677 :
678 : /* {{{ proto int|false RecursiveIteratorIterator::getMaxDepth()
679 : Return the maximum accepted depth or false if any depth is allowed */
680 : SPL_METHOD(RecursiveIteratorIterator, getMaxDepth)
681 0 : {
682 0 : spl_recursive_it_object *object = (spl_recursive_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
683 :
684 0 : if (object->max_depth == -1) {
685 0 : RETURN_FALSE;
686 : } else {
687 0 : RETURN_LONG(object->max_depth);
688 : }
689 : } /* }}} */
690 :
691 : static union _zend_function *spl_recursive_it_get_method(zval **object_ptr, char *method, int method_len TSRMLS_DC)
692 0 : {
693 : union _zend_function *function_handler;
694 0 : spl_recursive_it_object *object = (spl_recursive_it_object*)zend_object_store_get_object(*object_ptr TSRMLS_CC);
695 0 : long level = object->level;
696 0 : zval *zobj = object->iterators[level].zobject;
697 :
698 0 : function_handler = std_object_handlers.get_method(object_ptr, method, method_len TSRMLS_CC);
699 0 : if (!function_handler) {
700 0 : if (zend_hash_find(&Z_OBJCE_P(zobj)->function_table, method, method_len+1, (void **) &function_handler) == FAILURE) {
701 0 : if (Z_OBJ_HT_P(zobj)->get_method) {
702 0 : *object_ptr = zobj;
703 0 : function_handler = Z_OBJ_HT_P(*object_ptr)->get_method(object_ptr, method, method_len TSRMLS_CC);
704 : }
705 : }
706 : }
707 0 : return function_handler;
708 : }
709 :
710 : /* {{{ spl_RecursiveIteratorIterator_dtor */
711 : static void spl_RecursiveIteratorIterator_free_storage(void *_object TSRMLS_DC)
712 0 : {
713 0 : spl_recursive_it_object *object = (spl_recursive_it_object *)_object;
714 : zend_object_iterator *sub_iter;
715 :
716 0 : if (object->iterators) {
717 0 : while (object->level >= 0) {
718 0 : sub_iter = object->iterators[object->level].iterator;
719 0 : sub_iter->funcs->dtor(sub_iter TSRMLS_CC);
720 0 : zval_ptr_dtor(&object->iterators[object->level--].zobject);
721 : }
722 0 : efree(object->iterators);
723 0 : object->iterators = NULL;
724 : }
725 :
726 0 : zend_object_std_dtor(&object->std TSRMLS_CC);
727 :
728 0 : efree(object);
729 0 : }
730 : /* }}} */
731 :
732 : /* {{{ spl_RecursiveIteratorIterator_new */
733 : static zend_object_value spl_RecursiveIteratorIterator_new(zend_class_entry *class_type TSRMLS_DC)
734 0 : {
735 : zend_object_value retval;
736 : spl_recursive_it_object *intern;
737 : zval *tmp;
738 :
739 0 : intern = emalloc(sizeof(spl_recursive_it_object));
740 0 : memset(intern, 0, sizeof(spl_recursive_it_object));
741 :
742 0 : zend_object_std_init(&intern->std, class_type TSRMLS_CC);
743 0 : zend_hash_copy(intern->std.properties, &class_type->default_properties, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *));
744 :
745 0 : retval.handle = zend_objects_store_put(intern, (zend_objects_store_dtor_t)zend_objects_destroy_object, (zend_objects_free_object_storage_t) spl_RecursiveIteratorIterator_free_storage, NULL TSRMLS_CC);
746 0 : retval.handlers = &spl_handlers_rec_it_it;
747 0 : return retval;
748 : }
749 : /* }}} */
750 :
751 : static
752 : ZEND_BEGIN_ARG_INFO_EX(arginfo_recursive_it___construct, 0, 0, 1)
753 : ZEND_ARG_OBJ_INFO(0, iterator, Traversable, 0)
754 : ZEND_ARG_INFO(0, mode)
755 : ZEND_ARG_INFO(0, flags)
756 : ZEND_END_ARG_INFO();
757 :
758 : static
759 : ZEND_BEGIN_ARG_INFO_EX(arginfo_recursive_it_getSubIterator, 0, 0, 0)
760 : ZEND_ARG_INFO(0, level)
761 : ZEND_END_ARG_INFO();
762 :
763 : static
764 : ZEND_BEGIN_ARG_INFO_EX(arginfo_recursive_it_setMaxDepth, 0, 0, 0)
765 : ZEND_ARG_INFO(0, max_depth)
766 : ZEND_END_ARG_INFO();
767 :
768 : static zend_function_entry spl_funcs_RecursiveIteratorIterator[] = {
769 : SPL_ME(RecursiveIteratorIterator, __construct, arginfo_recursive_it___construct, ZEND_ACC_PUBLIC)
770 : SPL_ME(RecursiveIteratorIterator, rewind, NULL, ZEND_ACC_PUBLIC)
771 : SPL_ME(RecursiveIteratorIterator, valid, NULL, ZEND_ACC_PUBLIC)
772 : SPL_ME(RecursiveIteratorIterator, key, NULL, ZEND_ACC_PUBLIC)
773 : SPL_ME(RecursiveIteratorIterator, current, NULL, ZEND_ACC_PUBLIC)
774 : SPL_ME(RecursiveIteratorIterator, next, NULL, ZEND_ACC_PUBLIC)
775 : SPL_ME(RecursiveIteratorIterator, getDepth, NULL, ZEND_ACC_PUBLIC)
776 : SPL_ME(RecursiveIteratorIterator, getSubIterator, arginfo_recursive_it_getSubIterator, ZEND_ACC_PUBLIC)
777 : SPL_ME(RecursiveIteratorIterator, getInnerIterator, NULL, ZEND_ACC_PUBLIC)
778 : SPL_ME(RecursiveIteratorIterator, beginIteration, NULL, ZEND_ACC_PUBLIC)
779 : SPL_ME(RecursiveIteratorIterator, endIteration, NULL, ZEND_ACC_PUBLIC)
780 : SPL_ME(RecursiveIteratorIterator, callHasChildren, NULL, ZEND_ACC_PUBLIC)
781 : SPL_ME(RecursiveIteratorIterator, callGetChildren, NULL, ZEND_ACC_PUBLIC)
782 : SPL_ME(RecursiveIteratorIterator, beginChildren, NULL, ZEND_ACC_PUBLIC)
783 : SPL_ME(RecursiveIteratorIterator, endChildren, NULL, ZEND_ACC_PUBLIC)
784 : SPL_ME(RecursiveIteratorIterator, nextElement, NULL, ZEND_ACC_PUBLIC)
785 : SPL_ME(RecursiveIteratorIterator, setMaxDepth, arginfo_recursive_it_setMaxDepth, ZEND_ACC_PUBLIC)
786 : SPL_ME(RecursiveIteratorIterator, getMaxDepth, NULL, ZEND_ACC_PUBLIC)
787 : {NULL, NULL, NULL}
788 : };
789 :
790 : #if MBO_0
791 : static int spl_dual_it_gets_implemented(zend_class_entry *interface, zend_class_entry *class_type TSRMLS_DC)
792 : {
793 : class_type->iterator_funcs.zf_valid = NULL;
794 : class_type->iterator_funcs.zf_current = NULL;
795 : class_type->iterator_funcs.zf_key = NULL;
796 : class_type->iterator_funcs.zf_next = NULL;
797 : class_type->iterator_funcs.zf_rewind = NULL;
798 : if (!class_type->iterator_funcs.funcs) {
799 : class_type->iterator_funcs.funcs = &zend_interface_iterator_funcs_iterator;
800 : }
801 :
802 : return SUCCESS;
803 : }
804 : #endif
805 :
806 : static union _zend_function *spl_dual_it_get_method(zval **object_ptr, char *method, int method_len TSRMLS_DC)
807 0 : {
808 : union _zend_function *function_handler;
809 : spl_dual_it_object *intern;
810 :
811 0 : intern = (spl_dual_it_object*)zend_object_store_get_object(*object_ptr TSRMLS_CC);
812 :
813 0 : function_handler = std_object_handlers.get_method(object_ptr, method, method_len TSRMLS_CC);
814 0 : if (!function_handler) {
815 0 : if (zend_hash_find(&intern->inner.ce->function_table, method, method_len+1, (void **) &function_handler) == FAILURE) {
816 0 : if (Z_OBJ_HT_P(intern->inner.zobject)->get_method) {
817 0 : *object_ptr = intern->inner.zobject;
818 0 : function_handler = Z_OBJ_HT_P(*object_ptr)->get_method(object_ptr, method, method_len TSRMLS_CC);
819 : }
820 : }
821 : }
822 0 : return function_handler;
823 : }
824 :
825 : #if MBO_0
826 : int spl_dual_it_call_method(char *method, INTERNAL_FUNCTION_PARAMETERS)
827 : {
828 : zval ***func_params, func;
829 : zval *retval_ptr;
830 : int arg_count;
831 : int current = 0;
832 : int success;
833 : void **p;
834 : spl_dual_it_object *intern;
835 :
836 : intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
837 :
838 : ZVAL_STRING(&func, method, 0);
839 : if (!zend_is_callable(&func, 0, &method)) {
840 : php_error_docref(NULL TSRMLS_CC, E_ERROR, "Method %s::%s() does not exist", intern->inner.ce->name, method);
841 : return FAILURE;
842 : }
843 :
844 : p = EG(argument_stack).top_element-2;
845 : arg_count = (ulong) *p;
846 :
847 : func_params = safe_emalloc(sizeof(zval **), arg_count, 0);
848 :
849 : current = 0;
850 : while (arg_count-- > 0) {
851 : func_params[current] = (zval **) p - (arg_count-current);
852 : current++;
853 : }
854 :
855 : if (call_user_function_ex(EG(function_table), NULL, &func, &retval_ptr, arg_count, func_params, 0, NULL TSRMLS_CC) == SUCCESS && retval_ptr) {
856 : RETURN_ZVAL(retval_ptr, 0, 1);
857 :
858 : success = SUCCESS;
859 : } else {
860 : php_error_docref(NULL TSRMLS_CC, E_ERROR, "Unable to call %s::%s()", intern->inner.ce->name, method);
861 : success = FAILURE;
862 : }
863 :
864 : efree(func_params);
865 : return success;
866 : }
867 : #endif
868 :
869 : #define SPL_CHECK_CTOR(intern, classname) \
870 : if (intern->dit_type == DIT_Unknown) { \
871 : zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "Classes derived from %s must call %s::__construct()", \
872 : (spl_ce_##classname)->name, (spl_ce_##classname)->name); \
873 : return; \
874 : }
875 :
876 : #define APPENDIT_CHECK_CTOR(intern) SPL_CHECK_CTOR(intern, AppendIterator)
877 :
878 : static inline int spl_dual_it_fetch(spl_dual_it_object *intern, int check_more TSRMLS_DC);
879 :
880 : static inline int spl_cit_check_flags(int flags)
881 0 : {
882 0 : int cnt = 0;
883 :
884 0 : cnt += (flags & CIT_CALL_TOSTRING) ? 1 : 0;
885 0 : cnt += (flags & CIT_TOSTRING_USE_KEY) ? 1 : 0;
886 0 : cnt += (flags & CIT_TOSTRING_USE_CURRENT) ? 1 : 0;
887 0 : cnt += (flags & CIT_TOSTRING_USE_INNER) ? 1 : 0;
888 :
889 0 : return cnt <= 1 ? SUCCESS : FAILURE;
890 : }
891 :
892 : static spl_dual_it_object* spl_dual_it_construct(INTERNAL_FUNCTION_PARAMETERS, zend_class_entry *ce_base, zend_class_entry *ce_inner, dual_it_type dit_type)
893 0 : {
894 : zval *zobject, *retval;
895 : spl_dual_it_object *intern;
896 0 : zend_class_entry *ce = NULL;
897 0 : int inc_refcount = 1;
898 :
899 0 : intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
900 :
901 0 : if (intern->dit_type != DIT_Unknown) {
902 0 : zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "%s::getIterator() must be called exactly once per instance", ce_base->name);
903 0 : return NULL;
904 : }
905 :
906 0 : php_set_error_handling(EH_THROW, spl_ce_InvalidArgumentException TSRMLS_CC);
907 :
908 0 : intern->dit_type = dit_type;
909 0 : switch (dit_type) {
910 : case DIT_LimitIterator: {
911 0 : intern->u.limit.offset = 0; /* start at beginning */
912 0 : intern->u.limit.count = -1; /* get all */
913 0 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O|ll", &zobject, ce_inner, &intern->u.limit.offset, &intern->u.limit.count) == FAILURE) {
914 0 : php_set_error_handling(EH_NORMAL, NULL TSRMLS_CC);
915 0 : return NULL;
916 : }
917 0 : if (intern->u.limit.offset < 0) {
918 0 : php_set_error_handling(EH_NORMAL, NULL TSRMLS_CC);
919 0 : zend_throw_exception(spl_ce_OutOfRangeException, "Parameter offset must be > 0", 0 TSRMLS_CC);
920 0 : return NULL;
921 : }
922 0 : if (intern->u.limit.count < 0 && intern->u.limit.count != -1) {
923 0 : php_set_error_handling(EH_NORMAL, NULL TSRMLS_CC);
924 0 : zend_throw_exception(spl_ce_OutOfRangeException, "Parameter count must either be -1 or a value greater than or equal 0", 0 TSRMLS_CC);
925 0 : return NULL;
926 : }
927 0 : break;
928 : }
929 : case DIT_CachingIterator:
930 : case DIT_RecursiveCachingIterator: {
931 0 : long flags = CIT_CALL_TOSTRING;
932 0 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O|l", &zobject, ce_inner, &flags) == FAILURE) {
933 0 : php_set_error_handling(EH_NORMAL, NULL TSRMLS_CC);
934 0 : return NULL;
935 : }
936 0 : if (spl_cit_check_flags(flags) != SUCCESS) {
937 0 : php_set_error_handling(EH_NORMAL, NULL TSRMLS_CC);
938 0 : zend_throw_exception(spl_ce_InvalidArgumentException, "Flags must contain only one of CALL_TOSTRING, TOSTRING_USE_KEY, TOSTRING_USE_CURRENT, TOSTRING_USE_CURRENT", 0 TSRMLS_CC);
939 0 : return NULL;
940 : }
941 0 : intern->u.caching.flags |= flags & CIT_PUBLIC;
942 0 : MAKE_STD_ZVAL(intern->u.caching.zcache);
943 0 : array_init(intern->u.caching.zcache);
944 0 : break;
945 : }
946 : case DIT_IteratorIterator: {
947 : zend_class_entry **pce_cast;
948 : char * class_name;
949 : int class_name_len;
950 :
951 0 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O|s", &zobject, ce_inner, &class_name, &class_name_len) == FAILURE) {
952 0 : php_set_error_handling(EH_NORMAL, NULL TSRMLS_CC);
953 0 : return NULL;
954 : }
955 0 : ce = Z_OBJCE_P(zobject);
956 0 : if (!instanceof_function(ce, zend_ce_iterator TSRMLS_CC)) {
957 0 : if (ZEND_NUM_ARGS() > 1) {
958 0 : if (zend_lookup_class(class_name, class_name_len, &pce_cast TSRMLS_CC) == FAILURE
959 : || !instanceof_function(ce, *pce_cast TSRMLS_CC)
960 : || !(*pce_cast)->get_iterator
961 : ) {
962 0 : zend_throw_exception(spl_ce_LogicException, "Class to downcast to not found or not base class or does not implement Traversable", 0 TSRMLS_CC);
963 0 : php_set_error_handling(EH_NORMAL, NULL TSRMLS_CC);
964 0 : return NULL;
965 : }
966 0 : ce = *pce_cast;
967 : }
968 0 : if (instanceof_function(ce, zend_ce_aggregate TSRMLS_CC)) {
969 0 : zend_call_method_with_0_params(&zobject, ce, &ce->iterator_funcs.zf_new_iterator, "getiterator", &retval);
970 0 : if (EG(exception)) {
971 0 : if (retval) {
972 0 : zval_ptr_dtor(&retval);
973 : }
974 0 : php_set_error_handling(EH_NORMAL, NULL TSRMLS_CC);
975 0 : return NULL;
976 : }
977 0 : if (!retval || Z_TYPE_P(retval) != IS_OBJECT || !instanceof_function(Z_OBJCE_P(retval), zend_ce_traversable TSRMLS_CC)) {
978 0 : zend_throw_exception_ex(spl_ce_LogicException, 0 TSRMLS_CC, "%s::getIterator() must return an object that implememnts Traversable", ce->name);
979 0 : php_set_error_handling(EH_NORMAL, NULL TSRMLS_CC);
980 0 : return NULL;
981 : }
982 0 : zobject = retval;
983 0 : ce = Z_OBJCE_P(zobject);
984 0 : inc_refcount = 0;
985 : }
986 : }
987 0 : break;
988 : }
989 : case DIT_AppendIterator:
990 0 : spl_instantiate(spl_ce_ArrayIterator, &intern->u.append.zarrayit, 1 TSRMLS_CC);
991 0 : zend_call_method_with_0_params(&intern->u.append.zarrayit, spl_ce_ArrayIterator, &spl_ce_ArrayIterator->constructor, "__construct", NULL);
992 0 : intern->u.append.iterator = spl_ce_ArrayIterator->get_iterator(spl_ce_ArrayIterator, intern->u.append.zarrayit, 0 TSRMLS_CC);
993 0 : php_set_error_handling(EH_NORMAL, NULL TSRMLS_CC);
994 0 : return intern;
995 : #if HAVE_PCRE || HAVE_BUNDLED_PCRE
996 : case DIT_RegexIterator:
997 : case DIT_RecursiveRegexIterator: {
998 : char *regex;
999 : int regex_len;
1000 : long mode = REGIT_MODE_MATCH;
1001 :
1002 : intern->u.regex.use_flags = ZEND_NUM_ARGS() >= 5;
1003 : intern->u.regex.flags = 0;
1004 : intern->u.regex.preg_flags = 0;
1005 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Os|lll", &zobject, ce_inner, ®ex, ®ex_len, &mode, &intern->u.regex.flags, &intern->u.regex.preg_flags) == FAILURE) {
1006 : php_set_error_handling(EH_NORMAL, NULL TSRMLS_CC);
1007 : return NULL;
1008 : }
1009 : if (mode < 0 || mode >= REGIT_MODE_MAX) {
1010 : zend_throw_exception_ex(spl_ce_InvalidArgumentException, 0 TSRMLS_CC, "Illegal mode %ld", mode);
1011 : php_set_error_handling(EH_NORMAL, NULL TSRMLS_CC);
1012 : return NULL;
1013 : }
1014 : intern->u.regex.mode = mode;
1015 : intern->u.regex.regex = estrndup(regex, regex_len);
1016 : intern->u.regex.pce = pcre_get_compiled_regex_cache(regex, regex_len TSRMLS_CC);
1017 : if (intern->u.regex.pce == NULL) {
1018 : /* pcre_get_compiled_regex_cache has already sent error */
1019 : php_set_error_handling(EH_NORMAL, NULL TSRMLS_CC);
1020 : return NULL;
1021 : }
1022 : intern->u.regex.pce->refcount++;
1023 : break;
1024 : }
1025 : #endif
1026 : default:
1027 0 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &zobject, ce_inner) == FAILURE) {
1028 0 : php_set_error_handling(EH_NORMAL, NULL TSRMLS_CC);
1029 0 : return NULL;
1030 : }
1031 : break;
1032 : }
1033 :
1034 0 : php_set_error_handling(EH_THROW, zend_exception_get_default(TSRMLS_C) TSRMLS_CC);
1035 :
1036 0 : if (inc_refcount) {
1037 0 : zobject->refcount++;
1038 : }
1039 0 : intern->inner.zobject = zobject;
1040 0 : intern->inner.ce = dit_type == DIT_IteratorIterator ? ce : Z_OBJCE_P(zobject);
1041 0 : intern->inner.object = zend_object_store_get_object(zobject TSRMLS_CC);
1042 0 : intern->inner.iterator = intern->inner.ce->get_iterator(intern->inner.ce, zobject, 0 TSRMLS_CC);
1043 :
1044 0 : php_set_error_handling(EH_NORMAL, NULL TSRMLS_CC);
1045 0 : return intern;
1046 : }
1047 :
1048 : /* {{{ proto void FilterIterator::__construct(Iterator it)
1049 : Create an Iterator from another iterator */
1050 : SPL_METHOD(FilterIterator, __construct)
1051 0 : {
1052 0 : spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_FilterIterator, zend_ce_iterator, DIT_FilterIterator);
1053 0 : } /* }}} */
1054 :
1055 : /* {{{ proto Iterator FilterIterator::getInnerIterator()
1056 : proto Iterator CachingIterator::getInnerIterator()
1057 : proto Iterator LimitIterator::getInnerIterator()
1058 : proto Iterator ParentIterator::getInnerIterator()
1059 : Get the inner iterator */
1060 : SPL_METHOD(dual_it, getInnerIterator)
1061 0 : {
1062 : spl_dual_it_object *intern;
1063 :
1064 0 : intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
1065 :
1066 0 : if (intern->inner.zobject) {
1067 0 : RETVAL_ZVAL(intern->inner.zobject, 1, 0);
1068 : } else {
1069 0 : RETURN_NULL();
1070 : }
1071 : } /* }}} */
1072 :
1073 : static inline void spl_dual_it_require(spl_dual_it_object *intern TSRMLS_DC)
1074 0 : {
1075 0 : if (!intern->inner.iterator) {
1076 0 : php_error_docref(NULL TSRMLS_CC, E_ERROR, "The inner constructor wasn't initialized with an iterator instance");
1077 : }
1078 0 : }
1079 :
1080 : static inline void spl_dual_it_free(spl_dual_it_object *intern TSRMLS_DC)
1081 0 : {
1082 0 : if (intern->inner.iterator && intern->inner.iterator->funcs->invalidate_current) {
1083 0 : intern->inner.iterator->funcs->invalidate_current(intern->inner.iterator TSRMLS_CC);
1084 : }
1085 0 : if (intern->current.data) {
1086 0 : zval_ptr_dtor(&intern->current.data);
1087 0 : intern->current.data = NULL;
1088 : }
1089 0 : if (intern->current.str_key) {
1090 0 : efree(intern->current.str_key);
1091 0 : intern->current.str_key = NULL;
1092 : }
1093 0 : if (intern->dit_type == DIT_CachingIterator || intern->dit_type == DIT_RecursiveCachingIterator) {
1094 0 : if (intern->u.caching.zstr) {
1095 0 : zval_ptr_dtor(&intern->u.caching.zstr);
1096 0 : intern->u.caching.zstr = NULL;
1097 : }
1098 0 : if (intern->u.caching.zchildren) {
1099 0 : zval_ptr_dtor(&intern->u.caching.zchildren);
1100 0 : intern->u.caching.zchildren = NULL;
1101 : }
1102 : }
1103 0 : }
1104 :
1105 : static inline void spl_dual_it_rewind(spl_dual_it_object *intern TSRMLS_DC)
1106 0 : {
1107 0 : spl_dual_it_free(intern TSRMLS_CC);
1108 0 : intern->current.pos = 0;
1109 0 : if (intern->inner.iterator->funcs->rewind) {
1110 0 : intern->inner.iterator->funcs->rewind(intern->inner.iterator TSRMLS_CC);
1111 : }
1112 0 : }
1113 :
1114 : static inline int spl_dual_it_valid(spl_dual_it_object *intern TSRMLS_DC)
1115 0 : {
1116 : /* FAILURE / SUCCESS */
1117 0 : return intern->inner.iterator->funcs->valid(intern->inner.iterator TSRMLS_CC);
1118 : }
1119 :
1120 : static inline int spl_dual_it_fetch(spl_dual_it_object *intern, int check_more TSRMLS_DC)
1121 0 : {
1122 : zval **data;
1123 :
1124 0 : spl_dual_it_free(intern TSRMLS_CC);
1125 0 : if (!check_more || spl_dual_it_valid(intern TSRMLS_CC) == SUCCESS) {
1126 0 : intern->inner.iterator->funcs->get_current_data(intern->inner.iterator, &data TSRMLS_CC);
1127 0 : intern->current.data = *data;
1128 0 : intern->current.data->refcount++;
1129 0 : if (intern->inner.iterator->funcs->get_current_key) {
1130 0 : intern->current.key_type = intern->inner.iterator->funcs->get_current_key(intern->inner.iterator, &intern->current.str_key, &intern->current.str_key_len, &intern->current.int_key TSRMLS_CC);
1131 : } else {
1132 0 : intern->current.key_type = HASH_KEY_IS_LONG;
1133 0 : intern->current.int_key = intern->current.pos;
1134 : }
1135 0 : return SUCCESS;
1136 : }
1137 0 : return FAILURE;
1138 : }
1139 :
1140 : static inline void spl_dual_it_next(spl_dual_it_object *intern, int do_free TSRMLS_DC)
1141 0 : {
1142 0 : if (do_free) {
1143 0 : spl_dual_it_free(intern TSRMLS_CC);
1144 : } else {
1145 0 : spl_dual_it_require(intern TSRMLS_CC);
1146 : }
1147 0 : intern->inner.iterator->funcs->move_forward(intern->inner.iterator TSRMLS_CC);
1148 0 : intern->current.pos++;
1149 0 : }
1150 :
1151 : /* {{{ proto void ParentIterator::rewind()
1152 : proto void IteratorIterator::rewind()
1153 : Rewind the iterator
1154 : */
1155 : SPL_METHOD(dual_it, rewind)
1156 0 : {
1157 : spl_dual_it_object *intern;
1158 :
1159 0 : intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
1160 0 : spl_dual_it_rewind(intern TSRMLS_CC);
1161 0 : spl_dual_it_fetch(intern, 1 TSRMLS_CC);
1162 0 : } /* }}} */
1163 :
1164 : /* {{{ proto bool FilterIterator::valid()
1165 : proto bool ParentIterator::valid()
1166 : proto bool IteratorIterator::valid()
1167 : proto bool NoRewindIterator::valid()
1168 : Check whether the current element is valid */
1169 : SPL_METHOD(dual_it, valid)
1170 0 : {
1171 : spl_dual_it_object *intern;
1172 :
1173 0 : intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
1174 :
1175 0 : RETURN_BOOL(intern->current.data);
1176 : } /* }}} */
1177 :
1178 : /* {{{ proto mixed FilterIterator::key()
1179 : proto mixed CachingIterator::key()
1180 : proto mixed LimitIterator::key()
1181 : proto mixed ParentIterator::key()
1182 : proto mixed IteratorIterator::key()
1183 : proto mixed NoRewindIterator::key()
1184 : proto mixed AppendIterator::key()
1185 : Get the current key */
1186 : SPL_METHOD(dual_it, key)
1187 0 : {
1188 : spl_dual_it_object *intern;
1189 :
1190 0 : intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
1191 :
1192 0 : if (intern->current.data) {
1193 0 : if (intern->current.key_type == HASH_KEY_IS_STRING) {
1194 0 : RETURN_STRINGL(intern->current.str_key, intern->current.str_key_len-1, 1);
1195 : } else {
1196 0 : RETURN_LONG(intern->current.int_key);
1197 : }
1198 : }
1199 0 : RETURN_NULL();
1200 : } /* }}} */
1201 :
1202 : /* {{{ proto mixed FilterIterator::current()
1203 : proto mixed CachingIterator::current()
1204 : proto mixed LimitIterator::current()
1205 : proto mixed ParentIterator::current()
1206 : proto mixed IteratorIterator::current()
1207 : proto mixed NoRewindIterator::current()
1208 : proto mixed AppendIterator::current()
1209 : Get the current element value */
1210 : SPL_METHOD(dual_it, current)
1211 0 : {
1212 : spl_dual_it_object *intern;
1213 :
1214 0 : intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
1215 :
1216 0 : if (intern->current.data) {
1217 0 : RETVAL_ZVAL(intern->current.data, 1, 0);
1218 : } else {
1219 0 : RETURN_NULL();
1220 : }
1221 : } /* }}} */
1222 :
1223 : /* {{{ proto void ParentIterator::next()
1224 : proto void IteratorIterator::next()
1225 : proto void NoRewindIterator::next()
1226 : Move the iterator forward */
1227 : SPL_METHOD(dual_it, next)
1228 0 : {
1229 : spl_dual_it_object *intern;
1230 :
1231 0 : intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
1232 :
1233 0 : spl_dual_it_next(intern, 1 TSRMLS_CC);
1234 0 : spl_dual_it_fetch(intern, 1 TSRMLS_CC);
1235 0 : } /* }}} */
1236 :
1237 : static inline void spl_filter_it_fetch(zval *zthis, spl_dual_it_object *intern TSRMLS_DC)
1238 0 : {
1239 : zval *retval;
1240 :
1241 0 : while (spl_dual_it_fetch(intern, 1 TSRMLS_CC) == SUCCESS) {
1242 0 : zend_call_method_with_0_params(&zthis, intern->std.ce, NULL, "accept", &retval);
1243 0 : if (retval) {
1244 0 : if (zend_is_true(retval)) {
1245 0 : zval_ptr_dtor(&retval);
1246 0 : return;
1247 : }
1248 0 : zval_ptr_dtor(&retval);
1249 : }
1250 0 : if (EG(exception)) {
1251 0 : return;
1252 : }
1253 0 : intern->inner.iterator->funcs->move_forward(intern->inner.iterator TSRMLS_CC);
1254 : }
1255 0 : spl_dual_it_free(intern TSRMLS_CC);
1256 : }
1257 :
1258 : static inline void spl_filter_it_rewind(zval *zthis, spl_dual_it_object *intern TSRMLS_DC)
1259 0 : {
1260 0 : spl_dual_it_rewind(intern TSRMLS_CC);
1261 0 : spl_filter_it_fetch(zthis, intern TSRMLS_CC);
1262 0 : }
1263 :
1264 : static inline void spl_filter_it_next(zval *zthis, spl_dual_it_object *intern TSRMLS_DC)
1265 0 : {
1266 0 : spl_dual_it_next(intern, 1 TSRMLS_CC);
1267 0 : spl_filter_it_fetch(zthis, intern TSRMLS_CC);
1268 0 : }
1269 :
1270 : /* {{{ proto void FilterIterator::rewind()
1271 : Rewind the iterator */
1272 : SPL_METHOD(FilterIterator, rewind)
1273 0 : {
1274 : spl_dual_it_object *intern;
1275 :
1276 0 : intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
1277 0 : spl_filter_it_rewind(getThis(), intern TSRMLS_CC);
1278 0 : } /* }}} */
1279 :
1280 : /* {{{ proto void FilterIterator::next()
1281 : Move the iterator forward */
1282 : SPL_METHOD(FilterIterator, next)
1283 0 : {
1284 : spl_dual_it_object *intern;
1285 :
1286 0 : intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
1287 0 : spl_filter_it_next(getThis(), intern TSRMLS_CC);
1288 0 : } /* }}} */
1289 :
1290 : /* {{{ proto void RecursiveFilterIterator::__construct(RecursiveIterator it)
1291 : Create a RecursiveFilterIterator from a RecursiveIterator */
1292 : SPL_METHOD(RecursiveFilterIterator, __construct)
1293 0 : {
1294 0 : spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_RecursiveFilterIterator, spl_ce_RecursiveIterator, DIT_RecursiveFilterIterator);
1295 0 : } /* }}} */
1296 :
1297 : /* {{{ proto bool RecursiveFilterIterator::hasChildren()
1298 : Check whether the inner iterator's current element has children */
1299 : SPL_METHOD(RecursiveFilterIterator, hasChildren)
1300 0 : {
1301 : spl_dual_it_object *intern;
1302 : zval *retval;
1303 :
1304 0 : intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
1305 :
1306 0 : zend_call_method_with_0_params(&intern->inner.zobject, intern->inner.ce, NULL, "haschildren", &retval);
1307 0 : if (retval) {
1308 0 : RETURN_ZVAL(retval, 0, 1);
1309 : } else {
1310 0 : RETURN_FALSE;
1311 : }
1312 : } /* }}} */
1313 :
1314 : /* {{{ proto RecursiveFilterIterator RecursiveFilterIterator::getChildren()
1315 : Return the inner iterator's children contained in a RecursiveFilterIterator */
1316 : SPL_METHOD(RecursiveFilterIterator, getChildren)
1317 0 : {
1318 : spl_dual_it_object *intern;
1319 : zval *retval;
1320 :
1321 0 : intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
1322 :
1323 0 : zend_call_method_with_0_params(&intern->inner.zobject, intern->inner.ce, NULL, "getchildren", &retval);
1324 0 : if (!EG(exception) && retval) {
1325 0 : spl_instantiate_arg_ex1(Z_OBJCE_P(getThis()), &return_value, 0, retval TSRMLS_CC);
1326 : }
1327 0 : if (retval) {
1328 0 : zval_ptr_dtor(&retval);
1329 : }
1330 0 : } /* }}} */
1331 :
1332 : /* {{{ proto void ParentIterator::__construct(RecursiveIterator it)
1333 : Create a ParentIterator from a RecursiveIterator */
1334 : SPL_METHOD(ParentIterator, __construct)
1335 0 : {
1336 0 : spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_ParentIterator, spl_ce_RecursiveIterator, DIT_ParentIterator);
1337 0 : } /* }}} */
1338 :
1339 : #if HAVE_PCRE || HAVE_BUNDLED_PCRE
1340 : /* {{{ proto void RegexIterator::__construct(Iterator it, string regex [, int mode [, int flags [, int preg_flags]]])
1341 : Create an RegexIterator from another iterator and a regular expression */
1342 : SPL_METHOD(RegexIterator, __construct)
1343 : {
1344 : spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_RegexIterator, zend_ce_iterator, DIT_RegexIterator);
1345 : } /* }}} */
1346 :
1347 : /* {{{ proto bool RegexIterator::accept()
1348 : Match (string)current() against regular expression */
1349 : SPL_METHOD(RegexIterator, accept)
1350 : {
1351 : spl_dual_it_object *intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
1352 : char *subject, tmp[32], *result;
1353 : int subject_len, use_copy, count, result_len;
1354 : zval subject_copy, zcount, *replacement;
1355 :
1356 : if (intern->u.regex.flags & REGIT_USE_KEY) {
1357 : if (intern->current.key_type == HASH_KEY_IS_LONG) {
1358 : subject_len = slprintf(tmp, sizeof(tmp), "%ld", intern->current.int_key);
1359 : subject = &tmp[0];
1360 : use_copy = 0;
1361 : } else {
1362 : subject_len = intern->current.str_key_len - 1;
1363 : subject = estrndup(intern->current.str_key, subject_len);
1364 : use_copy = 1;
1365 : }
1366 : } else {
1367 : zend_make_printable_zval(intern->current.data, &subject_copy, &use_copy);
1368 : if (use_copy) {
1369 : subject = Z_STRVAL(subject_copy);
1370 : subject_len = Z_STRLEN(subject_copy);
1371 : } else {
1372 : subject = Z_STRVAL_P(intern->current.data);
1373 : subject_len = Z_STRLEN_P(intern->current.data);
1374 : }
1375 : }
1376 :
1377 : switch (intern->u.regex.mode)
1378 : {
1379 : case REGIT_MODE_MAX: /* won't happen but makes compiler happy */
1380 : case REGIT_MODE_MATCH:
1381 : count = pcre_exec(intern->u.regex.pce->re, intern->u.regex.pce->extra, subject, subject_len, 0, 0, NULL, 0);
1382 : RETVAL_BOOL(count >= 0);
1383 : break;
1384 :
1385 : case REGIT_MODE_ALL_MATCHES:
1386 : case REGIT_MODE_GET_MATCH:
1387 : if (!use_copy) {
1388 : subject = estrndup(subject, subject_len);
1389 : use_copy = 1;
1390 : }
1391 : zval_ptr_dtor(&intern->current.data);
1392 : ALLOC_INIT_ZVAL(intern->current.data);
1393 : php_pcre_match_impl(intern->u.regex.pce, subject, subject_len, &zcount,
1394 : intern->current.data, intern->u.regex.mode == REGIT_MODE_ALL_MATCHES, intern->u.regex.use_flags, intern->u.regex.preg_flags, 0 TSRMLS_CC);
1395 : count = zend_hash_num_elements(Z_ARRVAL_P(intern->current.data));
1396 : RETVAL_BOOL(count > 0);
1397 : break;
1398 :
1399 : case REGIT_MODE_SPLIT:
1400 : if (!use_copy) {
1401 : subject = estrndup(subject, subject_len);
1402 : use_copy = 1;
1403 : }
1404 : zval_ptr_dtor(&intern->current.data);
1405 : ALLOC_INIT_ZVAL(intern->current.data);
1406 : php_pcre_split_impl(intern->u.regex.pce, subject, subject_len, intern->current.data, -1, intern->u.regex.preg_flags TSRMLS_CC);
1407 : count = zend_hash_num_elements(Z_ARRVAL_P(intern->current.data));
1408 : RETVAL_BOOL(count > 1);
1409 : break;
1410 :
1411 : case REGIT_MODE_REPLACE:
1412 : replacement = zend_read_property(intern->std.ce, getThis(), "replacement", sizeof("replacement")-1, 1 TSRMLS_CC);
1413 : result = php_pcre_replace_impl(intern->u.regex.pce, subject, subject_len, replacement, 0, &result_len, 0, NULL TSRMLS_CC);
1414 :
1415 : if (intern->u.regex.flags & REGIT_USE_KEY) {
1416 : if (intern->current.key_type != HASH_KEY_IS_LONG) {
1417 : efree(intern->current.str_key);
1418 : }
1419 : intern->current.key_type = HASH_KEY_IS_STRING;
1420 : intern->current.str_key = result;
1421 : intern->current.str_key_len = result_len + 1;
1422 : } else {
1423 : zval_ptr_dtor(&intern->current.data);
1424 : MAKE_STD_ZVAL(intern->current.data);
1425 : ZVAL_STRINGL(intern->current.data, result, result_len, 0);
1426 : }
1427 : }
1428 :
1429 : if (use_copy) {
1430 : efree(subject);
1431 : }
1432 : } /* }}} */
1433 :
1434 : /* {{{ proto bool RegexIterator::getMode()
1435 : Returns current operation mode */
1436 : SPL_METHOD(RegexIterator, getMode)
1437 : {
1438 : spl_dual_it_object *intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
1439 :
1440 : RETURN_LONG(intern->u.regex.mode);
1441 : } /* }}} */
1442 :
1443 : /* {{{ proto bool RegexIterator::setMode(int new_mode)
1444 : Set new operation mode */
1445 : SPL_METHOD(RegexIterator, setMode)
1446 : {
1447 : spl_dual_it_object *intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
1448 : long mode;
1449 :
1450 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &mode) == FAILURE) {
1451 : return;
1452 : }
1453 :
1454 : if (mode < 0 || mode >= REGIT_MODE_MAX) {
1455 : zend_throw_exception_ex(spl_ce_InvalidArgumentException, 0 TSRMLS_CC, "Illegal mode %ld", mode);
1456 : return;/* NULL */
1457 : }
1458 :
1459 : intern->u.regex.mode = mode;
1460 : } /* }}} */
1461 :
1462 : /* {{{ proto bool RegexIterator::getFlags()
1463 : Returns current operation flags */
1464 : SPL_METHOD(RegexIterator, getFlags)
1465 : {
1466 : spl_dual_it_object *intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
1467 :
1468 : RETURN_LONG(intern->u.regex.flags);
1469 : } /* }}} */
1470 :
1471 : /* {{{ proto bool RegexIterator::setFlags(int new_flags)
1472 : Set operation flags */
1473 : SPL_METHOD(RegexIterator, setFlags)
1474 : {
1475 : spl_dual_it_object *intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
1476 : long flags;
1477 :
1478 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &flags) == FAILURE) {
1479 : return;
1480 : }
1481 :
1482 : intern->u.regex.flags = flags;
1483 : } /* }}} */
1484 :
1485 : /* {{{ proto bool RegexIterator::getFlags()
1486 : Returns current PREG flags (if in use or NULL) */
1487 : SPL_METHOD(RegexIterator, getPregFlags)
1488 : {
1489 : spl_dual_it_object *intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
1490 :
1491 : if (intern->u.regex.use_flags) {
1492 : RETURN_LONG(intern->u.regex.preg_flags);
1493 : } else {
1494 : return;
1495 : }
1496 : } /* }}} */
1497 :
1498 : /* {{{ proto bool RegexIterator::setPregFlags(int new_flags)
1499 : Set PREG flags */
1500 : SPL_METHOD(RegexIterator, setPregFlags)
1501 : {
1502 : spl_dual_it_object *intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
1503 : long preg_flags;
1504 :
1505 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &preg_flags) == FAILURE) {
1506 : return;
1507 : }
1508 :
1509 : intern->u.regex.preg_flags = preg_flags;
1510 : intern->u.regex.use_flags = 1;
1511 : } /* }}} */
1512 :
1513 : /* {{{ proto void RecursiveRegexIterator::__construct(RecursiveIterator it, string regex [, int mode [, int flags [, int preg_flags]]])
1514 : Create an RecursiveRegexIterator from another recursive iterator and a regular expression */
1515 : SPL_METHOD(RecursiveRegexIterator, __construct)
1516 : {
1517 : spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_RecursiveRegexIterator, spl_ce_RecursiveIterator, DIT_RecursiveRegexIterator);
1518 : } /* }}} */
1519 :
1520 : /* {{{ proto RecursiveRegexIterator RecursiveRegexIterator::getChildren()
1521 : Return the inner iterator's children contained in a RecursiveRegexIterator */
1522 : SPL_METHOD(RecursiveRegexIterator, getChildren)
1523 : {
1524 : spl_dual_it_object *intern;
1525 : zval *retval, *regex;
1526 :
1527 : intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
1528 :
1529 : zend_call_method_with_0_params(&intern->inner.zobject, intern->inner.ce, NULL, "getchildren", &retval);
1530 : if (!EG(exception)) {
1531 : MAKE_STD_ZVAL(regex);
1532 : ZVAL_STRING(regex, intern->u.regex.regex, 1);
1533 : spl_instantiate_arg_ex2(Z_OBJCE_P(getThis()), &return_value, 0, retval, regex TSRMLS_CC);
1534 : zval_ptr_dtor(®ex);
1535 : }
1536 : if (retval) {
1537 : zval_ptr_dtor(&retval);
1538 : }
1539 : } /* }}} */
1540 :
1541 : #endif
1542 :
1543 : /* {{{ spl_dual_it_free_storage */
1544 : static void spl_dual_it_free_storage(void *_object TSRMLS_DC)
1545 0 : {
1546 0 : spl_dual_it_object *object = (spl_dual_it_object *)_object;
1547 :
1548 0 : spl_dual_it_free(object TSRMLS_CC);
1549 :
1550 0 : if (object->inner.iterator) {
1551 0 : object->inner.iterator->funcs->dtor(object->inner.iterator TSRMLS_CC);
1552 : }
1553 :
1554 0 : if (object->inner.zobject) {
1555 0 : zval_ptr_dtor(&object->inner.zobject);
1556 : }
1557 :
1558 0 : if (object->dit_type == DIT_AppendIterator) {
1559 0 : object->u.append.iterator->funcs->dtor(object->u.append.iterator TSRMLS_CC);
1560 0 : if (object->u.append.zarrayit) {
1561 0 : zval_ptr_dtor(&object->u.append.zarrayit);
1562 : }
1563 : }
1564 :
1565 0 : if (object->dit_type == DIT_CachingIterator || object->dit_type == DIT_RecursiveCachingIterator) {
1566 0 : if (object->u.caching.zcache) {
1567 0 : zval_ptr_dtor(&object->u.caching.zcache);
1568 0 : object->u.caching.zcache = NULL;
1569 : }
1570 : }
1571 :
1572 : #if HAVE_PCRE || HAVE_BUNDLED_PCRE
1573 : if (object->dit_type == DIT_RegexIterator || object->dit_type == DIT_RecursiveRegexIterator) {
1574 : if (object->u.regex.pce) {
1575 : object->u.regex.pce->refcount--;
1576 : }
1577 : if (object->u.regex.regex) {
1578 : efree(object->u.regex.regex);
1579 : }
1580 : }
1581 : #endif
1582 :
1583 0 : zend_object_std_dtor(&object->std TSRMLS_CC);
1584 :
1585 0 : efree(object);
1586 0 : }
1587 : /* }}} */
1588 :
1589 : /* {{{ spl_dual_it_new */
1590 : static zend_object_value spl_dual_it_new(zend_class_entry *class_type TSRMLS_DC)
1591 0 : {
1592 : zend_object_value retval;
1593 : spl_dual_it_object *intern;
1594 : zval *tmp;
1595 :
1596 0 : intern = emalloc(sizeof(spl_dual_it_object));
1597 0 : memset(intern, 0, sizeof(spl_dual_it_object));
1598 0 : intern->dit_type = DIT_Unknown;
1599 :
1600 0 : zend_object_std_init(&intern->std, class_type TSRMLS_CC);
1601 0 : zend_hash_copy(intern->std.properties, &class_type->default_properties, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *));
1602 :
1603 0 : retval.handle = zend_objects_store_put(intern, (zend_objects_store_dtor_t)zend_objects_destroy_object, (zend_objects_free_object_storage_t) spl_dual_it_free_storage, NULL TSRMLS_CC);
1604 0 : retval.handlers = &spl_handlers_dual_it;
1605 0 : return retval;
1606 : }
1607 : /* }}} */
1608 :
1609 : static
1610 : ZEND_BEGIN_ARG_INFO(arginfo_filter_it___construct, 0)
1611 : ZEND_ARG_OBJ_INFO(0, iterator, Iterator, 0)
1612 : ZEND_END_ARG_INFO();
1613 :
1614 : static zend_function_entry spl_funcs_FilterIterator[] = {
1615 : SPL_ME(FilterIterator, __construct, arginfo_filter_it___construct, ZEND_ACC_PUBLIC)
1616 : SPL_ME(FilterIterator, rewind, NULL, ZEND_ACC_PUBLIC)
1617 : SPL_ME(dual_it, valid, NULL, ZEND_ACC_PUBLIC)
1618 : SPL_ME(dual_it, key, NULL, ZEND_ACC_PUBLIC)
1619 : SPL_ME(dual_it, current, NULL, ZEND_ACC_PUBLIC)
1620 : SPL_ME(FilterIterator, next, NULL, ZEND_ACC_PUBLIC)
1621 : SPL_ME(dual_it, getInnerIterator, NULL, ZEND_ACC_PUBLIC)
1622 : SPL_ABSTRACT_ME(FilterIterator, accept, NULL)
1623 : {NULL, NULL, NULL}
1624 : };
1625 :
1626 : static
1627 : ZEND_BEGIN_ARG_INFO(arginfo_parent_it___construct, 0)
1628 : ZEND_ARG_OBJ_INFO(0, iterator, RecursiveIterator, 0)
1629 : ZEND_END_ARG_INFO();
1630 :
1631 : static zend_function_entry spl_funcs_RecursiveFilterIterator[] = {
1632 : SPL_ME(RecursiveFilterIterator, __construct, arginfo_parent_it___construct, ZEND_ACC_PUBLIC)
1633 : SPL_ME(RecursiveFilterIterator, hasChildren, NULL, ZEND_ACC_PUBLIC)
1634 : SPL_ME(RecursiveFilterIterator, getChildren, NULL, ZEND_ACC_PUBLIC)
1635 : {NULL, NULL, NULL}
1636 : };
1637 :
1638 : static zend_function_entry spl_funcs_ParentIterator[] = {
1639 : SPL_ME(ParentIterator, __construct, arginfo_parent_it___construct, ZEND_ACC_PUBLIC)
1640 : SPL_MA(ParentIterator, accept, RecursiveFilterIterator, hasChildren, NULL, ZEND_ACC_PUBLIC)
1641 : {NULL, NULL, NULL}
1642 : };
1643 :
1644 : #if HAVE_PCRE || HAVE_BUNDLED_PCRE
1645 : static
1646 : ZEND_BEGIN_ARG_INFO_EX(arginfo_regex_it___construct, 0, 0, 2)
1647 : ZEND_ARG_OBJ_INFO(0, iterator, Iterator, 0)
1648 : ZEND_ARG_INFO(0, regex)
1649 : ZEND_ARG_INFO(0, mode)
1650 : ZEND_ARG_INFO(0, flags)
1651 : ZEND_ARG_INFO(0, preg_flags)
1652 : ZEND_END_ARG_INFO();
1653 :
1654 : static
1655 : ZEND_BEGIN_ARG_INFO_EX(arginfo_regex_it_set_mode, 0, 0, 1)
1656 : ZEND_ARG_INFO(0, mode)
1657 : ZEND_END_ARG_INFO();
1658 :
1659 : static
1660 : ZEND_BEGIN_ARG_INFO_EX(arginfo_regex_it_set_flags, 0, 0, 1)
1661 : ZEND_ARG_INFO(0, flags)
1662 : ZEND_END_ARG_INFO();
1663 :
1664 : static
1665 : ZEND_BEGIN_ARG_INFO_EX(arginfo_regex_it_set_preg_flags, 0, 0, 1)
1666 : ZEND_ARG_INFO(0, preg_flags)
1667 : ZEND_END_ARG_INFO();
1668 :
1669 : static zend_function_entry spl_funcs_RegexIterator[] = {
1670 : SPL_ME(RegexIterator, __construct, arginfo_regex_it___construct, ZEND_ACC_PUBLIC)
1671 : SPL_ME(RegexIterator, accept, NULL, ZEND_ACC_PUBLIC)
1672 : SPL_ME(RegexIterator, getMode, NULL, ZEND_ACC_PUBLIC)
1673 : SPL_ME(RegexIterator, setMode, arginfo_regex_it_set_mode, ZEND_ACC_PUBLIC)
1674 : SPL_ME(RegexIterator, getFlags, NULL, ZEND_ACC_PUBLIC)
1675 : SPL_ME(RegexIterator, setFlags, arginfo_regex_it_set_flags, ZEND_ACC_PUBLIC)
1676 : SPL_ME(RegexIterator, getPregFlags, NULL, ZEND_ACC_PUBLIC)
1677 : SPL_ME(RegexIterator, setPregFlags, arginfo_regex_it_set_preg_flags, ZEND_ACC_PUBLIC)
1678 : {NULL, NULL, NULL}
1679 : };
1680 :
1681 : static
1682 : ZEND_BEGIN_ARG_INFO_EX(arginfo_rec_regex_it___construct, 0, 0, 2)
1683 : ZEND_ARG_OBJ_INFO(0, iterator, RecursiveIterator, 0)
1684 : ZEND_ARG_INFO(0, regex)
1685 : ZEND_ARG_INFO(0, mode)
1686 : ZEND_ARG_INFO(0, flags)
1687 : ZEND_ARG_INFO(0, preg_flags)
1688 : ZEND_END_ARG_INFO();
1689 :
1690 : static zend_function_entry spl_funcs_RecursiveRegexIterator[] = {
1691 : SPL_ME(RecursiveRegexIterator, __construct, arginfo_rec_regex_it___construct, ZEND_ACC_PUBLIC)
1692 : SPL_ME(RecursiveFilterIterator, hasChildren, NULL, ZEND_ACC_PUBLIC)
1693 : SPL_ME(RecursiveRegexIterator, getChildren, NULL, ZEND_ACC_PUBLIC)
1694 : {NULL, NULL, NULL}
1695 : };
1696 : #endif
1697 :
1698 : static inline int spl_limit_it_valid(spl_dual_it_object *intern TSRMLS_DC)
1699 0 : {
1700 : /* FAILURE / SUCCESS */
1701 0 : if (intern->u.limit.count != -1 && intern->current.pos >= intern->u.limit.offset + intern->u.limit.count) {
1702 0 : return FAILURE;
1703 : } else {
1704 0 : return spl_dual_it_valid(intern TSRMLS_CC);
1705 : }
1706 : }
1707 :
1708 : static inline void spl_limit_it_seek(spl_dual_it_object *intern, long pos TSRMLS_DC)
1709 0 : {
1710 : zval *zpos;
1711 :
1712 0 : spl_dual_it_free(intern TSRMLS_CC);
1713 0 : if (pos < intern->u.limit.offset) {
1714 0 : zend_throw_exception_ex(spl_ce_OutOfBoundsException, 0 TSRMLS_CC, "Cannot seek to %ld which is below the offset %ld", pos, intern->u.limit.offset);
1715 0 : return;
1716 : }
1717 0 : if (pos >= intern->u.limit.offset + intern->u.limit.count && intern->u.limit.count != -1) {
1718 0 : zend_throw_exception_ex(spl_ce_OutOfBoundsException, 0 TSRMLS_CC, "Cannot seek to %ld which is behind offest %ld plus count %ld", pos, intern->u.limit.offset, intern->u.limit.count);
1719 0 : return;
1720 : }
1721 0 : if (instanceof_function(intern->inner.ce, spl_ce_SeekableIterator TSRMLS_CC)) {
1722 0 : MAKE_STD_ZVAL(zpos);
1723 0 : ZVAL_LONG(zpos, pos);
1724 0 : spl_dual_it_free(intern TSRMLS_CC);
1725 0 : zend_call_method_with_1_params(&intern->inner.zobject, intern->inner.ce, NULL, "seek", NULL, zpos);
1726 0 : zval_ptr_dtor(&zpos);
1727 0 : if (!EG(exception)) {
1728 0 : intern->current.pos = pos;
1729 0 : if (spl_limit_it_valid(intern TSRMLS_CC) == SUCCESS) {
1730 0 : spl_dual_it_fetch(intern, 0 TSRMLS_CC);
1731 : }
1732 : }
1733 : } else {
1734 : /* emulate the forward seek, by next() calls */
1735 : /* a back ward seek is done by a previous rewind() */
1736 0 : if (pos < intern->current.pos) {
1737 0 : spl_dual_it_rewind(intern TSRMLS_CC);
1738 : }
1739 0 : while (pos > intern->current.pos && spl_dual_it_valid(intern TSRMLS_CC) == SUCCESS) {
1740 0 : spl_dual_it_next(intern, 1 TSRMLS_CC);
1741 : }
1742 0 : if (spl_dual_it_valid(intern TSRMLS_CC) == SUCCESS) {
1743 0 : spl_dual_it_fetch(intern, 1 TSRMLS_CC);
1744 : }
1745 : }
1746 : }
1747 :
1748 : /* {{{ proto LimitIterator::__construct(Iterator it [, int offset, int count])
1749 : Construct a LimitIterator from an Iterator with a given starting offset and optionally a maximum count */
1750 : SPL_METHOD(LimitIterator, __construct)
1751 0 : {
1752 0 : spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_LimitIterator, zend_ce_iterator, DIT_LimitIterator);
1753 0 : } /* }}} */
1754 :
1755 : /* {{{ proto void LimitIterator::rewind()
1756 : Rewind the iterator to the specified starting offset */
1757 : SPL_METHOD(LimitIterator, rewind)
1758 0 : {
1759 : spl_dual_it_object *intern;
1760 :
1761 0 : intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
1762 0 : spl_dual_it_rewind(intern TSRMLS_CC);
1763 0 : spl_limit_it_seek(intern, intern->u.limit.offset TSRMLS_CC);
1764 0 : } /* }}} */
1765 :
1766 : /* {{{ proto bool LimitIterator::valid()
1767 : Check whether the current element is valid */
1768 : SPL_METHOD(LimitIterator, valid)
1769 0 : {
1770 : spl_dual_it_object *intern;
1771 :
1772 0 : intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
1773 :
1774 : /* RETURN_BOOL(spl_limit_it_valid(intern TSRMLS_CC) == SUCCESS);*/
1775 0 : RETURN_BOOL((intern->u.limit.count == -1 || intern->current.pos < intern->u.limit.offset + intern->u.limit.count) && intern->current.data);
1776 : } /* }}} */
1777 :
1778 : /* {{{ proto void LimitIterator::next()
1779 : Move the iterator forward */
1780 : SPL_METHOD(LimitIterator, next)
1781 0 : {
1782 : spl_dual_it_object *intern;
1783 :
1784 0 : intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
1785 :
1786 0 : spl_dual_it_next(intern, 1 TSRMLS_CC);
1787 0 : if (intern->u.limit.count == -1 || intern->current.pos < intern->u.limit.offset + intern->u.limit.count) {
1788 0 : spl_dual_it_fetch(intern, 1 TSRMLS_CC);
1789 : }
1790 0 : } /* }}} */
1791 :
1792 : /* {{{ proto void LimitIterator::seek(int position)
1793 : Seek to the given position */
1794 : SPL_METHOD(LimitIterator, seek)
1795 0 : {
1796 : spl_dual_it_object *intern;
1797 : long pos;
1798 :
1799 0 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &pos) == FAILURE) {
1800 0 : return;
1801 : }
1802 :
1803 0 : intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
1804 0 : spl_limit_it_seek(intern, pos TSRMLS_CC);
1805 0 : RETURN_LONG(intern->current.pos);
1806 : } /* }}} */
1807 :
1808 : /* {{{ proto int LimitIterator::getPosition()
1809 : Return the current position */
1810 : SPL_METHOD(LimitIterator, getPosition)
1811 0 : {
1812 : spl_dual_it_object *intern;
1813 0 : intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
1814 0 : RETURN_LONG(intern->current.pos);
1815 : } /* }}} */
1816 :
1817 : static
1818 : ZEND_BEGIN_ARG_INFO(arginfo_seekable_it_seek, 0)
1819 : ZEND_ARG_INFO(0, position)
1820 : ZEND_END_ARG_INFO();
1821 :
1822 : static zend_function_entry spl_funcs_SeekableIterator[] = {
1823 : SPL_ABSTRACT_ME(SeekableIterator, seek, arginfo_seekable_it_seek)
1824 : {NULL, NULL, NULL}
1825 : };
1826 :
1827 : static
1828 : ZEND_BEGIN_ARG_INFO_EX(arginfo_limit_it___construct, 0, 0, 1)
1829 : ZEND_ARG_OBJ_INFO(0, iterator, Iterator, 0)
1830 : ZEND_ARG_INFO(0, offset)
1831 : ZEND_ARG_INFO(0, count)
1832 : ZEND_END_ARG_INFO();
1833 :
1834 : static
1835 : ZEND_BEGIN_ARG_INFO(arginfo_limit_it_seek, 0)
1836 : ZEND_ARG_INFO(0, position)
1837 : ZEND_END_ARG_INFO();
1838 :
1839 : static zend_function_entry spl_funcs_LimitIterator[] = {
1840 : SPL_ME(LimitIterator, __construct, arginfo_limit_it___construct, ZEND_ACC_PUBLIC)
1841 : SPL_ME(LimitIterator, rewind, NULL, ZEND_ACC_PUBLIC)
1842 : SPL_ME(LimitIterator, valid, NULL, ZEND_ACC_PUBLIC)
1843 : SPL_ME(dual_it, key, NULL, ZEND_ACC_PUBLIC)
1844 : SPL_ME(dual_it, current, NULL, ZEND_ACC_PUBLIC)
1845 : SPL_ME(LimitIterator, next, NULL, ZEND_ACC_PUBLIC)
1846 : SPL_ME(LimitIterator, seek, arginfo_limit_it_seek, ZEND_ACC_PUBLIC)
1847 : SPL_ME(LimitIterator, getPosition, NULL, ZEND_ACC_PUBLIC)
1848 : SPL_ME(dual_it, getInnerIterator, NULL, ZEND_ACC_PUBLIC)
1849 : {NULL, NULL, NULL}
1850 : };
1851 :
1852 : static inline int spl_caching_it_valid(spl_dual_it_object *intern TSRMLS_DC)
1853 0 : {
1854 0 : return intern->u.caching.flags & CIT_VALID ? SUCCESS : FAILURE;
1855 : }
1856 :
1857 : static inline int spl_caching_it_has_next(spl_dual_it_object *intern TSRMLS_DC)
1858 0 : {
1859 0 : return spl_dual_it_valid(intern TSRMLS_CC);
1860 : }
1861 :
1862 : static inline void spl_caching_it_next(spl_dual_it_object *intern TSRMLS_DC)
1863 0 : {
1864 0 : if (spl_dual_it_fetch(intern, 1 TSRMLS_CC) == SUCCESS) {
1865 0 : intern->u.caching.flags |= CIT_VALID;
1866 : /* Full cache ? */
1867 0 : if (intern->u.caching.flags & CIT_FULL_CACHE) {
1868 : zval *zcacheval;
1869 :
1870 0 : MAKE_STD_ZVAL(zcacheval);
1871 0 : ZVAL_ZVAL(zcacheval, intern->current.data, 1, 0);
1872 0 : if (intern->current.key_type == HASH_KEY_IS_LONG) {
1873 0 : add_index_zval(intern->u.caching.zcache, intern->current.int_key, zcacheval);
1874 : } else {
1875 0 : zend_symtable_update(HASH_OF(intern->u.caching.zcache), intern->current.str_key, intern->current.str_key_len, &zcacheval, sizeof(void*), NULL);
1876 : }
1877 : }
1878 : /* Recursion ? */
1879 0 : if (intern->dit_type == DIT_RecursiveCachingIterator) {
1880 : zval *retval, *zchildren, zflags;
1881 0 : zend_call_method_with_0_params(&intern->inner.zobject, intern->inner.ce, NULL, "haschildren", &retval);
1882 0 : if (EG(exception)) {
1883 0 : if (retval) {
1884 0 : zval_ptr_dtor(&retval);
1885 : }
1886 0 : if (intern->u.caching.flags & CIT_CATCH_GET_CHILD) {
1887 0 : zend_clear_exception(TSRMLS_C);
1888 : } else {
1889 0 : return;
1890 : }
1891 : } else {
1892 0 : if (zend_is_true(retval)) {
1893 0 : zend_call_method_with_0_params(&intern->inner.zobject, intern->inner.ce, NULL, "getchildren", &zchildren);
1894 0 : if (EG(exception)) {
1895 0 : if (zchildren) {
1896 0 : zval_ptr_dtor(&zchildren);
1897 : }
1898 0 : if (intern->u.caching.flags & CIT_CATCH_GET_CHILD) {
1899 0 : zend_clear_exception(TSRMLS_C);
1900 : } else {
1901 0 : zval_ptr_dtor(&retval);
1902 0 : return;
1903 : }
1904 : } else {
1905 0 : INIT_PZVAL(&zflags);
1906 0 : ZVAL_LONG(&zflags, intern->u.caching.flags & CIT_PUBLIC);
1907 0 : spl_instantiate_arg_ex2(spl_ce_RecursiveCachingIterator, &intern->u.caching.zchildren, 1, zchildren, &zflags TSRMLS_CC);
1908 0 : zval_ptr_dtor(&zchildren);
1909 : }
1910 : }
1911 0 : zval_ptr_dtor(&retval);
1912 0 : if (EG(exception)) {
1913 0 : if (intern->u.caching.flags & CIT_CATCH_GET_CHILD) {
1914 0 : zend_clear_exception(TSRMLS_C);
1915 : } else {
1916 0 : return;
1917 : }
1918 : }
1919 : }
1920 : }
1921 0 : if (intern->u.caching.flags & (CIT_TOSTRING_USE_INNER|CIT_CALL_TOSTRING)) {
1922 : int use_copy;
1923 : zval expr_copy;
1924 0 : ALLOC_ZVAL(intern->u.caching.zstr);
1925 0 : if (intern->u.caching.flags & CIT_TOSTRING_USE_INNER) {
1926 0 : *intern->u.caching.zstr = *intern->inner.zobject;
1927 : } else {
1928 0 : *intern->u.caching.zstr = *intern->current.data;
1929 : }
1930 0 : zend_make_printable_zval(intern->u.caching.zstr, &expr_copy, &use_copy);
1931 0 : if (use_copy) {
1932 0 : *intern->u.caching.zstr = expr_copy;
1933 0 : INIT_PZVAL(intern->u.caching.zstr);
1934 0 : zval_copy_ctor(intern->u.caching.zstr);
1935 0 : zval_dtor(&expr_copy);
1936 : } else {
1937 0 : INIT_PZVAL(intern->u.caching.zstr);
1938 0 : zval_copy_ctor(intern->u.caching.zstr);
1939 : }
1940 : }
1941 0 : spl_dual_it_next(intern, 0 TSRMLS_CC);
1942 : } else {
1943 0 : intern->u.caching.flags &= ~CIT_VALID;
1944 : }
1945 : }
1946 :
1947 : static inline void spl_caching_it_rewind(spl_dual_it_object *intern TSRMLS_DC)
1948 0 : {
1949 0 : spl_dual_it_rewind(intern TSRMLS_CC);
1950 0 : zend_hash_clean(HASH_OF(intern->u.caching.zcache));
1951 0 : spl_caching_it_next(intern TSRMLS_CC);
1952 0 : }
1953 :
1954 : /* {{{ proto void CachingIterator::__construct(Iterator it [, flags = CIT_CALL_TOSTRING])
1955 : Construct a CachingIterator from an Iterator */
1956 : SPL_METHOD(CachingIterator, __construct)
1957 0 : {
1958 0 : spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_CachingIterator, zend_ce_iterator, DIT_CachingIterator);
1959 0 : } /* }}} */
1960 :
1961 : /* {{{ proto void CachingIterator::rewind()
1962 : Rewind the iterator */
1963 : SPL_METHOD(CachingIterator, rewind)
1964 0 : {
1965 : spl_dual_it_object *intern;
1966 :
1967 0 : intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
1968 :
1969 0 : spl_caching_it_rewind(intern TSRMLS_CC);
1970 0 : } /* }}} */
1971 :
1972 : /* {{{ proto bool CachingIterator::valid()
1973 : Check whether the current element is valid */
1974 : SPL_METHOD(CachingIterator, valid)
1975 0 : {
1976 : spl_dual_it_object *intern;
1977 :
1978 0 : intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
1979 :
1980 0 : RETURN_BOOL(spl_caching_it_valid(intern TSRMLS_CC) == SUCCESS);
1981 : } /* }}} */
1982 :
1983 : /* {{{ proto void CachingIterator::next()
1984 : Move the iterator forward */
1985 : SPL_METHOD(CachingIterator, next)
1986 0 : {
1987 : spl_dual_it_object *intern;
1988 :
1989 0 : intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
1990 :
1991 0 : spl_caching_it_next(intern TSRMLS_CC);
1992 0 : } /* }}} */
1993 :
1994 : /* {{{ proto bool CachingIterator::hasNext()
1995 : Check whether the inner iterator has a valid next element */
1996 : SPL_METHOD(CachingIterator, hasNext)
1997 0 : {
1998 : spl_dual_it_object *intern;
1999 :
2000 0 : intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
2001 :
2002 0 : RETURN_BOOL(spl_caching_it_has_next(intern TSRMLS_CC) == SUCCESS);
2003 : } /* }}} */
2004 :
2005 : /* {{{ proto string CachingIterator::__toString()
2006 : Return the string representation of the current element */
2007 : SPL_METHOD(CachingIterator, __toString)
2008 0 : {
2009 : spl_dual_it_object *intern;
2010 :
2011 0 : intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
2012 :
2013 0 : if (!(intern->u.caching.flags & (CIT_CALL_TOSTRING|CIT_TOSTRING_USE_KEY|CIT_TOSTRING_USE_CURRENT|CIT_TOSTRING_USE_INNER))) {
2014 0 : zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "%s does not fetch string value (see CachingIterator::__construct)", Z_OBJCE_P(getThis())->name);
2015 : }
2016 0 : if (intern->u.caching.flags & CIT_TOSTRING_USE_KEY) {
2017 0 : if (intern->current.key_type == HASH_KEY_IS_STRING) {
2018 0 : RETURN_STRINGL(intern->current.str_key, intern->current.str_key_len-1, 1);
2019 : } else {
2020 0 : RETVAL_LONG(intern->current.int_key);
2021 0 : convert_to_string(return_value);
2022 0 : return;
2023 : }
2024 0 : } else if (intern->u.caching.flags & CIT_TOSTRING_USE_CURRENT) {
2025 0 : *return_value = *intern->current.data;
2026 0 : zval_copy_ctor(return_value);
2027 0 : convert_to_string(return_value);
2028 0 : INIT_PZVAL(return_value);
2029 0 : return;
2030 : }
2031 0 : if (intern->u.caching.zstr) {
2032 0 : RETURN_STRINGL(Z_STRVAL_P(intern->u.caching.zstr), Z_STRLEN_P(intern->u.caching.zstr), 1);
2033 : } else {
2034 0 : RETURN_NULL();
2035 : }
2036 : } /* }}} */
2037 :
2038 : /* {{{ proto void CachingIterator::offsetSet(mixed index, mixed newval)
2039 : Set given index in cache */
2040 : SPL_METHOD(CachingIterator, offsetSet)
2041 0 : {
2042 : spl_dual_it_object *intern;
2043 : char *arKey;
2044 : uint nKeyLength;
2045 : zval *value;
2046 :
2047 0 : intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
2048 :
2049 0 : if (!(intern->u.caching.flags & CIT_FULL_CACHE)) {
2050 0 : zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "%s does not use a full cache (see CachingIterator::__construct)", Z_OBJCE_P(getThis())->name);
2051 : }
2052 :
2053 0 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz", &arKey, &nKeyLength, &value) == FAILURE) {
2054 0 : return;
2055 : }
2056 :
2057 0 : value->refcount++;
2058 0 : zend_symtable_update(HASH_OF(intern->u.caching.zcache), arKey, nKeyLength+1, &value, sizeof(value), NULL);
2059 : }
2060 : /* }}} */
2061 :
2062 : /* {{{ proto string CachingIterator::offsetGet(mixed index)
2063 : Return the internal cache if used */
2064 : SPL_METHOD(CachingIterator, offsetGet)
2065 0 : {
2066 : spl_dual_it_object *intern;
2067 : char *arKey;
2068 : uint nKeyLength;
2069 : zval **value;
2070 :
2071 0 : intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
2072 :
2073 0 : if (!(intern->u.caching.flags & CIT_FULL_CACHE)) {
2074 0 : zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "%s does not use a full cache (see CachingIterator::__construct)", Z_OBJCE_P(getThis())->name);
2075 : }
2076 :
2077 0 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &arKey, &nKeyLength) == FAILURE) {
2078 0 : return;
2079 : }
2080 :
2081 0 : if (zend_symtable_find(HASH_OF(intern->u.caching.zcache), arKey, nKeyLength+1, (void**)&value) == FAILURE) {
2082 0 : zend_error(E_NOTICE, "Undefined index: %s", arKey);
2083 0 : return;
2084 : }
2085 :
2086 0 : RETURN_ZVAL(*value, 1, 0);
2087 : }
2088 : /* }}} */
2089 :
2090 : /* {{{ proto void CachingIterator::offsetUnset(mixed index)
2091 : Unset given index in cache */
2092 : SPL_METHOD(CachingIterator, offsetUnset)
2093 0 : {
2094 : spl_dual_it_object *intern;
2095 : char *arKey;
2096 : uint nKeyLength;
2097 :
2098 0 : intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
2099 :
2100 0 : if (!(intern->u.caching.flags & CIT_FULL_CACHE)) {
2101 0 : zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "%s does not use a full cache (see CachingIterator::__construct)", Z_OBJCE_P(getThis())->name);
2102 : }
2103 :
2104 0 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &arKey, &nKeyLength) == FAILURE) {
2105 0 : return;
2106 : }
2107 :
2108 0 : zend_symtable_del(HASH_OF(intern->u.caching.zcache), arKey, nKeyLength+1);
2109 : }
2110 : /* }}} */
2111 :
2112 : /* {{{ proto bool CachingIterator::offsetExists(mixed index)
2113 : Return whether the requested index exists */
2114 : SPL_METHOD(CachingIterator, offsetExists)
2115 0 : {
2116 : spl_dual_it_object *intern;
2117 : char *arKey;
2118 : uint nKeyLength;
2119 :
2120 0 : intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
2121 :
2122 0 : if (!(intern->u.caching.flags & CIT_FULL_CACHE)) {
2123 0 : zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "%s does not use a full cache (see CachingIterator::__construct)", Z_OBJCE_P(getThis())->name);
2124 : }
2125 :
2126 0 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &arKey, &nKeyLength) == FAILURE) {
2127 0 : return;
2128 : }
2129 :
2130 0 : RETURN_BOOL(zend_symtable_exists(HASH_OF(intern->u.caching.zcache), arKey, nKeyLength+1));
2131 : }
2132 : /* }}} */
2133 :
2134 : /* {{{ proto bool CachingIterator::getCache()
2135 : Return the cache */
2136 : SPL_METHOD(CachingIterator, getCache)
2137 0 : {
2138 : spl_dual_it_object *intern;
2139 :
2140 0 : intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
2141 :
2142 0 : if (!(intern->u.caching.flags & CIT_FULL_CACHE)) {
2143 0 : zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "%v does not use a full cache (see CachingIterator::__construct)", Z_OBJCE_P(getThis())->name);
2144 0 : return;
2145 : }
2146 :
2147 0 : RETURN_ZVAL(intern->u.caching.zcache, 1, 0);
2148 : }
2149 : /* }}} */
2150 :
2151 : /* {{{ proto int CachingIterator::getFlags()
2152 : Return the internal flags */
2153 : SPL_METHOD(CachingIterator, getFlags)
2154 0 : {
2155 : spl_dual_it_object *intern;
2156 :
2157 0 : intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
2158 :
2159 0 : RETURN_LONG(intern->u.caching.flags);
2160 : }
2161 : /* }}} */
2162 :
2163 : /* {{{ proto void CachingIterator::setFlags(int flags)
2164 : Set the internal flags */
2165 : SPL_METHOD(CachingIterator, setFlags)
2166 0 : {
2167 : spl_dual_it_object *intern;
2168 : long flags;
2169 :
2170 0 : intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
2171 :
2172 0 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &flags) == FAILURE) {
2173 0 : return;
2174 : }
2175 :
2176 0 : if (spl_cit_check_flags(flags) != SUCCESS) {
2177 0 : zend_throw_exception(spl_ce_InvalidArgumentException , "Flags must contain only one of CALL_TOSTRING, TOSTRING_USE_KEY, TOSTRING_USE_CURRENT, TOSTRING_USE_INNER", 0 TSRMLS_CC);
2178 0 : return;
2179 : }
2180 0 : if ((intern->u.caching.flags & CIT_CALL_TOSTRING) != 0 && (flags & CIT_CALL_TOSTRING) == 0) {
2181 0 : zend_throw_exception(spl_ce_InvalidArgumentException, "Unsetting flag CALL_TO_STRING is not possible", 0 TSRMLS_CC);
2182 0 : return;
2183 : }
2184 0 : if ((intern->u.caching.flags & CIT_TOSTRING_USE_INNER) != 0 && (flags & CIT_TOSTRING_USE_INNER) == 0) {
2185 0 : zend_throw_exception(spl_ce_InvalidArgumentException, "Unsetting flag TOSTRING_USE_INNER is not possible", 0 TSRMLS_CC);
2186 0 : return;
2187 : }
2188 0 : if ((flags && CIT_FULL_CACHE) != 0 && (intern->u.caching.flags & CIT_FULL_CACHE) == 0) {
2189 : /* clear on (re)enable */
2190 0 : zend_hash_clean(HASH_OF(intern->u.caching.zcache));
2191 : }
2192 0 : intern->u.caching.flags = (intern->u.caching.flags & ~CIT_PUBLIC) | (flags & CIT_PUBLIC);
2193 : }
2194 : /* }}} */
2195 :
2196 : /* {{{ proto void CachingIterator::count()
2197 : Number of cached elements */
2198 : SPL_METHOD(CachingIterator, count)
2199 0 : {
2200 : spl_dual_it_object *intern;
2201 :
2202 0 : intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
2203 :
2204 0 : if (!(intern->u.caching.flags & CIT_FULL_CACHE)) {
2205 0 : zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "%v does not use a full cache (see CachingIterator::__construct)", Z_OBJCE_P(getThis())->name);
2206 0 : return;
2207 : }
2208 :
2209 0 : RETURN_LONG(zend_hash_num_elements(HASH_OF(intern->u.caching.zcache)));
2210 : }
2211 : /* }}} */
2212 :
2213 : static
2214 : ZEND_BEGIN_ARG_INFO_EX(arginfo_caching_it___construct, 0, 0, 1)
2215 : ZEND_ARG_OBJ_INFO(0, iterator, Iterator, 0)
2216 : ZEND_ARG_INFO(0, flags)
2217 : ZEND_END_ARG_INFO();
2218 :
2219 : static
2220 : ZEND_BEGIN_ARG_INFO(arginfo_caching_it_setFlags, 0)
2221 : ZEND_ARG_INFO(0, flags)
2222 : ZEND_END_ARG_INFO();
2223 :
2224 : static
2225 : ZEND_BEGIN_ARG_INFO(arginfo_caching_it_offsetGet, 0)
2226 : ZEND_ARG_INFO(0, index)
2227 : ZEND_END_ARG_INFO();
2228 :
2229 : static
2230 : ZEND_BEGIN_ARG_INFO(arginfo_caching_it_offsetSet, 0)
2231 : ZEND_ARG_INFO(0, index)
2232 : ZEND_ARG_INFO(0, newval)
2233 : ZEND_END_ARG_INFO();
2234 :
2235 : static zend_function_entry spl_funcs_CachingIterator[] = {
2236 : SPL_ME(CachingIterator, __construct, arginfo_caching_it___construct, ZEND_ACC_PUBLIC)
2237 : SPL_ME(CachingIterator, rewind, NULL, ZEND_ACC_PUBLIC)
2238 : SPL_ME(CachingIterator, valid, NULL, ZEND_ACC_PUBLIC)
2239 : SPL_ME(dual_it, key, NULL, ZEND_ACC_PUBLIC)
2240 : SPL_ME(dual_it, current, NULL, ZEND_ACC_PUBLIC)
2241 : SPL_ME(CachingIterator, next, NULL, ZEND_ACC_PUBLIC)
2242 : SPL_ME(CachingIterator, hasNext, NULL, ZEND_ACC_PUBLIC)
2243 : SPL_ME(CachingIterator, __toString, NULL, ZEND_ACC_PUBLIC)
2244 : SPL_ME(dual_it, getInnerIterator, NULL, ZEND_ACC_PUBLIC)
2245 : SPL_ME(CachingIterator, getFlags, NULL, ZEND_ACC_PUBLIC)
2246 : SPL_ME(CachingIterator, setFlags, arginfo_caching_it_setFlags, ZEND_ACC_PUBLIC)
2247 : SPL_ME(CachingIterator, offsetGet, arginfo_caching_it_offsetGet, ZEND_ACC_PUBLIC)
2248 : SPL_ME(CachingIterator, offsetSet, arginfo_caching_it_offsetSet, ZEND_ACC_PUBLIC)
2249 : SPL_ME(CachingIterator, offsetUnset, arginfo_caching_it_offsetGet, ZEND_ACC_PUBLIC)
2250 : SPL_ME(CachingIterator, offsetExists, arginfo_caching_it_offsetGet, ZEND_ACC_PUBLIC)
2251 : SPL_ME(CachingIterator, getCache, NULL, ZEND_ACC_PUBLIC)
2252 : SPL_ME(CachingIterator, count, NULL, ZEND_ACC_PUBLIC)
2253 : {NULL, NULL, NULL}
2254 : };
2255 :
2256 : /* {{{ proto void RecursiveCachingIterator::__construct(RecursiveIterator it [, flags = CIT_CALL_TOSTRING])
2257 : Create an iterator from a RecursiveIterator */
2258 : SPL_METHOD(RecursiveCachingIterator, __construct)
2259 0 : {
2260 0 : spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_RecursiveCachingIterator, spl_ce_RecursiveIterator, DIT_RecursiveCachingIterator);
2261 0 : } /* }}} */
2262 :
2263 : /* {{{ proto bool RecursiveCachingIterator::hasChildren()
2264 : Check whether the current element of the inner iterator has children */
2265 : SPL_METHOD(RecursiveCachingIterator, hasChildren)
2266 0 : {
2267 : spl_dual_it_object *intern;
2268 :
2269 0 : intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
2270 :
2271 0 : RETURN_BOOL(intern->u.caching.zchildren);
2272 : } /* }}} */
2273 :
2274 : /* {{{ proto RecursiveCachingIterator RecursiveCachingIterator::getChildren()
2275 : Return the inner iterator's children as a RecursiveCachingIterator */
2276 : SPL_METHOD(RecursiveCachingIterator, getChildren)
2277 0 : {
2278 : spl_dual_it_object *intern;
2279 :
2280 0 : intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
2281 :
2282 0 : if (intern->u.caching.zchildren) {
2283 0 : RETURN_ZVAL(intern->u.caching.zchildren, 1, 0);
2284 : } else {
2285 0 : RETURN_NULL();
2286 : }
2287 : } /* }}} */
2288 :
2289 : static
2290 : ZEND_BEGIN_ARG_INFO_EX(arginfo_caching_rec_it___construct, 0, ZEND_RETURN_VALUE, 1)
2291 : ZEND_ARG_OBJ_INFO(0, iterator, Iterator, 0)
2292 : ZEND_ARG_INFO(0, flags)
2293 : ZEND_END_ARG_INFO();
2294 :
2295 : static zend_function_entry spl_funcs_RecursiveCachingIterator[] = {
2296 : SPL_ME(RecursiveCachingIterator, __construct, arginfo_caching_rec_it___construct, ZEND_ACC_PUBLIC)
2297 : SPL_ME(RecursiveCachingIterator, hasChildren, NULL, ZEND_ACC_PUBLIC)
2298 : SPL_ME(RecursiveCachingIterator, getChildren, NULL, ZEND_ACC_PUBLIC)
2299 : {NULL, NULL, NULL}
2300 : };
2301 :
2302 : /* {{{ proto void IteratorIterator::__construct(Traversable it)
2303 : Create an iterator from anything that is traversable */
2304 : SPL_METHOD(IteratorIterator, __construct)
2305 0 : {
2306 0 : spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_IteratorIterator, zend_ce_traversable, DIT_IteratorIterator);
2307 0 : } /* }}} */
2308 :
2309 : static
2310 : ZEND_BEGIN_ARG_INFO(arginfo_iterator_it___construct, 0)
2311 : ZEND_ARG_OBJ_INFO(0, iterator, Traversable, 0)
2312 : ZEND_END_ARG_INFO();
2313 :
2314 : static zend_function_entry spl_funcs_IteratorIterator[] = {
2315 : SPL_ME(IteratorIterator, __construct, arginfo_iterator_it___construct, ZEND_ACC_PUBLIC)
2316 : SPL_ME(dual_it, rewind, NULL, ZEND_ACC_PUBLIC)
2317 : SPL_ME(dual_it, valid, NULL, ZEND_ACC_PUBLIC)
2318 : SPL_ME(dual_it, key, NULL, ZEND_ACC_PUBLIC)
2319 : SPL_ME(dual_it, current, NULL, ZEND_ACC_PUBLIC)
2320 : SPL_ME(dual_it, next, NULL, ZEND_ACC_PUBLIC)
2321 : SPL_ME(dual_it, getInnerIterator, NULL, ZEND_ACC_PUBLIC)
2322 : {NULL, NULL, NULL}
2323 : };
2324 :
2325 : /* {{{ proto void NoRewindIterator::__construct(Iterator it)
2326 : Create an iterator from another iterator */
2327 : SPL_METHOD(NoRewindIterator, __construct)
2328 0 : {
2329 0 : spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_NoRewindIterator, zend_ce_iterator, DIT_NoRewindIterator);
2330 0 : } /* }}} */
2331 :
2332 : /* {{{ proto void NoRewindIterator::rewind()
2333 : Prevent a call to inner iterators rewind() */
2334 : SPL_METHOD(NoRewindIterator, rewind)
2335 0 : {
2336 : /* nothing to do */
2337 0 : } /* }}} */
2338 :
2339 : /* {{{ proto bool NoRewindIterator::valid()
2340 : Return inner iterators valid() */
2341 : SPL_METHOD(NoRewindIterator, valid)
2342 0 : {
2343 : spl_dual_it_object *intern;
2344 :
2345 0 : intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
2346 0 : RETURN_BOOL(intern->inner.iterator->funcs->valid(intern->inner.iterator TSRMLS_CC) == SUCCESS);
2347 : } /* }}} */
2348 :
2349 : /* {{{ proto mixed NoRewindIterator::key()
2350 : Return inner iterators key() */
2351 : SPL_METHOD(NoRewindIterator, key)
2352 0 : {
2353 : spl_dual_it_object *intern;
2354 :
2355 0 : intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
2356 :
2357 0 : if (intern->inner.iterator->funcs->get_current_key) {
2358 : char *str_key;
2359 : uint str_key_len;
2360 : ulong int_key;
2361 0 : if (intern->inner.iterator->funcs->get_current_key(intern->inner.iterator, &str_key, &str_key_len, &int_key TSRMLS_CC) == HASH_KEY_IS_LONG) {
2362 0 : RETURN_LONG(int_key);
2363 : } else {
2364 0 : RETURN_STRINGL(str_key, str_key_len-1, 0);
2365 : }
2366 : } else {
2367 0 : RETURN_NULL();
2368 : }
2369 : } /* }}} */
2370 :
2371 : /* {{{ proto mixed NoRewindIterator::current()
2372 : Return inner iterators current() */
2373 : SPL_METHOD(NoRewindIterator, current)
2374 0 : {
2375 : spl_dual_it_object *intern;
2376 : zval **data;
2377 :
2378 0 : intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
2379 0 : intern->inner.iterator->funcs->get_current_data(intern->inner.iterator, &data TSRMLS_CC);
2380 0 : RETURN_ZVAL(*data, 1, 0);
2381 : } /* }}} */
2382 :
2383 : /* {{{ proto void NoRewindIterator::next()
2384 : Return inner iterators next() */
2385 : SPL_METHOD(NoRewindIterator, next)
2386 0 : {
2387 : spl_dual_it_object *intern;
2388 :
2389 0 : intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
2390 0 : intern->inner.iterator->funcs->move_forward(intern->inner.iterator TSRMLS_CC);
2391 0 : } /* }}} */
2392 :
2393 : static
2394 : ZEND_BEGIN_ARG_INFO(arginfo_norewind_it___construct, 0)
2395 : ZEND_ARG_OBJ_INFO(0, iterator, Iterator, 0)
2396 : ZEND_END_ARG_INFO();
2397 :
2398 : static zend_function_entry spl_funcs_NoRewindIterator[] = {
2399 : SPL_ME(NoRewindIterator, __construct, arginfo_norewind_it___construct, ZEND_ACC_PUBLIC)
2400 : SPL_ME(NoRewindIterator, rewind, NULL, ZEND_ACC_PUBLIC)
2401 : SPL_ME(NoRewindIterator, valid, NULL, ZEND_ACC_PUBLIC)
2402 : SPL_ME(NoRewindIterator, key, NULL, ZEND_ACC_PUBLIC)
2403 : SPL_ME(NoRewindIterator, current, NULL, ZEND_ACC_PUBLIC)
2404 : SPL_ME(NoRewindIterator, next, NULL, ZEND_ACC_PUBLIC)
2405 : SPL_ME(dual_it, getInnerIterator, NULL, ZEND_ACC_PUBLIC)
2406 : {NULL, NULL, NULL}
2407 : };
2408 :
2409 : /* {{{ proto void InfiniteIterator::__construct(Iterator it)
2410 : Create an iterator from another iterator */
2411 : SPL_METHOD(InfiniteIterator, __construct)
2412 0 : {
2413 0 : spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_InfiniteIterator, zend_ce_iterator, DIT_InfiniteIterator);
2414 0 : } /* }}} */
2415 :
2416 : /* {{{ proto void InfiniteIterator::next()
2417 : Prevent a call to inner iterators rewind() (internally the current data will be fetched if valid()) */
2418 : SPL_METHOD(InfiniteIterator, next)
2419 0 : {
2420 : spl_dual_it_object *intern;
2421 :
2422 0 : intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
2423 :
2424 0 : spl_dual_it_next(intern, 1 TSRMLS_CC);
2425 0 : if (spl_dual_it_valid(intern TSRMLS_CC) == SUCCESS) {
2426 0 : spl_dual_it_fetch(intern, 0 TSRMLS_CC);
2427 : } else {
2428 0 : spl_dual_it_rewind(intern TSRMLS_CC);
2429 0 : if (spl_dual_it_valid(intern TSRMLS_CC) == SUCCESS) {
2430 0 : spl_dual_it_fetch(intern, 0 TSRMLS_CC);
2431 : }
2432 : }
2433 0 : } /* }}} */
2434 :
2435 : static zend_function_entry spl_funcs_InfiniteIterator[] = {
2436 : SPL_ME(InfiniteIterator, __construct, arginfo_norewind_it___construct, ZEND_ACC_PUBLIC)
2437 : SPL_ME(InfiniteIterator, next, NULL, ZEND_ACC_PUBLIC)
2438 : {NULL, NULL, NULL}
2439 : };
2440 :
2441 : /* {{{ proto void EmptyIterator::rewind()
2442 : Does nothing */
2443 : SPL_METHOD(EmptyIterator, rewind)
2444 0 : {
2445 0 : } /* }}} */
2446 :
2447 : /* {{{ proto false EmptyIterator::valid()
2448 : Return false */
2449 : SPL_METHOD(EmptyIterator, valid)
2450 0 : {
2451 0 : RETURN_FALSE;
2452 : } /* }}} */
2453 :
2454 : /* {{{ proto void EmptyIterator::key()
2455 : Throws exception BadMethodCallException */
2456 : SPL_METHOD(EmptyIterator, key)
2457 0 : {
2458 0 : zend_throw_exception(spl_ce_BadMethodCallException, "Accessing the key of an EmptyIterator", 0 TSRMLS_CC);
2459 0 : } /* }}} */
2460 :
2461 : /* {{{ proto void EmptyIterator::current()
2462 : Throws exception BadMethodCallException */
2463 : SPL_METHOD(EmptyIterator, current)
2464 0 : {
2465 0 : zend_throw_exception(spl_ce_BadMethodCallException, "Accessing the value of an EmptyIterator", 0 TSRMLS_CC);
2466 0 : } /* }}} */
2467 :
2468 : /* {{{ proto void EmptyIterator::next()
2469 : Does nothing */
2470 : SPL_METHOD(EmptyIterator, next)
2471 0 : {
2472 0 : } /* }}} */
2473 :
2474 : static zend_function_entry spl_funcs_EmptyIterator[] = {
2475 : SPL_ME(EmptyIterator, rewind, NULL, ZEND_ACC_PUBLIC)
2476 : SPL_ME(EmptyIterator, valid, NULL, ZEND_ACC_PUBLIC)
2477 : SPL_ME(EmptyIterator, key, NULL, ZEND_ACC_PUBLIC)
2478 : SPL_ME(EmptyIterator, current, NULL, ZEND_ACC_PUBLIC)
2479 : SPL_ME(EmptyIterator, next, NULL, ZEND_ACC_PUBLIC)
2480 : {NULL, NULL, NULL}
2481 : };
2482 :
2483 : int spl_append_it_next_iterator(spl_dual_it_object *intern TSRMLS_DC) /* {{{*/
2484 0 : {
2485 0 : spl_dual_it_free(intern TSRMLS_CC);
2486 :
2487 0 : if (intern->inner.zobject) {
2488 0 : zval_ptr_dtor(&intern->inner.zobject);
2489 0 : intern->inner.zobject = NULL;
2490 0 : intern->inner.ce = NULL;
2491 0 : intern->inner.object = NULL;
2492 0 : if (intern->inner.iterator) {
2493 0 : intern->inner.iterator->funcs->dtor(intern->inner.iterator TSRMLS_CC);
2494 0 : intern->inner.iterator = NULL;
2495 : }
2496 : }
2497 0 : if (intern->u.append.iterator->funcs->valid(intern->u.append.iterator TSRMLS_CC) == SUCCESS) {
2498 : zval **it;
2499 :
2500 0 : intern->u.append.iterator->funcs->get_current_data(intern->u.append.iterator, &it TSRMLS_CC);
2501 0 : (*it)->refcount++;
2502 0 : intern->inner.zobject = *it;
2503 0 : intern->inner.ce = Z_OBJCE_PP(it);
2504 0 : intern->inner.object = zend_object_store_get_object(*it TSRMLS_CC);
2505 0 : intern->inner.iterator = intern->inner.ce->get_iterator(intern->inner.ce, *it, 0 TSRMLS_CC);
2506 0 : spl_dual_it_rewind(intern TSRMLS_CC);
2507 0 : return SUCCESS;
2508 : } else {
2509 0 : return FAILURE;
2510 : }
2511 : } /* }}} */
2512 :
2513 : void spl_append_it_fetch(spl_dual_it_object *intern TSRMLS_DC) /* {{{*/
2514 0 : {
2515 0 : while (spl_dual_it_valid(intern TSRMLS_CC) != SUCCESS) {
2516 0 : intern->u.append.iterator->funcs->move_forward(intern->u.append.iterator TSRMLS_CC);
2517 0 : if (spl_append_it_next_iterator(intern TSRMLS_CC) != SUCCESS) {
2518 0 : return;
2519 : }
2520 : }
2521 0 : spl_dual_it_fetch(intern, 0 TSRMLS_CC);
2522 : } /* }}} */
2523 :
2524 : void spl_append_it_next(spl_dual_it_object *intern TSRMLS_DC) /* {{{ */
2525 0 : {
2526 0 : if (spl_dual_it_valid(intern TSRMLS_CC) == SUCCESS) {
2527 0 : spl_dual_it_next(intern, 1 TSRMLS_CC);
2528 : }
2529 0 : spl_append_it_fetch(intern TSRMLS_CC);
2530 0 : } /* }}} */
2531 :
2532 : /* {{{ proto void AppendIterator::__construct()
2533 : Create an AppendIterator */
2534 : SPL_METHOD(AppendIterator, __construct)
2535 0 : {
2536 0 : spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_AppendIterator, zend_ce_iterator, DIT_AppendIterator);
2537 0 : } /* }}} */
2538 :
2539 : /* {{{ proto void AppendIterator::append(Iterator it)
2540 : Append an iterator */
2541 : SPL_METHOD(AppendIterator, append)
2542 0 : {
2543 : spl_dual_it_object *intern;
2544 : zval *it;
2545 :
2546 0 : intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
2547 :
2548 0 : APPENDIT_CHECK_CTOR(intern);
2549 :
2550 0 : if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "O", &it, zend_ce_iterator) == FAILURE) {
2551 0 : return;
2552 : }
2553 0 : spl_array_iterator_append(intern->u.append.zarrayit, it TSRMLS_CC);
2554 :
2555 0 : if (!intern->inner.iterator || spl_dual_it_valid(intern TSRMLS_CC) != SUCCESS) {
2556 0 : if (intern->u.append.iterator->funcs->valid(intern->u.append.iterator TSRMLS_CC) != SUCCESS) {
2557 0 : intern->u.append.iterator->funcs->rewind(intern->u.append.iterator TSRMLS_CC);
2558 : }
2559 : do {
2560 0 : spl_append_it_next_iterator(intern TSRMLS_CC);
2561 0 : } while (intern->inner.zobject != it);
2562 0 : spl_append_it_fetch(intern TSRMLS_CC);
2563 : }
2564 : } /* }}} */
2565 :
2566 : /* {{{ proto void AppendIterator::rewind()
2567 : Rewind to the first iterator and rewind the first iterator, too */
2568 : SPL_METHOD(AppendIterator, rewind)
2569 0 : {
2570 : spl_dual_it_object *intern;
2571 :
2572 0 : intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
2573 :
2574 0 : intern->u.append.iterator->funcs->rewind(intern->u.append.iterator TSRMLS_CC);
2575 0 : if (spl_append_it_next_iterator(intern TSRMLS_CC) == SUCCESS) {
2576 0 : spl_append_it_fetch(intern TSRMLS_CC);
2577 : }
2578 0 : } /* }}} */
2579 :
2580 : /* {{{ proto bool AppendIterator::valid()
2581 : Check if the current state is valid */
2582 : SPL_METHOD(AppendIterator, valid)
2583 0 : {
2584 : spl_dual_it_object *intern;
2585 :
2586 0 : intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
2587 :
2588 0 : RETURN_BOOL(intern->current.data);
2589 : } /* }}} */
2590 :
2591 : /* {{{ proto void AppendIterator::next()
2592 : Forward to next element */
2593 : SPL_METHOD(AppendIterator, next)
2594 0 : {
2595 : spl_dual_it_object *intern;
2596 :
2597 0 : intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
2598 :
2599 0 : spl_append_it_next(intern TSRMLS_CC);
2600 0 : } /* }}} */
2601 :
2602 : /* {{{ proto int AppendIterator::getIteratorIndex()
2603 : Get index of iterator */
2604 : SPL_METHOD(AppendIterator, getIteratorIndex)
2605 0 : {
2606 : spl_dual_it_object *intern;
2607 :
2608 0 : intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
2609 :
2610 0 : APPENDIT_CHECK_CTOR(intern);
2611 0 : spl_array_iterator_key(intern->u.append.zarrayit, return_value TSRMLS_CC);
2612 : } /* }}} */
2613 :
2614 : /* {{{ proto ArrayIterator AppendIterator::getArrayIterator()
2615 : Get access to inner ArrayIterator */
2616 : SPL_METHOD(AppendIterator, getArrayIterator)
2617 0 : {
2618 : spl_dual_it_object *intern;
2619 :
2620 0 : intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
2621 :
2622 0 : APPENDIT_CHECK_CTOR(intern);
2623 0 : RETURN_ZVAL(intern->u.append.zarrayit, 1, 0);
2624 : } /* }}} */
2625 :
2626 : static
2627 : ZEND_BEGIN_ARG_INFO(arginfo_append_it_append, 0)
2628 : ZEND_ARG_OBJ_INFO(0, iterator, Iterator, 0)
2629 : ZEND_END_ARG_INFO();
2630 :
2631 : static zend_function_entry spl_funcs_AppendIterator[] = {
2632 : SPL_ME(AppendIterator, __construct, NULL, ZEND_ACC_PUBLIC)
2633 : SPL_ME(AppendIterator, append, arginfo_append_it_append, ZEND_ACC_PUBLIC)
2634 : SPL_ME(AppendIterator, rewind, NULL, ZEND_ACC_PUBLIC)
2635 : SPL_ME(AppendIterator, valid, NULL, ZEND_ACC_PUBLIC)
2636 : SPL_ME(dual_it, key, NULL, ZEND_ACC_PUBLIC)
2637 : SPL_ME(dual_it, current, NULL, ZEND_ACC_PUBLIC)
2638 : SPL_ME(AppendIterator, next, NULL, ZEND_ACC_PUBLIC)
2639 : SPL_ME(dual_it, getInnerIterator, NULL, ZEND_ACC_PUBLIC)
2640 : SPL_ME(AppendIterator, getIteratorIndex, NULL, ZEND_ACC_PUBLIC)
2641 : SPL_ME(AppendIterator, getArrayIterator, NULL, ZEND_ACC_PUBLIC)
2642 : {NULL, NULL, NULL}
2643 : };
2644 :
2645 : PHPAPI int spl_iterator_apply(zval *obj, spl_iterator_apply_func_t apply_func, void *puser TSRMLS_DC)
2646 0 : {
2647 : zend_object_iterator *iter;
2648 0 : zend_class_entry *ce = Z_OBJCE_P(obj);
2649 :
2650 0 : iter = ce->get_iterator(ce, obj, 0 TSRMLS_CC);
2651 :
2652 0 : if (EG(exception)) {
2653 0 : goto done;
2654 : }
2655 :
2656 0 : if (iter->funcs->rewind) {
2657 0 : iter->funcs->rewind(iter TSRMLS_CC);
2658 0 : if (EG(exception)) {
2659 0 : goto done;
2660 : }
2661 : }
2662 :
2663 0 : while (iter->funcs->valid(iter TSRMLS_CC) == SUCCESS) {
2664 0 : if (EG(exception)) {
2665 0 : goto done;
2666 : }
2667 0 : if (apply_func(iter, puser TSRMLS_CC) == ZEND_HASH_APPLY_STOP || EG(exception)) {
2668 : goto done;
2669 : }
2670 0 : iter->funcs->move_forward(iter TSRMLS_CC);
2671 0 : if (EG(exception)) {
2672 0 : goto done;
2673 : }
2674 : }
2675 :
2676 0 : done:
2677 0 : iter->funcs->dtor(iter TSRMLS_CC);
2678 0 : return EG(exception) ? FAILURE : SUCCESS;
2679 : }
2680 : /* }}} */
2681 :
2682 : static int spl_iterator_to_array_apply(zend_object_iterator *iter, void *puser TSRMLS_DC) /* {{{ */
2683 0 : {
2684 0 : zval **data, *return_value = (zval*)puser;
2685 : char *str_key;
2686 : uint str_key_len;
2687 : ulong int_key;
2688 : int key_type;
2689 :
2690 0 : iter->funcs->get_current_data(iter, &data TSRMLS_CC);
2691 0 : if (EG(exception)) {
2692 0 : return ZEND_HASH_APPLY_STOP;
2693 : }
2694 0 : if (iter->funcs->get_current_key) {
2695 0 : key_type = iter->funcs->get_current_key(iter, &str_key, &str_key_len, &int_key TSRMLS_CC);
2696 0 : if (EG(exception)) {
2697 0 : return ZEND_HASH_APPLY_STOP;
2698 : }
2699 0 : (*data)->refcount++;
2700 0 : switch(key_type) {
2701 : case HASH_KEY_IS_STRING:
2702 0 : add_assoc_zval_ex(return_value, str_key, str_key_len, *data);
2703 0 : efree(str_key);
2704 0 : break;
2705 : case HASH_KEY_IS_LONG:
2706 0 : add_index_zval(return_value, int_key, *data);
2707 : break;
2708 : }
2709 : } else {
2710 0 : (*data)->refcount++;
2711 0 : add_next_index_zval(return_value, *data);
2712 : }
2713 0 : return ZEND_HASH_APPLY_KEEP;
2714 : }
2715 : /* }}} */
2716 :
2717 : static int spl_iterator_to_values_apply(zend_object_iterator *iter, void *puser TSRMLS_DC) /* {{{ */
2718 0 : {
2719 0 : zval **data, *return_value = (zval*)puser;
2720 :
2721 0 : iter->funcs->get_current_data(iter, &data TSRMLS_CC);
2722 0 : if (EG(exception)) {
2723 0 : return ZEND_HASH_APPLY_STOP;
2724 : }
2725 0 : (*data)->refcount++;
2726 0 : add_next_index_zval(return_value, *data);
2727 0 : return ZEND_HASH_APPLY_KEEP;
2728 : }
2729 : /* }}} */
2730 :
2731 : /* {{{ proto array iterator_to_array(Traversable it [, bool use_keys = true])
2732 : Copy the iterator into an array */
2733 : PHP_FUNCTION(iterator_to_array)
2734 0 : {
2735 : zval *obj;
2736 0 : zend_bool use_keys = 1;
2737 :
2738 0 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O|b", &obj, zend_ce_traversable, &use_keys) == FAILURE) {
2739 0 : RETURN_FALSE;
2740 : }
2741 :
2742 0 : array_init(return_value);
2743 :
2744 0 : if (spl_iterator_apply(obj, use_keys ? spl_iterator_to_array_apply : spl_iterator_to_values_apply, (void*)return_value TSRMLS_CC) != SUCCESS) {
2745 0 : zval_dtor(return_value);
2746 0 : RETURN_NULL();
2747 : }
2748 : } /* }}} */
2749 :
2750 : static int spl_iterator_count_apply(zend_object_iterator *iter, void *puser TSRMLS_DC) /* {{{ */
2751 0 : {
2752 0 : (*(long*)puser)++;
2753 0 : return ZEND_HASH_APPLY_KEEP;
2754 : }
2755 : /* }}} */
2756 :
2757 : /* {{{ proto int iterator_count(Traversable it)
2758 : Count the elements in an iterator */
2759 : PHP_FUNCTION(iterator_count)
2760 0 : {
2761 : zval *obj;
2762 0 : long count = 0;
2763 :
2764 0 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &obj, zend_ce_traversable) == FAILURE) {
2765 0 : RETURN_FALSE;
2766 : }
2767 :
2768 0 : if (spl_iterator_apply(obj, spl_iterator_count_apply, (void*)&count TSRMLS_CC) == SUCCESS) {
2769 0 : RETURN_LONG(count);
2770 : }
2771 : }
2772 : /* }}} */
2773 :
2774 : typedef struct {
2775 : zval *obj;
2776 : zval *args;
2777 : long count;
2778 : zend_fcall_info fci;
2779 : zend_fcall_info_cache fcc;
2780 : } spl_iterator_apply_info;
2781 :
2782 : static int spl_iterator_func_apply(zend_object_iterator *iter, void *puser TSRMLS_DC) /* {{{ */
2783 0 : {
2784 : zval *retval;
2785 0 : spl_iterator_apply_info *apply_info = (spl_iterator_apply_info*)puser;
2786 : int result;
2787 :
2788 0 : apply_info->count++;
2789 0 : zend_fcall_info_call(&apply_info->fci, &apply_info->fcc, &retval, NULL TSRMLS_CC);
2790 0 : if (retval) {
2791 0 : result = zend_is_true(retval) ? ZEND_HASH_APPLY_KEEP : ZEND_HASH_APPLY_STOP;
2792 0 : zval_ptr_dtor(&retval);
2793 : } else {
2794 0 : result = ZEND_HASH_APPLY_STOP;
2795 : }
2796 0 : return result;
2797 : }
2798 : /* }}} */
2799 :
2800 : /* {{{ proto int iterator_apply(Traversable it, mixed function [, mixed params])
2801 : Calls a function for every element in an iterator */
2802 : PHP_FUNCTION(iterator_apply)
2803 0 : {
2804 : spl_iterator_apply_info apply_info;
2805 :
2806 0 : apply_info.args = NULL;
2807 0 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Of|a!", &apply_info.obj, zend_ce_traversable, &apply_info.fci, &apply_info.fcc, &apply_info.args) == FAILURE) {
2808 0 : return;
2809 : }
2810 :
2811 0 : apply_info.count = 0;
2812 0 : zend_fcall_info_args(&apply_info.fci, apply_info.args TSRMLS_CC);
2813 0 : if (spl_iterator_apply(apply_info.obj, spl_iterator_func_apply, (void*)&apply_info TSRMLS_CC) == SUCCESS) {
2814 0 : RETVAL_LONG(apply_info.count);
2815 : } else {
2816 0 : RETVAL_FALSE;
2817 : }
2818 0 : zend_fcall_info_args(&apply_info.fci, NULL TSRMLS_CC);
2819 : }
2820 : /* }}} */
2821 :
2822 : static zend_function_entry spl_funcs_OuterIterator[] = {
2823 : SPL_ABSTRACT_ME(OuterIterator, getInnerIterator, NULL)
2824 : {NULL, NULL, NULL}
2825 : };
2826 :
2827 : static zend_function_entry spl_funcs_Countable[] = {
2828 : SPL_ABSTRACT_ME(Countable, count, NULL)
2829 : {NULL, NULL, NULL}
2830 : };
2831 :
2832 : /* {{{ PHP_MINIT_FUNCTION(spl_iterators)
2833 : */
2834 : PHP_MINIT_FUNCTION(spl_iterators)
2835 220 : {
2836 220 : REGISTER_SPL_INTERFACE(RecursiveIterator);
2837 220 : REGISTER_SPL_ITERATOR(RecursiveIterator);
2838 :
2839 220 : REGISTER_SPL_STD_CLASS_EX(RecursiveIteratorIterator, spl_RecursiveIteratorIterator_new, spl_funcs_RecursiveIteratorIterator);
2840 220 : REGISTER_SPL_ITERATOR(RecursiveIteratorIterator);
2841 :
2842 220 : memcpy(&spl_handlers_rec_it_it, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
2843 220 : spl_handlers_rec_it_it.get_method = spl_recursive_it_get_method;
2844 220 : spl_handlers_rec_it_it.clone_obj = NULL;
2845 :
2846 220 : memcpy(&spl_handlers_dual_it, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
2847 220 : spl_handlers_dual_it.get_method = spl_dual_it_get_method;
2848 : /*spl_handlers_dual_it.call_method = spl_dual_it_call_method;*/
2849 220 : spl_handlers_dual_it.clone_obj = NULL;
2850 :
2851 220 : spl_ce_RecursiveIteratorIterator->get_iterator = spl_recursive_it_get_iterator;
2852 220 : spl_ce_RecursiveIteratorIterator->iterator_funcs.funcs = &spl_recursive_it_iterator_funcs;
2853 :
2854 220 : REGISTER_SPL_CLASS_CONST_LONG(RecursiveIteratorIterator, "LEAVES_ONLY", RIT_LEAVES_ONLY);
2855 220 : REGISTER_SPL_CLASS_CONST_LONG(RecursiveIteratorIterator, "SELF_FIRST", RIT_SELF_FIRST);
2856 220 : REGISTER_SPL_CLASS_CONST_LONG(RecursiveIteratorIterator, "CHILD_FIRST", RIT_CHILD_FIRST);
2857 220 : REGISTER_SPL_CLASS_CONST_LONG(RecursiveIteratorIterator, "CATCH_GET_CHILD", RIT_CATCH_GET_CHILD);
2858 :
2859 220 : REGISTER_SPL_INTERFACE(OuterIterator);
2860 220 : REGISTER_SPL_ITERATOR(OuterIterator);
2861 :
2862 220 : REGISTER_SPL_STD_CLASS_EX(IteratorIterator, spl_dual_it_new, spl_funcs_IteratorIterator);
2863 220 : REGISTER_SPL_ITERATOR(IteratorIterator);
2864 220 : REGISTER_SPL_IMPLEMENTS(IteratorIterator, OuterIterator);
2865 :
2866 220 : REGISTER_SPL_SUB_CLASS_EX(FilterIterator, IteratorIterator, spl_dual_it_new, spl_funcs_FilterIterator);
2867 220 : spl_ce_FilterIterator->ce_flags |= ZEND_ACC_EXPLICIT_ABSTRACT_CLASS;
2868 :
2869 220 : REGISTER_SPL_SUB_CLASS_EX(RecursiveFilterIterator, FilterIterator, spl_dual_it_new, spl_funcs_RecursiveFilterIterator);
2870 220 : REGISTER_SPL_IMPLEMENTS(RecursiveFilterIterator, RecursiveIterator);
2871 :
2872 220 : REGISTER_SPL_SUB_CLASS_EX(ParentIterator, RecursiveFilterIterator, spl_dual_it_new, spl_funcs_ParentIterator);
2873 :
2874 220 : REGISTER_SPL_INTERFACE(Countable);
2875 220 : REGISTER_SPL_INTERFACE(SeekableIterator);
2876 220 : REGISTER_SPL_ITERATOR(SeekableIterator);
2877 :
2878 220 : REGISTER_SPL_SUB_CLASS_EX(LimitIterator, IteratorIterator, spl_dual_it_new, spl_funcs_LimitIterator);
2879 :
2880 220 : REGISTER_SPL_SUB_CLASS_EX(CachingIterator, IteratorIterator, spl_dual_it_new, spl_funcs_CachingIterator);
2881 220 : REGISTER_SPL_IMPLEMENTS(CachingIterator, ArrayAccess);
2882 220 : REGISTER_SPL_IMPLEMENTS(CachingIterator, Countable);
2883 :
2884 220 : REGISTER_SPL_CLASS_CONST_LONG(CachingIterator, "CALL_TOSTRING", CIT_CALL_TOSTRING);
2885 220 : REGISTER_SPL_CLASS_CONST_LONG(CachingIterator, "CATCH_GET_CHILD", CIT_CATCH_GET_CHILD);
2886 220 : REGISTER_SPL_CLASS_CONST_LONG(CachingIterator, "TOSTRING_USE_KEY", CIT_TOSTRING_USE_KEY);
2887 220 : REGISTER_SPL_CLASS_CONST_LONG(CachingIterator, "TOSTRING_USE_CURRENT", CIT_TOSTRING_USE_CURRENT);
2888 220 : REGISTER_SPL_CLASS_CONST_LONG(CachingIterator, "TOSTRING_USE_INNER", CIT_TOSTRING_USE_INNER);
2889 220 : REGISTER_SPL_CLASS_CONST_LONG(CachingIterator, "FULL_CACHE", CIT_FULL_CACHE);
2890 :
2891 220 : REGISTER_SPL_SUB_CLASS_EX(RecursiveCachingIterator, CachingIterator, spl_dual_it_new, spl_funcs_RecursiveCachingIterator);
2892 220 : REGISTER_SPL_IMPLEMENTS(RecursiveCachingIterator, RecursiveIterator);
2893 :
2894 220 : REGISTER_SPL_SUB_CLASS_EX(NoRewindIterator, IteratorIterator, spl_dual_it_new, spl_funcs_NoRewindIterator);
2895 :
2896 220 : REGISTER_SPL_SUB_CLASS_EX(AppendIterator, IteratorIterator, spl_dual_it_new, spl_funcs_AppendIterator);
2897 :
2898 220 : REGISTER_SPL_IMPLEMENTS(RecursiveIteratorIterator, OuterIterator);
2899 :
2900 220 : REGISTER_SPL_SUB_CLASS_EX(InfiniteIterator, IteratorIterator, spl_dual_it_new, spl_funcs_InfiniteIterator);
2901 : #if HAVE_PCRE || HAVE_BUNDLED_PCRE
2902 : REGISTER_SPL_SUB_CLASS_EX(RegexIterator, FilterIterator, spl_dual_it_new, spl_funcs_RegexIterator);
2903 : REGISTER_SPL_CLASS_CONST_LONG(RegexIterator, "USE_KEY", REGIT_USE_KEY);
2904 : REGISTER_SPL_CLASS_CONST_LONG(RegexIterator, "MATCH", REGIT_MODE_MATCH);
2905 : REGISTER_SPL_CLASS_CONST_LONG(RegexIterator, "GET_MATCH", REGIT_MODE_GET_MATCH);
2906 : REGISTER_SPL_CLASS_CONST_LONG(RegexIterator, "ALL_MATCHES", REGIT_MODE_ALL_MATCHES);
2907 : REGISTER_SPL_CLASS_CONST_LONG(RegexIterator, "SPLIT", REGIT_MODE_SPLIT);
2908 : REGISTER_SPL_CLASS_CONST_LONG(RegexIterator, "REPLACE", REGIT_MODE_REPLACE);
2909 : REGISTER_SPL_PROPERTY(RegexIterator, "replacement", 0);
2910 : REGISTER_SPL_SUB_CLASS_EX(RecursiveRegexIterator, RegexIterator, spl_dual_it_new, spl_funcs_RecursiveRegexIterator);
2911 : REGISTER_SPL_IMPLEMENTS(RecursiveRegexIterator, RecursiveIterator);
2912 : #else
2913 220 : spl_ce_RegexIterator = NULL;
2914 220 : spl_ce_RecursiveRegexIterator = NULL;
2915 : #endif
2916 :
2917 220 : REGISTER_SPL_STD_CLASS_EX(EmptyIterator, NULL, spl_funcs_EmptyIterator);
2918 220 : REGISTER_SPL_ITERATOR(EmptyIterator);
2919 :
2920 220 : return SUCCESS;
2921 : }
2922 : /* }}} */
2923 :
2924 : /*
2925 : * Local variables:
2926 : * tab-width: 4
2927 : * c-basic-offset: 4
2928 : * End:
2929 : * vim600: fdm=marker
2930 : * vim: noet sw=4 ts=4
2931 : */
|