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