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, ®ex, ®ex_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] = ®ex;
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(®ex);
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