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