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