xref: /PHP-5.5/ext/spl/spl_iterators.c (revision 73c1be26)
1 /*
2    +----------------------------------------------------------------------+
3    | PHP Version 5                                                        |
4    +----------------------------------------------------------------------+
5    | Copyright (c) 1997-2015 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$ */
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 #include "ext/standard/php_smart_str.h"
39 
40 #ifdef accept
41 #undef accept
42 #endif
43 
44 PHPAPI zend_class_entry *spl_ce_RecursiveIterator;
45 PHPAPI zend_class_entry *spl_ce_RecursiveIteratorIterator;
46 PHPAPI zend_class_entry *spl_ce_FilterIterator;
47 PHPAPI zend_class_entry *spl_ce_CallbackFilterIterator;
48 PHPAPI zend_class_entry *spl_ce_RecursiveFilterIterator;
49 PHPAPI zend_class_entry *spl_ce_RecursiveCallbackFilterIterator;
50 PHPAPI zend_class_entry *spl_ce_ParentIterator;
51 PHPAPI zend_class_entry *spl_ce_SeekableIterator;
52 PHPAPI zend_class_entry *spl_ce_LimitIterator;
53 PHPAPI zend_class_entry *spl_ce_CachingIterator;
54 PHPAPI zend_class_entry *spl_ce_RecursiveCachingIterator;
55 PHPAPI zend_class_entry *spl_ce_OuterIterator;
56 PHPAPI zend_class_entry *spl_ce_IteratorIterator;
57 PHPAPI zend_class_entry *spl_ce_NoRewindIterator;
58 PHPAPI zend_class_entry *spl_ce_InfiniteIterator;
59 PHPAPI zend_class_entry *spl_ce_EmptyIterator;
60 PHPAPI zend_class_entry *spl_ce_AppendIterator;
61 PHPAPI zend_class_entry *spl_ce_RegexIterator;
62 PHPAPI zend_class_entry *spl_ce_RecursiveRegexIterator;
63 PHPAPI zend_class_entry *spl_ce_Countable;
64 PHPAPI zend_class_entry *spl_ce_RecursiveTreeIterator;
65 
66 ZEND_BEGIN_ARG_INFO(arginfo_recursive_it_void, 0)
67 ZEND_END_ARG_INFO()
68 
69 const zend_function_entry spl_funcs_RecursiveIterator[] = {
70 	SPL_ABSTRACT_ME(RecursiveIterator, hasChildren,  arginfo_recursive_it_void)
71 	SPL_ABSTRACT_ME(RecursiveIterator, getChildren,  arginfo_recursive_it_void)
72 	PHP_FE_END
73 };
74 
75 typedef enum {
76 	RIT_LEAVES_ONLY = 0,
77 	RIT_SELF_FIRST  = 1,
78 	RIT_CHILD_FIRST = 2
79 } RecursiveIteratorMode;
80 
81 #define RIT_CATCH_GET_CHILD CIT_CATCH_GET_CHILD
82 
83 typedef enum {
84 	RTIT_BYPASS_CURRENT = 4,
85 	RTIT_BYPASS_KEY	    = 8
86 } RecursiveTreeIteratorFlags;
87 
88 typedef enum {
89 	RS_NEXT  = 0,
90 	RS_TEST  = 1,
91 	RS_SELF  = 2,
92 	RS_CHILD = 3,
93 	RS_START = 4
94 } RecursiveIteratorState;
95 
96 typedef struct _spl_sub_iterator {
97 	zend_object_iterator    *iterator;
98 	zval                    *zobject;
99 	zend_class_entry        *ce;
100 	RecursiveIteratorState  state;
101 } spl_sub_iterator;
102 
103 typedef struct _spl_recursive_it_object {
104 	zend_object              std;
105 	spl_sub_iterator         *iterators;
106 	int                      level;
107 	RecursiveIteratorMode    mode;
108 	int                      flags;
109 	int                      max_depth;
110 	zend_bool                in_iteration;
111 	zend_function            *beginIteration;
112 	zend_function            *endIteration;
113 	zend_function            *callHasChildren;
114 	zend_function            *callGetChildren;
115 	zend_function            *beginChildren;
116 	zend_function            *endChildren;
117 	zend_function            *nextElement;
118 	zend_class_entry         *ce;
119 	smart_str                prefix[6];
120 	smart_str                postfix[1];
121 } spl_recursive_it_object;
122 
123 typedef struct _spl_recursive_it_iterator {
124 	zend_object_iterator   intern;
125 	zval                   *zobject;
126 } spl_recursive_it_iterator;
127 
128 static zend_object_handlers spl_handlers_rec_it_it;
129 static zend_object_handlers spl_handlers_dual_it;
130 
131 #define SPL_FETCH_AND_CHECK_DUAL_IT(var, objzval) \
132 	do { \
133 		spl_dual_it_object *it = zend_object_store_get_object((objzval) TSRMLS_CC); \
134 		if (it->dit_type == DIT_Unknown) { \
135 			zend_throw_exception_ex(spl_ce_LogicException, 0 TSRMLS_CC, \
136 				"The object is in an invalid state as the parent constructor was not called"); \
137 			return; \
138 		} \
139 		(var) = it; \
140 	} while (0)
141 
spl_recursive_it_dtor(zend_object_iterator * _iter TSRMLS_DC)142 static void spl_recursive_it_dtor(zend_object_iterator *_iter TSRMLS_DC)
143 {
144 	spl_recursive_it_iterator *iter   = (spl_recursive_it_iterator*)_iter;
145 	spl_recursive_it_object   *object = (spl_recursive_it_object*)_iter->data;
146 	zend_object_iterator      *sub_iter;
147 
148 	while (object->level > 0) {
149 		sub_iter = object->iterators[object->level].iterator;
150 		sub_iter->funcs->dtor(sub_iter TSRMLS_CC);
151 		zval_ptr_dtor(&object->iterators[object->level--].zobject);
152 	}
153 	object->iterators = erealloc(object->iterators, sizeof(spl_sub_iterator));
154 	object->level = 0;
155 
156 	zval_ptr_dtor(&iter->zobject);
157 	efree(iter);
158 }
159 
spl_recursive_it_valid_ex(spl_recursive_it_object * object,zval * zthis TSRMLS_DC)160 static int spl_recursive_it_valid_ex(spl_recursive_it_object *object, zval *zthis TSRMLS_DC)
161 {
162 	zend_object_iterator      *sub_iter;
163 	int                       level = object->level;
164 
165 	while (level >=0) {
166 		sub_iter = object->iterators[level].iterator;
167 		if (sub_iter->funcs->valid(sub_iter TSRMLS_CC) == SUCCESS) {
168 			return SUCCESS;
169 		}
170 		level--;
171 	}
172 	if (object->endIteration && object->in_iteration) {
173 		zend_call_method_with_0_params(&zthis, object->ce, &object->endIteration, "endIteration", NULL);
174 	}
175 	object->in_iteration = 0;
176 	return FAILURE;
177 }
178 
spl_recursive_it_valid(zend_object_iterator * iter TSRMLS_DC)179 static int spl_recursive_it_valid(zend_object_iterator *iter TSRMLS_DC)
180 {
181 	spl_recursive_it_object   *object = (spl_recursive_it_object*)iter->data;
182 
183 	return spl_recursive_it_valid_ex(object, ((spl_recursive_it_iterator*)iter)->zobject TSRMLS_CC);
184 }
185 
spl_recursive_it_get_current_data(zend_object_iterator * iter,zval *** data TSRMLS_DC)186 static void spl_recursive_it_get_current_data(zend_object_iterator *iter, zval ***data TSRMLS_DC)
187 {
188 	spl_recursive_it_object   *object = (spl_recursive_it_object*)iter->data;
189 	zend_object_iterator      *sub_iter = object->iterators[object->level].iterator;
190 
191 	sub_iter->funcs->get_current_data(sub_iter, data TSRMLS_CC);
192 }
193 
spl_recursive_it_get_current_key(zend_object_iterator * iter,zval * key TSRMLS_DC)194 static void spl_recursive_it_get_current_key(zend_object_iterator *iter, zval *key TSRMLS_DC)
195 {
196 	spl_recursive_it_object   *object = (spl_recursive_it_object*)iter->data;
197 	zend_object_iterator      *sub_iter = object->iterators[object->level].iterator;
198 
199 	if (sub_iter->funcs->get_current_key) {
200 		sub_iter->funcs->get_current_key(sub_iter, key TSRMLS_CC);
201 	} else {
202 		ZVAL_LONG(key, iter->index);
203 	}
204 }
205 
spl_recursive_it_move_forward_ex(spl_recursive_it_object * object,zval * zthis TSRMLS_DC)206 static void spl_recursive_it_move_forward_ex(spl_recursive_it_object *object, zval *zthis TSRMLS_DC)
207 {
208 	zend_object_iterator      *iterator;
209 	zval                      *zobject;
210 	zend_class_entry          *ce;
211 	zval                      *retval, *child;
212 	zend_object_iterator      *sub_iter;
213 	int                       has_children;
214 
215 	while (!EG(exception)) {
216 next_step:
217 		iterator = object->iterators[object->level].iterator;
218 		switch (object->iterators[object->level].state) {
219 			case RS_NEXT:
220 				iterator->funcs->move_forward(iterator TSRMLS_CC);
221 				if (EG(exception)) {
222 					if (!(object->flags & RIT_CATCH_GET_CHILD)) {
223 						return;
224 					} else {
225 						zend_clear_exception(TSRMLS_C);
226 					}
227 				}
228 				/* fall through */
229 			case RS_START:
230 				if (iterator->funcs->valid(iterator TSRMLS_CC) == FAILURE) {
231 					break;
232 				}
233 				object->iterators[object->level].state = RS_TEST;
234 				/* break; */
235 			case RS_TEST:
236 				ce = object->iterators[object->level].ce;
237 				zobject = object->iterators[object->level].zobject;
238 				if (object->callHasChildren) {
239 					zend_call_method_with_0_params(&zthis, object->ce, &object->callHasChildren, "callHasChildren", &retval);
240 				} else {
241 					zend_call_method_with_0_params(&zobject, ce, NULL, "haschildren", &retval);
242 				}
243 				if (EG(exception)) {
244 					if (!(object->flags & RIT_CATCH_GET_CHILD)) {
245 						object->iterators[object->level].state = RS_NEXT;
246 						return;
247 					} else {
248 						zend_clear_exception(TSRMLS_C);
249 					}
250 				}
251 				if (retval) {
252 					has_children = zend_is_true(retval);
253 					zval_ptr_dtor(&retval);
254 					if (has_children) {
255 						if (object->max_depth == -1 || object->max_depth > object->level) {
256 							switch (object->mode) {
257 							case RIT_LEAVES_ONLY:
258 							case RIT_CHILD_FIRST:
259 								object->iterators[object->level].state = RS_CHILD;
260 								goto next_step;
261 							case RIT_SELF_FIRST:
262 								object->iterators[object->level].state = RS_SELF;
263 								goto next_step;
264 							}
265 						} else {
266 							/* do not recurse into */
267 							if (object->mode == RIT_LEAVES_ONLY) {
268 								/* this is not a leave, so skip it */
269 								object->iterators[object->level].state = RS_NEXT;
270 								goto next_step;
271 							}
272 						}
273 					}
274 				}
275 				if (object->nextElement) {
276 					zend_call_method_with_0_params(&zthis, object->ce, &object->nextElement, "nextelement", NULL);
277 				}
278 				object->iterators[object->level].state = RS_NEXT;
279 				if (EG(exception)) {
280 					if (!(object->flags & RIT_CATCH_GET_CHILD)) {
281 						return;
282 					} else {
283 						zend_clear_exception(TSRMLS_C);
284 					}
285 				}
286 				return /* self */;
287 			case RS_SELF:
288 				if (object->nextElement && (object->mode == RIT_SELF_FIRST || object->mode == RIT_CHILD_FIRST)) {
289 					zend_call_method_with_0_params(&zthis, object->ce, &object->nextElement, "nextelement", NULL);
290 				}
291 				if (object->mode == RIT_SELF_FIRST) {
292 					object->iterators[object->level].state = RS_CHILD;
293 				} else {
294 					object->iterators[object->level].state = RS_NEXT;
295 				}
296 				return /* self */;
297 			case RS_CHILD:
298 				ce = object->iterators[object->level].ce;
299 				zobject = object->iterators[object->level].zobject;
300 				if (object->callGetChildren) {
301 					zend_call_method_with_0_params(&zthis, object->ce, &object->callGetChildren, "callGetChildren", &child);
302 				} else {
303 					zend_call_method_with_0_params(&zobject, ce, NULL, "getchildren", &child);
304 				}
305 
306 				if (EG(exception)) {
307 					if (!(object->flags & RIT_CATCH_GET_CHILD)) {
308 						return;
309 					} else {
310 						zend_clear_exception(TSRMLS_C);
311 						if (child) {
312 							zval_ptr_dtor(&child);
313 						}
314 						object->iterators[object->level].state = RS_NEXT;
315 						goto next_step;
316 					}
317 				}
318 
319 				ce = child && Z_TYPE_P(child) == IS_OBJECT ? Z_OBJCE_P(child) : NULL;
320 				if (!ce || !instanceof_function(ce, spl_ce_RecursiveIterator TSRMLS_CC)) {
321 					if (child) {
322 						zval_ptr_dtor(&child);
323 					}
324 					zend_throw_exception(spl_ce_UnexpectedValueException, "Objects returned by RecursiveIterator::getChildren() must implement RecursiveIterator", 0 TSRMLS_CC);
325 					return;
326 				}
327 				if (object->mode == RIT_CHILD_FIRST) {
328 					object->iterators[object->level].state = RS_SELF;
329 				} else {
330 					object->iterators[object->level].state = RS_NEXT;
331 				}
332 				object->iterators = erealloc(object->iterators, sizeof(spl_sub_iterator) * (++object->level+1));
333 				sub_iter = ce->get_iterator(ce, child, 0 TSRMLS_CC);
334 				object->iterators[object->level].iterator = sub_iter;
335 				object->iterators[object->level].zobject = child;
336 				object->iterators[object->level].ce = ce;
337 				object->iterators[object->level].state = RS_START;
338 				if (sub_iter->funcs->rewind) {
339 					sub_iter->funcs->rewind(sub_iter TSRMLS_CC);
340 				}
341 				if (object->beginChildren) {
342 					zend_call_method_with_0_params(&zthis, object->ce, &object->beginChildren, "beginchildren", NULL);
343 					if (EG(exception)) {
344 						if (!(object->flags & RIT_CATCH_GET_CHILD)) {
345 							return;
346 						} else {
347 							zend_clear_exception(TSRMLS_C);
348 						}
349 					}
350 				}
351 				goto next_step;
352 		}
353 		/* no more elements */
354 		if (object->level > 0) {
355 			if (object->endChildren) {
356 				zend_call_method_with_0_params(&zthis, object->ce, &object->endChildren, "endchildren", NULL);
357 				if (EG(exception)) {
358 					if (!(object->flags & RIT_CATCH_GET_CHILD)) {
359 						return;
360 					} else {
361 						zend_clear_exception(TSRMLS_C);
362 					}
363 				}
364 			}
365 			iterator->funcs->dtor(iterator TSRMLS_CC);
366 			zval_ptr_dtor(&object->iterators[object->level].zobject);
367 			object->level--;
368 		} else {
369 			return; /* done completeley */
370 		}
371 	}
372 }
373 
spl_recursive_it_rewind_ex(spl_recursive_it_object * object,zval * zthis TSRMLS_DC)374 static void spl_recursive_it_rewind_ex(spl_recursive_it_object *object, zval *zthis TSRMLS_DC)
375 {
376 	zend_object_iterator      *sub_iter;
377 
378 	if (!object->iterators) {
379 		php_error_docref(NULL TSRMLS_CC, E_ERROR, "The %s instance wasn't initialized properly", Z_OBJCE_P(zthis)->name);
380 	}
381 
382 	while (object->level) {
383 		sub_iter = object->iterators[object->level].iterator;
384 		sub_iter->funcs->dtor(sub_iter TSRMLS_CC);
385 		zval_ptr_dtor(&object->iterators[object->level--].zobject);
386 		if (!EG(exception) && (!object->endChildren || object->endChildren->common.scope != spl_ce_RecursiveIteratorIterator)) {
387 			zend_call_method_with_0_params(&zthis, object->ce, &object->endChildren, "endchildren", NULL);
388 		}
389 	}
390 	object->iterators = erealloc(object->iterators, sizeof(spl_sub_iterator));
391 	object->iterators[0].state = RS_START;
392 	sub_iter = object->iterators[0].iterator;
393 	if (sub_iter->funcs->rewind) {
394 		sub_iter->funcs->rewind(sub_iter TSRMLS_CC);
395 	}
396 	if (!EG(exception) && object->beginIteration && !object->in_iteration) {
397 		zend_call_method_with_0_params(&zthis, object->ce, &object->beginIteration, "beginIteration", NULL);
398 	}
399 	object->in_iteration = 1;
400 	spl_recursive_it_move_forward_ex(object, zthis TSRMLS_CC);
401 }
402 
spl_recursive_it_move_forward(zend_object_iterator * iter TSRMLS_DC)403 static void spl_recursive_it_move_forward(zend_object_iterator *iter TSRMLS_DC)
404 {
405 	spl_recursive_it_move_forward_ex((spl_recursive_it_object*)iter->data, ((spl_recursive_it_iterator*)iter)->zobject TSRMLS_CC);
406 }
407 
spl_recursive_it_rewind(zend_object_iterator * iter TSRMLS_DC)408 static void spl_recursive_it_rewind(zend_object_iterator *iter TSRMLS_DC)
409 {
410 	spl_recursive_it_rewind_ex((spl_recursive_it_object*)iter->data, ((spl_recursive_it_iterator*)iter)->zobject TSRMLS_CC);
411 }
412 
spl_recursive_it_get_iterator(zend_class_entry * ce,zval * zobject,int by_ref TSRMLS_DC)413 static zend_object_iterator *spl_recursive_it_get_iterator(zend_class_entry *ce, zval *zobject, int by_ref TSRMLS_DC)
414 {
415 	spl_recursive_it_iterator *iterator;
416 	spl_recursive_it_object   *object;
417 
418 	if (by_ref) {
419 		zend_error(E_ERROR, "An iterator cannot be used with foreach by reference");
420 	}
421 	iterator = emalloc(sizeof(spl_recursive_it_iterator));
422 	object   = (spl_recursive_it_object*)zend_object_store_get_object(zobject TSRMLS_CC);
423 	if (object->iterators == NULL) {
424 		zend_error(E_ERROR, "The object to be iterated is in an invalid state: "
425 				"the parent constructor has not been called");
426 	}
427 
428 	Z_ADDREF_P(zobject);
429 	iterator->intern.data = (void*)object;
430 	iterator->intern.funcs = ce->iterator_funcs.funcs;
431 	iterator->zobject = zobject;
432 	return (zend_object_iterator*)iterator;
433 }
434 
435 zend_object_iterator_funcs spl_recursive_it_iterator_funcs = {
436 	spl_recursive_it_dtor,
437 	spl_recursive_it_valid,
438 	spl_recursive_it_get_current_data,
439 	spl_recursive_it_get_current_key,
440 	spl_recursive_it_move_forward,
441 	spl_recursive_it_rewind
442 };
443 
spl_recursive_it_it_construct(INTERNAL_FUNCTION_PARAMETERS,zend_class_entry * ce_base,zend_class_entry * ce_inner,recursive_it_it_type rit_type)444 static void spl_recursive_it_it_construct(INTERNAL_FUNCTION_PARAMETERS, zend_class_entry *ce_base, zend_class_entry *ce_inner, recursive_it_it_type rit_type)
445 {
446 	zval                      *object = getThis();
447 	spl_recursive_it_object   *intern;
448 	zval                      *iterator;
449 	zend_class_entry          *ce_iterator;
450 	long                       mode, flags;
451 	int                        inc_refcount = 1;
452 	zend_error_handling        error_handling;
453 
454 	zend_replace_error_handling(EH_THROW, spl_ce_InvalidArgumentException, &error_handling TSRMLS_CC);
455 
456 	switch(rit_type) {
457 		case RIT_RecursiveTreeIterator: {
458 
459 			zval *caching_it, *caching_it_flags, *user_caching_it_flags = NULL;
460 			mode = RIT_SELF_FIRST;
461 			flags = RTIT_BYPASS_KEY;
462 
463 			if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "o|lzl", &iterator, &flags, &user_caching_it_flags, &mode) == SUCCESS) {
464 				if (instanceof_function(Z_OBJCE_P(iterator), zend_ce_aggregate TSRMLS_CC)) {
465 					zval *aggregate = iterator;
466 					zend_call_method_with_0_params(&aggregate, Z_OBJCE_P(aggregate), &Z_OBJCE_P(aggregate)->iterator_funcs.zf_new_iterator, "getiterator", &iterator);
467 					inc_refcount = 0;
468 				}
469 
470 				MAKE_STD_ZVAL(caching_it_flags);
471 				if (user_caching_it_flags) {
472 					ZVAL_ZVAL(caching_it_flags, user_caching_it_flags, 1, 0);
473 				} else {
474 					ZVAL_LONG(caching_it_flags, CIT_CATCH_GET_CHILD);
475 				}
476 				spl_instantiate_arg_ex2(spl_ce_RecursiveCachingIterator, &caching_it, 1, iterator, caching_it_flags TSRMLS_CC);
477 				zval_ptr_dtor(&caching_it_flags);
478 				if (inc_refcount == 0 && iterator) {
479 					zval_ptr_dtor(&iterator);
480 				}
481 				iterator = caching_it;
482 				inc_refcount = 0;
483 			} else {
484 				iterator = NULL;
485 			}
486 			break;
487 		}
488 		case RIT_RecursiveIteratorIterator:
489 		default: {
490 			mode = RIT_LEAVES_ONLY;
491 			flags = 0;
492 
493 			if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "o|ll", &iterator, &mode, &flags) == SUCCESS) {
494 				if (instanceof_function(Z_OBJCE_P(iterator), zend_ce_aggregate TSRMLS_CC)) {
495 					zval *aggregate = iterator;
496 					zend_call_method_with_0_params(&aggregate, Z_OBJCE_P(aggregate), &Z_OBJCE_P(aggregate)->iterator_funcs.zf_new_iterator, "getiterator", &iterator);
497 					inc_refcount = 0;
498 				}
499 			} else {
500 				iterator = NULL;
501 			}
502 			break;
503 		}
504 	}
505 	if (!iterator || !instanceof_function(Z_OBJCE_P(iterator), spl_ce_RecursiveIterator TSRMLS_CC)) {
506 		if (iterator && !inc_refcount) {
507 			zval_ptr_dtor(&iterator);
508 		}
509 		zend_throw_exception(spl_ce_InvalidArgumentException, "An instance of RecursiveIterator or IteratorAggregate creating it is required", 0 TSRMLS_CC);
510 		zend_restore_error_handling(&error_handling TSRMLS_CC);
511 		return;
512 	}
513 
514 	intern = (spl_recursive_it_object*)zend_object_store_get_object(object TSRMLS_CC);
515 	intern->iterators = emalloc(sizeof(spl_sub_iterator));
516 	intern->level = 0;
517 	intern->mode = mode;
518 	intern->flags = flags;
519 	intern->max_depth = -1;
520 	intern->in_iteration = 0;
521 	intern->ce = Z_OBJCE_P(object);
522 
523 	zend_hash_find(&intern->ce->function_table, "beginiteration", sizeof("beginiteration"), (void **) &intern->beginIteration);
524 	if (intern->beginIteration->common.scope == ce_base) {
525 		intern->beginIteration = NULL;
526 	}
527 	zend_hash_find(&intern->ce->function_table, "enditeration", sizeof("enditeration"), (void **) &intern->endIteration);
528 	if (intern->endIteration->common.scope == ce_base) {
529 		intern->endIteration = NULL;
530 	}
531 	zend_hash_find(&intern->ce->function_table, "callhaschildren", sizeof("callHasChildren"), (void **) &intern->callHasChildren);
532 	if (intern->callHasChildren->common.scope == ce_base) {
533 		intern->callHasChildren = NULL;
534 	}
535 	zend_hash_find(&intern->ce->function_table, "callgetchildren", sizeof("callGetChildren"), (void **) &intern->callGetChildren);
536 	if (intern->callGetChildren->common.scope == ce_base) {
537 		intern->callGetChildren = NULL;
538 	}
539 	zend_hash_find(&intern->ce->function_table, "beginchildren", sizeof("beginchildren"), (void **) &intern->beginChildren);
540 	if (intern->beginChildren->common.scope == ce_base) {
541 		intern->beginChildren = NULL;
542 	}
543 	zend_hash_find(&intern->ce->function_table, "endchildren", sizeof("endchildren"), (void **) &intern->endChildren);
544 	if (intern->endChildren->common.scope == ce_base) {
545 		intern->endChildren = NULL;
546 	}
547 	zend_hash_find(&intern->ce->function_table, "nextelement", sizeof("nextElement"), (void **) &intern->nextElement);
548 	if (intern->nextElement->common.scope == ce_base) {
549 		intern->nextElement = NULL;
550 	}
551 	ce_iterator = Z_OBJCE_P(iterator); /* respect inheritance, don't use spl_ce_RecursiveIterator */
552 	intern->iterators[0].iterator = ce_iterator->get_iterator(ce_iterator, iterator, 0 TSRMLS_CC);
553 	if (inc_refcount) {
554 		Z_ADDREF_P(iterator);
555 	}
556 	intern->iterators[0].zobject = iterator;
557 	intern->iterators[0].ce = ce_iterator;
558 	intern->iterators[0].state = RS_START;
559 
560 	zend_restore_error_handling(&error_handling TSRMLS_CC);
561 
562 	if (EG(exception)) {
563 		zend_object_iterator *sub_iter;
564 
565 		while (intern->level >= 0) {
566 			sub_iter = intern->iterators[intern->level].iterator;
567 			sub_iter->funcs->dtor(sub_iter TSRMLS_CC);
568 			zval_ptr_dtor(&intern->iterators[intern->level--].zobject);
569 		}
570 		efree(intern->iterators);
571 		intern->iterators = NULL;
572 	}
573 }
574 
575 /* {{{ proto void RecursiveIteratorIterator::__construct(RecursiveIterator|IteratorAggregate it [, int mode = RIT_LEAVES_ONLY [, int flags = 0]]) throws InvalidArgumentException
576    Creates a RecursiveIteratorIterator from a RecursiveIterator. */
SPL_METHOD(RecursiveIteratorIterator,__construct)577 SPL_METHOD(RecursiveIteratorIterator, __construct)
578 {
579 	spl_recursive_it_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_RecursiveIteratorIterator, zend_ce_iterator, RIT_RecursiveIteratorIterator);
580 } /* }}} */
581 
582 /* {{{ proto void RecursiveIteratorIterator::rewind()
583    Rewind the iterator to the first element of the top level inner iterator. */
SPL_METHOD(RecursiveIteratorIterator,rewind)584 SPL_METHOD(RecursiveIteratorIterator, rewind)
585 {
586 	spl_recursive_it_object   *object = (spl_recursive_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
587 
588 	if (zend_parse_parameters_none() == FAILURE) {
589 		return;
590 	}
591 
592 	spl_recursive_it_rewind_ex(object, getThis() TSRMLS_CC);
593 } /* }}} */
594 
595 /* {{{ proto bool RecursiveIteratorIterator::valid()
596    Check whether the current position is valid */
SPL_METHOD(RecursiveIteratorIterator,valid)597 SPL_METHOD(RecursiveIteratorIterator, valid)
598 {
599 	spl_recursive_it_object   *object = (spl_recursive_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
600 
601 	if (zend_parse_parameters_none() == FAILURE) {
602 		return;
603 	}
604 
605 	RETURN_BOOL(spl_recursive_it_valid_ex(object, getThis() TSRMLS_CC) == SUCCESS);
606 } /* }}} */
607 
608 /* {{{ proto mixed RecursiveIteratorIterator::key()
609    Access the current key */
SPL_METHOD(RecursiveIteratorIterator,key)610 SPL_METHOD(RecursiveIteratorIterator, key)
611 {
612 	spl_recursive_it_object   *object = (spl_recursive_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
613 	zend_object_iterator      *iterator = object->iterators[object->level].iterator;
614 
615 	if (zend_parse_parameters_none() == FAILURE) {
616 		return;
617 	}
618 
619 	if (iterator->funcs->get_current_key) {
620 		iterator->funcs->get_current_key(iterator, return_value TSRMLS_CC);
621 	} else {
622 		RETURN_NULL();
623 	}
624 } /* }}} */
625 
626 /* {{{ proto mixed RecursiveIteratorIterator::current()
627    Access the current element value */
SPL_METHOD(RecursiveIteratorIterator,current)628 SPL_METHOD(RecursiveIteratorIterator, current)
629 {
630 	spl_recursive_it_object   *object = (spl_recursive_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
631 	zend_object_iterator      *iterator = object->iterators[object->level].iterator;
632 	zval                      **data;
633 
634 	if (zend_parse_parameters_none() == FAILURE) {
635 		return;
636 	}
637 
638 	iterator->funcs->get_current_data(iterator, &data TSRMLS_CC);
639 	if (data && *data) {
640 		RETURN_ZVAL(*data, 1, 0);
641 	}
642 } /* }}} */
643 
644 /* {{{ proto void RecursiveIteratorIterator::next()
645    Move forward to the next element */
SPL_METHOD(RecursiveIteratorIterator,next)646 SPL_METHOD(RecursiveIteratorIterator, next)
647 {
648 	spl_recursive_it_object   *object = (spl_recursive_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
649 
650 	if (zend_parse_parameters_none() == FAILURE) {
651 		return;
652 	}
653 
654 	spl_recursive_it_move_forward_ex(object, getThis() TSRMLS_CC);
655 } /* }}} */
656 
657 /* {{{ proto int RecursiveIteratorIterator::getDepth()
658    Get the current depth of the recursive iteration */
SPL_METHOD(RecursiveIteratorIterator,getDepth)659 SPL_METHOD(RecursiveIteratorIterator, getDepth)
660 {
661 	spl_recursive_it_object   *object = (spl_recursive_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
662 
663 	if (zend_parse_parameters_none() == FAILURE) {
664 		return;
665 	}
666 
667 	RETURN_LONG(object->level);
668 } /* }}} */
669 
670 /* {{{ proto RecursiveIterator RecursiveIteratorIterator::getSubIterator([int level])
671    The current active sub iterator or the iterator at specified level */
SPL_METHOD(RecursiveIteratorIterator,getSubIterator)672 SPL_METHOD(RecursiveIteratorIterator, getSubIterator)
673 {
674 	spl_recursive_it_object   *object = (spl_recursive_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
675 	long  level = object->level;
676 
677 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &level) == FAILURE) {
678 		return;
679 	}
680 	if (level < 0 || level > object->level) {
681 		RETURN_NULL();
682 	}
683 	RETURN_ZVAL(object->iterators[level].zobject, 1, 0);
684 } /* }}} */
685 
686 /* {{{ proto RecursiveIterator RecursiveIteratorIterator::getInnerIterator()
687    The current active sub iterator */
SPL_METHOD(RecursiveIteratorIterator,getInnerIterator)688 SPL_METHOD(RecursiveIteratorIterator, getInnerIterator)
689 {
690 	spl_recursive_it_object   *object = (spl_recursive_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
691 	long  level = object->level;
692 
693 	if (zend_parse_parameters_none() == FAILURE) {
694 		return;
695 	}
696 
697 	RETURN_ZVAL(object->iterators[level].zobject, 1, 0);
698 } /* }}} */
699 
700 /* {{{ proto RecursiveIterator RecursiveIteratorIterator::beginIteration()
701    Called when iteration begins (after first rewind() call) */
SPL_METHOD(RecursiveIteratorIterator,beginIteration)702 SPL_METHOD(RecursiveIteratorIterator, beginIteration)
703 {
704 	if (zend_parse_parameters_none() == FAILURE) {
705 		return;
706 	}
707 	/* nothing to do */
708 } /* }}} */
709 
710 /* {{{ proto RecursiveIterator RecursiveIteratorIterator::endIteration()
711    Called when iteration ends (when valid() first returns false */
SPL_METHOD(RecursiveIteratorIterator,endIteration)712 SPL_METHOD(RecursiveIteratorIterator, endIteration)
713 {
714 	if (zend_parse_parameters_none() == FAILURE) {
715 		return;
716 	}
717 	/* nothing to do */
718 } /* }}} */
719 
720 /* {{{ proto bool RecursiveIteratorIterator::callHasChildren()
721    Called for each element to test whether it has children */
SPL_METHOD(RecursiveIteratorIterator,callHasChildren)722 SPL_METHOD(RecursiveIteratorIterator, callHasChildren)
723 {
724 	spl_recursive_it_object   *object = (spl_recursive_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
725 	zend_class_entry *ce = object->iterators[object->level].ce;
726 	zval *retval, *zobject;
727 
728 	if (zend_parse_parameters_none() == FAILURE) {
729 		return;
730 	}
731 
732 	zobject = object->iterators[object->level].zobject;
733 	if (!zobject) {
734 		RETURN_FALSE;
735 	} else {
736 		zend_call_method_with_0_params(&zobject, ce, NULL, "haschildren", &retval);
737 		if (retval) {
738 			RETURN_ZVAL(retval, 0, 1);
739 		} else {
740 			RETURN_FALSE;
741 		}
742 	}
743 } /* }}} */
744 
745 /* {{{ proto RecursiveIterator RecursiveIteratorIterator::callGetChildren()
746    Return children of current element */
SPL_METHOD(RecursiveIteratorIterator,callGetChildren)747 SPL_METHOD(RecursiveIteratorIterator, callGetChildren)
748 {
749 	spl_recursive_it_object   *object = (spl_recursive_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
750 	zend_class_entry *ce = object->iterators[object->level].ce;
751 	zval *retval, *zobject;
752 
753 	if (zend_parse_parameters_none() == FAILURE) {
754 		return;
755 	}
756 
757 	zobject = object->iterators[object->level].zobject;
758 	if (!zobject) {
759 		return;
760 	} else {
761 		zend_call_method_with_0_params(&zobject, ce, NULL, "getchildren", &retval);
762 		if (retval) {
763 			RETURN_ZVAL(retval, 0, 1);
764 		}
765 	}
766 } /* }}} */
767 
768 /* {{{ proto void RecursiveIteratorIterator::beginChildren()
769    Called when recursing one level down */
SPL_METHOD(RecursiveIteratorIterator,beginChildren)770 SPL_METHOD(RecursiveIteratorIterator, beginChildren)
771 {
772 	if (zend_parse_parameters_none() == FAILURE) {
773 		return;
774 	}
775 	/* nothing to do */
776 } /* }}} */
777 
778 /* {{{ proto void RecursiveIteratorIterator::endChildren()
779    Called when end recursing one level */
SPL_METHOD(RecursiveIteratorIterator,endChildren)780 SPL_METHOD(RecursiveIteratorIterator, endChildren)
781 {
782 	if (zend_parse_parameters_none() == FAILURE) {
783 		return;
784 	}
785 	/* nothing to do */
786 } /* }}} */
787 
788 /* {{{ proto void RecursiveIteratorIterator::nextElement()
789    Called when the next element is available */
SPL_METHOD(RecursiveIteratorIterator,nextElement)790 SPL_METHOD(RecursiveIteratorIterator, nextElement)
791 {
792 	if (zend_parse_parameters_none() == FAILURE) {
793 		return;
794 	}
795 	/* nothing to do */
796 } /* }}} */
797 
798 /* {{{ proto void RecursiveIteratorIterator::setMaxDepth([$max_depth = -1])
799    Set the maximum allowed depth (or any depth if pmax_depth = -1] */
SPL_METHOD(RecursiveIteratorIterator,setMaxDepth)800 SPL_METHOD(RecursiveIteratorIterator, setMaxDepth)
801 {
802 	spl_recursive_it_object   *object = (spl_recursive_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
803 	long  max_depth = -1;
804 
805 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &max_depth) == FAILURE) {
806 		return;
807 	}
808 	if (max_depth < -1) {
809 		zend_throw_exception(spl_ce_OutOfRangeException, "Parameter max_depth must be >= -1", 0 TSRMLS_CC);
810 		return;
811 	}
812 	object->max_depth = max_depth;
813 } /* }}} */
814 
815 /* {{{ proto int|false RecursiveIteratorIterator::getMaxDepth()
816    Return the maximum accepted depth or false if any depth is allowed */
SPL_METHOD(RecursiveIteratorIterator,getMaxDepth)817 SPL_METHOD(RecursiveIteratorIterator, getMaxDepth)
818 {
819 	spl_recursive_it_object   *object = (spl_recursive_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
820 
821 	if (zend_parse_parameters_none() == FAILURE) {
822 		return;
823 	}
824 
825 	if (object->max_depth == -1) {
826 		RETURN_FALSE;
827 	} else {
828 		RETURN_LONG(object->max_depth);
829 	}
830 } /* }}} */
831 
spl_recursive_it_get_method(zval ** object_ptr,char * method,int method_len,const zend_literal * key TSRMLS_DC)832 static union _zend_function *spl_recursive_it_get_method(zval **object_ptr, char *method, int method_len, const zend_literal *key TSRMLS_DC)
833 {
834 	union _zend_function    *function_handler;
835 	spl_recursive_it_object *object = (spl_recursive_it_object*)zend_object_store_get_object(*object_ptr TSRMLS_CC);
836 	long                     level = object->level;
837 	zval                    *zobj;
838 
839 	if (!object->iterators) {
840 		php_error_docref(NULL TSRMLS_CC, E_ERROR, "The %s instance wasn't initialized properly", Z_OBJCE_PP(object_ptr)->name);
841 	}
842 	zobj = object->iterators[level].zobject;
843 
844 	function_handler = std_object_handlers.get_method(object_ptr, method, method_len, key TSRMLS_CC);
845 	if (!function_handler) {
846 		if (zend_hash_find(&Z_OBJCE_P(zobj)->function_table, method, method_len+1, (void **) &function_handler) == FAILURE) {
847 			if (Z_OBJ_HT_P(zobj)->get_method) {
848 				*object_ptr = zobj;
849 				function_handler = Z_OBJ_HT_P(*object_ptr)->get_method(object_ptr, method, method_len, key TSRMLS_CC);
850 			}
851 		} else {
852 			*object_ptr = zobj;
853 		}
854 	}
855 	return function_handler;
856 }
857 
858 /* {{{ spl_RecursiveIteratorIterator_dtor */
spl_RecursiveIteratorIterator_dtor(zend_object * _object,zend_object_handle handle TSRMLS_DC)859 static void spl_RecursiveIteratorIterator_dtor(zend_object *_object, zend_object_handle handle TSRMLS_DC)
860 {
861 	spl_recursive_it_object   *object = (spl_recursive_it_object *)_object;
862 	zend_object_iterator      *sub_iter;
863 
864 	/* call standard dtor */
865 	zend_objects_destroy_object(_object, handle TSRMLS_CC);
866 
867 	if (object->iterators) {
868 		while (object->level >= 0) {
869 			sub_iter = object->iterators[object->level].iterator;
870 			sub_iter->funcs->dtor(sub_iter TSRMLS_CC);
871 			zval_ptr_dtor(&object->iterators[object->level--].zobject);
872 		}
873 		efree(object->iterators);
874 		object->iterators = NULL;
875 	}
876 }
877 /* }}} */
878 
879 /* {{{ spl_RecursiveIteratorIterator_free_storage */
spl_RecursiveIteratorIterator_free_storage(void * _object TSRMLS_DC)880 static void spl_RecursiveIteratorIterator_free_storage(void *_object TSRMLS_DC)
881 {
882 	spl_recursive_it_object   *object = (spl_recursive_it_object *)_object;
883 
884 	zend_object_std_dtor(&object->std TSRMLS_CC);
885 	smart_str_free(&object->prefix[0]);
886 	smart_str_free(&object->prefix[1]);
887 	smart_str_free(&object->prefix[2]);
888 	smart_str_free(&object->prefix[3]);
889 	smart_str_free(&object->prefix[4]);
890 	smart_str_free(&object->prefix[5]);
891 
892 	smart_str_free(&object->postfix[0]);
893 
894 	efree(object);
895 }
896 /* }}} */
897 
898 /* {{{ spl_RecursiveIteratorIterator_new_ex */
spl_RecursiveIteratorIterator_new_ex(zend_class_entry * class_type,int init_prefix TSRMLS_DC)899 static zend_object_value spl_RecursiveIteratorIterator_new_ex(zend_class_entry *class_type, int init_prefix TSRMLS_DC)
900 {
901 	zend_object_value retval;
902 	spl_recursive_it_object *intern;
903 
904 	intern = emalloc(sizeof(spl_recursive_it_object));
905 	memset(intern, 0, sizeof(spl_recursive_it_object));
906 
907 	if (init_prefix) {
908 		smart_str_appendl(&intern->prefix[0], "",    0);
909 		smart_str_appendl(&intern->prefix[1], "| ",  2);
910 		smart_str_appendl(&intern->prefix[2], "  ",  2);
911 		smart_str_appendl(&intern->prefix[3], "|-",  2);
912 		smart_str_appendl(&intern->prefix[4], "\\-", 2);
913 		smart_str_appendl(&intern->prefix[5], "",    0);
914 
915 		smart_str_appendl(&intern->postfix[0], "",    0);
916 	}
917 
918 	zend_object_std_init(&intern->std, class_type TSRMLS_CC);
919 	object_properties_init(&intern->std, class_type);
920 
921 	retval.handle = zend_objects_store_put(intern, (zend_objects_store_dtor_t)spl_RecursiveIteratorIterator_dtor, (zend_objects_free_object_storage_t) spl_RecursiveIteratorIterator_free_storage, NULL TSRMLS_CC);
922 	retval.handlers = &spl_handlers_rec_it_it;
923 	return retval;
924 }
925 /* }}} */
926 
927 /* {{{ spl_RecursiveIteratorIterator_new */
spl_RecursiveIteratorIterator_new(zend_class_entry * class_type TSRMLS_DC)928 static zend_object_value spl_RecursiveIteratorIterator_new(zend_class_entry *class_type TSRMLS_DC)
929 {
930 	return spl_RecursiveIteratorIterator_new_ex(class_type, 0 TSRMLS_CC);
931 }
932 /* }}} */
933 
934 /* {{{ spl_RecursiveTreeIterator_new */
spl_RecursiveTreeIterator_new(zend_class_entry * class_type TSRMLS_DC)935 static zend_object_value spl_RecursiveTreeIterator_new(zend_class_entry *class_type TSRMLS_DC)
936 {
937 	return spl_RecursiveIteratorIterator_new_ex(class_type, 1 TSRMLS_CC);
938 }
939 /* }}} */
940 
941 ZEND_BEGIN_ARG_INFO_EX(arginfo_recursive_it___construct, 0, 0, 1)
942 	ZEND_ARG_OBJ_INFO(0, iterator, Traversable, 0)
943 	ZEND_ARG_INFO(0, mode)
944 	ZEND_ARG_INFO(0, flags)
945 ZEND_END_ARG_INFO();
946 
947 ZEND_BEGIN_ARG_INFO_EX(arginfo_recursive_it_getSubIterator, 0, 0, 0)
948 	ZEND_ARG_INFO(0, level)
949 ZEND_END_ARG_INFO();
950 
951 ZEND_BEGIN_ARG_INFO_EX(arginfo_recursive_it_setMaxDepth, 0, 0, 0)
952 	ZEND_ARG_INFO(0, max_depth)
953 ZEND_END_ARG_INFO();
954 
955 static const zend_function_entry spl_funcs_RecursiveIteratorIterator[] = {
956 	SPL_ME(RecursiveIteratorIterator, __construct,       arginfo_recursive_it___construct,    ZEND_ACC_PUBLIC)
957 	SPL_ME(RecursiveIteratorIterator, rewind,            arginfo_recursive_it_void,           ZEND_ACC_PUBLIC)
958 	SPL_ME(RecursiveIteratorIterator, valid,             arginfo_recursive_it_void,           ZEND_ACC_PUBLIC)
959 	SPL_ME(RecursiveIteratorIterator, key,               arginfo_recursive_it_void,           ZEND_ACC_PUBLIC)
960 	SPL_ME(RecursiveIteratorIterator, current,           arginfo_recursive_it_void,           ZEND_ACC_PUBLIC)
961 	SPL_ME(RecursiveIteratorIterator, next,              arginfo_recursive_it_void,           ZEND_ACC_PUBLIC)
962 	SPL_ME(RecursiveIteratorIterator, getDepth,          arginfo_recursive_it_void,           ZEND_ACC_PUBLIC)
963 	SPL_ME(RecursiveIteratorIterator, getSubIterator,    arginfo_recursive_it_getSubIterator, ZEND_ACC_PUBLIC)
964 	SPL_ME(RecursiveIteratorIterator, getInnerIterator,  arginfo_recursive_it_void,           ZEND_ACC_PUBLIC)
965 	SPL_ME(RecursiveIteratorIterator, beginIteration,    arginfo_recursive_it_void,           ZEND_ACC_PUBLIC)
966 	SPL_ME(RecursiveIteratorIterator, endIteration,      arginfo_recursive_it_void,           ZEND_ACC_PUBLIC)
967 	SPL_ME(RecursiveIteratorIterator, callHasChildren,   arginfo_recursive_it_void,           ZEND_ACC_PUBLIC)
968 	SPL_ME(RecursiveIteratorIterator, callGetChildren,   arginfo_recursive_it_void,           ZEND_ACC_PUBLIC)
969 	SPL_ME(RecursiveIteratorIterator, beginChildren,     arginfo_recursive_it_void,           ZEND_ACC_PUBLIC)
970 	SPL_ME(RecursiveIteratorIterator, endChildren,       arginfo_recursive_it_void,           ZEND_ACC_PUBLIC)
971 	SPL_ME(RecursiveIteratorIterator, nextElement,       arginfo_recursive_it_void,           ZEND_ACC_PUBLIC)
972 	SPL_ME(RecursiveIteratorIterator, setMaxDepth,       arginfo_recursive_it_setMaxDepth,    ZEND_ACC_PUBLIC)
973 	SPL_ME(RecursiveIteratorIterator, getMaxDepth,       arginfo_recursive_it_void,           ZEND_ACC_PUBLIC)
974 	PHP_FE_END
975 };
976 
spl_recursive_tree_iterator_get_prefix(spl_recursive_it_object * object,zval * return_value TSRMLS_DC)977 static void spl_recursive_tree_iterator_get_prefix(spl_recursive_it_object *object, zval *return_value TSRMLS_DC)
978 {
979 	smart_str  str = {0};
980 	zval      *has_next;
981 	int        level;
982 
983 	smart_str_appendl(&str, object->prefix[0].c, object->prefix[0].len);
984 
985 	for (level = 0; level < object->level; ++level) {
986 		zend_call_method_with_0_params(&object->iterators[level].zobject, object->iterators[level].ce, NULL, "hasnext", &has_next);
987 		if (has_next) {
988 			if (Z_LVAL_P(has_next)) {
989 				smart_str_appendl(&str, object->prefix[1].c, object->prefix[1].len);
990 			} else {
991 				smart_str_appendl(&str, object->prefix[2].c, object->prefix[2].len);
992 			}
993 			zval_ptr_dtor(&has_next);
994 		}
995 	}
996 	zend_call_method_with_0_params(&object->iterators[level].zobject, object->iterators[level].ce, NULL, "hasnext", &has_next);
997 	if (has_next) {
998 		if (Z_LVAL_P(has_next)) {
999 			smart_str_appendl(&str, object->prefix[3].c, object->prefix[3].len);
1000 		} else {
1001 			smart_str_appendl(&str, object->prefix[4].c, object->prefix[4].len);
1002 		}
1003 		zval_ptr_dtor(&has_next);
1004 	}
1005 
1006 	smart_str_appendl(&str, object->prefix[5].c, object->prefix[5].len);
1007 	smart_str_0(&str);
1008 
1009 	RETVAL_STRINGL(str.c, str.len, 0);
1010 }
1011 
spl_recursive_tree_iterator_get_entry(spl_recursive_it_object * object,zval * return_value TSRMLS_DC)1012 static void spl_recursive_tree_iterator_get_entry(spl_recursive_it_object * object, zval * return_value TSRMLS_DC)
1013 {
1014 	zend_object_iterator      *iterator = object->iterators[object->level].iterator;
1015 	zval                     **data;
1016 	zend_error_handling        error_handling;
1017 
1018 	iterator->funcs->get_current_data(iterator, &data TSRMLS_CC);
1019 
1020 	zend_replace_error_handling(EH_THROW, spl_ce_UnexpectedValueException, &error_handling TSRMLS_CC);
1021 	if (data && *data) {
1022 		RETVAL_ZVAL(*data, 1, 0);
1023 		if (Z_TYPE_P(return_value) == IS_ARRAY) {
1024 			zval_dtor(return_value);
1025 			ZVAL_STRINGL(return_value, "Array", sizeof("Array")-1, 1);
1026 		} else {
1027 			convert_to_string(return_value);
1028 		}
1029 	}
1030 	zend_restore_error_handling(&error_handling TSRMLS_CC);
1031 }
1032 
spl_recursive_tree_iterator_get_postfix(spl_recursive_it_object * object,zval * return_value TSRMLS_DC)1033 static void spl_recursive_tree_iterator_get_postfix(spl_recursive_it_object * object, zval * return_value TSRMLS_DC)
1034 {
1035 	RETVAL_STRINGL(object->postfix[0].c, object->postfix[0].len, 1);
1036 }
1037 
1038 /* {{{ proto void RecursiveTreeIterator::__construct(RecursiveIterator|IteratorAggregate it [, int flags = RTIT_BYPASS_KEY [, int cit_flags = CIT_CATCH_GET_CHILD [, mode = RIT_SELF_FIRST ]]]) throws InvalidArgumentException
1039    RecursiveIteratorIterator to generate ASCII graphic trees for the entries in a RecursiveIterator */
SPL_METHOD(RecursiveTreeIterator,__construct)1040 SPL_METHOD(RecursiveTreeIterator, __construct)
1041 {
1042 	spl_recursive_it_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_RecursiveTreeIterator, zend_ce_iterator, RIT_RecursiveTreeIterator);
1043 } /* }}} */
1044 
1045 /* {{{ proto void RecursiveTreeIterator::setPrefixPart(int part, string prefix) throws OutOfRangeException
1046    Sets prefix parts as used in getPrefix() */
SPL_METHOD(RecursiveTreeIterator,setPrefixPart)1047 SPL_METHOD(RecursiveTreeIterator, setPrefixPart)
1048 {
1049 	spl_recursive_it_object   *object = (spl_recursive_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
1050 	long  part;
1051 	char* prefix;
1052 	int   prefix_len;
1053 
1054 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ls", &part, &prefix, &prefix_len) == FAILURE) {
1055 		return;
1056 	}
1057 	if (0 > part || part > 5) {
1058 		zend_throw_exception_ex(spl_ce_OutOfRangeException, 0 TSRMLS_CC, "Use RecursiveTreeIterator::PREFIX_* constant");
1059 		return;
1060 	}
1061 
1062 	smart_str_free(&object->prefix[part]);
1063 	smart_str_appendl(&object->prefix[part], prefix, prefix_len);
1064 } /* }}} */
1065 
1066 /* {{{ proto string RecursiveTreeIterator::getPrefix()
1067    Returns the string to place in front of current element */
SPL_METHOD(RecursiveTreeIterator,getPrefix)1068 SPL_METHOD(RecursiveTreeIterator, getPrefix)
1069 {
1070 	spl_recursive_it_object   *object = (spl_recursive_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
1071 
1072 	if (zend_parse_parameters_none() == FAILURE) {
1073 		return;
1074 	}
1075 	spl_recursive_tree_iterator_get_prefix(object, return_value TSRMLS_CC);
1076 } /* }}} */
1077 
1078 /* {{{ proto void RecursiveTreeIterator::setPostfix(string prefix)
1079    Sets postfix as used in getPostfix() */
SPL_METHOD(RecursiveTreeIterator,setPostfix)1080 SPL_METHOD(RecursiveTreeIterator, setPostfix)
1081 {
1082 	spl_recursive_it_object   *object = (spl_recursive_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
1083 	char* postfix;
1084 	int   postfix_len;
1085 
1086 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &postfix, &postfix_len) == FAILURE) {
1087 		return;
1088 	}
1089 
1090 	smart_str_free(&object->postfix[0]);
1091 	smart_str_appendl(&object->postfix[0], postfix, postfix_len);
1092 } /* }}} */
1093 
1094 /* {{{ proto string RecursiveTreeIterator::getEntry()
1095    Returns the string presentation built for current element */
SPL_METHOD(RecursiveTreeIterator,getEntry)1096 SPL_METHOD(RecursiveTreeIterator, getEntry)
1097 {
1098 	spl_recursive_it_object   *object = (spl_recursive_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
1099 
1100 	if (zend_parse_parameters_none() == FAILURE) {
1101 		return;
1102 	}
1103 
1104 	spl_recursive_tree_iterator_get_entry(object, return_value TSRMLS_CC);
1105 } /* }}} */
1106 
1107 /* {{{ proto string RecursiveTreeIterator::getPostfix()
1108    Returns the string to place after the current element */
SPL_METHOD(RecursiveTreeIterator,getPostfix)1109 SPL_METHOD(RecursiveTreeIterator, getPostfix)
1110 {
1111 	spl_recursive_it_object   *object = (spl_recursive_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
1112 
1113 	if (zend_parse_parameters_none() == FAILURE) {
1114 		return;
1115 	}
1116 
1117 	spl_recursive_tree_iterator_get_postfix(object, return_value TSRMLS_CC);
1118 } /* }}} */
1119 
1120 /* {{{ proto mixed RecursiveTreeIterator::current()
1121    Returns the current element prefixed and postfixed */
SPL_METHOD(RecursiveTreeIterator,current)1122 SPL_METHOD(RecursiveTreeIterator, current)
1123 {
1124 	spl_recursive_it_object   *object = (spl_recursive_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
1125 	zval                       prefix, entry, postfix;
1126 	char                      *str, *ptr;
1127 	size_t                     str_len;
1128 
1129 	if (zend_parse_parameters_none() == FAILURE) {
1130 		return;
1131 	}
1132 
1133 	if (object->flags & RTIT_BYPASS_CURRENT) {
1134 		zend_object_iterator      *iterator = object->iterators[object->level].iterator;
1135 		zval                      **data;
1136 
1137 		iterator->funcs->get_current_data(iterator, &data TSRMLS_CC);
1138 		if (data && *data) {
1139 			RETURN_ZVAL(*data, 1, 0);
1140 		} else {
1141 			RETURN_NULL();
1142 		}
1143 	}
1144 
1145 	INIT_ZVAL(prefix);
1146 	INIT_ZVAL(entry);
1147 	spl_recursive_tree_iterator_get_prefix(object, &prefix TSRMLS_CC);
1148 	spl_recursive_tree_iterator_get_entry(object, &entry TSRMLS_CC);
1149 	if (Z_TYPE(entry) != IS_STRING) {
1150 		zval_dtor(&prefix);
1151 		zval_dtor(&entry);
1152 		RETURN_NULL();
1153 	}
1154 	spl_recursive_tree_iterator_get_postfix(object, &postfix TSRMLS_CC);
1155 
1156 	str_len = Z_STRLEN(prefix) + Z_STRLEN(entry) + Z_STRLEN(postfix);
1157 	str = (char *) emalloc(str_len + 1U);
1158 	ptr = str;
1159 
1160 	memcpy(ptr, Z_STRVAL(prefix), Z_STRLEN(prefix));
1161 	ptr += Z_STRLEN(prefix);
1162 	memcpy(ptr, Z_STRVAL(entry), Z_STRLEN(entry));
1163 	ptr += Z_STRLEN(entry);
1164 	memcpy(ptr, Z_STRVAL(postfix), Z_STRLEN(postfix));
1165 	ptr += Z_STRLEN(postfix);
1166 	*ptr = 0;
1167 
1168 	zval_dtor(&prefix);
1169 	zval_dtor(&entry);
1170 	zval_dtor(&postfix);
1171 
1172 	RETURN_STRINGL(str, str_len, 0);
1173 } /* }}} */
1174 
1175 /* {{{ proto mixed RecursiveTreeIterator::key()
1176    Returns the current key prefixed and postfixed */
SPL_METHOD(RecursiveTreeIterator,key)1177 SPL_METHOD(RecursiveTreeIterator, key)
1178 {
1179 	spl_recursive_it_object   *object = (spl_recursive_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
1180 	zend_object_iterator      *iterator = object->iterators[object->level].iterator;
1181 	zval                       prefix, key, postfix, key_copy;
1182 	char                      *str, *ptr;
1183 	size_t                     str_len;
1184 
1185 	if (zend_parse_parameters_none() == FAILURE) {
1186 		return;
1187 	}
1188 
1189 	if (iterator->funcs->get_current_key) {
1190 		iterator->funcs->get_current_key(iterator, &key TSRMLS_CC);
1191 	} else {
1192 		ZVAL_NULL(&key);
1193 	}
1194 
1195 	if (object->flags & RTIT_BYPASS_KEY) {
1196 		zval *key_ptr = &key;
1197 		RETVAL_ZVAL(key_ptr, 1, 0);
1198 		zval_dtor(&key);
1199 		return;
1200 	}
1201 
1202 	if (Z_TYPE(key) != IS_STRING) {
1203 		int use_copy;
1204 		zend_make_printable_zval(&key, &key_copy, &use_copy);
1205 		if (use_copy) {
1206 			key = key_copy;
1207 		}
1208 	}
1209 
1210 	spl_recursive_tree_iterator_get_prefix(object, &prefix TSRMLS_CC);
1211 	spl_recursive_tree_iterator_get_postfix(object, &postfix TSRMLS_CC);
1212 
1213 	str_len = Z_STRLEN(prefix) + Z_STRLEN(key) + Z_STRLEN(postfix);
1214 	str = (char *) emalloc(str_len + 1U);
1215 	ptr = str;
1216 
1217 	memcpy(ptr, Z_STRVAL(prefix), Z_STRLEN(prefix));
1218 	ptr += Z_STRLEN(prefix);
1219 	memcpy(ptr, Z_STRVAL(key), Z_STRLEN(key));
1220 	ptr += Z_STRLEN(key);
1221 	memcpy(ptr, Z_STRVAL(postfix), Z_STRLEN(postfix));
1222 	ptr += Z_STRLEN(postfix);
1223 	*ptr = 0;
1224 
1225 	zval_dtor(&prefix);
1226 	zval_dtor(&key);
1227 	zval_dtor(&postfix);
1228 
1229 	RETVAL_STRINGL(str, str_len, 0);
1230 } /* }}} */
1231 
1232 ZEND_BEGIN_ARG_INFO_EX(arginfo_recursive_tree_it___construct, 0, 0, 1)
1233 	ZEND_ARG_OBJ_INFO(0, iterator, Traversable, 0)
1234 	ZEND_ARG_INFO(0, flags)
1235 	ZEND_ARG_INFO(0, caching_it_flags)
1236 	ZEND_ARG_INFO(0, mode)
1237 ZEND_END_ARG_INFO();
1238 
1239 ZEND_BEGIN_ARG_INFO_EX(arginfo_recursive_tree_it_setPrefixPart, 0, 0, 2)
1240 	ZEND_ARG_INFO(0, part)
1241 	ZEND_ARG_INFO(0, value)
1242 ZEND_END_ARG_INFO();
1243 
1244 static const zend_function_entry spl_funcs_RecursiveTreeIterator[] = {
1245 	SPL_ME(RecursiveTreeIterator,     __construct,       arginfo_recursive_tree_it___construct,   ZEND_ACC_PUBLIC)
1246 	SPL_ME(RecursiveIteratorIterator, rewind,            arginfo_recursive_it_void,               ZEND_ACC_PUBLIC)
1247 	SPL_ME(RecursiveIteratorIterator, valid,             arginfo_recursive_it_void,               ZEND_ACC_PUBLIC)
1248 	SPL_ME(RecursiveTreeIterator,     key,               arginfo_recursive_it_void,               ZEND_ACC_PUBLIC)
1249 	SPL_ME(RecursiveTreeIterator,     current,           arginfo_recursive_it_void,               ZEND_ACC_PUBLIC)
1250 	SPL_ME(RecursiveIteratorIterator, next,              arginfo_recursive_it_void,               ZEND_ACC_PUBLIC)
1251 	SPL_ME(RecursiveIteratorIterator, beginIteration,    arginfo_recursive_it_void,               ZEND_ACC_PUBLIC)
1252 	SPL_ME(RecursiveIteratorIterator, endIteration,      arginfo_recursive_it_void,               ZEND_ACC_PUBLIC)
1253 	SPL_ME(RecursiveIteratorIterator, callHasChildren,   arginfo_recursive_it_void,               ZEND_ACC_PUBLIC)
1254 	SPL_ME(RecursiveIteratorIterator, callGetChildren,   arginfo_recursive_it_void,               ZEND_ACC_PUBLIC)
1255 	SPL_ME(RecursiveIteratorIterator, beginChildren,     arginfo_recursive_it_void,               ZEND_ACC_PUBLIC)
1256 	SPL_ME(RecursiveIteratorIterator, endChildren,       arginfo_recursive_it_void,               ZEND_ACC_PUBLIC)
1257 	SPL_ME(RecursiveIteratorIterator, nextElement,       arginfo_recursive_it_void,               ZEND_ACC_PUBLIC)
1258 	SPL_ME(RecursiveTreeIterator,     getPrefix,         arginfo_recursive_it_void,               ZEND_ACC_PUBLIC)
1259 	SPL_ME(RecursiveTreeIterator,     setPrefixPart,     arginfo_recursive_tree_it_setPrefixPart, ZEND_ACC_PUBLIC)
1260 	SPL_ME(RecursiveTreeIterator,     getEntry,          arginfo_recursive_it_void,               ZEND_ACC_PUBLIC)
1261 	SPL_ME(RecursiveTreeIterator,     setPostfix,        arginfo_recursive_it_void,               ZEND_ACC_PUBLIC)
1262 	SPL_ME(RecursiveTreeIterator,     getPostfix,        arginfo_recursive_it_void,               ZEND_ACC_PUBLIC)
1263 	PHP_FE_END
1264 };
1265 
1266 #if MBO_0
spl_dual_it_gets_implemented(zend_class_entry * interface,zend_class_entry * class_type TSRMLS_DC)1267 static int spl_dual_it_gets_implemented(zend_class_entry *interface, zend_class_entry *class_type TSRMLS_DC)
1268 {
1269 	class_type->iterator_funcs.zf_valid = NULL;
1270 	class_type->iterator_funcs.zf_current = NULL;
1271 	class_type->iterator_funcs.zf_key = NULL;
1272 	class_type->iterator_funcs.zf_next = NULL;
1273 	class_type->iterator_funcs.zf_rewind = NULL;
1274 	if (!class_type->iterator_funcs.funcs) {
1275 		class_type->iterator_funcs.funcs = &zend_interface_iterator_funcs_iterator;
1276 	}
1277 
1278 	return SUCCESS;
1279 }
1280 #endif
1281 
spl_dual_it_get_method(zval ** object_ptr,char * method,int method_len,const zend_literal * key TSRMLS_DC)1282 static union _zend_function *spl_dual_it_get_method(zval **object_ptr, char *method, int method_len, const zend_literal *key TSRMLS_DC)
1283 {
1284 	union _zend_function *function_handler;
1285 	spl_dual_it_object   *intern;
1286 
1287 	intern = (spl_dual_it_object*)zend_object_store_get_object(*object_ptr TSRMLS_CC);
1288 
1289 	function_handler = std_object_handlers.get_method(object_ptr, method, method_len, key TSRMLS_CC);
1290 	if (!function_handler && intern->inner.ce) {
1291 		if (zend_hash_find(&intern->inner.ce->function_table, method, method_len+1, (void **) &function_handler) == FAILURE) {
1292 			if (Z_OBJ_HT_P(intern->inner.zobject)->get_method) {
1293 				*object_ptr = intern->inner.zobject;
1294 				function_handler = Z_OBJ_HT_P(*object_ptr)->get_method(object_ptr, method, method_len, key TSRMLS_CC);
1295 			}
1296 		} else {
1297 			*object_ptr = intern->inner.zobject;
1298 		}
1299 	}
1300 	return function_handler;
1301 }
1302 
1303 #if MBO_0
spl_dual_it_call_method(char * method,INTERNAL_FUNCTION_PARAMETERS)1304 int spl_dual_it_call_method(char *method, INTERNAL_FUNCTION_PARAMETERS)
1305 {
1306 	zval ***func_params, func;
1307 	zval *retval_ptr;
1308 	int arg_count;
1309 	int current = 0;
1310 	int success;
1311 	void **p;
1312 	spl_dual_it_object   *intern;
1313 
1314 	intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
1315 
1316 	ZVAL_STRING(&func, method, 0);
1317 	if (!zend_is_callable(&func, 0, &method TSRMLS_CC)) {
1318 		php_error_docref(NULL TSRMLS_CC, E_ERROR, "Method %s::%s() does not exist", intern->inner.ce->name, method);
1319 		return FAILURE;
1320 	}
1321 
1322 	p = EG(argument_stack).top_element-2;
1323 	arg_count = (ulong) *p;
1324 
1325 	func_params = safe_emalloc(sizeof(zval **), arg_count, 0);
1326 
1327 	current = 0;
1328 	while (arg_count-- > 0) {
1329 		func_params[current] = (zval **) p - (arg_count-current);
1330 		current++;
1331 	}
1332 	arg_count = current; /* restore */
1333 
1334 	if (call_user_function_ex(EG(function_table), NULL, &func, &retval_ptr, arg_count, func_params, 0, NULL TSRMLS_CC) == SUCCESS && retval_ptr) {
1335 		RETURN_ZVAL(retval_ptr, 0, 1);
1336 
1337 		success = SUCCESS;
1338 	} else {
1339 		php_error_docref(NULL TSRMLS_CC, E_ERROR, "Unable to call %s::%s()", intern->inner.ce->name, method);
1340 		success = FAILURE;
1341 	}
1342 
1343 	efree(func_params);
1344 	return success;
1345 }
1346 #endif
1347 
1348 #define SPL_CHECK_CTOR(intern, classname) \
1349 	if (intern->dit_type == DIT_Unknown) { \
1350 		zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "Classes derived from %s must call %s::__construct()", \
1351 				(spl_ce_##classname)->name, (spl_ce_##classname)->name); \
1352 		return; \
1353 	}
1354 
1355 #define APPENDIT_CHECK_CTOR(intern) SPL_CHECK_CTOR(intern, AppendIterator)
1356 
1357 static inline int spl_dual_it_fetch(spl_dual_it_object *intern, int check_more TSRMLS_DC);
1358 
spl_cit_check_flags(int flags)1359 static inline int spl_cit_check_flags(int flags)
1360 {
1361 	int cnt = 0;
1362 
1363 	cnt += (flags & CIT_CALL_TOSTRING) ? 1 : 0;
1364 	cnt += (flags & CIT_TOSTRING_USE_KEY) ? 1 : 0;
1365 	cnt += (flags & CIT_TOSTRING_USE_CURRENT) ? 1 : 0;
1366 	cnt += (flags & CIT_TOSTRING_USE_INNER) ? 1 : 0;
1367 
1368 	return cnt <= 1 ? SUCCESS : FAILURE;
1369 }
1370 
spl_dual_it_construct(INTERNAL_FUNCTION_PARAMETERS,zend_class_entry * ce_base,zend_class_entry * ce_inner,dual_it_type dit_type)1371 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)
1372 {
1373 	zval                 *zobject, *retval;
1374 	spl_dual_it_object   *intern;
1375 	zend_class_entry     *ce = NULL;
1376 	int                   inc_refcount = 1;
1377 	zend_error_handling   error_handling;
1378 
1379 	intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
1380 
1381 	if (intern->dit_type != DIT_Unknown) {
1382 		zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "%s::getIterator() must be called exactly once per instance", ce_base->name);
1383 		return NULL;
1384 	}
1385 
1386 	zend_replace_error_handling(EH_THROW, spl_ce_InvalidArgumentException, &error_handling TSRMLS_CC);
1387 
1388 	intern->dit_type = dit_type;
1389 	switch (dit_type) {
1390 		case DIT_LimitIterator: {
1391 			intern->u.limit.offset = 0; /* start at beginning */
1392 			intern->u.limit.count = -1; /* get all */
1393 			if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O|ll", &zobject, ce_inner, &intern->u.limit.offset, &intern->u.limit.count) == FAILURE) {
1394 				zend_restore_error_handling(&error_handling TSRMLS_CC);
1395 				return NULL;
1396 			}
1397 			if (intern->u.limit.offset < 0) {
1398 				zend_throw_exception(spl_ce_OutOfRangeException, "Parameter offset must be >= 0", 0 TSRMLS_CC);
1399 				zend_restore_error_handling(&error_handling TSRMLS_CC);
1400 				return NULL;
1401 			}
1402 			if (intern->u.limit.count < 0 && intern->u.limit.count != -1) {
1403 				zend_throw_exception(spl_ce_OutOfRangeException, "Parameter count must either be -1 or a value greater than or equal 0", 0 TSRMLS_CC);
1404 				zend_restore_error_handling(&error_handling TSRMLS_CC);
1405 				return NULL;
1406 			}
1407 			break;
1408 		}
1409 		case DIT_CachingIterator:
1410 		case DIT_RecursiveCachingIterator: {
1411 			long flags = CIT_CALL_TOSTRING;
1412 			if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O|l", &zobject, ce_inner, &flags) == FAILURE) {
1413 				zend_restore_error_handling(&error_handling TSRMLS_CC);
1414 				return NULL;
1415 			}
1416 			if (spl_cit_check_flags(flags) != SUCCESS) {
1417 				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);
1418 				zend_restore_error_handling(&error_handling TSRMLS_CC);
1419 				return NULL;
1420 			}
1421 			intern->u.caching.flags |= flags & CIT_PUBLIC;
1422 			MAKE_STD_ZVAL(intern->u.caching.zcache);
1423 			array_init(intern->u.caching.zcache);
1424 			break;
1425 		}
1426 		case DIT_IteratorIterator: {
1427 			zend_class_entry **pce_cast;
1428 			char * class_name = NULL;
1429 			int class_name_len = 0;
1430 
1431 			if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O|s", &zobject, ce_inner, &class_name, &class_name_len) == FAILURE) {
1432 				zend_restore_error_handling(&error_handling TSRMLS_CC);
1433 				return NULL;
1434 			}
1435 			ce = Z_OBJCE_P(zobject);
1436 			if (!instanceof_function(ce, zend_ce_iterator TSRMLS_CC)) {
1437 				if (ZEND_NUM_ARGS() > 1) {
1438 					if (zend_lookup_class(class_name, class_name_len, &pce_cast TSRMLS_CC) == FAILURE
1439 					|| !instanceof_function(ce, *pce_cast TSRMLS_CC)
1440 					|| !(*pce_cast)->get_iterator
1441 					) {
1442 						zend_throw_exception(spl_ce_LogicException, "Class to downcast to not found or not base class or does not implement Traversable", 0 TSRMLS_CC);
1443 						zend_restore_error_handling(&error_handling TSRMLS_CC);
1444 						return NULL;
1445 					}
1446 					ce = *pce_cast;
1447 				}
1448 				if (instanceof_function(ce, zend_ce_aggregate TSRMLS_CC)) {
1449 					zend_call_method_with_0_params(&zobject, ce, &ce->iterator_funcs.zf_new_iterator, "getiterator", &retval);
1450 					if (EG(exception)) {
1451 						if (retval) {
1452 							zval_ptr_dtor(&retval);
1453 						}
1454 						zend_restore_error_handling(&error_handling TSRMLS_CC);
1455 						return NULL;
1456 					}
1457 					if (!retval || Z_TYPE_P(retval) != IS_OBJECT || !instanceof_function(Z_OBJCE_P(retval), zend_ce_traversable TSRMLS_CC)) {
1458 						zend_throw_exception_ex(spl_ce_LogicException, 0 TSRMLS_CC, "%s::getIterator() must return an object that implements Traversable", ce->name);
1459 						zend_restore_error_handling(&error_handling TSRMLS_CC);
1460 						return NULL;
1461 					}
1462 					zobject = retval;
1463 					ce = Z_OBJCE_P(zobject);
1464 					inc_refcount = 0;
1465 				}
1466 			}
1467 			break;
1468 		}
1469 		case DIT_AppendIterator:
1470 			spl_instantiate(spl_ce_ArrayIterator, &intern->u.append.zarrayit, 1 TSRMLS_CC);
1471 			zend_call_method_with_0_params(&intern->u.append.zarrayit, spl_ce_ArrayIterator, &spl_ce_ArrayIterator->constructor, "__construct", NULL);
1472 			intern->u.append.iterator = spl_ce_ArrayIterator->get_iterator(spl_ce_ArrayIterator, intern->u.append.zarrayit, 0 TSRMLS_CC);
1473 			zend_restore_error_handling(&error_handling TSRMLS_CC);
1474 			return intern;
1475 #if HAVE_PCRE || HAVE_BUNDLED_PCRE
1476 		case DIT_RegexIterator:
1477 		case DIT_RecursiveRegexIterator: {
1478 			char *regex;
1479 			int regex_len;
1480 			long mode = REGIT_MODE_MATCH;
1481 
1482 			intern->u.regex.use_flags = ZEND_NUM_ARGS() >= 5;
1483 			intern->u.regex.flags = 0;
1484 			intern->u.regex.preg_flags = 0;
1485 			if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Os|lll", &zobject, ce_inner, &regex, &regex_len, &mode, &intern->u.regex.flags, &intern->u.regex.preg_flags) == FAILURE) {
1486 				zend_restore_error_handling(&error_handling TSRMLS_CC);
1487 				return NULL;
1488 			}
1489 			if (mode < 0 || mode >= REGIT_MODE_MAX) {
1490 				zend_throw_exception_ex(spl_ce_InvalidArgumentException, 0 TSRMLS_CC, "Illegal mode %ld", mode);
1491 				zend_restore_error_handling(&error_handling TSRMLS_CC);
1492 				return NULL;
1493 			}
1494 			intern->u.regex.mode = mode;
1495 			intern->u.regex.regex = estrndup(regex, regex_len);
1496 			intern->u.regex.regex_len = regex_len;
1497 			intern->u.regex.pce = pcre_get_compiled_regex_cache(regex, regex_len TSRMLS_CC);
1498 			if (intern->u.regex.pce == NULL) {
1499 				/* pcre_get_compiled_regex_cache has already sent error */
1500 				zend_restore_error_handling(&error_handling TSRMLS_CC);
1501 				return NULL;
1502 			}
1503 			intern->u.regex.pce->refcount++;
1504 			break;
1505 		}
1506 #endif
1507 		case DIT_CallbackFilterIterator:
1508 		case DIT_RecursiveCallbackFilterIterator: {
1509 			_spl_cbfilter_it_intern *cfi = emalloc(sizeof(*cfi));
1510 			if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Of", &zobject, ce_inner, &cfi->fci, &cfi->fcc) == FAILURE) {
1511 				zend_restore_error_handling(&error_handling TSRMLS_CC);
1512 				efree(cfi);
1513 				return NULL;
1514 			}
1515 			if (cfi->fci.function_name) {
1516 				Z_ADDREF_P(cfi->fci.function_name);
1517 			}
1518 			if (cfi->fci.object_ptr) {
1519 				Z_ADDREF_P(cfi->fci.object_ptr);
1520 			}
1521 			intern->u.cbfilter = cfi;
1522 			break;
1523 		}
1524 		default:
1525 			if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &zobject, ce_inner) == FAILURE) {
1526 				zend_restore_error_handling(&error_handling TSRMLS_CC);
1527 				return NULL;
1528 			}
1529 			break;
1530 	}
1531 
1532 	zend_restore_error_handling(&error_handling TSRMLS_CC);
1533 
1534 	if (inc_refcount) {
1535 		Z_ADDREF_P(zobject);
1536 	}
1537 	intern->inner.zobject = zobject;
1538 	intern->inner.ce = dit_type == DIT_IteratorIterator ? ce : Z_OBJCE_P(zobject);
1539 	intern->inner.object = zend_object_store_get_object(zobject TSRMLS_CC);
1540 	intern->inner.iterator = intern->inner.ce->get_iterator(intern->inner.ce, zobject, 0 TSRMLS_CC);
1541 
1542 	return intern;
1543 }
1544 
1545 /* {{{ proto void FilterIterator::__construct(Iterator it)
1546    Create an Iterator from another iterator */
SPL_METHOD(FilterIterator,__construct)1547 SPL_METHOD(FilterIterator, __construct)
1548 {
1549 	spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_FilterIterator, zend_ce_iterator, DIT_FilterIterator);
1550 } /* }}} */
1551 
1552 /* {{{ proto void CallbackFilterIterator::__construct(Iterator it, callback)
1553    Create an Iterator from another iterator */
SPL_METHOD(CallbackFilterIterator,__construct)1554 SPL_METHOD(CallbackFilterIterator, __construct)
1555 {
1556 	spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_CallbackFilterIterator, zend_ce_iterator, DIT_CallbackFilterIterator);
1557 } /* }}} */
1558 
1559 /* {{{ proto Iterator FilterIterator::getInnerIterator()
1560        proto Iterator CachingIterator::getInnerIterator()
1561        proto Iterator LimitIterator::getInnerIterator()
1562        proto Iterator ParentIterator::getInnerIterator()
1563    Get the inner iterator */
SPL_METHOD(dual_it,getInnerIterator)1564 SPL_METHOD(dual_it, getInnerIterator)
1565 {
1566 	spl_dual_it_object   *intern;
1567 
1568 	if (zend_parse_parameters_none() == FAILURE) {
1569 		return;
1570 	}
1571 
1572 	SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
1573 
1574 	if (intern->inner.zobject) {
1575 		RETVAL_ZVAL(intern->inner.zobject, 1, 0);
1576 	} else {
1577 		RETURN_NULL();
1578 	}
1579 } /* }}} */
1580 
spl_dual_it_require(spl_dual_it_object * intern TSRMLS_DC)1581 static inline void spl_dual_it_require(spl_dual_it_object *intern TSRMLS_DC)
1582 {
1583 	if (!intern->inner.iterator) {
1584 		php_error_docref(NULL TSRMLS_CC, E_ERROR, "The inner constructor wasn't initialized with an iterator instance");
1585 	}
1586 }
1587 
spl_dual_it_free(spl_dual_it_object * intern TSRMLS_DC)1588 static inline void spl_dual_it_free(spl_dual_it_object *intern TSRMLS_DC)
1589 {
1590 	if (intern->inner.iterator && intern->inner.iterator->funcs->invalidate_current) {
1591 		intern->inner.iterator->funcs->invalidate_current(intern->inner.iterator TSRMLS_CC);
1592 	}
1593 	if (intern->current.data) {
1594 		zval_ptr_dtor(&intern->current.data);
1595 		intern->current.data = NULL;
1596 	}
1597 	if (intern->current.key) {
1598 		zval_ptr_dtor(&intern->current.key);
1599 		intern->current.key = NULL;
1600 	}
1601 	if (intern->dit_type == DIT_CachingIterator || intern->dit_type == DIT_RecursiveCachingIterator) {
1602 		if (intern->u.caching.zstr) {
1603 			zval_ptr_dtor(&intern->u.caching.zstr);
1604 			intern->u.caching.zstr = NULL;
1605 		}
1606 		if (intern->u.caching.zchildren) {
1607 			zval_ptr_dtor(&intern->u.caching.zchildren);
1608 			intern->u.caching.zchildren = NULL;
1609 		}
1610 	}
1611 }
1612 
spl_dual_it_rewind(spl_dual_it_object * intern TSRMLS_DC)1613 static inline void spl_dual_it_rewind(spl_dual_it_object *intern TSRMLS_DC)
1614 {
1615 	spl_dual_it_free(intern TSRMLS_CC);
1616 	intern->current.pos = 0;
1617 	if (intern->inner.iterator->funcs->rewind) {
1618 		intern->inner.iterator->funcs->rewind(intern->inner.iterator TSRMLS_CC);
1619 	}
1620 }
1621 
spl_dual_it_valid(spl_dual_it_object * intern TSRMLS_DC)1622 static inline int spl_dual_it_valid(spl_dual_it_object *intern TSRMLS_DC)
1623 {
1624 	if (!intern->inner.iterator) {
1625 		return FAILURE;
1626 	}
1627 	/* FAILURE / SUCCESS */
1628 	return intern->inner.iterator->funcs->valid(intern->inner.iterator TSRMLS_CC);
1629 }
1630 
spl_dual_it_fetch(spl_dual_it_object * intern,int check_more TSRMLS_DC)1631 static inline int spl_dual_it_fetch(spl_dual_it_object *intern, int check_more TSRMLS_DC)
1632 {
1633 	zval **data;
1634 
1635 	spl_dual_it_free(intern TSRMLS_CC);
1636 	if (!check_more || spl_dual_it_valid(intern TSRMLS_CC) == SUCCESS) {
1637 		intern->inner.iterator->funcs->get_current_data(intern->inner.iterator, &data TSRMLS_CC);
1638 		if (data && *data) {
1639 			intern->current.data = *data;
1640 			Z_ADDREF_P(intern->current.data);
1641 		}
1642 
1643 		MAKE_STD_ZVAL(intern->current.key);
1644 		if (intern->inner.iterator->funcs->get_current_key) {
1645 			intern->inner.iterator->funcs->get_current_key(intern->inner.iterator, intern->current.key TSRMLS_CC);
1646 			if (EG(exception)) {
1647 				zval_ptr_dtor(&intern->current.key);
1648 				intern->current.key = NULL;
1649 			}
1650 		} else {
1651 			ZVAL_LONG(intern->current.key, intern->current.pos);
1652 		}
1653 		return EG(exception) ? FAILURE : SUCCESS;
1654 	}
1655 	return FAILURE;
1656 }
1657 
spl_dual_it_next(spl_dual_it_object * intern,int do_free TSRMLS_DC)1658 static inline void spl_dual_it_next(spl_dual_it_object *intern, int do_free TSRMLS_DC)
1659 {
1660 	if (do_free) {
1661 		spl_dual_it_free(intern TSRMLS_CC);
1662 	} else {
1663 		spl_dual_it_require(intern TSRMLS_CC);
1664 	}
1665 	intern->inner.iterator->funcs->move_forward(intern->inner.iterator TSRMLS_CC);
1666 	intern->current.pos++;
1667 }
1668 
1669 /* {{{ proto void ParentIterator::rewind()
1670        proto void IteratorIterator::rewind()
1671    Rewind the iterator
1672    */
SPL_METHOD(dual_it,rewind)1673 SPL_METHOD(dual_it, rewind)
1674 {
1675 	spl_dual_it_object   *intern;
1676 
1677 	if (zend_parse_parameters_none() == FAILURE) {
1678 		return;
1679 	}
1680 
1681 	SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
1682 
1683 	spl_dual_it_rewind(intern TSRMLS_CC);
1684 	spl_dual_it_fetch(intern, 1 TSRMLS_CC);
1685 } /* }}} */
1686 
1687 /* {{{ proto bool FilterIterator::valid()
1688        proto bool ParentIterator::valid()
1689        proto bool IteratorIterator::valid()
1690        proto bool NoRewindIterator::valid()
1691    Check whether the current element is valid */
SPL_METHOD(dual_it,valid)1692 SPL_METHOD(dual_it, valid)
1693 {
1694 	spl_dual_it_object   *intern;
1695 
1696 	if (zend_parse_parameters_none() == FAILURE) {
1697 		return;
1698 	}
1699 
1700 	SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
1701 
1702 	RETURN_BOOL(intern->current.data);
1703 } /* }}} */
1704 
1705 /* {{{ proto mixed FilterIterator::key()
1706        proto mixed CachingIterator::key()
1707        proto mixed LimitIterator::key()
1708        proto mixed ParentIterator::key()
1709        proto mixed IteratorIterator::key()
1710        proto mixed NoRewindIterator::key()
1711        proto mixed AppendIterator::key()
1712    Get the current key */
SPL_METHOD(dual_it,key)1713 SPL_METHOD(dual_it, key)
1714 {
1715 	spl_dual_it_object   *intern;
1716 
1717 	if (zend_parse_parameters_none() == FAILURE) {
1718 		return;
1719 	}
1720 
1721 	SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
1722 
1723 	if (intern->current.key) {
1724 		RETURN_ZVAL(intern->current.key, 1, 0);
1725 	}
1726 	RETURN_NULL();
1727 } /* }}} */
1728 
1729 /* {{{ proto mixed FilterIterator::current()
1730        proto mixed CachingIterator::current()
1731        proto mixed LimitIterator::current()
1732        proto mixed ParentIterator::current()
1733        proto mixed IteratorIterator::current()
1734        proto mixed NoRewindIterator::current()
1735        proto mixed AppendIterator::current()
1736    Get the current element value */
SPL_METHOD(dual_it,current)1737 SPL_METHOD(dual_it, current)
1738 {
1739 	spl_dual_it_object   *intern;
1740 
1741 	if (zend_parse_parameters_none() == FAILURE) {
1742 		return;
1743 	}
1744 
1745 	SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
1746 
1747 	if (intern->current.data) {
1748 		RETVAL_ZVAL(intern->current.data, 1, 0);
1749 	} else {
1750 		RETURN_NULL();
1751 	}
1752 } /* }}} */
1753 
1754 /* {{{ proto void ParentIterator::next()
1755        proto void IteratorIterator::next()
1756        proto void NoRewindIterator::next()
1757    Move the iterator forward */
SPL_METHOD(dual_it,next)1758 SPL_METHOD(dual_it, next)
1759 {
1760 	spl_dual_it_object   *intern;
1761 
1762 	if (zend_parse_parameters_none() == FAILURE) {
1763 		return;
1764 	}
1765 
1766 	SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
1767 
1768 	spl_dual_it_next(intern, 1 TSRMLS_CC);
1769 	spl_dual_it_fetch(intern, 1 TSRMLS_CC);
1770 } /* }}} */
1771 
spl_filter_it_fetch(zval * zthis,spl_dual_it_object * intern TSRMLS_DC)1772 static inline void spl_filter_it_fetch(zval *zthis, spl_dual_it_object *intern TSRMLS_DC)
1773 {
1774 	zval *retval;
1775 
1776 	while (spl_dual_it_fetch(intern, 1 TSRMLS_CC) == SUCCESS) {
1777 		zend_call_method_with_0_params(&zthis, intern->std.ce, NULL, "accept", &retval);
1778 		if (retval) {
1779 			if (zend_is_true(retval)) {
1780 				zval_ptr_dtor(&retval);
1781 				return;
1782 			}
1783 			zval_ptr_dtor(&retval);
1784 		}
1785 		if (EG(exception)) {
1786 			return;
1787 		}
1788 		intern->inner.iterator->funcs->move_forward(intern->inner.iterator TSRMLS_CC);
1789 	}
1790 	spl_dual_it_free(intern TSRMLS_CC);
1791 }
1792 
spl_filter_it_rewind(zval * zthis,spl_dual_it_object * intern TSRMLS_DC)1793 static inline void spl_filter_it_rewind(zval *zthis, spl_dual_it_object *intern TSRMLS_DC)
1794 {
1795 	spl_dual_it_rewind(intern TSRMLS_CC);
1796 	spl_filter_it_fetch(zthis, intern TSRMLS_CC);
1797 }
1798 
spl_filter_it_next(zval * zthis,spl_dual_it_object * intern TSRMLS_DC)1799 static inline void spl_filter_it_next(zval *zthis, spl_dual_it_object *intern TSRMLS_DC)
1800 {
1801 	spl_dual_it_next(intern, 1 TSRMLS_CC);
1802 	spl_filter_it_fetch(zthis, intern TSRMLS_CC);
1803 }
1804 
1805 /* {{{ proto void FilterIterator::rewind()
1806    Rewind the iterator */
SPL_METHOD(FilterIterator,rewind)1807 SPL_METHOD(FilterIterator, rewind)
1808 {
1809 	spl_dual_it_object   *intern;
1810 
1811 	if (zend_parse_parameters_none() == FAILURE) {
1812 		return;
1813 	}
1814 
1815 	SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
1816 	spl_filter_it_rewind(getThis(), intern TSRMLS_CC);
1817 } /* }}} */
1818 
1819 /* {{{ proto void FilterIterator::next()
1820    Move the iterator forward */
SPL_METHOD(FilterIterator,next)1821 SPL_METHOD(FilterIterator, next)
1822 {
1823 	spl_dual_it_object   *intern;
1824 
1825 	if (zend_parse_parameters_none() == FAILURE) {
1826 		return;
1827 	}
1828 
1829 	SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
1830 	spl_filter_it_next(getThis(), intern TSRMLS_CC);
1831 } /* }}} */
1832 
1833 /* {{{ proto void RecursiveCallbackFilterIterator::__construct(RecursiveIterator it, callback)
1834    Create a RecursiveCallbackFilterIterator from a RecursiveIterator */
SPL_METHOD(RecursiveCallbackFilterIterator,__construct)1835 SPL_METHOD(RecursiveCallbackFilterIterator, __construct)
1836 {
1837 	spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_RecursiveCallbackFilterIterator, spl_ce_RecursiveIterator, DIT_RecursiveCallbackFilterIterator);
1838 } /* }}} */
1839 
1840 
1841 /* {{{ proto void RecursiveFilterIterator::__construct(RecursiveIterator it)
1842    Create a RecursiveFilterIterator from a RecursiveIterator */
SPL_METHOD(RecursiveFilterIterator,__construct)1843 SPL_METHOD(RecursiveFilterIterator, __construct)
1844 {
1845 	spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_RecursiveFilterIterator, spl_ce_RecursiveIterator, DIT_RecursiveFilterIterator);
1846 } /* }}} */
1847 
1848 /* {{{ proto bool RecursiveFilterIterator::hasChildren()
1849    Check whether the inner iterator's current element has children */
SPL_METHOD(RecursiveFilterIterator,hasChildren)1850 SPL_METHOD(RecursiveFilterIterator, hasChildren)
1851 {
1852 	spl_dual_it_object   *intern;
1853 	zval                 *retval;
1854 
1855 	if (zend_parse_parameters_none() == FAILURE) {
1856 		return;
1857 	}
1858 
1859 	SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
1860 
1861 	zend_call_method_with_0_params(&intern->inner.zobject, intern->inner.ce, NULL, "haschildren", &retval);
1862 	if (retval) {
1863 		RETURN_ZVAL(retval, 0, 1);
1864 	} else {
1865 		RETURN_FALSE;
1866 	}
1867 } /* }}} */
1868 
1869 /* {{{ proto RecursiveFilterIterator RecursiveFilterIterator::getChildren()
1870    Return the inner iterator's children contained in a RecursiveFilterIterator */
SPL_METHOD(RecursiveFilterIterator,getChildren)1871 SPL_METHOD(RecursiveFilterIterator, getChildren)
1872 {
1873 	spl_dual_it_object   *intern;
1874 	zval                 *retval;
1875 
1876 	if (zend_parse_parameters_none() == FAILURE) {
1877 		return;
1878 	}
1879 
1880 	SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
1881 
1882 	zend_call_method_with_0_params(&intern->inner.zobject, intern->inner.ce, NULL, "getchildren", &retval);
1883 	if (!EG(exception) && retval) {
1884 		spl_instantiate_arg_ex1(Z_OBJCE_P(getThis()), &return_value, 0, retval TSRMLS_CC);
1885 	}
1886 	if (retval) {
1887 		zval_ptr_dtor(&retval);
1888 	}
1889 } /* }}} */
1890 
1891 /* {{{ proto RecursiveCallbackFilterIterator RecursiveCallbackFilterIterator::getChildren()
1892    Return the inner iterator's children contained in a RecursiveCallbackFilterIterator */
SPL_METHOD(RecursiveCallbackFilterIterator,getChildren)1893 SPL_METHOD(RecursiveCallbackFilterIterator, getChildren)
1894 {
1895 	spl_dual_it_object   *intern;
1896 	zval                 *retval;
1897 
1898 	if (zend_parse_parameters_none() == FAILURE) {
1899 		return;
1900 	}
1901 
1902 	intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
1903 
1904 	zend_call_method_with_0_params(&intern->inner.zobject, intern->inner.ce, NULL, "getchildren", &retval);
1905 	if (!EG(exception) && retval) {
1906 		spl_instantiate_arg_ex2(Z_OBJCE_P(getThis()), &return_value, 0, retval, intern->u.cbfilter->fci.function_name TSRMLS_CC);
1907 	}
1908 	if (retval) {
1909 		zval_ptr_dtor(&retval);
1910 	}
1911 } /* }}} */
1912 /* {{{ proto void ParentIterator::__construct(RecursiveIterator it)
1913    Create a ParentIterator from a RecursiveIterator */
SPL_METHOD(ParentIterator,__construct)1914 SPL_METHOD(ParentIterator, __construct)
1915 {
1916 	spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_ParentIterator, spl_ce_RecursiveIterator, DIT_ParentIterator);
1917 } /* }}} */
1918 
1919 #if HAVE_PCRE || HAVE_BUNDLED_PCRE
1920 /* {{{ proto void RegexIterator::__construct(Iterator it, string regex [, int mode [, int flags [, int preg_flags]]])
1921    Create an RegexIterator from another iterator and a regular expression */
SPL_METHOD(RegexIterator,__construct)1922 SPL_METHOD(RegexIterator, __construct)
1923 {
1924 	spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_RegexIterator, zend_ce_iterator, DIT_RegexIterator);
1925 } /* }}} */
1926 
1927 /* {{{ proto bool CallbackFilterIterator::accept()
1928    Calls the callback with the current value, the current key and the inner iterator as arguments */
SPL_METHOD(CallbackFilterIterator,accept)1929 SPL_METHOD(CallbackFilterIterator, accept)
1930 {
1931 	spl_dual_it_object     *intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
1932 	zend_fcall_info        *fci = &intern->u.cbfilter->fci;
1933 	zend_fcall_info_cache  *fcc = &intern->u.cbfilter->fcc;
1934 	zval                  **params[3];
1935 	zval                   *result;
1936 
1937 	if (zend_parse_parameters_none() == FAILURE) {
1938 		return;
1939 	}
1940 
1941 	if (intern->current.data == NULL || intern->current.key == NULL) {
1942 		RETURN_FALSE;
1943 	}
1944 
1945 	params[0] = &intern->current.data;
1946 	params[1] = &intern->current.key;
1947 	params[2] = &intern->inner.zobject;
1948 
1949 	fci->retval_ptr_ptr = &result;
1950 	fci->param_count = 3;
1951 	fci->params = params;
1952 	fci->no_separation = 0;
1953 
1954 	if (zend_call_function(fci, fcc TSRMLS_CC) != SUCCESS || !result) {
1955 		RETURN_FALSE;
1956 	}
1957 	if (EG(exception)) {
1958 		return;
1959 	}
1960 
1961 	RETURN_ZVAL(result, 1, 1);
1962 }
1963 /* }}} */
1964 
1965 /* {{{ proto bool RegexIterator::accept()
1966    Match (string)current() against regular expression */
SPL_METHOD(RegexIterator,accept)1967 SPL_METHOD(RegexIterator, accept)
1968 {
1969 	spl_dual_it_object *intern;
1970 	char       *subject, *result;
1971 	int        subject_len, use_copy, count = 0, result_len;
1972 	zval       *subject_ptr, subject_copy, zcount, *replacement, tmp_replacement;
1973 
1974 	if (zend_parse_parameters_none() == FAILURE) {
1975 		return;
1976 	}
1977 
1978 	SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
1979 
1980 	if (intern->current.data == NULL) {
1981 		RETURN_FALSE;
1982 	} else if (Z_TYPE_P(intern->current.data) == IS_ARRAY) {
1983 		RETURN_FALSE;
1984 	}
1985 
1986 	if (intern->u.regex.flags & REGIT_USE_KEY) {
1987 		subject_ptr = intern->current.key;
1988 	} else {
1989 		subject_ptr = intern->current.data;
1990 	}
1991 
1992 	zend_make_printable_zval(subject_ptr, &subject_copy, &use_copy);
1993 	if (use_copy) {
1994 		subject = Z_STRVAL(subject_copy);
1995 		subject_len = Z_STRLEN(subject_copy);
1996 	} else {
1997 		subject = Z_STRVAL_P(subject_ptr);
1998 		subject_len = Z_STRLEN_P(subject_ptr);
1999 	}
2000 
2001 	switch (intern->u.regex.mode)
2002 	{
2003 	case REGIT_MODE_MAX: /* won't happen but makes compiler happy */
2004 	case REGIT_MODE_MATCH:
2005 		count = pcre_exec(intern->u.regex.pce->re, intern->u.regex.pce->extra, subject, subject_len, 0, 0, NULL, 0);
2006 		RETVAL_BOOL(count >= 0);
2007 		break;
2008 
2009 	case REGIT_MODE_ALL_MATCHES:
2010 	case REGIT_MODE_GET_MATCH:
2011 		if (!use_copy) {
2012 			subject = estrndup(subject, subject_len);
2013 			use_copy = 1;
2014 		}
2015 		zval_ptr_dtor(&intern->current.data);
2016 		ALLOC_INIT_ZVAL(intern->current.data);
2017 		php_pcre_match_impl(intern->u.regex.pce, subject, subject_len, &zcount,
2018 			intern->current.data, intern->u.regex.mode == REGIT_MODE_ALL_MATCHES, intern->u.regex.use_flags, intern->u.regex.preg_flags, 0 TSRMLS_CC);
2019 		RETVAL_BOOL(Z_LVAL(zcount) > 0);
2020 		break;
2021 
2022 	case REGIT_MODE_SPLIT:
2023 		if (!use_copy) {
2024 			subject = estrndup(subject, subject_len);
2025 			use_copy = 1;
2026 		}
2027 		zval_ptr_dtor(&intern->current.data);
2028 		ALLOC_INIT_ZVAL(intern->current.data);
2029 		php_pcre_split_impl(intern->u.regex.pce, subject, subject_len, intern->current.data, -1, intern->u.regex.preg_flags TSRMLS_CC);
2030 		count = zend_hash_num_elements(Z_ARRVAL_P(intern->current.data));
2031 		RETVAL_BOOL(count > 1);
2032 		break;
2033 
2034 	case REGIT_MODE_REPLACE:
2035 		replacement = zend_read_property(intern->std.ce, getThis(), "replacement", sizeof("replacement")-1, 1 TSRMLS_CC);
2036 		if (Z_TYPE_P(replacement) != IS_STRING) {
2037 			tmp_replacement = *replacement;
2038 			zval_copy_ctor(&tmp_replacement);
2039 			convert_to_string(&tmp_replacement);
2040 			replacement = &tmp_replacement;
2041 		}
2042 		result = php_pcre_replace_impl(intern->u.regex.pce, subject, subject_len, replacement, 0, &result_len, -1, &count TSRMLS_CC);
2043 
2044 		if (intern->u.regex.flags & REGIT_USE_KEY) {
2045 			zval_ptr_dtor(&intern->current.key);
2046 			MAKE_STD_ZVAL(intern->current.key);
2047 			ZVAL_STRINGL(intern->current.key, result, result_len, 0);
2048 		} else {
2049 			zval_ptr_dtor(&intern->current.data);
2050 			MAKE_STD_ZVAL(intern->current.data);
2051 			ZVAL_STRINGL(intern->current.data, result, result_len, 0);
2052 		}
2053 
2054 		if (replacement == &tmp_replacement) {
2055 			zval_dtor(replacement);
2056 		}
2057 		RETVAL_BOOL(count > 0);
2058 	}
2059 
2060 	if (intern->u.regex.flags & REGIT_INVERTED) {
2061 		RETVAL_BOOL(! Z_LVAL_P(return_value));
2062 	}
2063 
2064 	if (use_copy) {
2065 		efree(subject);
2066 	}
2067 } /* }}} */
2068 
2069 /* {{{ proto string RegexIterator::getRegex()
2070    Returns current regular expression */
SPL_METHOD(RegexIterator,getRegex)2071 SPL_METHOD(RegexIterator, getRegex)
2072 {
2073 	spl_dual_it_object *intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
2074 
2075 	if (zend_parse_parameters_none() == FAILURE) {
2076 		return;
2077 	}
2078 
2079 	RETURN_STRINGL(intern->u.regex.regex, intern->u.regex.regex_len, 1);
2080 } /* }}} */
2081 
2082 /* {{{ proto bool RegexIterator::getMode()
2083    Returns current operation mode */
SPL_METHOD(RegexIterator,getMode)2084 SPL_METHOD(RegexIterator, getMode)
2085 {
2086 	spl_dual_it_object *intern;
2087 
2088 	if (zend_parse_parameters_none() == FAILURE) {
2089 		return;
2090 	}
2091 
2092 	SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
2093 
2094 	RETURN_LONG(intern->u.regex.mode);
2095 } /* }}} */
2096 
2097 /* {{{ proto bool RegexIterator::setMode(int new_mode)
2098    Set new operation mode */
SPL_METHOD(RegexIterator,setMode)2099 SPL_METHOD(RegexIterator, setMode)
2100 {
2101 	spl_dual_it_object *intern;
2102 	long mode;
2103 
2104 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &mode) == FAILURE) {
2105 		return;
2106 	}
2107 
2108 	if (mode < 0 || mode >= REGIT_MODE_MAX) {
2109 		zend_throw_exception_ex(spl_ce_InvalidArgumentException, 0 TSRMLS_CC, "Illegal mode %ld", mode);
2110 		return;/* NULL */
2111 	}
2112 
2113 	SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
2114 
2115 	intern->u.regex.mode = mode;
2116 } /* }}} */
2117 
2118 /* {{{ proto bool RegexIterator::getFlags()
2119    Returns current operation flags */
SPL_METHOD(RegexIterator,getFlags)2120 SPL_METHOD(RegexIterator, getFlags)
2121 {
2122 	spl_dual_it_object *intern;
2123 
2124 	if (zend_parse_parameters_none() == FAILURE) {
2125 		return;
2126 	}
2127 
2128 	SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
2129 
2130 	RETURN_LONG(intern->u.regex.flags);
2131 } /* }}} */
2132 
2133 /* {{{ proto bool RegexIterator::setFlags(int new_flags)
2134    Set operation flags */
SPL_METHOD(RegexIterator,setFlags)2135 SPL_METHOD(RegexIterator, setFlags)
2136 {
2137 	spl_dual_it_object *intern;
2138 	long flags;
2139 
2140 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &flags) == FAILURE) {
2141 		return;
2142 	}
2143 
2144 	SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
2145 
2146 	intern->u.regex.flags = flags;
2147 } /* }}} */
2148 
2149 /* {{{ proto bool RegexIterator::getFlags()
2150    Returns current PREG flags (if in use or NULL) */
SPL_METHOD(RegexIterator,getPregFlags)2151 SPL_METHOD(RegexIterator, getPregFlags)
2152 {
2153 	spl_dual_it_object *intern;
2154 
2155 	if (zend_parse_parameters_none() == FAILURE) {
2156 		return;
2157 	}
2158 
2159 	SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
2160 
2161 	if (intern->u.regex.use_flags) {
2162 		RETURN_LONG(intern->u.regex.preg_flags);
2163 	} else {
2164 		return;
2165 	}
2166 } /* }}} */
2167 
2168 /* {{{ proto bool RegexIterator::setPregFlags(int new_flags)
2169    Set PREG flags */
SPL_METHOD(RegexIterator,setPregFlags)2170 SPL_METHOD(RegexIterator, setPregFlags)
2171 {
2172 	spl_dual_it_object *intern;
2173 	long preg_flags;
2174 
2175 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &preg_flags) == FAILURE) {
2176 		return;
2177 	}
2178 
2179 	SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
2180 
2181 	intern->u.regex.preg_flags = preg_flags;
2182 	intern->u.regex.use_flags = 1;
2183 } /* }}} */
2184 
2185 /* {{{ proto void RecursiveRegexIterator::__construct(RecursiveIterator it, string regex [, int mode [, int flags [, int preg_flags]]])
2186    Create an RecursiveRegexIterator from another recursive iterator and a regular expression */
SPL_METHOD(RecursiveRegexIterator,__construct)2187 SPL_METHOD(RecursiveRegexIterator, __construct)
2188 {
2189 	spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_RecursiveRegexIterator, spl_ce_RecursiveIterator, DIT_RecursiveRegexIterator);
2190 } /* }}} */
2191 
2192 /* {{{ proto RecursiveRegexIterator RecursiveRegexIterator::getChildren()
2193    Return the inner iterator's children contained in a RecursiveRegexIterator */
SPL_METHOD(RecursiveRegexIterator,getChildren)2194 SPL_METHOD(RecursiveRegexIterator, getChildren)
2195 {
2196 	spl_dual_it_object   *intern;
2197 	zval                 *retval;
2198 
2199 	if (zend_parse_parameters_none() == FAILURE) {
2200 		return;
2201 	}
2202 
2203 	SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
2204 
2205 	zend_call_method_with_0_params(&intern->inner.zobject, intern->inner.ce, NULL, "getchildren", &retval);
2206 	if (!EG(exception)) {
2207 		zval **args[5], *object, *regex, *mode, *flags, *preg_flags;
2208 
2209 		MAKE_STD_ZVAL(object);
2210 		MAKE_STD_ZVAL(regex);
2211 		MAKE_STD_ZVAL(mode);
2212 		MAKE_STD_ZVAL(flags);
2213 		MAKE_STD_ZVAL(preg_flags);
2214 
2215 		MAKE_COPY_ZVAL(&retval, object);
2216 		ZVAL_STRING(regex, intern->u.regex.regex, 1);
2217 		ZVAL_LONG(mode, intern->u.regex.mode);
2218 		ZVAL_LONG(flags, intern->u.regex.flags);
2219 		ZVAL_LONG(preg_flags, intern->u.regex.preg_flags);
2220 
2221 		args[0] = &object;
2222 		args[1] = &regex;
2223 		args[2] = &mode;
2224 		args[3] = &flags;
2225 		args[4] = &preg_flags;
2226 
2227 		spl_instantiate_arg_n(Z_OBJCE_P(getThis()), &return_value, 5, args TSRMLS_CC);
2228 
2229 		zval_ptr_dtor(&object);
2230 		zval_ptr_dtor(&regex);
2231 		zval_ptr_dtor(&mode);
2232 		zval_ptr_dtor(&flags);
2233 		zval_ptr_dtor(&preg_flags);
2234 	}
2235 	if (retval) {
2236 		zval_ptr_dtor(&retval);
2237 	}
2238 } /* }}} */
2239 
SPL_METHOD(RecursiveRegexIterator,accept)2240 SPL_METHOD(RecursiveRegexIterator, accept)
2241 {
2242 	spl_dual_it_object *intern;
2243 	zval *rv;
2244 
2245 	if (zend_parse_parameters_none() == FAILURE) {
2246 		return;
2247 	}
2248 
2249 	SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
2250 
2251 	if (intern->current.data == NULL) {
2252 		RETURN_FALSE;
2253 	} else if (Z_TYPE_P(intern->current.data) == IS_ARRAY) {
2254 		RETURN_BOOL(zend_hash_num_elements(Z_ARRVAL_P(intern->current.data)) > 0);
2255 	}
2256 
2257 	zend_call_method_with_0_params(&(getThis()), spl_ce_RegexIterator, NULL, "accept", &rv);
2258 
2259 	RETURN_ZVAL(rv, 1, 1);
2260 }
2261 
2262 #endif
2263 
2264 /* {{{ spl_dual_it_dtor */
spl_dual_it_dtor(zend_object * _object,zend_object_handle handle TSRMLS_DC)2265 static void spl_dual_it_dtor(zend_object *_object, zend_object_handle handle TSRMLS_DC)
2266 {
2267 	spl_dual_it_object        *object = (spl_dual_it_object *)_object;
2268 
2269 	/* call standard dtor */
2270 	zend_objects_destroy_object(_object, handle TSRMLS_CC);
2271 
2272 	spl_dual_it_free(object TSRMLS_CC);
2273 
2274 	if (object->inner.iterator) {
2275 		object->inner.iterator->funcs->dtor(object->inner.iterator TSRMLS_CC);
2276 	}
2277 }
2278 /* }}} */
2279 
2280 /* {{{ spl_dual_it_free_storage */
spl_dual_it_free_storage(void * _object TSRMLS_DC)2281 static void spl_dual_it_free_storage(void *_object TSRMLS_DC)
2282 {
2283 	spl_dual_it_object        *object = (spl_dual_it_object *)_object;
2284 
2285 
2286 	if (object->inner.zobject) {
2287 		zval_ptr_dtor(&object->inner.zobject);
2288 	}
2289 
2290 	if (object->dit_type == DIT_AppendIterator) {
2291 		object->u.append.iterator->funcs->dtor(object->u.append.iterator TSRMLS_CC);
2292 		if (object->u.append.zarrayit) {
2293 			zval_ptr_dtor(&object->u.append.zarrayit);
2294 		}
2295 	}
2296 
2297 	if (object->dit_type == DIT_CachingIterator || object->dit_type == DIT_RecursiveCachingIterator) {
2298 		if (object->u.caching.zcache) {
2299 			zval_ptr_dtor(&object->u.caching.zcache);
2300 			object->u.caching.zcache = NULL;
2301 		}
2302 	}
2303 
2304 #if HAVE_PCRE || HAVE_BUNDLED_PCRE
2305 	if (object->dit_type == DIT_RegexIterator || object->dit_type == DIT_RecursiveRegexIterator) {
2306 		if (object->u.regex.pce) {
2307 			object->u.regex.pce->refcount--;
2308 		}
2309 		if (object->u.regex.regex) {
2310 			efree(object->u.regex.regex);
2311 		}
2312 	}
2313 #endif
2314 
2315 	if (object->dit_type == DIT_CallbackFilterIterator || object->dit_type == DIT_RecursiveCallbackFilterIterator) {
2316 		if (object->u.cbfilter) {
2317 			if (object->u.cbfilter->fci.function_name) {
2318 				zval_ptr_dtor(&object->u.cbfilter->fci.function_name);
2319 			}
2320 			if (object->u.cbfilter->fci.object_ptr) {
2321 				zval_ptr_dtor(&object->u.cbfilter->fci.object_ptr);
2322 			}
2323 			efree(object->u.cbfilter);
2324 		}
2325 	}
2326 
2327 	zend_object_std_dtor(&object->std TSRMLS_CC);
2328 
2329 	efree(object);
2330 }
2331 /* }}} */
2332 
2333 /* {{{ spl_dual_it_new */
spl_dual_it_new(zend_class_entry * class_type TSRMLS_DC)2334 static zend_object_value spl_dual_it_new(zend_class_entry *class_type TSRMLS_DC)
2335 {
2336 	zend_object_value retval;
2337 	spl_dual_it_object *intern;
2338 
2339 	intern = emalloc(sizeof(spl_dual_it_object));
2340 	memset(intern, 0, sizeof(spl_dual_it_object));
2341 	intern->dit_type = DIT_Unknown;
2342 
2343 	zend_object_std_init(&intern->std, class_type TSRMLS_CC);
2344 	object_properties_init(&intern->std, class_type);
2345 
2346 	retval.handle = zend_objects_store_put(intern, (zend_objects_store_dtor_t)spl_dual_it_dtor, (zend_objects_free_object_storage_t) spl_dual_it_free_storage, NULL TSRMLS_CC);
2347 	retval.handlers = &spl_handlers_dual_it;
2348 	return retval;
2349 }
2350 /* }}} */
2351 
2352 ZEND_BEGIN_ARG_INFO(arginfo_filter_it___construct, 0)
2353 	ZEND_ARG_OBJ_INFO(0, iterator, Iterator, 0)
2354 ZEND_END_ARG_INFO();
2355 
2356 static const zend_function_entry spl_funcs_FilterIterator[] = {
2357 	SPL_ME(FilterIterator,  __construct,      arginfo_filter_it___construct, ZEND_ACC_PUBLIC)
2358 	SPL_ME(FilterIterator,  rewind,           arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
2359 	SPL_ME(dual_it,         valid,            arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
2360 	SPL_ME(dual_it,         key,              arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
2361 	SPL_ME(dual_it,         current,          arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
2362 	SPL_ME(FilterIterator,  next,             arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
2363 	SPL_ME(dual_it,         getInnerIterator, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
2364 	SPL_ABSTRACT_ME(FilterIterator, accept,   arginfo_recursive_it_void)
2365 	PHP_FE_END
2366 };
2367 
2368 ZEND_BEGIN_ARG_INFO(arginfo_callback_filter_it___construct, 0)
2369 	ZEND_ARG_OBJ_INFO(0, iterator, Iterator, 0)
2370 	ZEND_ARG_INFO(0, callback)
2371 ZEND_END_ARG_INFO();
2372 
2373 static const zend_function_entry spl_funcs_CallbackFilterIterator[] = {
2374 	SPL_ME(CallbackFilterIterator, __construct, arginfo_callback_filter_it___construct, ZEND_ACC_PUBLIC)
2375 	SPL_ME(CallbackFilterIterator, accept,      arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
2376 	PHP_FE_END
2377 };
2378 
2379 ZEND_BEGIN_ARG_INFO(arginfo_recursive_callback_filter_it___construct, 0)
2380 	ZEND_ARG_OBJ_INFO(0, iterator, RecursiveIterator, 0)
2381 	ZEND_ARG_INFO(0, callback)
2382 ZEND_END_ARG_INFO();
2383 
2384 static const zend_function_entry spl_funcs_RecursiveCallbackFilterIterator[] = {
2385 	SPL_ME(RecursiveCallbackFilterIterator, __construct, arginfo_recursive_callback_filter_it___construct, ZEND_ACC_PUBLIC)
2386 	SPL_ME(RecursiveFilterIterator,  hasChildren,      arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
2387 	SPL_ME(RecursiveCallbackFilterIterator,  getChildren,      arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
2388 	PHP_FE_END
2389 };
2390 
2391 ZEND_BEGIN_ARG_INFO(arginfo_parent_it___construct, 0)
2392 	ZEND_ARG_OBJ_INFO(0, iterator, RecursiveIterator, 0)
2393 ZEND_END_ARG_INFO();
2394 
2395 static const zend_function_entry spl_funcs_RecursiveFilterIterator[] = {
2396 	SPL_ME(RecursiveFilterIterator,  __construct,      arginfo_parent_it___construct, ZEND_ACC_PUBLIC)
2397 	SPL_ME(RecursiveFilterIterator,  hasChildren,      arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
2398 	SPL_ME(RecursiveFilterIterator,  getChildren,      arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
2399 	PHP_FE_END
2400 };
2401 
2402 static const zend_function_entry spl_funcs_ParentIterator[] = {
2403 	SPL_ME(ParentIterator,  __construct,      arginfo_parent_it___construct, ZEND_ACC_PUBLIC)
2404 	SPL_MA(ParentIterator,  accept,           RecursiveFilterIterator, hasChildren, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
2405 	PHP_FE_END
2406 };
2407 
2408 #if HAVE_PCRE || HAVE_BUNDLED_PCRE
2409 ZEND_BEGIN_ARG_INFO_EX(arginfo_regex_it___construct, 0, 0, 2)
2410 	ZEND_ARG_OBJ_INFO(0, iterator, Iterator, 0)
2411 	ZEND_ARG_INFO(0, regex)
2412 	ZEND_ARG_INFO(0, mode)
2413 	ZEND_ARG_INFO(0, flags)
2414 	ZEND_ARG_INFO(0, preg_flags)
2415 ZEND_END_ARG_INFO();
2416 
2417 ZEND_BEGIN_ARG_INFO_EX(arginfo_regex_it_set_mode, 0, 0, 1)
2418 	ZEND_ARG_INFO(0, mode)
2419 ZEND_END_ARG_INFO();
2420 
2421 ZEND_BEGIN_ARG_INFO_EX(arginfo_regex_it_set_flags, 0, 0, 1)
2422 	ZEND_ARG_INFO(0, flags)
2423 ZEND_END_ARG_INFO();
2424 
2425 ZEND_BEGIN_ARG_INFO_EX(arginfo_regex_it_set_preg_flags, 0, 0, 1)
2426 	ZEND_ARG_INFO(0, preg_flags)
2427 ZEND_END_ARG_INFO();
2428 
2429 static const zend_function_entry spl_funcs_RegexIterator[] = {
2430 	SPL_ME(RegexIterator,   __construct,      arginfo_regex_it___construct,    ZEND_ACC_PUBLIC)
2431 	SPL_ME(RegexIterator,   accept,           arginfo_recursive_it_void,       ZEND_ACC_PUBLIC)
2432 	SPL_ME(RegexIterator,   getMode,          arginfo_recursive_it_void,       ZEND_ACC_PUBLIC)
2433 	SPL_ME(RegexIterator,   setMode,          arginfo_regex_it_set_mode,       ZEND_ACC_PUBLIC)
2434 	SPL_ME(RegexIterator,   getFlags,         arginfo_recursive_it_void,       ZEND_ACC_PUBLIC)
2435 	SPL_ME(RegexIterator,   setFlags,         arginfo_regex_it_set_flags,      ZEND_ACC_PUBLIC)
2436 	SPL_ME(RegexIterator,   getPregFlags,     arginfo_recursive_it_void,       ZEND_ACC_PUBLIC)
2437 	SPL_ME(RegexIterator,   setPregFlags,     arginfo_regex_it_set_preg_flags, ZEND_ACC_PUBLIC)
2438 	SPL_ME(RegexIterator,   getRegex,         arginfo_recursive_it_void,       ZEND_ACC_PUBLIC)
2439 	PHP_FE_END
2440 };
2441 
2442 ZEND_BEGIN_ARG_INFO_EX(arginfo_rec_regex_it___construct, 0, 0, 2)
2443 	ZEND_ARG_OBJ_INFO(0, iterator, RecursiveIterator, 0)
2444 	ZEND_ARG_INFO(0, regex)
2445 	ZEND_ARG_INFO(0, mode)
2446 	ZEND_ARG_INFO(0, flags)
2447 	ZEND_ARG_INFO(0, preg_flags)
2448 ZEND_END_ARG_INFO();
2449 
2450 static const zend_function_entry spl_funcs_RecursiveRegexIterator[] = {
2451 	SPL_ME(RecursiveRegexIterator,  __construct,      arginfo_rec_regex_it___construct, ZEND_ACC_PUBLIC)
2452 	SPL_ME(RecursiveRegexIterator,  accept,           arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
2453 	SPL_ME(RecursiveFilterIterator, hasChildren,      arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
2454 	SPL_ME(RecursiveRegexIterator,  getChildren,      arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
2455 	PHP_FE_END
2456 };
2457 #endif
2458 
spl_limit_it_valid(spl_dual_it_object * intern TSRMLS_DC)2459 static inline int spl_limit_it_valid(spl_dual_it_object *intern TSRMLS_DC)
2460 {
2461 	/* FAILURE / SUCCESS */
2462 	if (intern->u.limit.count != -1 && intern->current.pos >= intern->u.limit.offset + intern->u.limit.count) {
2463 		return FAILURE;
2464 	} else {
2465 		return spl_dual_it_valid(intern TSRMLS_CC);
2466 	}
2467 }
2468 
spl_limit_it_seek(spl_dual_it_object * intern,long pos TSRMLS_DC)2469 static inline void spl_limit_it_seek(spl_dual_it_object *intern, long pos TSRMLS_DC)
2470 {
2471 	zval  *zpos;
2472 
2473 	spl_dual_it_free(intern TSRMLS_CC);
2474 	if (pos < intern->u.limit.offset) {
2475 		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);
2476 		return;
2477 	}
2478 	if (pos >= intern->u.limit.offset + intern->u.limit.count && intern->u.limit.count != -1) {
2479 		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);
2480 		return;
2481 	}
2482 	if (pos != intern->current.pos && instanceof_function(intern->inner.ce, spl_ce_SeekableIterator TSRMLS_CC)) {
2483 		MAKE_STD_ZVAL(zpos);
2484 		ZVAL_LONG(zpos, pos);
2485 		spl_dual_it_free(intern TSRMLS_CC);
2486 		zend_call_method_with_1_params(&intern->inner.zobject, intern->inner.ce, NULL, "seek", NULL, zpos);
2487 		zval_ptr_dtor(&zpos);
2488 		if (!EG(exception)) {
2489 			intern->current.pos = pos;
2490 			if (spl_limit_it_valid(intern TSRMLS_CC) == SUCCESS) {
2491 				spl_dual_it_fetch(intern, 0 TSRMLS_CC);
2492 			}
2493 		}
2494 	} else {
2495 		/* emulate the forward seek, by next() calls */
2496 		/* a back ward seek is done by a previous rewind() */
2497 		if (pos < intern->current.pos) {
2498 			spl_dual_it_rewind(intern TSRMLS_CC);
2499 		}
2500 		while (pos > intern->current.pos && spl_dual_it_valid(intern TSRMLS_CC) == SUCCESS) {
2501 			spl_dual_it_next(intern, 1 TSRMLS_CC);
2502 		}
2503 		if (spl_dual_it_valid(intern TSRMLS_CC) == SUCCESS) {
2504 			spl_dual_it_fetch(intern, 1 TSRMLS_CC);
2505 		}
2506 	}
2507 }
2508 
2509 /* {{{ proto LimitIterator::__construct(Iterator it [, int offset, int count])
2510    Construct a LimitIterator from an Iterator with a given starting offset and optionally a maximum count */
SPL_METHOD(LimitIterator,__construct)2511 SPL_METHOD(LimitIterator, __construct)
2512 {
2513 	spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_LimitIterator, zend_ce_iterator, DIT_LimitIterator);
2514 } /* }}} */
2515 
2516 /* {{{ proto void LimitIterator::rewind()
2517    Rewind the iterator to the specified starting offset */
SPL_METHOD(LimitIterator,rewind)2518 SPL_METHOD(LimitIterator, rewind)
2519 {
2520 	spl_dual_it_object   *intern;
2521 
2522 	SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
2523 	spl_dual_it_rewind(intern TSRMLS_CC);
2524 	spl_limit_it_seek(intern, intern->u.limit.offset TSRMLS_CC);
2525 } /* }}} */
2526 
2527 /* {{{ proto bool LimitIterator::valid()
2528    Check whether the current element is valid */
SPL_METHOD(LimitIterator,valid)2529 SPL_METHOD(LimitIterator, valid)
2530 {
2531 	spl_dual_it_object   *intern;
2532 
2533 	SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
2534 
2535 /*	RETURN_BOOL(spl_limit_it_valid(intern TSRMLS_CC) == SUCCESS);*/
2536 	RETURN_BOOL((intern->u.limit.count == -1 || intern->current.pos < intern->u.limit.offset + intern->u.limit.count) && intern->current.data);
2537 } /* }}} */
2538 
2539 /* {{{ proto void LimitIterator::next()
2540    Move the iterator forward */
SPL_METHOD(LimitIterator,next)2541 SPL_METHOD(LimitIterator, next)
2542 {
2543 	spl_dual_it_object   *intern;
2544 
2545 	SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
2546 
2547 	spl_dual_it_next(intern, 1 TSRMLS_CC);
2548 	if (intern->u.limit.count == -1 || intern->current.pos < intern->u.limit.offset + intern->u.limit.count) {
2549 		spl_dual_it_fetch(intern, 1 TSRMLS_CC);
2550 	}
2551 } /* }}} */
2552 
2553 /* {{{ proto void LimitIterator::seek(int position)
2554    Seek to the given position */
SPL_METHOD(LimitIterator,seek)2555 SPL_METHOD(LimitIterator, seek)
2556 {
2557 	spl_dual_it_object   *intern;
2558 	long                 pos;
2559 
2560 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &pos) == FAILURE) {
2561 		return;
2562 	}
2563 
2564 	SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
2565 	spl_limit_it_seek(intern, pos TSRMLS_CC);
2566 	RETURN_LONG(intern->current.pos);
2567 } /* }}} */
2568 
2569 /* {{{ proto int LimitIterator::getPosition()
2570    Return the current position */
SPL_METHOD(LimitIterator,getPosition)2571 SPL_METHOD(LimitIterator, getPosition)
2572 {
2573 	spl_dual_it_object   *intern;
2574 	SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
2575 	RETURN_LONG(intern->current.pos);
2576 } /* }}} */
2577 
2578 ZEND_BEGIN_ARG_INFO(arginfo_seekable_it_seek, 0)
2579 	ZEND_ARG_INFO(0, position)
2580 ZEND_END_ARG_INFO();
2581 
2582 static const zend_function_entry spl_funcs_SeekableIterator[] = {
2583 	SPL_ABSTRACT_ME(SeekableIterator, seek, arginfo_seekable_it_seek)
2584 	PHP_FE_END
2585 };
2586 
2587 ZEND_BEGIN_ARG_INFO_EX(arginfo_limit_it___construct, 0, 0, 1)
2588 	ZEND_ARG_OBJ_INFO(0, iterator, Iterator, 0)
2589 	ZEND_ARG_INFO(0, offset)
2590 	ZEND_ARG_INFO(0, count)
2591 ZEND_END_ARG_INFO();
2592 
2593 ZEND_BEGIN_ARG_INFO(arginfo_limit_it_seek, 0)
2594 	ZEND_ARG_INFO(0, position)
2595 ZEND_END_ARG_INFO();
2596 
2597 static const zend_function_entry spl_funcs_LimitIterator[] = {
2598 	SPL_ME(LimitIterator,   __construct,      arginfo_limit_it___construct, ZEND_ACC_PUBLIC)
2599 	SPL_ME(LimitIterator,   rewind,           arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
2600 	SPL_ME(LimitIterator,   valid,            arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
2601 	SPL_ME(dual_it,         key,              arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
2602 	SPL_ME(dual_it,         current,          arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
2603 	SPL_ME(LimitIterator,   next,             arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
2604 	SPL_ME(LimitIterator,   seek,             arginfo_limit_it_seek, ZEND_ACC_PUBLIC)
2605 	SPL_ME(LimitIterator,   getPosition,      arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
2606 	SPL_ME(dual_it,         getInnerIterator, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
2607 	PHP_FE_END
2608 };
2609 
spl_caching_it_valid(spl_dual_it_object * intern TSRMLS_DC)2610 static inline int spl_caching_it_valid(spl_dual_it_object *intern TSRMLS_DC)
2611 {
2612 	return intern->u.caching.flags & CIT_VALID ? SUCCESS : FAILURE;
2613 }
2614 
spl_caching_it_has_next(spl_dual_it_object * intern TSRMLS_DC)2615 static inline int spl_caching_it_has_next(spl_dual_it_object *intern TSRMLS_DC)
2616 {
2617 	return spl_dual_it_valid(intern TSRMLS_CC);
2618 }
2619 
spl_caching_it_next(spl_dual_it_object * intern TSRMLS_DC)2620 static inline void spl_caching_it_next(spl_dual_it_object *intern TSRMLS_DC)
2621 {
2622 	if (spl_dual_it_fetch(intern, 1 TSRMLS_CC) == SUCCESS) {
2623 		intern->u.caching.flags |= CIT_VALID;
2624 		/* Full cache ? */
2625 		if (intern->u.caching.flags & CIT_FULL_CACHE) {
2626 			zval *zcacheval;
2627 			zval *key = intern->current.key;
2628 
2629 			MAKE_STD_ZVAL(zcacheval);
2630 			ZVAL_ZVAL(zcacheval, intern->current.data, 1, 0);
2631 
2632 			array_set_zval_key(HASH_OF(intern->u.caching.zcache), key, zcacheval);
2633 
2634 			zval_ptr_dtor(&zcacheval);
2635 		}
2636 		/* Recursion ? */
2637 		if (intern->dit_type == DIT_RecursiveCachingIterator) {
2638 			zval *retval, *zchildren, zflags;
2639 			zend_call_method_with_0_params(&intern->inner.zobject, intern->inner.ce, NULL, "haschildren", &retval);
2640 			if (EG(exception)) {
2641 				if (retval) {
2642 					zval_ptr_dtor(&retval);
2643 				}
2644 				if (intern->u.caching.flags & CIT_CATCH_GET_CHILD) {
2645 					zend_clear_exception(TSRMLS_C);
2646 				} else {
2647 					return;
2648 				}
2649 			} else {
2650 				if (zend_is_true(retval)) {
2651 					zend_call_method_with_0_params(&intern->inner.zobject, intern->inner.ce, NULL, "getchildren", &zchildren);
2652 					if (EG(exception)) {
2653 						if (zchildren) {
2654 							zval_ptr_dtor(&zchildren);
2655 						}
2656 						if (intern->u.caching.flags & CIT_CATCH_GET_CHILD) {
2657 							zend_clear_exception(TSRMLS_C);
2658 						} else {
2659 							zval_ptr_dtor(&retval);
2660 							return;
2661 						}
2662 					} else {
2663 						INIT_PZVAL(&zflags);
2664 						ZVAL_LONG(&zflags, intern->u.caching.flags & CIT_PUBLIC);
2665 						spl_instantiate_arg_ex2(spl_ce_RecursiveCachingIterator, &intern->u.caching.zchildren, 1, zchildren, &zflags TSRMLS_CC);
2666 						zval_ptr_dtor(&zchildren);
2667 					}
2668 				}
2669 				zval_ptr_dtor(&retval);
2670 				if (EG(exception)) {
2671 					if (intern->u.caching.flags & CIT_CATCH_GET_CHILD) {
2672 						zend_clear_exception(TSRMLS_C);
2673 					} else {
2674 						return;
2675 					}
2676 				}
2677 			}
2678 		}
2679 		if (intern->u.caching.flags & (CIT_TOSTRING_USE_INNER|CIT_CALL_TOSTRING)) {
2680 			int  use_copy;
2681 			zval expr_copy;
2682 			ALLOC_ZVAL(intern->u.caching.zstr);
2683 			if (intern->u.caching.flags & CIT_TOSTRING_USE_INNER) {
2684 				*intern->u.caching.zstr = *intern->inner.zobject;
2685 			} else {
2686 				*intern->u.caching.zstr = *intern->current.data;
2687 			}
2688 			zend_make_printable_zval(intern->u.caching.zstr, &expr_copy, &use_copy);
2689 			if (use_copy) {
2690 				*intern->u.caching.zstr = expr_copy;
2691 				INIT_PZVAL(intern->u.caching.zstr);
2692 				zval_copy_ctor(intern->u.caching.zstr);
2693 				zval_dtor(&expr_copy);
2694 			} else {
2695 				INIT_PZVAL(intern->u.caching.zstr);
2696 				zval_copy_ctor(intern->u.caching.zstr);
2697 			}
2698 		}
2699 		spl_dual_it_next(intern, 0 TSRMLS_CC);
2700 	} else {
2701 		intern->u.caching.flags &= ~CIT_VALID;
2702 	}
2703 }
2704 
spl_caching_it_rewind(spl_dual_it_object * intern TSRMLS_DC)2705 static inline void spl_caching_it_rewind(spl_dual_it_object *intern TSRMLS_DC)
2706 {
2707 	spl_dual_it_rewind(intern TSRMLS_CC);
2708 	zend_hash_clean(HASH_OF(intern->u.caching.zcache));
2709 	spl_caching_it_next(intern TSRMLS_CC);
2710 }
2711 
2712 /* {{{ proto void CachingIterator::__construct(Iterator it [, flags = CIT_CALL_TOSTRING])
2713    Construct a CachingIterator from an Iterator */
SPL_METHOD(CachingIterator,__construct)2714 SPL_METHOD(CachingIterator, __construct)
2715 {
2716 	spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_CachingIterator, zend_ce_iterator, DIT_CachingIterator);
2717 } /* }}} */
2718 
2719 /* {{{ proto void CachingIterator::rewind()
2720    Rewind the iterator */
SPL_METHOD(CachingIterator,rewind)2721 SPL_METHOD(CachingIterator, rewind)
2722 {
2723 	spl_dual_it_object   *intern;
2724 
2725 	if (zend_parse_parameters_none() == FAILURE) {
2726 		return;
2727 	}
2728 
2729 	SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
2730 
2731 	spl_caching_it_rewind(intern TSRMLS_CC);
2732 } /* }}} */
2733 
2734 /* {{{ proto bool CachingIterator::valid()
2735    Check whether the current element is valid */
SPL_METHOD(CachingIterator,valid)2736 SPL_METHOD(CachingIterator, valid)
2737 {
2738 	spl_dual_it_object   *intern;
2739 
2740 	if (zend_parse_parameters_none() == FAILURE) {
2741 		return;
2742 	}
2743 
2744 	SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
2745 
2746 	RETURN_BOOL(spl_caching_it_valid(intern TSRMLS_CC) == SUCCESS);
2747 } /* }}} */
2748 
2749 /* {{{ proto void CachingIterator::next()
2750    Move the iterator forward */
SPL_METHOD(CachingIterator,next)2751 SPL_METHOD(CachingIterator, next)
2752 {
2753 	spl_dual_it_object   *intern;
2754 
2755 	if (zend_parse_parameters_none() == FAILURE) {
2756 		return;
2757 	}
2758 
2759 	SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
2760 
2761 	spl_caching_it_next(intern TSRMLS_CC);
2762 } /* }}} */
2763 
2764 /* {{{ proto bool CachingIterator::hasNext()
2765    Check whether the inner iterator has a valid next element */
SPL_METHOD(CachingIterator,hasNext)2766 SPL_METHOD(CachingIterator, hasNext)
2767 {
2768 	spl_dual_it_object   *intern;
2769 
2770 	if (zend_parse_parameters_none() == FAILURE) {
2771 		return;
2772 	}
2773 
2774 	SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
2775 
2776 	RETURN_BOOL(spl_caching_it_has_next(intern TSRMLS_CC) == SUCCESS);
2777 } /* }}} */
2778 
2779 /* {{{ proto string CachingIterator::__toString()
2780    Return the string representation of the current element */
SPL_METHOD(CachingIterator,__toString)2781 SPL_METHOD(CachingIterator, __toString)
2782 {
2783 	spl_dual_it_object   *intern;
2784 
2785 	SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
2786 
2787 	if (!(intern->u.caching.flags & (CIT_CALL_TOSTRING|CIT_TOSTRING_USE_KEY|CIT_TOSTRING_USE_CURRENT|CIT_TOSTRING_USE_INNER)))	{
2788 		zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "%s does not fetch string value (see CachingIterator::__construct)", Z_OBJCE_P(getThis())->name);
2789 		return;
2790 	}
2791 	if (intern->u.caching.flags & CIT_TOSTRING_USE_KEY) {
2792 		MAKE_COPY_ZVAL(&intern->current.key, return_value);
2793 		convert_to_string(return_value);
2794 		return;
2795 	} else if (intern->u.caching.flags & CIT_TOSTRING_USE_CURRENT) {
2796 		MAKE_COPY_ZVAL(&intern->current.data, return_value);
2797 		convert_to_string(return_value);
2798 		return;
2799 	}
2800 	if (intern->u.caching.zstr) {
2801 		RETURN_STRINGL(Z_STRVAL_P(intern->u.caching.zstr), Z_STRLEN_P(intern->u.caching.zstr), 1);
2802 	} else {
2803 		RETURN_NULL();
2804 	}
2805 } /* }}} */
2806 
2807 /* {{{ proto void CachingIterator::offsetSet(mixed index, mixed newval)
2808    Set given index in cache */
SPL_METHOD(CachingIterator,offsetSet)2809 SPL_METHOD(CachingIterator, offsetSet)
2810 {
2811 	spl_dual_it_object   *intern;
2812 	char *arKey;
2813 	uint nKeyLength;
2814 	zval *value;
2815 
2816 	SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
2817 
2818 	if (!(intern->u.caching.flags & CIT_FULL_CACHE))	{
2819 		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);
2820 		return;
2821 	}
2822 
2823 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz", &arKey, &nKeyLength, &value) == FAILURE) {
2824 		return;
2825 	}
2826 
2827 	Z_ADDREF_P(value);
2828 	zend_symtable_update(HASH_OF(intern->u.caching.zcache), arKey, nKeyLength+1, &value, sizeof(value), NULL);
2829 }
2830 /* }}} */
2831 
2832 /* {{{ proto string CachingIterator::offsetGet(mixed index)
2833    Return the internal cache if used */
SPL_METHOD(CachingIterator,offsetGet)2834 SPL_METHOD(CachingIterator, offsetGet)
2835 {
2836 	spl_dual_it_object   *intern;
2837 	char *arKey;
2838 	uint nKeyLength;
2839 	zval **value;
2840 
2841 	SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
2842 
2843 	if (!(intern->u.caching.flags & CIT_FULL_CACHE))	{
2844 		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);
2845 		return;
2846 	}
2847 
2848 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &arKey, &nKeyLength) == FAILURE) {
2849 		return;
2850 	}
2851 
2852 	if (zend_symtable_find(HASH_OF(intern->u.caching.zcache), arKey, nKeyLength+1, (void**)&value) == FAILURE) {
2853 		zend_error(E_NOTICE, "Undefined index: %s", arKey);
2854 		return;
2855 	}
2856 
2857 	RETURN_ZVAL(*value, 1, 0);
2858 }
2859 /* }}} */
2860 
2861 /* {{{ proto void CachingIterator::offsetUnset(mixed index)
2862    Unset given index in cache */
SPL_METHOD(CachingIterator,offsetUnset)2863 SPL_METHOD(CachingIterator, offsetUnset)
2864 {
2865 	spl_dual_it_object   *intern;
2866 	char *arKey;
2867 	uint nKeyLength;
2868 
2869 	SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
2870 
2871 	if (!(intern->u.caching.flags & CIT_FULL_CACHE))	{
2872 		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);
2873 		return;
2874 	}
2875 
2876 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &arKey, &nKeyLength) == FAILURE) {
2877 		return;
2878 	}
2879 
2880 	zend_symtable_del(HASH_OF(intern->u.caching.zcache), arKey, nKeyLength+1);
2881 }
2882 /* }}} */
2883 
2884 /* {{{ proto bool CachingIterator::offsetExists(mixed index)
2885    Return whether the requested index exists */
SPL_METHOD(CachingIterator,offsetExists)2886 SPL_METHOD(CachingIterator, offsetExists)
2887 {
2888 	spl_dual_it_object   *intern;
2889 	char *arKey;
2890 	uint nKeyLength;
2891 
2892 	SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
2893 
2894 	if (!(intern->u.caching.flags & CIT_FULL_CACHE))	{
2895 		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);
2896 		return;
2897 	}
2898 
2899 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &arKey, &nKeyLength) == FAILURE) {
2900 		return;
2901 	}
2902 
2903 	RETURN_BOOL(zend_symtable_exists(HASH_OF(intern->u.caching.zcache), arKey, nKeyLength+1));
2904 }
2905 /* }}} */
2906 
2907 /* {{{ proto bool CachingIterator::getCache()
2908    Return the cache */
SPL_METHOD(CachingIterator,getCache)2909 SPL_METHOD(CachingIterator, getCache)
2910 {
2911 	spl_dual_it_object   *intern;
2912 
2913 	if (zend_parse_parameters_none() == FAILURE) {
2914 		return;
2915 	}
2916 
2917 	SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
2918 
2919 	if (!(intern->u.caching.flags & CIT_FULL_CACHE))	{
2920 		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);
2921 		return;
2922 	}
2923 
2924 	RETURN_ZVAL(intern->u.caching.zcache, 1, 0);
2925 }
2926 /* }}} */
2927 
2928 /* {{{ proto int CachingIterator::getFlags()
2929    Return the internal flags */
SPL_METHOD(CachingIterator,getFlags)2930 SPL_METHOD(CachingIterator, getFlags)
2931 {
2932 	spl_dual_it_object   *intern;
2933 
2934 	if (zend_parse_parameters_none() == FAILURE) {
2935 		return;
2936 	}
2937 
2938 	SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
2939 
2940 	RETURN_LONG(intern->u.caching.flags);
2941 }
2942 /* }}} */
2943 
2944 /* {{{ proto void CachingIterator::setFlags(int flags)
2945    Set the internal flags */
SPL_METHOD(CachingIterator,setFlags)2946 SPL_METHOD(CachingIterator, setFlags)
2947 {
2948 	spl_dual_it_object   *intern;
2949 	long flags;
2950 
2951 	SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
2952 
2953 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &flags) == FAILURE) {
2954 		return;
2955 	}
2956 
2957 	if (spl_cit_check_flags(flags) != SUCCESS) {
2958 		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);
2959 		return;
2960 	}
2961 	if ((intern->u.caching.flags & CIT_CALL_TOSTRING) != 0 && (flags & CIT_CALL_TOSTRING) == 0) {
2962 		zend_throw_exception(spl_ce_InvalidArgumentException, "Unsetting flag CALL_TO_STRING is not possible", 0 TSRMLS_CC);
2963 		return;
2964 	}
2965 	if ((intern->u.caching.flags & CIT_TOSTRING_USE_INNER) != 0 && (flags & CIT_TOSTRING_USE_INNER) == 0) {
2966 		zend_throw_exception(spl_ce_InvalidArgumentException, "Unsetting flag TOSTRING_USE_INNER is not possible", 0 TSRMLS_CC);
2967 		return;
2968 	}
2969 	if ((flags & CIT_FULL_CACHE) != 0 && (intern->u.caching.flags & CIT_FULL_CACHE) == 0) {
2970 		/* clear on (re)enable */
2971 		zend_hash_clean(HASH_OF(intern->u.caching.zcache));
2972 	}
2973 	intern->u.caching.flags = (intern->u.caching.flags & ~CIT_PUBLIC) | (flags & CIT_PUBLIC);
2974 }
2975 /* }}} */
2976 
2977 /* {{{ proto void CachingIterator::count()
2978    Number of cached elements */
SPL_METHOD(CachingIterator,count)2979 SPL_METHOD(CachingIterator, count)
2980 {
2981 	spl_dual_it_object   *intern;
2982 
2983 	if (zend_parse_parameters_none() == FAILURE) {
2984 		return;
2985 	}
2986 
2987 	SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
2988 
2989 	if (!(intern->u.caching.flags & CIT_FULL_CACHE))	{
2990 		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);
2991 		return;
2992 	}
2993 
2994 	RETURN_LONG(zend_hash_num_elements(HASH_OF(intern->u.caching.zcache)));
2995 }
2996 /* }}} */
2997 
2998 ZEND_BEGIN_ARG_INFO_EX(arginfo_caching_it___construct, 0, 0, 1)
2999 	ZEND_ARG_OBJ_INFO(0, iterator, Iterator, 0)
3000 	ZEND_ARG_INFO(0, flags)
3001 ZEND_END_ARG_INFO();
3002 
3003 ZEND_BEGIN_ARG_INFO(arginfo_caching_it_setFlags, 0)
3004 	ZEND_ARG_INFO(0, flags)
3005 ZEND_END_ARG_INFO();
3006 
3007 ZEND_BEGIN_ARG_INFO(arginfo_caching_it_offsetGet, 0)
3008 	ZEND_ARG_INFO(0, index)
3009 ZEND_END_ARG_INFO();
3010 
3011 ZEND_BEGIN_ARG_INFO(arginfo_caching_it_offsetSet, 0)
3012 	ZEND_ARG_INFO(0, index)
3013 	ZEND_ARG_INFO(0, newval)
3014 ZEND_END_ARG_INFO();
3015 
3016 static const zend_function_entry spl_funcs_CachingIterator[] = {
3017 	SPL_ME(CachingIterator, __construct,      arginfo_caching_it___construct, ZEND_ACC_PUBLIC)
3018 	SPL_ME(CachingIterator, rewind,           arginfo_recursive_it_void,      ZEND_ACC_PUBLIC)
3019 	SPL_ME(CachingIterator, valid,            arginfo_recursive_it_void,      ZEND_ACC_PUBLIC)
3020 	SPL_ME(dual_it,         key,              arginfo_recursive_it_void,      ZEND_ACC_PUBLIC)
3021 	SPL_ME(dual_it,         current,          arginfo_recursive_it_void,      ZEND_ACC_PUBLIC)
3022 	SPL_ME(CachingIterator, next,             arginfo_recursive_it_void,      ZEND_ACC_PUBLIC)
3023 	SPL_ME(CachingIterator, hasNext,          arginfo_recursive_it_void,      ZEND_ACC_PUBLIC)
3024 	SPL_ME(CachingIterator, __toString,       arginfo_recursive_it_void,      ZEND_ACC_PUBLIC)
3025 	SPL_ME(dual_it,         getInnerIterator, arginfo_recursive_it_void,      ZEND_ACC_PUBLIC)
3026 	SPL_ME(CachingIterator, getFlags,         arginfo_recursive_it_void,      ZEND_ACC_PUBLIC)
3027 	SPL_ME(CachingIterator, setFlags,         arginfo_caching_it_setFlags,    ZEND_ACC_PUBLIC)
3028 	SPL_ME(CachingIterator, offsetGet,        arginfo_caching_it_offsetGet,   ZEND_ACC_PUBLIC)
3029 	SPL_ME(CachingIterator, offsetSet,        arginfo_caching_it_offsetSet,   ZEND_ACC_PUBLIC)
3030 	SPL_ME(CachingIterator, offsetUnset,      arginfo_caching_it_offsetGet,   ZEND_ACC_PUBLIC)
3031 	SPL_ME(CachingIterator, offsetExists,     arginfo_caching_it_offsetGet,   ZEND_ACC_PUBLIC)
3032 	SPL_ME(CachingIterator, getCache,         arginfo_recursive_it_void,      ZEND_ACC_PUBLIC)
3033 	SPL_ME(CachingIterator, count,            arginfo_recursive_it_void,      ZEND_ACC_PUBLIC)
3034 	PHP_FE_END
3035 };
3036 
3037 /* {{{ proto void RecursiveCachingIterator::__construct(RecursiveIterator it [, flags = CIT_CALL_TOSTRING])
3038    Create an iterator from a RecursiveIterator */
SPL_METHOD(RecursiveCachingIterator,__construct)3039 SPL_METHOD(RecursiveCachingIterator, __construct)
3040 {
3041 	spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_RecursiveCachingIterator, spl_ce_RecursiveIterator, DIT_RecursiveCachingIterator);
3042 } /* }}} */
3043 
3044 /* {{{ proto bool RecursiveCachingIterator::hasChildren()
3045    Check whether the current element of the inner iterator has children */
SPL_METHOD(RecursiveCachingIterator,hasChildren)3046 SPL_METHOD(RecursiveCachingIterator, hasChildren)
3047 {
3048 	spl_dual_it_object   *intern;
3049 
3050 	if (zend_parse_parameters_none() == FAILURE) {
3051 		return;
3052 	}
3053 
3054 	SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
3055 
3056 	RETURN_BOOL(intern->u.caching.zchildren);
3057 } /* }}} */
3058 
3059 /* {{{ proto RecursiveCachingIterator RecursiveCachingIterator::getChildren()
3060   Return the inner iterator's children as a RecursiveCachingIterator */
SPL_METHOD(RecursiveCachingIterator,getChildren)3061 SPL_METHOD(RecursiveCachingIterator, getChildren)
3062 {
3063 	spl_dual_it_object   *intern;
3064 
3065 	if (zend_parse_parameters_none() == FAILURE) {
3066 		return;
3067 	}
3068 
3069 	SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
3070 
3071 	if (intern->u.caching.zchildren) {
3072 		RETURN_ZVAL(intern->u.caching.zchildren, 1, 0);
3073 	} else {
3074 		RETURN_NULL();
3075 	}
3076 } /* }}} */
3077 
3078 ZEND_BEGIN_ARG_INFO_EX(arginfo_caching_rec_it___construct, 0, ZEND_RETURN_VALUE, 1)
3079 	ZEND_ARG_OBJ_INFO(0, iterator, Iterator, 0)
3080 	ZEND_ARG_INFO(0, flags)
3081 ZEND_END_ARG_INFO();
3082 
3083 static const zend_function_entry spl_funcs_RecursiveCachingIterator[] = {
3084 	SPL_ME(RecursiveCachingIterator, __construct,   arginfo_caching_rec_it___construct, ZEND_ACC_PUBLIC)
3085 	SPL_ME(RecursiveCachingIterator, hasChildren,   arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
3086 	SPL_ME(RecursiveCachingIterator, getChildren,   arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
3087 	PHP_FE_END
3088 };
3089 
3090 /* {{{ proto void IteratorIterator::__construct(Traversable it)
3091    Create an iterator from anything that is traversable */
SPL_METHOD(IteratorIterator,__construct)3092 SPL_METHOD(IteratorIterator, __construct)
3093 {
3094 	spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_IteratorIterator, zend_ce_traversable, DIT_IteratorIterator);
3095 } /* }}} */
3096 
3097 ZEND_BEGIN_ARG_INFO(arginfo_iterator_it___construct, 0)
3098 	ZEND_ARG_OBJ_INFO(0, iterator, Traversable, 0)
3099 ZEND_END_ARG_INFO();
3100 
3101 static const zend_function_entry spl_funcs_IteratorIterator[] = {
3102 	SPL_ME(IteratorIterator, __construct,      arginfo_iterator_it___construct, ZEND_ACC_PUBLIC)
3103 	SPL_ME(dual_it,          rewind,           arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
3104 	SPL_ME(dual_it,          valid,            arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
3105 	SPL_ME(dual_it,          key,              arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
3106 	SPL_ME(dual_it,          current,          arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
3107 	SPL_ME(dual_it,          next,             arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
3108 	SPL_ME(dual_it,          getInnerIterator, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
3109 	PHP_FE_END
3110 };
3111 
3112 /* {{{ proto void NoRewindIterator::__construct(Iterator it)
3113    Create an iterator from another iterator */
SPL_METHOD(NoRewindIterator,__construct)3114 SPL_METHOD(NoRewindIterator, __construct)
3115 {
3116 	spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_NoRewindIterator, zend_ce_iterator, DIT_NoRewindIterator);
3117 } /* }}} */
3118 
3119 /* {{{ proto void NoRewindIterator::rewind()
3120    Prevent a call to inner iterators rewind() */
SPL_METHOD(NoRewindIterator,rewind)3121 SPL_METHOD(NoRewindIterator, rewind)
3122 {
3123 	if (zend_parse_parameters_none() == FAILURE) {
3124 		return;
3125 	}
3126 	/* nothing to do */
3127 } /* }}} */
3128 
3129 /* {{{ proto bool NoRewindIterator::valid()
3130    Return inner iterators valid() */
SPL_METHOD(NoRewindIterator,valid)3131 SPL_METHOD(NoRewindIterator, valid)
3132 {
3133 	spl_dual_it_object   *intern;
3134 
3135 	if (zend_parse_parameters_none() == FAILURE) {
3136 		return;
3137 	}
3138 
3139 	SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
3140 	RETURN_BOOL(intern->inner.iterator->funcs->valid(intern->inner.iterator TSRMLS_CC) == SUCCESS);
3141 } /* }}} */
3142 
3143 /* {{{ proto mixed NoRewindIterator::key()
3144    Return inner iterators key() */
SPL_METHOD(NoRewindIterator,key)3145 SPL_METHOD(NoRewindIterator, key)
3146 {
3147 	spl_dual_it_object   *intern;
3148 
3149 	if (zend_parse_parameters_none() == FAILURE) {
3150 		return;
3151 	}
3152 
3153 	SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
3154 
3155 	if (intern->inner.iterator->funcs->get_current_key) {
3156 		intern->inner.iterator->funcs->get_current_key(intern->inner.iterator, return_value TSRMLS_CC);
3157 	} else {
3158 		RETURN_NULL();
3159 	}
3160 } /* }}} */
3161 
3162 /* {{{ proto mixed NoRewindIterator::current()
3163    Return inner iterators current() */
SPL_METHOD(NoRewindIterator,current)3164 SPL_METHOD(NoRewindIterator, current)
3165 {
3166 	spl_dual_it_object   *intern;
3167 	zval **data;
3168 
3169 	if (zend_parse_parameters_none() == FAILURE) {
3170 		return;
3171 	}
3172 
3173 	SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
3174 	intern->inner.iterator->funcs->get_current_data(intern->inner.iterator, &data TSRMLS_CC);
3175 	if (data && *data) {
3176 		RETURN_ZVAL(*data, 1, 0);
3177 	}
3178 } /* }}} */
3179 
3180 /* {{{ proto void NoRewindIterator::next()
3181    Return inner iterators next() */
SPL_METHOD(NoRewindIterator,next)3182 SPL_METHOD(NoRewindIterator, next)
3183 {
3184 	spl_dual_it_object   *intern;
3185 
3186 	if (zend_parse_parameters_none() == FAILURE) {
3187 		return;
3188 	}
3189 
3190 	SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
3191 	intern->inner.iterator->funcs->move_forward(intern->inner.iterator TSRMLS_CC);
3192 } /* }}} */
3193 
3194 ZEND_BEGIN_ARG_INFO(arginfo_norewind_it___construct, 0)
3195 	ZEND_ARG_OBJ_INFO(0, iterator, Iterator, 0)
3196 ZEND_END_ARG_INFO();
3197 
3198 static const zend_function_entry spl_funcs_NoRewindIterator[] = {
3199 	SPL_ME(NoRewindIterator, __construct,      arginfo_norewind_it___construct, ZEND_ACC_PUBLIC)
3200 	SPL_ME(NoRewindIterator, rewind,           arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
3201 	SPL_ME(NoRewindIterator, valid,            arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
3202 	SPL_ME(NoRewindIterator, key,              arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
3203 	SPL_ME(NoRewindIterator, current,          arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
3204 	SPL_ME(NoRewindIterator, next,             arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
3205 	SPL_ME(dual_it,          getInnerIterator, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
3206 	PHP_FE_END
3207 };
3208 
3209 /* {{{ proto void InfiniteIterator::__construct(Iterator it)
3210    Create an iterator from another iterator */
SPL_METHOD(InfiniteIterator,__construct)3211 SPL_METHOD(InfiniteIterator, __construct)
3212 {
3213 	spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_InfiniteIterator, zend_ce_iterator, DIT_InfiniteIterator);
3214 } /* }}} */
3215 
3216 /* {{{ proto void InfiniteIterator::next()
3217    Prevent a call to inner iterators rewind() (internally the current data will be fetched if valid()) */
SPL_METHOD(InfiniteIterator,next)3218 SPL_METHOD(InfiniteIterator, next)
3219 {
3220 	spl_dual_it_object   *intern;
3221 
3222 	if (zend_parse_parameters_none() == FAILURE) {
3223 		return;
3224 	}
3225 
3226 	SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
3227 
3228 	spl_dual_it_next(intern, 1 TSRMLS_CC);
3229 	if (spl_dual_it_valid(intern TSRMLS_CC) == SUCCESS) {
3230 		spl_dual_it_fetch(intern, 0 TSRMLS_CC);
3231 	} else {
3232 		spl_dual_it_rewind(intern TSRMLS_CC);
3233 		if (spl_dual_it_valid(intern TSRMLS_CC) == SUCCESS) {
3234 			spl_dual_it_fetch(intern, 0 TSRMLS_CC);
3235 		}
3236 	}
3237 } /* }}} */
3238 
3239 static const zend_function_entry spl_funcs_InfiniteIterator[] = {
3240 	SPL_ME(InfiniteIterator, __construct,      arginfo_norewind_it___construct, ZEND_ACC_PUBLIC)
3241 	SPL_ME(InfiniteIterator, next,             arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
3242 	PHP_FE_END
3243 };
3244 
3245 /* {{{ proto void EmptyIterator::rewind()
3246    Does nothing  */
SPL_METHOD(EmptyIterator,rewind)3247 SPL_METHOD(EmptyIterator, rewind)
3248 {
3249 	if (zend_parse_parameters_none() == FAILURE) {
3250 		return;
3251 	}
3252 } /* }}} */
3253 
3254 /* {{{ proto false EmptyIterator::valid()
3255    Return false */
SPL_METHOD(EmptyIterator,valid)3256 SPL_METHOD(EmptyIterator, valid)
3257 {
3258 	if (zend_parse_parameters_none() == FAILURE) {
3259 		return;
3260 	}
3261 	RETURN_FALSE;
3262 } /* }}} */
3263 
3264 /* {{{ proto void EmptyIterator::key()
3265    Throws exception BadMethodCallException */
SPL_METHOD(EmptyIterator,key)3266 SPL_METHOD(EmptyIterator, key)
3267 {
3268 	if (zend_parse_parameters_none() == FAILURE) {
3269 		return;
3270 	}
3271 	zend_throw_exception(spl_ce_BadMethodCallException, "Accessing the key of an EmptyIterator", 0 TSRMLS_CC);
3272 } /* }}} */
3273 
3274 /* {{{ proto void EmptyIterator::current()
3275    Throws exception BadMethodCallException */
SPL_METHOD(EmptyIterator,current)3276 SPL_METHOD(EmptyIterator, current)
3277 {
3278 	if (zend_parse_parameters_none() == FAILURE) {
3279 		return;
3280 	}
3281 	zend_throw_exception(spl_ce_BadMethodCallException, "Accessing the value of an EmptyIterator", 0 TSRMLS_CC);
3282 } /* }}} */
3283 
3284 /* {{{ proto void EmptyIterator::next()
3285    Does nothing */
SPL_METHOD(EmptyIterator,next)3286 SPL_METHOD(EmptyIterator, next)
3287 {
3288 	if (zend_parse_parameters_none() == FAILURE) {
3289 		return;
3290 	}
3291 } /* }}} */
3292 
3293 static const zend_function_entry spl_funcs_EmptyIterator[] = {
3294 	SPL_ME(EmptyIterator, rewind,           arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
3295 	SPL_ME(EmptyIterator, valid,            arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
3296 	SPL_ME(EmptyIterator, key,              arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
3297 	SPL_ME(EmptyIterator, current,          arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
3298 	SPL_ME(EmptyIterator, next,             arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
3299 	PHP_FE_END
3300 };
3301 
spl_append_it_next_iterator(spl_dual_it_object * intern TSRMLS_DC)3302 int spl_append_it_next_iterator(spl_dual_it_object *intern TSRMLS_DC) /* {{{*/
3303 {
3304 	spl_dual_it_free(intern TSRMLS_CC);
3305 
3306 	if (intern->inner.zobject) {
3307 		zval_ptr_dtor(&intern->inner.zobject);
3308 		intern->inner.zobject = NULL;
3309 		intern->inner.ce = NULL;
3310 		intern->inner.object = NULL;
3311 		if (intern->inner.iterator) {
3312 			intern->inner.iterator->funcs->dtor(intern->inner.iterator TSRMLS_CC);
3313 			intern->inner.iterator = NULL;
3314 		}
3315 	}
3316 	if (intern->u.append.iterator->funcs->valid(intern->u.append.iterator TSRMLS_CC) == SUCCESS) {
3317 		zval **it;
3318 
3319 		intern->u.append.iterator->funcs->get_current_data(intern->u.append.iterator, &it TSRMLS_CC);
3320 		Z_ADDREF_PP(it);
3321 		intern->inner.zobject = *it;
3322 		intern->inner.ce = Z_OBJCE_PP(it);
3323 		intern->inner.object = zend_object_store_get_object(*it TSRMLS_CC);
3324 		intern->inner.iterator = intern->inner.ce->get_iterator(intern->inner.ce, *it, 0 TSRMLS_CC);
3325 		spl_dual_it_rewind(intern TSRMLS_CC);
3326 		return SUCCESS;
3327 	} else {
3328 		return FAILURE;
3329 	}
3330 } /* }}} */
3331 
spl_append_it_fetch(spl_dual_it_object * intern TSRMLS_DC)3332 void spl_append_it_fetch(spl_dual_it_object *intern TSRMLS_DC) /* {{{*/
3333 {
3334 	while (spl_dual_it_valid(intern TSRMLS_CC) != SUCCESS) {
3335 		intern->u.append.iterator->funcs->move_forward(intern->u.append.iterator TSRMLS_CC);
3336 		if (spl_append_it_next_iterator(intern TSRMLS_CC) != SUCCESS) {
3337 			return;
3338 		}
3339 	}
3340 	spl_dual_it_fetch(intern, 0 TSRMLS_CC);
3341 } /* }}} */
3342 
spl_append_it_next(spl_dual_it_object * intern TSRMLS_DC)3343 void spl_append_it_next(spl_dual_it_object *intern TSRMLS_DC) /* {{{ */
3344 {
3345 	if (spl_dual_it_valid(intern TSRMLS_CC) == SUCCESS) {
3346 		spl_dual_it_next(intern, 1 TSRMLS_CC);
3347 	}
3348 	spl_append_it_fetch(intern TSRMLS_CC);
3349 } /* }}} */
3350 
3351 /* {{{ proto void AppendIterator::__construct()
3352    Create an AppendIterator */
SPL_METHOD(AppendIterator,__construct)3353 SPL_METHOD(AppendIterator, __construct)
3354 {
3355 	spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_AppendIterator, zend_ce_iterator, DIT_AppendIterator);
3356 } /* }}} */
3357 
3358 /* {{{ proto void AppendIterator::append(Iterator it)
3359    Append an iterator */
SPL_METHOD(AppendIterator,append)3360 SPL_METHOD(AppendIterator, append)
3361 {
3362 	spl_dual_it_object   *intern;
3363 	zval *it;
3364 
3365 	SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
3366 
3367 	if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "O", &it, zend_ce_iterator) == FAILURE) {
3368 		return;
3369 	}
3370 	spl_array_iterator_append(intern->u.append.zarrayit, it TSRMLS_CC);
3371 
3372 	if (!intern->inner.iterator || spl_dual_it_valid(intern TSRMLS_CC) != SUCCESS) {
3373 		if (intern->u.append.iterator->funcs->valid(intern->u.append.iterator TSRMLS_CC) != SUCCESS) {
3374 			intern->u.append.iterator->funcs->rewind(intern->u.append.iterator TSRMLS_CC);
3375 		}
3376 		do {
3377 			spl_append_it_next_iterator(intern TSRMLS_CC);
3378 		} while (intern->inner.zobject != it);
3379 		spl_append_it_fetch(intern TSRMLS_CC);
3380 	}
3381 } /* }}} */
3382 
3383 /* {{{ proto void AppendIterator::rewind()
3384    Rewind to the first iterator and rewind the first iterator, too */
SPL_METHOD(AppendIterator,rewind)3385 SPL_METHOD(AppendIterator, rewind)
3386 {
3387 	spl_dual_it_object   *intern;
3388 
3389 	if (zend_parse_parameters_none() == FAILURE) {
3390 		return;
3391 	}
3392 
3393 	SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
3394 
3395 	intern->u.append.iterator->funcs->rewind(intern->u.append.iterator TSRMLS_CC);
3396 	if (spl_append_it_next_iterator(intern TSRMLS_CC) == SUCCESS) {
3397 		spl_append_it_fetch(intern TSRMLS_CC);
3398 	}
3399 } /* }}} */
3400 
3401 /* {{{ proto bool AppendIterator::valid()
3402    Check if the current state is valid */
SPL_METHOD(AppendIterator,valid)3403 SPL_METHOD(AppendIterator, valid)
3404 {
3405 	spl_dual_it_object   *intern;
3406 
3407 	if (zend_parse_parameters_none() == FAILURE) {
3408 		return;
3409 	}
3410 
3411 	SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
3412 
3413 	RETURN_BOOL(intern->current.data);
3414 } /* }}} */
3415 
3416 /* {{{ proto void AppendIterator::next()
3417    Forward to next element */
SPL_METHOD(AppendIterator,next)3418 SPL_METHOD(AppendIterator, next)
3419 {
3420 	spl_dual_it_object   *intern;
3421 
3422 	if (zend_parse_parameters_none() == FAILURE) {
3423 		return;
3424 	}
3425 
3426 	SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
3427 
3428 	spl_append_it_next(intern TSRMLS_CC);
3429 } /* }}} */
3430 
3431 /* {{{ proto int AppendIterator::getIteratorIndex()
3432    Get index of iterator */
SPL_METHOD(AppendIterator,getIteratorIndex)3433 SPL_METHOD(AppendIterator, getIteratorIndex)
3434 {
3435 	spl_dual_it_object   *intern;
3436 
3437 	if (zend_parse_parameters_none() == FAILURE) {
3438 		return;
3439 	}
3440 
3441 	SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
3442 
3443 	APPENDIT_CHECK_CTOR(intern);
3444 	spl_array_iterator_key(intern->u.append.zarrayit, return_value TSRMLS_CC);
3445 } /* }}} */
3446 
3447 /* {{{ proto ArrayIterator AppendIterator::getArrayIterator()
3448    Get access to inner ArrayIterator */
SPL_METHOD(AppendIterator,getArrayIterator)3449 SPL_METHOD(AppendIterator, getArrayIterator)
3450 {
3451 	spl_dual_it_object   *intern;
3452 
3453 	if (zend_parse_parameters_none() == FAILURE) {
3454 		return;
3455 	}
3456 
3457 	SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
3458 
3459 	RETURN_ZVAL(intern->u.append.zarrayit, 1, 0);
3460 } /* }}} */
3461 
3462 ZEND_BEGIN_ARG_INFO(arginfo_append_it_append, 0)
3463 	ZEND_ARG_OBJ_INFO(0, iterator, Iterator, 0)
3464 ZEND_END_ARG_INFO();
3465 
3466 static const zend_function_entry spl_funcs_AppendIterator[] = {
3467 	SPL_ME(AppendIterator, __construct,      arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
3468 	SPL_ME(AppendIterator, append,           arginfo_append_it_append, ZEND_ACC_PUBLIC)
3469 	SPL_ME(AppendIterator, rewind,           arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
3470 	SPL_ME(AppendIterator, valid,            arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
3471 	SPL_ME(dual_it,        key,              arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
3472 	SPL_ME(dual_it,        current,          arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
3473 	SPL_ME(AppendIterator, next,             arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
3474 	SPL_ME(dual_it,        getInnerIterator, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
3475 	SPL_ME(AppendIterator, getIteratorIndex, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
3476 	SPL_ME(AppendIterator, getArrayIterator, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
3477 	PHP_FE_END
3478 };
3479 
spl_iterator_apply(zval * obj,spl_iterator_apply_func_t apply_func,void * puser TSRMLS_DC)3480 PHPAPI int spl_iterator_apply(zval *obj, spl_iterator_apply_func_t apply_func, void *puser TSRMLS_DC)
3481 {
3482 	zend_object_iterator   *iter;
3483 	zend_class_entry       *ce = Z_OBJCE_P(obj);
3484 
3485 	iter = ce->get_iterator(ce, obj, 0 TSRMLS_CC);
3486 
3487 	if (EG(exception)) {
3488 		goto done;
3489 	}
3490 
3491 	iter->index = 0;
3492 	if (iter->funcs->rewind) {
3493 		iter->funcs->rewind(iter TSRMLS_CC);
3494 		if (EG(exception)) {
3495 			goto done;
3496 		}
3497 	}
3498 
3499 	while (iter->funcs->valid(iter TSRMLS_CC) == SUCCESS) {
3500 		if (EG(exception)) {
3501 			goto done;
3502 		}
3503 		if (apply_func(iter, puser TSRMLS_CC) == ZEND_HASH_APPLY_STOP || EG(exception)) {
3504 			goto done;
3505 		}
3506 		iter->index++;
3507 		iter->funcs->move_forward(iter TSRMLS_CC);
3508 		if (EG(exception)) {
3509 			goto done;
3510 		}
3511 	}
3512 
3513 done:
3514 	if (iter) {
3515 		iter->funcs->dtor(iter TSRMLS_CC);
3516 	}
3517 	return EG(exception) ? FAILURE : SUCCESS;
3518 }
3519 /* }}} */
3520 
spl_iterator_to_array_apply(zend_object_iterator * iter,void * puser TSRMLS_DC)3521 static int spl_iterator_to_array_apply(zend_object_iterator *iter, void *puser TSRMLS_DC) /* {{{ */
3522 {
3523 	zval **data, *return_value = (zval*)puser;
3524 
3525 	iter->funcs->get_current_data(iter, &data TSRMLS_CC);
3526 	if (EG(exception)) {
3527 		return ZEND_HASH_APPLY_STOP;
3528 	}
3529 	if (data == NULL || *data == NULL) {
3530 		return ZEND_HASH_APPLY_STOP;
3531 	}
3532 	if (iter->funcs->get_current_key) {
3533 		zval key;
3534 		iter->funcs->get_current_key(iter, &key TSRMLS_CC);
3535 		if (EG(exception)) {
3536 			return ZEND_HASH_APPLY_STOP;
3537 		}
3538 		array_set_zval_key(Z_ARRVAL_P(return_value), &key, *data);
3539 		zval_dtor(&key);
3540 	} else {
3541 		Z_ADDREF_PP(data);
3542 		add_next_index_zval(return_value, *data);
3543 	}
3544 	return ZEND_HASH_APPLY_KEEP;
3545 }
3546 /* }}} */
3547 
spl_iterator_to_values_apply(zend_object_iterator * iter,void * puser TSRMLS_DC)3548 static int spl_iterator_to_values_apply(zend_object_iterator *iter, void *puser TSRMLS_DC) /* {{{ */
3549 {
3550 	zval **data, *return_value = (zval*)puser;
3551 
3552 	iter->funcs->get_current_data(iter, &data TSRMLS_CC);
3553 	if (EG(exception)) {
3554 		return ZEND_HASH_APPLY_STOP;
3555 	}
3556 	if (data == NULL || *data == NULL) {
3557 		return ZEND_HASH_APPLY_STOP;
3558 	}
3559 	Z_ADDREF_PP(data);
3560 	add_next_index_zval(return_value, *data);
3561 	return ZEND_HASH_APPLY_KEEP;
3562 }
3563 /* }}} */
3564 
3565 /* {{{ proto array iterator_to_array(Traversable it [, bool use_keys = true])
3566    Copy the iterator into an array */
PHP_FUNCTION(iterator_to_array)3567 PHP_FUNCTION(iterator_to_array)
3568 {
3569 	zval  *obj;
3570 	zend_bool use_keys = 1;
3571 
3572 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O|b", &obj, zend_ce_traversable, &use_keys) == FAILURE) {
3573 		RETURN_FALSE;
3574 	}
3575 
3576 	array_init(return_value);
3577 
3578 	if (spl_iterator_apply(obj, use_keys ? spl_iterator_to_array_apply : spl_iterator_to_values_apply, (void*)return_value TSRMLS_CC) != SUCCESS) {
3579 		zval_dtor(return_value);
3580 		RETURN_NULL();
3581 	}
3582 } /* }}} */
3583 
spl_iterator_count_apply(zend_object_iterator * iter,void * puser TSRMLS_DC)3584 static int spl_iterator_count_apply(zend_object_iterator *iter, void *puser TSRMLS_DC) /* {{{ */
3585 {
3586 	(*(long*)puser)++;
3587 	return ZEND_HASH_APPLY_KEEP;
3588 }
3589 /* }}} */
3590 
3591 /* {{{ proto int iterator_count(Traversable it)
3592    Count the elements in an iterator */
PHP_FUNCTION(iterator_count)3593 PHP_FUNCTION(iterator_count)
3594 {
3595 	zval  *obj;
3596 	long  count = 0;
3597 
3598 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &obj, zend_ce_traversable) == FAILURE) {
3599 		RETURN_FALSE;
3600 	}
3601 
3602 	if (spl_iterator_apply(obj, spl_iterator_count_apply, (void*)&count TSRMLS_CC) == SUCCESS) {
3603 		RETURN_LONG(count);
3604 	}
3605 }
3606 /* }}} */
3607 
3608 typedef struct {
3609 	zval                   *obj;
3610 	zval                   *args;
3611 	long                   count;
3612 	zend_fcall_info        fci;
3613 	zend_fcall_info_cache  fcc;
3614 } spl_iterator_apply_info;
3615 
spl_iterator_func_apply(zend_object_iterator * iter,void * puser TSRMLS_DC)3616 static int spl_iterator_func_apply(zend_object_iterator *iter, void *puser TSRMLS_DC) /* {{{ */
3617 {
3618 	zval *retval;
3619 	spl_iterator_apply_info  *apply_info = (spl_iterator_apply_info*)puser;
3620 	int result;
3621 
3622 	apply_info->count++;
3623 	zend_fcall_info_call(&apply_info->fci, &apply_info->fcc, &retval, NULL TSRMLS_CC);
3624 	if (retval) {
3625 		result = zend_is_true(retval) ? ZEND_HASH_APPLY_KEEP : ZEND_HASH_APPLY_STOP;
3626 		zval_ptr_dtor(&retval);
3627 	} else {
3628 		result = ZEND_HASH_APPLY_STOP;
3629 	}
3630 	return result;
3631 }
3632 /* }}} */
3633 
3634 /* {{{ proto int iterator_apply(Traversable it, mixed function [, mixed params])
3635    Calls a function for every element in an iterator */
PHP_FUNCTION(iterator_apply)3636 PHP_FUNCTION(iterator_apply)
3637 {
3638 	spl_iterator_apply_info  apply_info;
3639 
3640 	apply_info.args = NULL;
3641 	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) {
3642 		return;
3643 	}
3644 
3645 	apply_info.count = 0;
3646 	zend_fcall_info_args(&apply_info.fci, apply_info.args TSRMLS_CC);
3647 	if (spl_iterator_apply(apply_info.obj, spl_iterator_func_apply, (void*)&apply_info TSRMLS_CC) == SUCCESS) {
3648 		RETVAL_LONG(apply_info.count);
3649 	} else {
3650 		RETVAL_FALSE;
3651 	}
3652 	zend_fcall_info_args(&apply_info.fci, NULL TSRMLS_CC);
3653 }
3654 /* }}} */
3655 
3656 static const zend_function_entry spl_funcs_OuterIterator[] = {
3657 	SPL_ABSTRACT_ME(OuterIterator, getInnerIterator,   arginfo_recursive_it_void)
3658 	PHP_FE_END
3659 };
3660 
3661 static const zend_function_entry spl_funcs_Countable[] = {
3662 	SPL_ABSTRACT_ME(Countable, count,   arginfo_recursive_it_void)
3663 	PHP_FE_END
3664 };
3665 
3666 /* {{{ PHP_MINIT_FUNCTION(spl_iterators)
3667  */
PHP_MINIT_FUNCTION(spl_iterators)3668 PHP_MINIT_FUNCTION(spl_iterators)
3669 {
3670 	REGISTER_SPL_INTERFACE(RecursiveIterator);
3671 	REGISTER_SPL_ITERATOR(RecursiveIterator);
3672 
3673 	REGISTER_SPL_STD_CLASS_EX(RecursiveIteratorIterator, spl_RecursiveIteratorIterator_new, spl_funcs_RecursiveIteratorIterator);
3674 	REGISTER_SPL_ITERATOR(RecursiveIteratorIterator);
3675 
3676 	memcpy(&spl_handlers_rec_it_it, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
3677 	spl_handlers_rec_it_it.get_method = spl_recursive_it_get_method;
3678 	spl_handlers_rec_it_it.clone_obj = NULL;
3679 
3680 	memcpy(&spl_handlers_dual_it, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
3681 	spl_handlers_dual_it.get_method = spl_dual_it_get_method;
3682 	/*spl_handlers_dual_it.call_method = spl_dual_it_call_method;*/
3683 	spl_handlers_dual_it.clone_obj = NULL;
3684 
3685 	spl_ce_RecursiveIteratorIterator->get_iterator = spl_recursive_it_get_iterator;
3686 	spl_ce_RecursiveIteratorIterator->iterator_funcs.funcs = &spl_recursive_it_iterator_funcs;
3687 
3688 	REGISTER_SPL_CLASS_CONST_LONG(RecursiveIteratorIterator, "LEAVES_ONLY",     RIT_LEAVES_ONLY);
3689 	REGISTER_SPL_CLASS_CONST_LONG(RecursiveIteratorIterator, "SELF_FIRST",      RIT_SELF_FIRST);
3690 	REGISTER_SPL_CLASS_CONST_LONG(RecursiveIteratorIterator, "CHILD_FIRST",     RIT_CHILD_FIRST);
3691 	REGISTER_SPL_CLASS_CONST_LONG(RecursiveIteratorIterator, "CATCH_GET_CHILD", RIT_CATCH_GET_CHILD);
3692 
3693 	REGISTER_SPL_INTERFACE(OuterIterator);
3694 	REGISTER_SPL_ITERATOR(OuterIterator);
3695 
3696 	REGISTER_SPL_STD_CLASS_EX(IteratorIterator, spl_dual_it_new, spl_funcs_IteratorIterator);
3697 	REGISTER_SPL_ITERATOR(IteratorIterator);
3698 	REGISTER_SPL_IMPLEMENTS(IteratorIterator, OuterIterator);
3699 
3700 	REGISTER_SPL_SUB_CLASS_EX(FilterIterator, IteratorIterator, spl_dual_it_new, spl_funcs_FilterIterator);
3701 	spl_ce_FilterIterator->ce_flags |= ZEND_ACC_EXPLICIT_ABSTRACT_CLASS;
3702 
3703 	REGISTER_SPL_SUB_CLASS_EX(RecursiveFilterIterator, FilterIterator, spl_dual_it_new, spl_funcs_RecursiveFilterIterator);
3704 	REGISTER_SPL_IMPLEMENTS(RecursiveFilterIterator, RecursiveIterator);
3705 
3706 	REGISTER_SPL_SUB_CLASS_EX(CallbackFilterIterator, FilterIterator, spl_dual_it_new, spl_funcs_CallbackFilterIterator);
3707 
3708 	REGISTER_SPL_SUB_CLASS_EX(RecursiveCallbackFilterIterator, CallbackFilterIterator, spl_dual_it_new, spl_funcs_RecursiveCallbackFilterIterator);
3709 	REGISTER_SPL_IMPLEMENTS(RecursiveCallbackFilterIterator, RecursiveIterator);
3710 
3711 
3712 	REGISTER_SPL_SUB_CLASS_EX(ParentIterator, RecursiveFilterIterator, spl_dual_it_new, spl_funcs_ParentIterator);
3713 
3714 	REGISTER_SPL_INTERFACE(Countable);
3715 	REGISTER_SPL_INTERFACE(SeekableIterator);
3716 	REGISTER_SPL_ITERATOR(SeekableIterator);
3717 
3718 	REGISTER_SPL_SUB_CLASS_EX(LimitIterator, IteratorIterator, spl_dual_it_new, spl_funcs_LimitIterator);
3719 
3720 	REGISTER_SPL_SUB_CLASS_EX(CachingIterator, IteratorIterator, spl_dual_it_new, spl_funcs_CachingIterator);
3721 	REGISTER_SPL_IMPLEMENTS(CachingIterator, ArrayAccess);
3722 	REGISTER_SPL_IMPLEMENTS(CachingIterator, Countable);
3723 
3724 	REGISTER_SPL_CLASS_CONST_LONG(CachingIterator, "CALL_TOSTRING",        CIT_CALL_TOSTRING);
3725 	REGISTER_SPL_CLASS_CONST_LONG(CachingIterator, "CATCH_GET_CHILD",      CIT_CATCH_GET_CHILD);
3726 	REGISTER_SPL_CLASS_CONST_LONG(CachingIterator, "TOSTRING_USE_KEY",     CIT_TOSTRING_USE_KEY);
3727 	REGISTER_SPL_CLASS_CONST_LONG(CachingIterator, "TOSTRING_USE_CURRENT", CIT_TOSTRING_USE_CURRENT);
3728 	REGISTER_SPL_CLASS_CONST_LONG(CachingIterator, "TOSTRING_USE_INNER",   CIT_TOSTRING_USE_INNER);
3729 	REGISTER_SPL_CLASS_CONST_LONG(CachingIterator, "FULL_CACHE",           CIT_FULL_CACHE);
3730 
3731 	REGISTER_SPL_SUB_CLASS_EX(RecursiveCachingIterator, CachingIterator, spl_dual_it_new, spl_funcs_RecursiveCachingIterator);
3732 	REGISTER_SPL_IMPLEMENTS(RecursiveCachingIterator, RecursiveIterator);
3733 
3734 	REGISTER_SPL_SUB_CLASS_EX(NoRewindIterator, IteratorIterator, spl_dual_it_new, spl_funcs_NoRewindIterator);
3735 
3736 	REGISTER_SPL_SUB_CLASS_EX(AppendIterator, IteratorIterator, spl_dual_it_new, spl_funcs_AppendIterator);
3737 
3738 	REGISTER_SPL_IMPLEMENTS(RecursiveIteratorIterator, OuterIterator);
3739 
3740 	REGISTER_SPL_SUB_CLASS_EX(InfiniteIterator, IteratorIterator, spl_dual_it_new, spl_funcs_InfiniteIterator);
3741 #if HAVE_PCRE || HAVE_BUNDLED_PCRE
3742 	REGISTER_SPL_SUB_CLASS_EX(RegexIterator, FilterIterator, spl_dual_it_new, spl_funcs_RegexIterator);
3743 	REGISTER_SPL_CLASS_CONST_LONG(RegexIterator, "USE_KEY",     REGIT_USE_KEY);
3744 	REGISTER_SPL_CLASS_CONST_LONG(RegexIterator, "INVERT_MATCH",REGIT_INVERTED);
3745 	REGISTER_SPL_CLASS_CONST_LONG(RegexIterator, "MATCH",       REGIT_MODE_MATCH);
3746 	REGISTER_SPL_CLASS_CONST_LONG(RegexIterator, "GET_MATCH",   REGIT_MODE_GET_MATCH);
3747 	REGISTER_SPL_CLASS_CONST_LONG(RegexIterator, "ALL_MATCHES", REGIT_MODE_ALL_MATCHES);
3748 	REGISTER_SPL_CLASS_CONST_LONG(RegexIterator, "SPLIT",       REGIT_MODE_SPLIT);
3749 	REGISTER_SPL_CLASS_CONST_LONG(RegexIterator, "REPLACE",     REGIT_MODE_REPLACE);
3750 	REGISTER_SPL_PROPERTY(RegexIterator, "replacement", 0);
3751 	REGISTER_SPL_SUB_CLASS_EX(RecursiveRegexIterator, RegexIterator, spl_dual_it_new, spl_funcs_RecursiveRegexIterator);
3752 	REGISTER_SPL_IMPLEMENTS(RecursiveRegexIterator, RecursiveIterator);
3753 #else
3754 	spl_ce_RegexIterator = NULL;
3755 	spl_ce_RecursiveRegexIterator = NULL;
3756 #endif
3757 
3758 	REGISTER_SPL_STD_CLASS_EX(EmptyIterator, NULL, spl_funcs_EmptyIterator);
3759 	REGISTER_SPL_ITERATOR(EmptyIterator);
3760 
3761 	REGISTER_SPL_SUB_CLASS_EX(RecursiveTreeIterator, RecursiveIteratorIterator, spl_RecursiveTreeIterator_new, spl_funcs_RecursiveTreeIterator);
3762 	REGISTER_SPL_CLASS_CONST_LONG(RecursiveTreeIterator, "BYPASS_CURRENT",      RTIT_BYPASS_CURRENT);
3763 	REGISTER_SPL_CLASS_CONST_LONG(RecursiveTreeIterator, "BYPASS_KEY",          RTIT_BYPASS_KEY);
3764 	REGISTER_SPL_CLASS_CONST_LONG(RecursiveTreeIterator, "PREFIX_LEFT",         0);
3765 	REGISTER_SPL_CLASS_CONST_LONG(RecursiveTreeIterator, "PREFIX_MID_HAS_NEXT", 1);
3766 	REGISTER_SPL_CLASS_CONST_LONG(RecursiveTreeIterator, "PREFIX_MID_LAST",     2);
3767 	REGISTER_SPL_CLASS_CONST_LONG(RecursiveTreeIterator, "PREFIX_END_HAS_NEXT", 3);
3768 	REGISTER_SPL_CLASS_CONST_LONG(RecursiveTreeIterator, "PREFIX_END_LAST",     4);
3769 	REGISTER_SPL_CLASS_CONST_LONG(RecursiveTreeIterator, "PREFIX_RIGHT",        5);
3770 
3771 	return SUCCESS;
3772 }
3773 /* }}} */
3774 
3775 /*
3776  * Local variables:
3777  * tab-width: 4
3778  * c-basic-offset: 4
3779  * End:
3780  * vim600: fdm=marker
3781  * vim: noet sw=4 ts=4
3782  */
3783