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 if (Z_TYPE_P(return_value) == IS_ARRAY) { 1017 zval_dtor(return_value); 1018 ZVAL_STRINGL(return_value, "Array", sizeof("Array")-1, 1); 1019 } else { 1020 convert_to_string(return_value); 1021 } 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 INIT_ZVAL(prefix); 1123 INIT_ZVAL(entry); 1124 spl_recursive_tree_iterator_get_prefix(object, &prefix TSRMLS_CC); 1125 spl_recursive_tree_iterator_get_entry(object, &entry TSRMLS_CC); 1126 if (Z_TYPE(entry) != IS_STRING) { 1127 zval_dtor(&prefix); 1128 zval_dtor(&entry); 1129 RETURN_NULL(); 1130 } 1131 spl_recursive_tree_iterator_get_postfix(object, &postfix TSRMLS_CC); 1132 1133 str_len = Z_STRLEN(prefix) + Z_STRLEN(entry) + Z_STRLEN(postfix); 1134 str = (char *) emalloc(str_len + 1U); 1135 ptr = str; 1136 1137 memcpy(ptr, Z_STRVAL(prefix), Z_STRLEN(prefix)); 1138 ptr += Z_STRLEN(prefix); 1139 memcpy(ptr, Z_STRVAL(entry), Z_STRLEN(entry)); 1140 ptr += Z_STRLEN(entry); 1141 memcpy(ptr, Z_STRVAL(postfix), Z_STRLEN(postfix)); 1142 ptr += Z_STRLEN(postfix); 1143 *ptr = 0; 1144 1145 zval_dtor(&prefix); 1146 zval_dtor(&entry); 1147 zval_dtor(&postfix); 1148 1149 RETURN_STRINGL(str, str_len, 0); 1150} /* }}} */ 1151 1152/* {{{ proto mixed RecursiveTreeIterator::key() 1153 Returns the current key prefixed and postfixed */ 1154SPL_METHOD(RecursiveTreeIterator, key) 1155{ 1156 spl_recursive_it_object *object = (spl_recursive_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC); 1157 zend_object_iterator *iterator = object->iterators[object->level].iterator; 1158 zval prefix, key, postfix, key_copy; 1159 char *str, *ptr; 1160 size_t str_len; 1161 1162 if (zend_parse_parameters_none() == FAILURE) { 1163 return; 1164 } 1165 1166 if (iterator->funcs->get_current_key) { 1167 iterator->funcs->get_current_key(iterator, &key TSRMLS_CC); 1168 } else { 1169 ZVAL_NULL(&key); 1170 } 1171 1172 if (object->flags & RTIT_BYPASS_KEY) { 1173 zval *key_ptr = &key; 1174 RETVAL_ZVAL(key_ptr, 1, 0); 1175 zval_dtor(&key); 1176 return; 1177 } 1178 1179 if (Z_TYPE(key) != IS_STRING) { 1180 int use_copy; 1181 zend_make_printable_zval(&key, &key_copy, &use_copy); 1182 if (use_copy) { 1183 key = key_copy; 1184 } 1185 } 1186 1187 spl_recursive_tree_iterator_get_prefix(object, &prefix TSRMLS_CC); 1188 spl_recursive_tree_iterator_get_postfix(object, &postfix TSRMLS_CC); 1189 1190 str_len = Z_STRLEN(prefix) + Z_STRLEN(key) + Z_STRLEN(postfix); 1191 str = (char *) emalloc(str_len + 1U); 1192 ptr = str; 1193 1194 memcpy(ptr, Z_STRVAL(prefix), Z_STRLEN(prefix)); 1195 ptr += Z_STRLEN(prefix); 1196 memcpy(ptr, Z_STRVAL(key), Z_STRLEN(key)); 1197 ptr += Z_STRLEN(key); 1198 memcpy(ptr, Z_STRVAL(postfix), Z_STRLEN(postfix)); 1199 ptr += Z_STRLEN(postfix); 1200 *ptr = 0; 1201 1202 zval_dtor(&prefix); 1203 zval_dtor(&key); 1204 zval_dtor(&postfix); 1205 1206 RETVAL_STRINGL(str, str_len, 0); 1207} /* }}} */ 1208 1209ZEND_BEGIN_ARG_INFO_EX(arginfo_recursive_tree_it___construct, 0, 0, 1) 1210 ZEND_ARG_OBJ_INFO(0, iterator, Traversable, 0) 1211 ZEND_ARG_INFO(0, flags) 1212 ZEND_ARG_INFO(0, caching_it_flags) 1213 ZEND_ARG_INFO(0, mode) 1214ZEND_END_ARG_INFO(); 1215 1216ZEND_BEGIN_ARG_INFO_EX(arginfo_recursive_tree_it_setPrefixPart, 0, 0, 2) 1217 ZEND_ARG_INFO(0, part) 1218 ZEND_ARG_INFO(0, value) 1219ZEND_END_ARG_INFO(); 1220 1221static const zend_function_entry spl_funcs_RecursiveTreeIterator[] = { 1222 SPL_ME(RecursiveTreeIterator, __construct, arginfo_recursive_tree_it___construct, ZEND_ACC_PUBLIC) 1223 SPL_ME(RecursiveIteratorIterator, rewind, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) 1224 SPL_ME(RecursiveIteratorIterator, valid, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) 1225 SPL_ME(RecursiveTreeIterator, key, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) 1226 SPL_ME(RecursiveTreeIterator, current, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) 1227 SPL_ME(RecursiveIteratorIterator, next, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) 1228 SPL_ME(RecursiveIteratorIterator, beginIteration, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) 1229 SPL_ME(RecursiveIteratorIterator, endIteration, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) 1230 SPL_ME(RecursiveIteratorIterator, callHasChildren, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) 1231 SPL_ME(RecursiveIteratorIterator, callGetChildren, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) 1232 SPL_ME(RecursiveIteratorIterator, beginChildren, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) 1233 SPL_ME(RecursiveIteratorIterator, endChildren, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) 1234 SPL_ME(RecursiveIteratorIterator, nextElement, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) 1235 SPL_ME(RecursiveTreeIterator, getPrefix, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) 1236 SPL_ME(RecursiveTreeIterator, setPrefixPart, arginfo_recursive_tree_it_setPrefixPart, ZEND_ACC_PUBLIC) 1237 SPL_ME(RecursiveTreeIterator, getEntry, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) 1238 SPL_ME(RecursiveTreeIterator, getPostfix, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) 1239 PHP_FE_END 1240}; 1241 1242#if MBO_0 1243static int spl_dual_it_gets_implemented(zend_class_entry *interface, zend_class_entry *class_type TSRMLS_DC) 1244{ 1245 class_type->iterator_funcs.zf_valid = NULL; 1246 class_type->iterator_funcs.zf_current = NULL; 1247 class_type->iterator_funcs.zf_key = NULL; 1248 class_type->iterator_funcs.zf_next = NULL; 1249 class_type->iterator_funcs.zf_rewind = NULL; 1250 if (!class_type->iterator_funcs.funcs) { 1251 class_type->iterator_funcs.funcs = &zend_interface_iterator_funcs_iterator; 1252 } 1253 1254 return SUCCESS; 1255} 1256#endif 1257 1258static union _zend_function *spl_dual_it_get_method(zval **object_ptr, char *method, int method_len, const zend_literal *key TSRMLS_DC) 1259{ 1260 union _zend_function *function_handler; 1261 spl_dual_it_object *intern; 1262 1263 intern = (spl_dual_it_object*)zend_object_store_get_object(*object_ptr TSRMLS_CC); 1264 1265 function_handler = std_object_handlers.get_method(object_ptr, method, method_len, key TSRMLS_CC); 1266 if (!function_handler && intern->inner.ce) { 1267 if (zend_hash_find(&intern->inner.ce->function_table, method, method_len+1, (void **) &function_handler) == FAILURE) { 1268 if (Z_OBJ_HT_P(intern->inner.zobject)->get_method) { 1269 *object_ptr = intern->inner.zobject; 1270 function_handler = Z_OBJ_HT_P(*object_ptr)->get_method(object_ptr, method, method_len, key TSRMLS_CC); 1271 } 1272 } else { 1273 *object_ptr = intern->inner.zobject; 1274 } 1275 } 1276 return function_handler; 1277} 1278 1279#if MBO_0 1280int spl_dual_it_call_method(char *method, INTERNAL_FUNCTION_PARAMETERS) 1281{ 1282 zval ***func_params, func; 1283 zval *retval_ptr; 1284 int arg_count; 1285 int current = 0; 1286 int success; 1287 void **p; 1288 spl_dual_it_object *intern; 1289 1290 intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC); 1291 1292 ZVAL_STRING(&func, method, 0); 1293 if (!zend_is_callable(&func, 0, &method TSRMLS_CC)) { 1294 php_error_docref(NULL TSRMLS_CC, E_ERROR, "Method %s::%s() does not exist", intern->inner.ce->name, method); 1295 return FAILURE; 1296 } 1297 1298 p = EG(argument_stack).top_element-2; 1299 arg_count = (ulong) *p; 1300 1301 func_params = safe_emalloc(sizeof(zval **), arg_count, 0); 1302 1303 current = 0; 1304 while (arg_count-- > 0) { 1305 func_params[current] = (zval **) p - (arg_count-current); 1306 current++; 1307 } 1308 arg_count = current; /* restore */ 1309 1310 if (call_user_function_ex(EG(function_table), NULL, &func, &retval_ptr, arg_count, func_params, 0, NULL TSRMLS_CC) == SUCCESS && retval_ptr) { 1311 RETURN_ZVAL(retval_ptr, 0, 1); 1312 1313 success = SUCCESS; 1314 } else { 1315 php_error_docref(NULL TSRMLS_CC, E_ERROR, "Unable to call %s::%s()", intern->inner.ce->name, method); 1316 success = FAILURE; 1317 } 1318 1319 efree(func_params); 1320 return success; 1321} 1322#endif 1323 1324#define SPL_CHECK_CTOR(intern, classname) \ 1325 if (intern->dit_type == DIT_Unknown) { \ 1326 zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "Classes derived from %s must call %s::__construct()", \ 1327 (spl_ce_##classname)->name, (spl_ce_##classname)->name); \ 1328 return; \ 1329 } 1330 1331#define APPENDIT_CHECK_CTOR(intern) SPL_CHECK_CTOR(intern, AppendIterator) 1332 1333static inline int spl_dual_it_fetch(spl_dual_it_object *intern, int check_more TSRMLS_DC); 1334 1335static inline int spl_cit_check_flags(int flags) 1336{ 1337 int cnt = 0; 1338 1339 cnt += (flags & CIT_CALL_TOSTRING) ? 1 : 0; 1340 cnt += (flags & CIT_TOSTRING_USE_KEY) ? 1 : 0; 1341 cnt += (flags & CIT_TOSTRING_USE_CURRENT) ? 1 : 0; 1342 cnt += (flags & CIT_TOSTRING_USE_INNER) ? 1 : 0; 1343 1344 return cnt <= 1 ? SUCCESS : FAILURE; 1345} 1346 1347static 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) 1348{ 1349 zval *zobject, *retval; 1350 spl_dual_it_object *intern; 1351 zend_class_entry *ce = NULL; 1352 int inc_refcount = 1; 1353 zend_error_handling error_handling; 1354 1355 intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC); 1356 1357 if (intern->dit_type != DIT_Unknown) { 1358 zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "%s::getIterator() must be called exactly once per instance", ce_base->name); 1359 return NULL; 1360 } 1361 1362 zend_replace_error_handling(EH_THROW, spl_ce_InvalidArgumentException, &error_handling TSRMLS_CC); 1363 1364 intern->dit_type = dit_type; 1365 switch (dit_type) { 1366 case DIT_LimitIterator: { 1367 intern->u.limit.offset = 0; /* start at beginning */ 1368 intern->u.limit.count = -1; /* get all */ 1369 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O|ll", &zobject, ce_inner, &intern->u.limit.offset, &intern->u.limit.count) == FAILURE) { 1370 zend_restore_error_handling(&error_handling TSRMLS_CC); 1371 return NULL; 1372 } 1373 if (intern->u.limit.offset < 0) { 1374 zend_throw_exception(spl_ce_OutOfRangeException, "Parameter offset must be >= 0", 0 TSRMLS_CC); 1375 zend_restore_error_handling(&error_handling TSRMLS_CC); 1376 return NULL; 1377 } 1378 if (intern->u.limit.count < 0 && intern->u.limit.count != -1) { 1379 zend_throw_exception(spl_ce_OutOfRangeException, "Parameter count must either be -1 or a value greater than or equal 0", 0 TSRMLS_CC); 1380 zend_restore_error_handling(&error_handling TSRMLS_CC); 1381 return NULL; 1382 } 1383 break; 1384 } 1385 case DIT_CachingIterator: 1386 case DIT_RecursiveCachingIterator: { 1387 long flags = CIT_CALL_TOSTRING; 1388 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O|l", &zobject, ce_inner, &flags) == FAILURE) { 1389 zend_restore_error_handling(&error_handling TSRMLS_CC); 1390 return NULL; 1391 } 1392 if (spl_cit_check_flags(flags) != SUCCESS) { 1393 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); 1394 zend_restore_error_handling(&error_handling TSRMLS_CC); 1395 return NULL; 1396 } 1397 intern->u.caching.flags |= flags & CIT_PUBLIC; 1398 MAKE_STD_ZVAL(intern->u.caching.zcache); 1399 array_init(intern->u.caching.zcache); 1400 break; 1401 } 1402 case DIT_IteratorIterator: { 1403 zend_class_entry **pce_cast; 1404 char * class_name = NULL; 1405 int class_name_len = 0; 1406 1407 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O|s", &zobject, ce_inner, &class_name, &class_name_len) == FAILURE) { 1408 zend_restore_error_handling(&error_handling TSRMLS_CC); 1409 return NULL; 1410 } 1411 ce = Z_OBJCE_P(zobject); 1412 if (!instanceof_function(ce, zend_ce_iterator TSRMLS_CC)) { 1413 if (ZEND_NUM_ARGS() > 1) { 1414 if (zend_lookup_class(class_name, class_name_len, &pce_cast TSRMLS_CC) == FAILURE 1415 || !instanceof_function(ce, *pce_cast TSRMLS_CC) 1416 || !(*pce_cast)->get_iterator 1417 ) { 1418 zend_throw_exception(spl_ce_LogicException, "Class to downcast to not found or not base class or does not implement Traversable", 0 TSRMLS_CC); 1419 zend_restore_error_handling(&error_handling TSRMLS_CC); 1420 return NULL; 1421 } 1422 ce = *pce_cast; 1423 } 1424 if (instanceof_function(ce, zend_ce_aggregate TSRMLS_CC)) { 1425 zend_call_method_with_0_params(&zobject, ce, &ce->iterator_funcs.zf_new_iterator, "getiterator", &retval); 1426 if (EG(exception)) { 1427 if (retval) { 1428 zval_ptr_dtor(&retval); 1429 } 1430 zend_restore_error_handling(&error_handling TSRMLS_CC); 1431 return NULL; 1432 } 1433 if (!retval || Z_TYPE_P(retval) != IS_OBJECT || !instanceof_function(Z_OBJCE_P(retval), zend_ce_traversable TSRMLS_CC)) { 1434 zend_throw_exception_ex(spl_ce_LogicException, 0 TSRMLS_CC, "%s::getIterator() must return an object that implements Traversable", ce->name); 1435 zend_restore_error_handling(&error_handling TSRMLS_CC); 1436 return NULL; 1437 } 1438 zobject = retval; 1439 ce = Z_OBJCE_P(zobject); 1440 inc_refcount = 0; 1441 } 1442 } 1443 break; 1444 } 1445 case DIT_AppendIterator: 1446 spl_instantiate(spl_ce_ArrayIterator, &intern->u.append.zarrayit, 1 TSRMLS_CC); 1447 zend_call_method_with_0_params(&intern->u.append.zarrayit, spl_ce_ArrayIterator, &spl_ce_ArrayIterator->constructor, "__construct", NULL); 1448 intern->u.append.iterator = spl_ce_ArrayIterator->get_iterator(spl_ce_ArrayIterator, intern->u.append.zarrayit, 0 TSRMLS_CC); 1449 zend_restore_error_handling(&error_handling TSRMLS_CC); 1450 return intern; 1451#if HAVE_PCRE || HAVE_BUNDLED_PCRE 1452 case DIT_RegexIterator: 1453 case DIT_RecursiveRegexIterator: { 1454 char *regex; 1455 int regex_len; 1456 long mode = REGIT_MODE_MATCH; 1457 1458 intern->u.regex.use_flags = ZEND_NUM_ARGS() >= 5; 1459 intern->u.regex.flags = 0; 1460 intern->u.regex.preg_flags = 0; 1461 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) { 1462 zend_restore_error_handling(&error_handling TSRMLS_CC); 1463 return NULL; 1464 } 1465 if (mode < 0 || mode >= REGIT_MODE_MAX) { 1466 zend_throw_exception_ex(spl_ce_InvalidArgumentException, 0 TSRMLS_CC, "Illegal mode %ld", mode); 1467 zend_restore_error_handling(&error_handling TSRMLS_CC); 1468 return NULL; 1469 } 1470 intern->u.regex.mode = mode; 1471 intern->u.regex.regex = estrndup(regex, regex_len); 1472 intern->u.regex.regex_len = regex_len; 1473 intern->u.regex.pce = pcre_get_compiled_regex_cache(regex, regex_len TSRMLS_CC); 1474 if (intern->u.regex.pce == NULL) { 1475 /* pcre_get_compiled_regex_cache has already sent error */ 1476 zend_restore_error_handling(&error_handling TSRMLS_CC); 1477 return NULL; 1478 } 1479 intern->u.regex.pce->refcount++; 1480 break; 1481 } 1482#endif 1483 case DIT_CallbackFilterIterator: 1484 case DIT_RecursiveCallbackFilterIterator: { 1485 _spl_cbfilter_it_intern *cfi = emalloc(sizeof(*cfi)); 1486 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Of", &zobject, ce_inner, &cfi->fci, &cfi->fcc) == FAILURE) { 1487 zend_restore_error_handling(&error_handling TSRMLS_CC); 1488 efree(cfi); 1489 return NULL; 1490 } 1491 if (cfi->fci.function_name) { 1492 Z_ADDREF_P(cfi->fci.function_name); 1493 } 1494 if (cfi->fci.object_ptr) { 1495 Z_ADDREF_P(cfi->fci.object_ptr); 1496 } 1497 intern->u.cbfilter = cfi; 1498 break; 1499 } 1500 default: 1501 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &zobject, ce_inner) == FAILURE) { 1502 zend_restore_error_handling(&error_handling TSRMLS_CC); 1503 return NULL; 1504 } 1505 break; 1506 } 1507 1508 zend_restore_error_handling(&error_handling TSRMLS_CC); 1509 1510 if (inc_refcount) { 1511 Z_ADDREF_P(zobject); 1512 } 1513 intern->inner.zobject = zobject; 1514 intern->inner.ce = dit_type == DIT_IteratorIterator ? ce : Z_OBJCE_P(zobject); 1515 intern->inner.object = zend_object_store_get_object(zobject TSRMLS_CC); 1516 intern->inner.iterator = intern->inner.ce->get_iterator(intern->inner.ce, zobject, 0 TSRMLS_CC); 1517 1518 return intern; 1519} 1520 1521/* {{{ proto void FilterIterator::__construct(Iterator it) 1522 Create an Iterator from another iterator */ 1523SPL_METHOD(FilterIterator, __construct) 1524{ 1525 spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_FilterIterator, zend_ce_iterator, DIT_FilterIterator); 1526} /* }}} */ 1527 1528/* {{{ proto void CallbackFilterIterator::__construct(Iterator it, callback) 1529 Create an Iterator from another iterator */ 1530SPL_METHOD(CallbackFilterIterator, __construct) 1531{ 1532 spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_CallbackFilterIterator, zend_ce_iterator, DIT_CallbackFilterIterator); 1533} /* }}} */ 1534 1535/* {{{ proto Iterator FilterIterator::getInnerIterator() 1536 proto Iterator CachingIterator::getInnerIterator() 1537 proto Iterator LimitIterator::getInnerIterator() 1538 proto Iterator ParentIterator::getInnerIterator() 1539 Get the inner iterator */ 1540SPL_METHOD(dual_it, getInnerIterator) 1541{ 1542 spl_dual_it_object *intern; 1543 1544 if (zend_parse_parameters_none() == FAILURE) { 1545 return; 1546 } 1547 1548 SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis()); 1549 1550 if (intern->inner.zobject) { 1551 RETVAL_ZVAL(intern->inner.zobject, 1, 0); 1552 } else { 1553 RETURN_NULL(); 1554 } 1555} /* }}} */ 1556 1557static inline void spl_dual_it_require(spl_dual_it_object *intern TSRMLS_DC) 1558{ 1559 if (!intern->inner.iterator) { 1560 php_error_docref(NULL TSRMLS_CC, E_ERROR, "The inner constructor wasn't initialized with an iterator instance"); 1561 } 1562} 1563 1564static inline void spl_dual_it_free(spl_dual_it_object *intern TSRMLS_DC) 1565{ 1566 if (intern->inner.iterator && intern->inner.iterator->funcs->invalidate_current) { 1567 intern->inner.iterator->funcs->invalidate_current(intern->inner.iterator TSRMLS_CC); 1568 } 1569 if (intern->current.data) { 1570 zval_ptr_dtor(&intern->current.data); 1571 intern->current.data = NULL; 1572 } 1573 if (intern->current.key) { 1574 zval_ptr_dtor(&intern->current.key); 1575 intern->current.key = NULL; 1576 } 1577 if (intern->dit_type == DIT_CachingIterator || intern->dit_type == DIT_RecursiveCachingIterator) { 1578 if (intern->u.caching.zstr) { 1579 zval_ptr_dtor(&intern->u.caching.zstr); 1580 intern->u.caching.zstr = NULL; 1581 } 1582 if (intern->u.caching.zchildren) { 1583 zval_ptr_dtor(&intern->u.caching.zchildren); 1584 intern->u.caching.zchildren = NULL; 1585 } 1586 } 1587} 1588 1589static inline void spl_dual_it_rewind(spl_dual_it_object *intern TSRMLS_DC) 1590{ 1591 spl_dual_it_free(intern TSRMLS_CC); 1592 intern->current.pos = 0; 1593 if (intern->inner.iterator->funcs->rewind) { 1594 intern->inner.iterator->funcs->rewind(intern->inner.iterator TSRMLS_CC); 1595 } 1596} 1597 1598static inline int spl_dual_it_valid(spl_dual_it_object *intern TSRMLS_DC) 1599{ 1600 if (!intern->inner.iterator) { 1601 return FAILURE; 1602 } 1603 /* FAILURE / SUCCESS */ 1604 return intern->inner.iterator->funcs->valid(intern->inner.iterator TSRMLS_CC); 1605} 1606 1607static inline int spl_dual_it_fetch(spl_dual_it_object *intern, int check_more TSRMLS_DC) 1608{ 1609 zval **data; 1610 1611 spl_dual_it_free(intern TSRMLS_CC); 1612 if (!check_more || spl_dual_it_valid(intern TSRMLS_CC) == SUCCESS) { 1613 intern->inner.iterator->funcs->get_current_data(intern->inner.iterator, &data TSRMLS_CC); 1614 if (data && *data) { 1615 intern->current.data = *data; 1616 Z_ADDREF_P(intern->current.data); 1617 } 1618 1619 MAKE_STD_ZVAL(intern->current.key); 1620 if (intern->inner.iterator->funcs->get_current_key) { 1621 intern->inner.iterator->funcs->get_current_key(intern->inner.iterator, intern->current.key TSRMLS_CC); 1622 if (EG(exception)) { 1623 zval_ptr_dtor(&intern->current.key); 1624 intern->current.key = NULL; 1625 } 1626 } else { 1627 ZVAL_LONG(intern->current.key, intern->current.pos); 1628 } 1629 return EG(exception) ? FAILURE : SUCCESS; 1630 } 1631 return FAILURE; 1632} 1633 1634static inline void spl_dual_it_next(spl_dual_it_object *intern, int do_free TSRMLS_DC) 1635{ 1636 if (do_free) { 1637 spl_dual_it_free(intern TSRMLS_CC); 1638 } else { 1639 spl_dual_it_require(intern TSRMLS_CC); 1640 } 1641 intern->inner.iterator->funcs->move_forward(intern->inner.iterator TSRMLS_CC); 1642 intern->current.pos++; 1643} 1644 1645/* {{{ proto void ParentIterator::rewind() 1646 proto void IteratorIterator::rewind() 1647 Rewind the iterator 1648 */ 1649SPL_METHOD(dual_it, rewind) 1650{ 1651 spl_dual_it_object *intern; 1652 1653 if (zend_parse_parameters_none() == FAILURE) { 1654 return; 1655 } 1656 1657 SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis()); 1658 1659 spl_dual_it_rewind(intern TSRMLS_CC); 1660 spl_dual_it_fetch(intern, 1 TSRMLS_CC); 1661} /* }}} */ 1662 1663/* {{{ proto bool FilterIterator::valid() 1664 proto bool ParentIterator::valid() 1665 proto bool IteratorIterator::valid() 1666 proto bool NoRewindIterator::valid() 1667 Check whether the current element is valid */ 1668SPL_METHOD(dual_it, valid) 1669{ 1670 spl_dual_it_object *intern; 1671 1672 if (zend_parse_parameters_none() == FAILURE) { 1673 return; 1674 } 1675 1676 SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis()); 1677 1678 RETURN_BOOL(intern->current.data); 1679} /* }}} */ 1680 1681/* {{{ proto mixed FilterIterator::key() 1682 proto mixed CachingIterator::key() 1683 proto mixed LimitIterator::key() 1684 proto mixed ParentIterator::key() 1685 proto mixed IteratorIterator::key() 1686 proto mixed NoRewindIterator::key() 1687 proto mixed AppendIterator::key() 1688 Get the current key */ 1689SPL_METHOD(dual_it, key) 1690{ 1691 spl_dual_it_object *intern; 1692 1693 if (zend_parse_parameters_none() == FAILURE) { 1694 return; 1695 } 1696 1697 SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis()); 1698 1699 if (intern->current.key) { 1700 RETURN_ZVAL(intern->current.key, 1, 0); 1701 } 1702 RETURN_NULL(); 1703} /* }}} */ 1704 1705/* {{{ proto mixed FilterIterator::current() 1706 proto mixed CachingIterator::current() 1707 proto mixed LimitIterator::current() 1708 proto mixed ParentIterator::current() 1709 proto mixed IteratorIterator::current() 1710 proto mixed NoRewindIterator::current() 1711 proto mixed AppendIterator::current() 1712 Get the current element value */ 1713SPL_METHOD(dual_it, current) 1714{ 1715 spl_dual_it_object *intern; 1716 1717 if (zend_parse_parameters_none() == FAILURE) { 1718 return; 1719 } 1720 1721 SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis()); 1722 1723 if (intern->current.data) { 1724 RETVAL_ZVAL(intern->current.data, 1, 0); 1725 } else { 1726 RETURN_NULL(); 1727 } 1728} /* }}} */ 1729 1730/* {{{ proto void ParentIterator::next() 1731 proto void IteratorIterator::next() 1732 proto void NoRewindIterator::next() 1733 Move the iterator forward */ 1734SPL_METHOD(dual_it, next) 1735{ 1736 spl_dual_it_object *intern; 1737 1738 if (zend_parse_parameters_none() == FAILURE) { 1739 return; 1740 } 1741 1742 SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis()); 1743 1744 spl_dual_it_next(intern, 1 TSRMLS_CC); 1745 spl_dual_it_fetch(intern, 1 TSRMLS_CC); 1746} /* }}} */ 1747 1748static inline void spl_filter_it_fetch(zval *zthis, spl_dual_it_object *intern TSRMLS_DC) 1749{ 1750 zval *retval; 1751 1752 while (spl_dual_it_fetch(intern, 1 TSRMLS_CC) == SUCCESS) { 1753 zend_call_method_with_0_params(&zthis, intern->std.ce, NULL, "accept", &retval); 1754 if (retval) { 1755 if (zend_is_true(retval)) { 1756 zval_ptr_dtor(&retval); 1757 return; 1758 } 1759 zval_ptr_dtor(&retval); 1760 } 1761 if (EG(exception)) { 1762 return; 1763 } 1764 intern->inner.iterator->funcs->move_forward(intern->inner.iterator TSRMLS_CC); 1765 } 1766 spl_dual_it_free(intern TSRMLS_CC); 1767} 1768 1769static inline void spl_filter_it_rewind(zval *zthis, spl_dual_it_object *intern TSRMLS_DC) 1770{ 1771 spl_dual_it_rewind(intern TSRMLS_CC); 1772 spl_filter_it_fetch(zthis, intern TSRMLS_CC); 1773} 1774 1775static inline void spl_filter_it_next(zval *zthis, spl_dual_it_object *intern TSRMLS_DC) 1776{ 1777 spl_dual_it_next(intern, 1 TSRMLS_CC); 1778 spl_filter_it_fetch(zthis, intern TSRMLS_CC); 1779} 1780 1781/* {{{ proto void FilterIterator::rewind() 1782 Rewind the iterator */ 1783SPL_METHOD(FilterIterator, rewind) 1784{ 1785 spl_dual_it_object *intern; 1786 1787 if (zend_parse_parameters_none() == FAILURE) { 1788 return; 1789 } 1790 1791 SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis()); 1792 spl_filter_it_rewind(getThis(), intern TSRMLS_CC); 1793} /* }}} */ 1794 1795/* {{{ proto void FilterIterator::next() 1796 Move the iterator forward */ 1797SPL_METHOD(FilterIterator, next) 1798{ 1799 spl_dual_it_object *intern; 1800 1801 if (zend_parse_parameters_none() == FAILURE) { 1802 return; 1803 } 1804 1805 SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis()); 1806 spl_filter_it_next(getThis(), intern TSRMLS_CC); 1807} /* }}} */ 1808 1809/* {{{ proto void RecursiveCallbackFilterIterator::__construct(RecursiveIterator it, callback) 1810 Create a RecursiveCallbackFilterIterator from a RecursiveIterator */ 1811SPL_METHOD(RecursiveCallbackFilterIterator, __construct) 1812{ 1813 spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_RecursiveCallbackFilterIterator, spl_ce_RecursiveIterator, DIT_RecursiveCallbackFilterIterator); 1814} /* }}} */ 1815 1816 1817/* {{{ proto void RecursiveFilterIterator::__construct(RecursiveIterator it) 1818 Create a RecursiveFilterIterator from a RecursiveIterator */ 1819SPL_METHOD(RecursiveFilterIterator, __construct) 1820{ 1821 spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_RecursiveFilterIterator, spl_ce_RecursiveIterator, DIT_RecursiveFilterIterator); 1822} /* }}} */ 1823 1824/* {{{ proto bool RecursiveFilterIterator::hasChildren() 1825 Check whether the inner iterator's current element has children */ 1826SPL_METHOD(RecursiveFilterIterator, hasChildren) 1827{ 1828 spl_dual_it_object *intern; 1829 zval *retval; 1830 1831 if (zend_parse_parameters_none() == FAILURE) { 1832 return; 1833 } 1834 1835 SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis()); 1836 1837 zend_call_method_with_0_params(&intern->inner.zobject, intern->inner.ce, NULL, "haschildren", &retval); 1838 if (retval) { 1839 RETURN_ZVAL(retval, 0, 1); 1840 } else { 1841 RETURN_FALSE; 1842 } 1843} /* }}} */ 1844 1845/* {{{ proto RecursiveFilterIterator RecursiveFilterIterator::getChildren() 1846 Return the inner iterator's children contained in a RecursiveFilterIterator */ 1847SPL_METHOD(RecursiveFilterIterator, getChildren) 1848{ 1849 spl_dual_it_object *intern; 1850 zval *retval; 1851 1852 if (zend_parse_parameters_none() == FAILURE) { 1853 return; 1854 } 1855 1856 SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis()); 1857 1858 zend_call_method_with_0_params(&intern->inner.zobject, intern->inner.ce, NULL, "getchildren", &retval); 1859 if (!EG(exception) && retval) { 1860 spl_instantiate_arg_ex1(Z_OBJCE_P(getThis()), &return_value, 0, retval TSRMLS_CC); 1861 } 1862 if (retval) { 1863 zval_ptr_dtor(&retval); 1864 } 1865} /* }}} */ 1866 1867/* {{{ proto RecursiveCallbackFilterIterator RecursiveCallbackFilterIterator::getChildren() 1868 Return the inner iterator's children contained in a RecursiveCallbackFilterIterator */ 1869SPL_METHOD(RecursiveCallbackFilterIterator, getChildren) 1870{ 1871 spl_dual_it_object *intern; 1872 zval *retval; 1873 1874 if (zend_parse_parameters_none() == FAILURE) { 1875 return; 1876 } 1877 1878 intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC); 1879 1880 zend_call_method_with_0_params(&intern->inner.zobject, intern->inner.ce, NULL, "getchildren", &retval); 1881 if (!EG(exception) && retval) { 1882 spl_instantiate_arg_ex2(Z_OBJCE_P(getThis()), &return_value, 0, retval, intern->u.cbfilter->fci.function_name TSRMLS_CC); 1883 } 1884 if (retval) { 1885 zval_ptr_dtor(&retval); 1886 } 1887} /* }}} */ 1888/* {{{ proto void ParentIterator::__construct(RecursiveIterator it) 1889 Create a ParentIterator from a RecursiveIterator */ 1890SPL_METHOD(ParentIterator, __construct) 1891{ 1892 spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_ParentIterator, spl_ce_RecursiveIterator, DIT_ParentIterator); 1893} /* }}} */ 1894 1895#if HAVE_PCRE || HAVE_BUNDLED_PCRE 1896/* {{{ proto void RegexIterator::__construct(Iterator it, string regex [, int mode [, int flags [, int preg_flags]]]) 1897 Create an RegexIterator from another iterator and a regular expression */ 1898SPL_METHOD(RegexIterator, __construct) 1899{ 1900 spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_RegexIterator, zend_ce_iterator, DIT_RegexIterator); 1901} /* }}} */ 1902 1903/* {{{ proto bool CallbackFilterIterator::accept() 1904 Calls the callback with the current value, the current key and the inner iterator as arguments */ 1905SPL_METHOD(CallbackFilterIterator, accept) 1906{ 1907 spl_dual_it_object *intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC); 1908 zend_fcall_info *fci = &intern->u.cbfilter->fci; 1909 zend_fcall_info_cache *fcc = &intern->u.cbfilter->fcc; 1910 zval **params[3]; 1911 zval *result; 1912 1913 if (zend_parse_parameters_none() == FAILURE) { 1914 return; 1915 } 1916 1917 if (intern->current.data == NULL || intern->current.key == NULL) { 1918 RETURN_FALSE; 1919 } 1920 1921 params[0] = &intern->current.data; 1922 params[1] = &intern->current.key; 1923 params[2] = &intern->inner.zobject; 1924 1925 fci->retval_ptr_ptr = &result; 1926 fci->param_count = 3; 1927 fci->params = params; 1928 fci->no_separation = 0; 1929 1930 if (zend_call_function(fci, fcc TSRMLS_CC) != SUCCESS || !result) { 1931 RETURN_FALSE; 1932 } 1933 if (EG(exception)) { 1934 return; 1935 } 1936 1937 RETURN_ZVAL(result, 1, 1); 1938} 1939/* }}} */ 1940 1941/* {{{ proto bool RegexIterator::accept() 1942 Match (string)current() against regular expression */ 1943SPL_METHOD(RegexIterator, accept) 1944{ 1945 spl_dual_it_object *intern; 1946 char *subject, *result; 1947 int subject_len, use_copy, count = 0, result_len; 1948 zval *subject_ptr, subject_copy, zcount, *replacement, tmp_replacement; 1949 1950 if (zend_parse_parameters_none() == FAILURE) { 1951 return; 1952 } 1953 1954 SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis()); 1955 1956 if (intern->current.data == NULL) { 1957 RETURN_FALSE; 1958 } 1959 1960 if (intern->u.regex.flags & REGIT_USE_KEY) { 1961 subject_ptr = intern->current.key; 1962 } else { 1963 subject_ptr = intern->current.data; 1964 } 1965 1966 zend_make_printable_zval(subject_ptr, &subject_copy, &use_copy); 1967 if (use_copy) { 1968 subject = Z_STRVAL(subject_copy); 1969 subject_len = Z_STRLEN(subject_copy); 1970 } else { 1971 subject = Z_STRVAL_P(subject_ptr); 1972 subject_len = Z_STRLEN_P(subject_ptr); 1973 } 1974 1975 switch (intern->u.regex.mode) 1976 { 1977 case REGIT_MODE_MAX: /* won't happen but makes compiler happy */ 1978 case REGIT_MODE_MATCH: 1979 count = pcre_exec(intern->u.regex.pce->re, intern->u.regex.pce->extra, subject, subject_len, 0, 0, NULL, 0); 1980 RETVAL_BOOL(count >= 0); 1981 break; 1982 1983 case REGIT_MODE_ALL_MATCHES: 1984 case REGIT_MODE_GET_MATCH: 1985 if (!use_copy) { 1986 subject = estrndup(subject, subject_len); 1987 use_copy = 1; 1988 } 1989 zval_ptr_dtor(&intern->current.data); 1990 ALLOC_INIT_ZVAL(intern->current.data); 1991 php_pcre_match_impl(intern->u.regex.pce, subject, subject_len, &zcount, 1992 intern->current.data, intern->u.regex.mode == REGIT_MODE_ALL_MATCHES, intern->u.regex.use_flags, intern->u.regex.preg_flags, 0 TSRMLS_CC); 1993 count = zend_hash_num_elements(Z_ARRVAL_P(intern->current.data)); 1994 RETVAL_BOOL(count > 0); 1995 break; 1996 1997 case REGIT_MODE_SPLIT: 1998 if (!use_copy) { 1999 subject = estrndup(subject, subject_len); 2000 use_copy = 1; 2001 } 2002 zval_ptr_dtor(&intern->current.data); 2003 ALLOC_INIT_ZVAL(intern->current.data); 2004 php_pcre_split_impl(intern->u.regex.pce, subject, subject_len, intern->current.data, -1, intern->u.regex.preg_flags TSRMLS_CC); 2005 count = zend_hash_num_elements(Z_ARRVAL_P(intern->current.data)); 2006 RETVAL_BOOL(count > 1); 2007 break; 2008 2009 case REGIT_MODE_REPLACE: 2010 replacement = zend_read_property(intern->std.ce, getThis(), "replacement", sizeof("replacement")-1, 1 TSRMLS_CC); 2011 if (Z_TYPE_P(replacement) != IS_STRING) { 2012 tmp_replacement = *replacement; 2013 zval_copy_ctor(&tmp_replacement); 2014 convert_to_string(&tmp_replacement); 2015 replacement = &tmp_replacement; 2016 } 2017 result = php_pcre_replace_impl(intern->u.regex.pce, subject, subject_len, replacement, 0, &result_len, -1, &count TSRMLS_CC); 2018 2019 if (intern->u.regex.flags & REGIT_USE_KEY) { 2020 zval_ptr_dtor(&intern->current.key); 2021 MAKE_STD_ZVAL(intern->current.key); 2022 ZVAL_STRINGL(intern->current.key, result, result_len, 0); 2023 } else { 2024 zval_ptr_dtor(&intern->current.data); 2025 MAKE_STD_ZVAL(intern->current.data); 2026 ZVAL_STRINGL(intern->current.data, result, result_len, 0); 2027 } 2028 2029 if (replacement == &tmp_replacement) { 2030 zval_dtor(replacement); 2031 } 2032 RETVAL_BOOL(count > 0); 2033 } 2034 2035 if (intern->u.regex.flags & REGIT_INVERTED) { 2036 RETVAL_BOOL(Z_LVAL_P(return_value)); 2037 } 2038 2039 if (use_copy) { 2040 efree(subject); 2041 } 2042} /* }}} */ 2043 2044/* {{{ proto string RegexIterator::getRegex() 2045 Returns current regular expression */ 2046SPL_METHOD(RegexIterator, getRegex) 2047{ 2048 spl_dual_it_object *intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC); 2049 2050 if (zend_parse_parameters_none() == FAILURE) { 2051 return; 2052 } 2053 2054 RETURN_STRINGL(intern->u.regex.regex, intern->u.regex.regex_len, 1); 2055} /* }}} */ 2056 2057/* {{{ proto bool RegexIterator::getMode() 2058 Returns current operation mode */ 2059SPL_METHOD(RegexIterator, getMode) 2060{ 2061 spl_dual_it_object *intern; 2062 2063 if (zend_parse_parameters_none() == FAILURE) { 2064 return; 2065 } 2066 2067 SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis()); 2068 2069 RETURN_LONG(intern->u.regex.mode); 2070} /* }}} */ 2071 2072/* {{{ proto bool RegexIterator::setMode(int new_mode) 2073 Set new operation mode */ 2074SPL_METHOD(RegexIterator, setMode) 2075{ 2076 spl_dual_it_object *intern; 2077 long mode; 2078 2079 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &mode) == FAILURE) { 2080 return; 2081 } 2082 2083 if (mode < 0 || mode >= REGIT_MODE_MAX) { 2084 zend_throw_exception_ex(spl_ce_InvalidArgumentException, 0 TSRMLS_CC, "Illegal mode %ld", mode); 2085 return;/* NULL */ 2086 } 2087 2088 SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis()); 2089 2090 intern->u.regex.mode = mode; 2091} /* }}} */ 2092 2093/* {{{ proto bool RegexIterator::getFlags() 2094 Returns current operation flags */ 2095SPL_METHOD(RegexIterator, getFlags) 2096{ 2097 spl_dual_it_object *intern; 2098 2099 if (zend_parse_parameters_none() == FAILURE) { 2100 return; 2101 } 2102 2103 SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis()); 2104 2105 RETURN_LONG(intern->u.regex.flags); 2106} /* }}} */ 2107 2108/* {{{ proto bool RegexIterator::setFlags(int new_flags) 2109 Set operation flags */ 2110SPL_METHOD(RegexIterator, setFlags) 2111{ 2112 spl_dual_it_object *intern; 2113 long flags; 2114 2115 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &flags) == FAILURE) { 2116 return; 2117 } 2118 2119 SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis()); 2120 2121 intern->u.regex.flags = flags; 2122} /* }}} */ 2123 2124/* {{{ proto bool RegexIterator::getFlags() 2125 Returns current PREG flags (if in use or NULL) */ 2126SPL_METHOD(RegexIterator, getPregFlags) 2127{ 2128 spl_dual_it_object *intern; 2129 2130 if (zend_parse_parameters_none() == FAILURE) { 2131 return; 2132 } 2133 2134 SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis()); 2135 2136 if (intern->u.regex.use_flags) { 2137 RETURN_LONG(intern->u.regex.preg_flags); 2138 } else { 2139 return; 2140 } 2141} /* }}} */ 2142 2143/* {{{ proto bool RegexIterator::setPregFlags(int new_flags) 2144 Set PREG flags */ 2145SPL_METHOD(RegexIterator, setPregFlags) 2146{ 2147 spl_dual_it_object *intern; 2148 long preg_flags; 2149 2150 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &preg_flags) == FAILURE) { 2151 return; 2152 } 2153 2154 SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis()); 2155 2156 intern->u.regex.preg_flags = preg_flags; 2157 intern->u.regex.use_flags = 1; 2158} /* }}} */ 2159 2160/* {{{ proto void RecursiveRegexIterator::__construct(RecursiveIterator it, string regex [, int mode [, int flags [, int preg_flags]]]) 2161 Create an RecursiveRegexIterator from another recursive iterator and a regular expression */ 2162SPL_METHOD(RecursiveRegexIterator, __construct) 2163{ 2164 spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_RecursiveRegexIterator, spl_ce_RecursiveIterator, DIT_RecursiveRegexIterator); 2165} /* }}} */ 2166 2167/* {{{ proto RecursiveRegexIterator RecursiveRegexIterator::getChildren() 2168 Return the inner iterator's children contained in a RecursiveRegexIterator */ 2169SPL_METHOD(RecursiveRegexIterator, getChildren) 2170{ 2171 spl_dual_it_object *intern; 2172 zval *retval, *regex; 2173 2174 if (zend_parse_parameters_none() == FAILURE) { 2175 return; 2176 } 2177 2178 SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis()); 2179 2180 zend_call_method_with_0_params(&intern->inner.zobject, intern->inner.ce, NULL, "getchildren", &retval); 2181 if (!EG(exception)) { 2182 MAKE_STD_ZVAL(regex); 2183 ZVAL_STRING(regex, intern->u.regex.regex, 1); 2184 spl_instantiate_arg_ex2(Z_OBJCE_P(getThis()), &return_value, 0, retval, regex TSRMLS_CC); 2185 zval_ptr_dtor(®ex); 2186 } 2187 if (retval) { 2188 zval_ptr_dtor(&retval); 2189 } 2190} /* }}} */ 2191 2192#endif 2193 2194/* {{{ spl_dual_it_dtor */ 2195static void spl_dual_it_dtor(zend_object *_object, zend_object_handle handle TSRMLS_DC) 2196{ 2197 spl_dual_it_object *object = (spl_dual_it_object *)_object; 2198 2199 /* call standard dtor */ 2200 zend_objects_destroy_object(_object, handle TSRMLS_CC); 2201 2202 spl_dual_it_free(object TSRMLS_CC); 2203 2204 if (object->inner.iterator) { 2205 object->inner.iterator->funcs->dtor(object->inner.iterator TSRMLS_CC); 2206 } 2207} 2208/* }}} */ 2209 2210/* {{{ spl_dual_it_free_storage */ 2211static void spl_dual_it_free_storage(void *_object TSRMLS_DC) 2212{ 2213 spl_dual_it_object *object = (spl_dual_it_object *)_object; 2214 2215 2216 if (object->inner.zobject) { 2217 zval_ptr_dtor(&object->inner.zobject); 2218 } 2219 2220 if (object->dit_type == DIT_AppendIterator) { 2221 object->u.append.iterator->funcs->dtor(object->u.append.iterator TSRMLS_CC); 2222 if (object->u.append.zarrayit) { 2223 zval_ptr_dtor(&object->u.append.zarrayit); 2224 } 2225 } 2226 2227 if (object->dit_type == DIT_CachingIterator || object->dit_type == DIT_RecursiveCachingIterator) { 2228 if (object->u.caching.zcache) { 2229 zval_ptr_dtor(&object->u.caching.zcache); 2230 object->u.caching.zcache = NULL; 2231 } 2232 } 2233 2234#if HAVE_PCRE || HAVE_BUNDLED_PCRE 2235 if (object->dit_type == DIT_RegexIterator || object->dit_type == DIT_RecursiveRegexIterator) { 2236 if (object->u.regex.pce) { 2237 object->u.regex.pce->refcount--; 2238 } 2239 if (object->u.regex.regex) { 2240 efree(object->u.regex.regex); 2241 } 2242 } 2243#endif 2244 2245 if (object->dit_type == DIT_CallbackFilterIterator || object->dit_type == DIT_RecursiveCallbackFilterIterator) { 2246 if (object->u.cbfilter) { 2247 if (object->u.cbfilter->fci.function_name) { 2248 zval_ptr_dtor(&object->u.cbfilter->fci.function_name); 2249 } 2250 if (object->u.cbfilter->fci.object_ptr) { 2251 zval_ptr_dtor(&object->u.cbfilter->fci.object_ptr); 2252 } 2253 efree(object->u.cbfilter); 2254 } 2255 } 2256 2257 zend_object_std_dtor(&object->std TSRMLS_CC); 2258 2259 efree(object); 2260} 2261/* }}} */ 2262 2263/* {{{ spl_dual_it_new */ 2264static zend_object_value spl_dual_it_new(zend_class_entry *class_type TSRMLS_DC) 2265{ 2266 zend_object_value retval; 2267 spl_dual_it_object *intern; 2268 2269 intern = emalloc(sizeof(spl_dual_it_object)); 2270 memset(intern, 0, sizeof(spl_dual_it_object)); 2271 intern->dit_type = DIT_Unknown; 2272 2273 zend_object_std_init(&intern->std, class_type TSRMLS_CC); 2274 object_properties_init(&intern->std, class_type); 2275 2276 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); 2277 retval.handlers = &spl_handlers_dual_it; 2278 return retval; 2279} 2280/* }}} */ 2281 2282ZEND_BEGIN_ARG_INFO(arginfo_filter_it___construct, 0) 2283 ZEND_ARG_OBJ_INFO(0, iterator, Iterator, 0) 2284ZEND_END_ARG_INFO(); 2285 2286static const zend_function_entry spl_funcs_FilterIterator[] = { 2287 SPL_ME(FilterIterator, __construct, arginfo_filter_it___construct, ZEND_ACC_PUBLIC) 2288 SPL_ME(FilterIterator, rewind, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) 2289 SPL_ME(dual_it, valid, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) 2290 SPL_ME(dual_it, key, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) 2291 SPL_ME(dual_it, current, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) 2292 SPL_ME(FilterIterator, next, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) 2293 SPL_ME(dual_it, getInnerIterator, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) 2294 SPL_ABSTRACT_ME(FilterIterator, accept, arginfo_recursive_it_void) 2295 PHP_FE_END 2296}; 2297 2298ZEND_BEGIN_ARG_INFO(arginfo_callback_filter_it___construct, 0) 2299 ZEND_ARG_OBJ_INFO(0, iterator, Iterator, 0) 2300 ZEND_ARG_INFO(0, callback) 2301ZEND_END_ARG_INFO(); 2302 2303static const zend_function_entry spl_funcs_CallbackFilterIterator[] = { 2304 SPL_ME(CallbackFilterIterator, __construct, arginfo_callback_filter_it___construct, ZEND_ACC_PUBLIC) 2305 SPL_ME(CallbackFilterIterator, accept, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) 2306 PHP_FE_END 2307}; 2308 2309ZEND_BEGIN_ARG_INFO(arginfo_recursive_callback_filter_it___construct, 0) 2310 ZEND_ARG_OBJ_INFO(0, iterator, RecursiveIterator, 0) 2311 ZEND_ARG_INFO(0, callback) 2312ZEND_END_ARG_INFO(); 2313 2314static const zend_function_entry spl_funcs_RecursiveCallbackFilterIterator[] = { 2315 SPL_ME(RecursiveCallbackFilterIterator, __construct, arginfo_recursive_callback_filter_it___construct, ZEND_ACC_PUBLIC) 2316 SPL_ME(RecursiveFilterIterator, hasChildren, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) 2317 SPL_ME(RecursiveCallbackFilterIterator, getChildren, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) 2318 PHP_FE_END 2319}; 2320 2321ZEND_BEGIN_ARG_INFO(arginfo_parent_it___construct, 0) 2322 ZEND_ARG_OBJ_INFO(0, iterator, RecursiveIterator, 0) 2323ZEND_END_ARG_INFO(); 2324 2325static const zend_function_entry spl_funcs_RecursiveFilterIterator[] = { 2326 SPL_ME(RecursiveFilterIterator, __construct, arginfo_parent_it___construct, ZEND_ACC_PUBLIC) 2327 SPL_ME(RecursiveFilterIterator, hasChildren, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) 2328 SPL_ME(RecursiveFilterIterator, getChildren, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) 2329 PHP_FE_END 2330}; 2331 2332static const zend_function_entry spl_funcs_ParentIterator[] = { 2333 SPL_ME(ParentIterator, __construct, arginfo_parent_it___construct, ZEND_ACC_PUBLIC) 2334 SPL_MA(ParentIterator, accept, RecursiveFilterIterator, hasChildren, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) 2335 PHP_FE_END 2336}; 2337 2338#if HAVE_PCRE || HAVE_BUNDLED_PCRE 2339ZEND_BEGIN_ARG_INFO_EX(arginfo_regex_it___construct, 0, 0, 2) 2340 ZEND_ARG_OBJ_INFO(0, iterator, Iterator, 0) 2341 ZEND_ARG_INFO(0, regex) 2342 ZEND_ARG_INFO(0, mode) 2343 ZEND_ARG_INFO(0, flags) 2344 ZEND_ARG_INFO(0, preg_flags) 2345ZEND_END_ARG_INFO(); 2346 2347ZEND_BEGIN_ARG_INFO_EX(arginfo_regex_it_set_mode, 0, 0, 1) 2348 ZEND_ARG_INFO(0, mode) 2349ZEND_END_ARG_INFO(); 2350 2351ZEND_BEGIN_ARG_INFO_EX(arginfo_regex_it_set_flags, 0, 0, 1) 2352 ZEND_ARG_INFO(0, flags) 2353ZEND_END_ARG_INFO(); 2354 2355ZEND_BEGIN_ARG_INFO_EX(arginfo_regex_it_set_preg_flags, 0, 0, 1) 2356 ZEND_ARG_INFO(0, preg_flags) 2357ZEND_END_ARG_INFO(); 2358 2359static const zend_function_entry spl_funcs_RegexIterator[] = { 2360 SPL_ME(RegexIterator, __construct, arginfo_regex_it___construct, ZEND_ACC_PUBLIC) 2361 SPL_ME(RegexIterator, accept, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) 2362 SPL_ME(RegexIterator, getMode, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) 2363 SPL_ME(RegexIterator, setMode, arginfo_regex_it_set_mode, ZEND_ACC_PUBLIC) 2364 SPL_ME(RegexIterator, getFlags, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) 2365 SPL_ME(RegexIterator, setFlags, arginfo_regex_it_set_flags, ZEND_ACC_PUBLIC) 2366 SPL_ME(RegexIterator, getPregFlags, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) 2367 SPL_ME(RegexIterator, setPregFlags, arginfo_regex_it_set_preg_flags, ZEND_ACC_PUBLIC) 2368 SPL_ME(RegexIterator, getRegex, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) 2369 PHP_FE_END 2370}; 2371 2372ZEND_BEGIN_ARG_INFO_EX(arginfo_rec_regex_it___construct, 0, 0, 2) 2373 ZEND_ARG_OBJ_INFO(0, iterator, RecursiveIterator, 0) 2374 ZEND_ARG_INFO(0, regex) 2375 ZEND_ARG_INFO(0, mode) 2376 ZEND_ARG_INFO(0, flags) 2377 ZEND_ARG_INFO(0, preg_flags) 2378ZEND_END_ARG_INFO(); 2379 2380static const zend_function_entry spl_funcs_RecursiveRegexIterator[] = { 2381 SPL_ME(RecursiveRegexIterator, __construct, arginfo_rec_regex_it___construct, ZEND_ACC_PUBLIC) 2382 SPL_ME(RecursiveFilterIterator, hasChildren, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) 2383 SPL_ME(RecursiveRegexIterator, getChildren, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) 2384 PHP_FE_END 2385}; 2386#endif 2387 2388static inline int spl_limit_it_valid(spl_dual_it_object *intern TSRMLS_DC) 2389{ 2390 /* FAILURE / SUCCESS */ 2391 if (intern->u.limit.count != -1 && intern->current.pos >= intern->u.limit.offset + intern->u.limit.count) { 2392 return FAILURE; 2393 } else { 2394 return spl_dual_it_valid(intern TSRMLS_CC); 2395 } 2396} 2397 2398static inline void spl_limit_it_seek(spl_dual_it_object *intern, long pos TSRMLS_DC) 2399{ 2400 zval *zpos; 2401 2402 spl_dual_it_free(intern TSRMLS_CC); 2403 if (pos < intern->u.limit.offset) { 2404 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); 2405 return; 2406 } 2407 if (pos >= intern->u.limit.offset + intern->u.limit.count && intern->u.limit.count != -1) { 2408 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); 2409 return; 2410 } 2411 if (pos != intern->current.pos && instanceof_function(intern->inner.ce, spl_ce_SeekableIterator TSRMLS_CC)) { 2412 MAKE_STD_ZVAL(zpos); 2413 ZVAL_LONG(zpos, pos); 2414 spl_dual_it_free(intern TSRMLS_CC); 2415 zend_call_method_with_1_params(&intern->inner.zobject, intern->inner.ce, NULL, "seek", NULL, zpos); 2416 zval_ptr_dtor(&zpos); 2417 if (!EG(exception)) { 2418 intern->current.pos = pos; 2419 if (spl_limit_it_valid(intern TSRMLS_CC) == SUCCESS) { 2420 spl_dual_it_fetch(intern, 0 TSRMLS_CC); 2421 } 2422 } 2423 } else { 2424 /* emulate the forward seek, by next() calls */ 2425 /* a back ward seek is done by a previous rewind() */ 2426 if (pos < intern->current.pos) { 2427 spl_dual_it_rewind(intern TSRMLS_CC); 2428 } 2429 while (pos > intern->current.pos && spl_dual_it_valid(intern TSRMLS_CC) == SUCCESS) { 2430 spl_dual_it_next(intern, 1 TSRMLS_CC); 2431 } 2432 if (spl_dual_it_valid(intern TSRMLS_CC) == SUCCESS) { 2433 spl_dual_it_fetch(intern, 1 TSRMLS_CC); 2434 } 2435 } 2436} 2437 2438/* {{{ proto LimitIterator::__construct(Iterator it [, int offset, int count]) 2439 Construct a LimitIterator from an Iterator with a given starting offset and optionally a maximum count */ 2440SPL_METHOD(LimitIterator, __construct) 2441{ 2442 spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_LimitIterator, zend_ce_iterator, DIT_LimitIterator); 2443} /* }}} */ 2444 2445/* {{{ proto void LimitIterator::rewind() 2446 Rewind the iterator to the specified starting offset */ 2447SPL_METHOD(LimitIterator, rewind) 2448{ 2449 spl_dual_it_object *intern; 2450 2451 SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis()); 2452 spl_dual_it_rewind(intern TSRMLS_CC); 2453 spl_limit_it_seek(intern, intern->u.limit.offset TSRMLS_CC); 2454} /* }}} */ 2455 2456/* {{{ proto bool LimitIterator::valid() 2457 Check whether the current element is valid */ 2458SPL_METHOD(LimitIterator, valid) 2459{ 2460 spl_dual_it_object *intern; 2461 2462 SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis()); 2463 2464/* RETURN_BOOL(spl_limit_it_valid(intern TSRMLS_CC) == SUCCESS);*/ 2465 RETURN_BOOL((intern->u.limit.count == -1 || intern->current.pos < intern->u.limit.offset + intern->u.limit.count) && intern->current.data); 2466} /* }}} */ 2467 2468/* {{{ proto void LimitIterator::next() 2469 Move the iterator forward */ 2470SPL_METHOD(LimitIterator, next) 2471{ 2472 spl_dual_it_object *intern; 2473 2474 SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis()); 2475 2476 spl_dual_it_next(intern, 1 TSRMLS_CC); 2477 if (intern->u.limit.count == -1 || intern->current.pos < intern->u.limit.offset + intern->u.limit.count) { 2478 spl_dual_it_fetch(intern, 1 TSRMLS_CC); 2479 } 2480} /* }}} */ 2481 2482/* {{{ proto void LimitIterator::seek(int position) 2483 Seek to the given position */ 2484SPL_METHOD(LimitIterator, seek) 2485{ 2486 spl_dual_it_object *intern; 2487 long pos; 2488 2489 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &pos) == FAILURE) { 2490 return; 2491 } 2492 2493 SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis()); 2494 spl_limit_it_seek(intern, pos TSRMLS_CC); 2495 RETURN_LONG(intern->current.pos); 2496} /* }}} */ 2497 2498/* {{{ proto int LimitIterator::getPosition() 2499 Return the current position */ 2500SPL_METHOD(LimitIterator, getPosition) 2501{ 2502 spl_dual_it_object *intern; 2503 SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis()); 2504 RETURN_LONG(intern->current.pos); 2505} /* }}} */ 2506 2507ZEND_BEGIN_ARG_INFO(arginfo_seekable_it_seek, 0) 2508 ZEND_ARG_INFO(0, position) 2509ZEND_END_ARG_INFO(); 2510 2511static const zend_function_entry spl_funcs_SeekableIterator[] = { 2512 SPL_ABSTRACT_ME(SeekableIterator, seek, arginfo_seekable_it_seek) 2513 PHP_FE_END 2514}; 2515 2516ZEND_BEGIN_ARG_INFO_EX(arginfo_limit_it___construct, 0, 0, 1) 2517 ZEND_ARG_OBJ_INFO(0, iterator, Iterator, 0) 2518 ZEND_ARG_INFO(0, offset) 2519 ZEND_ARG_INFO(0, count) 2520ZEND_END_ARG_INFO(); 2521 2522ZEND_BEGIN_ARG_INFO(arginfo_limit_it_seek, 0) 2523 ZEND_ARG_INFO(0, position) 2524ZEND_END_ARG_INFO(); 2525 2526static const zend_function_entry spl_funcs_LimitIterator[] = { 2527 SPL_ME(LimitIterator, __construct, arginfo_limit_it___construct, ZEND_ACC_PUBLIC) 2528 SPL_ME(LimitIterator, rewind, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) 2529 SPL_ME(LimitIterator, valid, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) 2530 SPL_ME(dual_it, key, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) 2531 SPL_ME(dual_it, current, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) 2532 SPL_ME(LimitIterator, next, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) 2533 SPL_ME(LimitIterator, seek, arginfo_limit_it_seek, ZEND_ACC_PUBLIC) 2534 SPL_ME(LimitIterator, getPosition, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) 2535 SPL_ME(dual_it, getInnerIterator, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) 2536 PHP_FE_END 2537}; 2538 2539static inline int spl_caching_it_valid(spl_dual_it_object *intern TSRMLS_DC) 2540{ 2541 return intern->u.caching.flags & CIT_VALID ? SUCCESS : FAILURE; 2542} 2543 2544static inline int spl_caching_it_has_next(spl_dual_it_object *intern TSRMLS_DC) 2545{ 2546 return spl_dual_it_valid(intern TSRMLS_CC); 2547} 2548 2549static inline void spl_caching_it_next(spl_dual_it_object *intern TSRMLS_DC) 2550{ 2551 if (spl_dual_it_fetch(intern, 1 TSRMLS_CC) == SUCCESS) { 2552 intern->u.caching.flags |= CIT_VALID; 2553 /* Full cache ? */ 2554 if (intern->u.caching.flags & CIT_FULL_CACHE) { 2555 zval *zcacheval; 2556 zval *key = intern->current.key; 2557 2558 MAKE_STD_ZVAL(zcacheval); 2559 ZVAL_ZVAL(zcacheval, intern->current.data, 1, 0); 2560 2561 array_set_zval_key(HASH_OF(intern->u.caching.zcache), key, zcacheval); 2562 2563 zval_ptr_dtor(&zcacheval); 2564 } 2565 /* Recursion ? */ 2566 if (intern->dit_type == DIT_RecursiveCachingIterator) { 2567 zval *retval, *zchildren, zflags; 2568 zend_call_method_with_0_params(&intern->inner.zobject, intern->inner.ce, NULL, "haschildren", &retval); 2569 if (EG(exception)) { 2570 if (retval) { 2571 zval_ptr_dtor(&retval); 2572 } 2573 if (intern->u.caching.flags & CIT_CATCH_GET_CHILD) { 2574 zend_clear_exception(TSRMLS_C); 2575 } else { 2576 return; 2577 } 2578 } else { 2579 if (zend_is_true(retval)) { 2580 zend_call_method_with_0_params(&intern->inner.zobject, intern->inner.ce, NULL, "getchildren", &zchildren); 2581 if (EG(exception)) { 2582 if (zchildren) { 2583 zval_ptr_dtor(&zchildren); 2584 } 2585 if (intern->u.caching.flags & CIT_CATCH_GET_CHILD) { 2586 zend_clear_exception(TSRMLS_C); 2587 } else { 2588 zval_ptr_dtor(&retval); 2589 return; 2590 } 2591 } else { 2592 INIT_PZVAL(&zflags); 2593 ZVAL_LONG(&zflags, intern->u.caching.flags & CIT_PUBLIC); 2594 spl_instantiate_arg_ex2(spl_ce_RecursiveCachingIterator, &intern->u.caching.zchildren, 1, zchildren, &zflags TSRMLS_CC); 2595 zval_ptr_dtor(&zchildren); 2596 } 2597 } 2598 zval_ptr_dtor(&retval); 2599 if (EG(exception)) { 2600 if (intern->u.caching.flags & CIT_CATCH_GET_CHILD) { 2601 zend_clear_exception(TSRMLS_C); 2602 } else { 2603 return; 2604 } 2605 } 2606 } 2607 } 2608 if (intern->u.caching.flags & (CIT_TOSTRING_USE_INNER|CIT_CALL_TOSTRING)) { 2609 int use_copy; 2610 zval expr_copy; 2611 ALLOC_ZVAL(intern->u.caching.zstr); 2612 if (intern->u.caching.flags & CIT_TOSTRING_USE_INNER) { 2613 *intern->u.caching.zstr = *intern->inner.zobject; 2614 } else { 2615 *intern->u.caching.zstr = *intern->current.data; 2616 } 2617 zend_make_printable_zval(intern->u.caching.zstr, &expr_copy, &use_copy); 2618 if (use_copy) { 2619 *intern->u.caching.zstr = expr_copy; 2620 INIT_PZVAL(intern->u.caching.zstr); 2621 zval_copy_ctor(intern->u.caching.zstr); 2622 zval_dtor(&expr_copy); 2623 } else { 2624 INIT_PZVAL(intern->u.caching.zstr); 2625 zval_copy_ctor(intern->u.caching.zstr); 2626 } 2627 } 2628 spl_dual_it_next(intern, 0 TSRMLS_CC); 2629 } else { 2630 intern->u.caching.flags &= ~CIT_VALID; 2631 } 2632} 2633 2634static inline void spl_caching_it_rewind(spl_dual_it_object *intern TSRMLS_DC) 2635{ 2636 spl_dual_it_rewind(intern TSRMLS_CC); 2637 zend_hash_clean(HASH_OF(intern->u.caching.zcache)); 2638 spl_caching_it_next(intern TSRMLS_CC); 2639} 2640 2641/* {{{ proto void CachingIterator::__construct(Iterator it [, flags = CIT_CALL_TOSTRING]) 2642 Construct a CachingIterator from an Iterator */ 2643SPL_METHOD(CachingIterator, __construct) 2644{ 2645 spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_CachingIterator, zend_ce_iterator, DIT_CachingIterator); 2646} /* }}} */ 2647 2648/* {{{ proto void CachingIterator::rewind() 2649 Rewind the iterator */ 2650SPL_METHOD(CachingIterator, rewind) 2651{ 2652 spl_dual_it_object *intern; 2653 2654 if (zend_parse_parameters_none() == FAILURE) { 2655 return; 2656 } 2657 2658 SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis()); 2659 2660 spl_caching_it_rewind(intern TSRMLS_CC); 2661} /* }}} */ 2662 2663/* {{{ proto bool CachingIterator::valid() 2664 Check whether the current element is valid */ 2665SPL_METHOD(CachingIterator, valid) 2666{ 2667 spl_dual_it_object *intern; 2668 2669 if (zend_parse_parameters_none() == FAILURE) { 2670 return; 2671 } 2672 2673 SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis()); 2674 2675 RETURN_BOOL(spl_caching_it_valid(intern TSRMLS_CC) == SUCCESS); 2676} /* }}} */ 2677 2678/* {{{ proto void CachingIterator::next() 2679 Move the iterator forward */ 2680SPL_METHOD(CachingIterator, next) 2681{ 2682 spl_dual_it_object *intern; 2683 2684 if (zend_parse_parameters_none() == FAILURE) { 2685 return; 2686 } 2687 2688 SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis()); 2689 2690 spl_caching_it_next(intern TSRMLS_CC); 2691} /* }}} */ 2692 2693/* {{{ proto bool CachingIterator::hasNext() 2694 Check whether the inner iterator has a valid next element */ 2695SPL_METHOD(CachingIterator, hasNext) 2696{ 2697 spl_dual_it_object *intern; 2698 2699 if (zend_parse_parameters_none() == FAILURE) { 2700 return; 2701 } 2702 2703 SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis()); 2704 2705 RETURN_BOOL(spl_caching_it_has_next(intern TSRMLS_CC) == SUCCESS); 2706} /* }}} */ 2707 2708/* {{{ proto string CachingIterator::__toString() 2709 Return the string representation of the current element */ 2710SPL_METHOD(CachingIterator, __toString) 2711{ 2712 spl_dual_it_object *intern; 2713 2714 SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis()); 2715 2716 if (!(intern->u.caching.flags & (CIT_CALL_TOSTRING|CIT_TOSTRING_USE_KEY|CIT_TOSTRING_USE_CURRENT|CIT_TOSTRING_USE_INNER))) { 2717 zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "%s does not fetch string value (see CachingIterator::__construct)", Z_OBJCE_P(getThis())->name); 2718 return; 2719 } 2720 if (intern->u.caching.flags & CIT_TOSTRING_USE_KEY) { 2721 MAKE_COPY_ZVAL(&intern->current.key, return_value); 2722 convert_to_string(return_value); 2723 return; 2724 } else if (intern->u.caching.flags & CIT_TOSTRING_USE_CURRENT) { 2725 MAKE_COPY_ZVAL(&intern->current.data, return_value); 2726 convert_to_string(return_value); 2727 return; 2728 } 2729 if (intern->u.caching.zstr) { 2730 RETURN_STRINGL(Z_STRVAL_P(intern->u.caching.zstr), Z_STRLEN_P(intern->u.caching.zstr), 1); 2731 } else { 2732 RETURN_NULL(); 2733 } 2734} /* }}} */ 2735 2736/* {{{ proto void CachingIterator::offsetSet(mixed index, mixed newval) 2737 Set given index in cache */ 2738SPL_METHOD(CachingIterator, offsetSet) 2739{ 2740 spl_dual_it_object *intern; 2741 char *arKey; 2742 uint nKeyLength; 2743 zval *value; 2744 2745 SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis()); 2746 2747 if (!(intern->u.caching.flags & CIT_FULL_CACHE)) { 2748 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); 2749 return; 2750 } 2751 2752 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz", &arKey, &nKeyLength, &value) == FAILURE) { 2753 return; 2754 } 2755 2756 Z_ADDREF_P(value); 2757 zend_symtable_update(HASH_OF(intern->u.caching.zcache), arKey, nKeyLength+1, &value, sizeof(value), NULL); 2758} 2759/* }}} */ 2760 2761/* {{{ proto string CachingIterator::offsetGet(mixed index) 2762 Return the internal cache if used */ 2763SPL_METHOD(CachingIterator, offsetGet) 2764{ 2765 spl_dual_it_object *intern; 2766 char *arKey; 2767 uint nKeyLength; 2768 zval **value; 2769 2770 SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis()); 2771 2772 if (!(intern->u.caching.flags & CIT_FULL_CACHE)) { 2773 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); 2774 return; 2775 } 2776 2777 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &arKey, &nKeyLength) == FAILURE) { 2778 return; 2779 } 2780 2781 if (zend_symtable_find(HASH_OF(intern->u.caching.zcache), arKey, nKeyLength+1, (void**)&value) == FAILURE) { 2782 zend_error(E_NOTICE, "Undefined index: %s", arKey); 2783 return; 2784 } 2785 2786 RETURN_ZVAL(*value, 1, 0); 2787} 2788/* }}} */ 2789 2790/* {{{ proto void CachingIterator::offsetUnset(mixed index) 2791 Unset given index in cache */ 2792SPL_METHOD(CachingIterator, offsetUnset) 2793{ 2794 spl_dual_it_object *intern; 2795 char *arKey; 2796 uint nKeyLength; 2797 2798 SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis()); 2799 2800 if (!(intern->u.caching.flags & CIT_FULL_CACHE)) { 2801 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); 2802 return; 2803 } 2804 2805 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &arKey, &nKeyLength) == FAILURE) { 2806 return; 2807 } 2808 2809 zend_symtable_del(HASH_OF(intern->u.caching.zcache), arKey, nKeyLength+1); 2810} 2811/* }}} */ 2812 2813/* {{{ proto bool CachingIterator::offsetExists(mixed index) 2814 Return whether the requested index exists */ 2815SPL_METHOD(CachingIterator, offsetExists) 2816{ 2817 spl_dual_it_object *intern; 2818 char *arKey; 2819 uint nKeyLength; 2820 2821 SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis()); 2822 2823 if (!(intern->u.caching.flags & CIT_FULL_CACHE)) { 2824 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); 2825 return; 2826 } 2827 2828 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &arKey, &nKeyLength) == FAILURE) { 2829 return; 2830 } 2831 2832 RETURN_BOOL(zend_symtable_exists(HASH_OF(intern->u.caching.zcache), arKey, nKeyLength+1)); 2833} 2834/* }}} */ 2835 2836/* {{{ proto bool CachingIterator::getCache() 2837 Return the cache */ 2838SPL_METHOD(CachingIterator, getCache) 2839{ 2840 spl_dual_it_object *intern; 2841 2842 if (zend_parse_parameters_none() == FAILURE) { 2843 return; 2844 } 2845 2846 SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis()); 2847 2848 if (!(intern->u.caching.flags & CIT_FULL_CACHE)) { 2849 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); 2850 return; 2851 } 2852 2853 RETURN_ZVAL(intern->u.caching.zcache, 1, 0); 2854} 2855/* }}} */ 2856 2857/* {{{ proto int CachingIterator::getFlags() 2858 Return the internal flags */ 2859SPL_METHOD(CachingIterator, getFlags) 2860{ 2861 spl_dual_it_object *intern; 2862 2863 if (zend_parse_parameters_none() == FAILURE) { 2864 return; 2865 } 2866 2867 SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis()); 2868 2869 RETURN_LONG(intern->u.caching.flags); 2870} 2871/* }}} */ 2872 2873/* {{{ proto void CachingIterator::setFlags(int flags) 2874 Set the internal flags */ 2875SPL_METHOD(CachingIterator, setFlags) 2876{ 2877 spl_dual_it_object *intern; 2878 long flags; 2879 2880 SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis()); 2881 2882 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &flags) == FAILURE) { 2883 return; 2884 } 2885 2886 if (spl_cit_check_flags(flags) != SUCCESS) { 2887 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); 2888 return; 2889 } 2890 if ((intern->u.caching.flags & CIT_CALL_TOSTRING) != 0 && (flags & CIT_CALL_TOSTRING) == 0) { 2891 zend_throw_exception(spl_ce_InvalidArgumentException, "Unsetting flag CALL_TO_STRING is not possible", 0 TSRMLS_CC); 2892 return; 2893 } 2894 if ((intern->u.caching.flags & CIT_TOSTRING_USE_INNER) != 0 && (flags & CIT_TOSTRING_USE_INNER) == 0) { 2895 zend_throw_exception(spl_ce_InvalidArgumentException, "Unsetting flag TOSTRING_USE_INNER is not possible", 0 TSRMLS_CC); 2896 return; 2897 } 2898 if ((flags & CIT_FULL_CACHE) != 0 && (intern->u.caching.flags & CIT_FULL_CACHE) == 0) { 2899 /* clear on (re)enable */ 2900 zend_hash_clean(HASH_OF(intern->u.caching.zcache)); 2901 } 2902 intern->u.caching.flags = (intern->u.caching.flags & ~CIT_PUBLIC) | (flags & CIT_PUBLIC); 2903} 2904/* }}} */ 2905 2906/* {{{ proto void CachingIterator::count() 2907 Number of cached elements */ 2908SPL_METHOD(CachingIterator, count) 2909{ 2910 spl_dual_it_object *intern; 2911 2912 if (zend_parse_parameters_none() == FAILURE) { 2913 return; 2914 } 2915 2916 SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis()); 2917 2918 if (!(intern->u.caching.flags & CIT_FULL_CACHE)) { 2919 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); 2920 return; 2921 } 2922 2923 RETURN_LONG(zend_hash_num_elements(HASH_OF(intern->u.caching.zcache))); 2924} 2925/* }}} */ 2926 2927ZEND_BEGIN_ARG_INFO_EX(arginfo_caching_it___construct, 0, 0, 1) 2928 ZEND_ARG_OBJ_INFO(0, iterator, Iterator, 0) 2929 ZEND_ARG_INFO(0, flags) 2930ZEND_END_ARG_INFO(); 2931 2932ZEND_BEGIN_ARG_INFO(arginfo_caching_it_setFlags, 0) 2933 ZEND_ARG_INFO(0, flags) 2934ZEND_END_ARG_INFO(); 2935 2936ZEND_BEGIN_ARG_INFO(arginfo_caching_it_offsetGet, 0) 2937 ZEND_ARG_INFO(0, index) 2938ZEND_END_ARG_INFO(); 2939 2940ZEND_BEGIN_ARG_INFO(arginfo_caching_it_offsetSet, 0) 2941 ZEND_ARG_INFO(0, index) 2942 ZEND_ARG_INFO(0, newval) 2943ZEND_END_ARG_INFO(); 2944 2945static const zend_function_entry spl_funcs_CachingIterator[] = { 2946 SPL_ME(CachingIterator, __construct, arginfo_caching_it___construct, ZEND_ACC_PUBLIC) 2947 SPL_ME(CachingIterator, rewind, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) 2948 SPL_ME(CachingIterator, valid, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) 2949 SPL_ME(dual_it, key, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) 2950 SPL_ME(dual_it, current, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) 2951 SPL_ME(CachingIterator, next, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) 2952 SPL_ME(CachingIterator, hasNext, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) 2953 SPL_ME(CachingIterator, __toString, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) 2954 SPL_ME(dual_it, getInnerIterator, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) 2955 SPL_ME(CachingIterator, getFlags, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) 2956 SPL_ME(CachingIterator, setFlags, arginfo_caching_it_setFlags, ZEND_ACC_PUBLIC) 2957 SPL_ME(CachingIterator, offsetGet, arginfo_caching_it_offsetGet, ZEND_ACC_PUBLIC) 2958 SPL_ME(CachingIterator, offsetSet, arginfo_caching_it_offsetSet, ZEND_ACC_PUBLIC) 2959 SPL_ME(CachingIterator, offsetUnset, arginfo_caching_it_offsetGet, ZEND_ACC_PUBLIC) 2960 SPL_ME(CachingIterator, offsetExists, arginfo_caching_it_offsetGet, ZEND_ACC_PUBLIC) 2961 SPL_ME(CachingIterator, getCache, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) 2962 SPL_ME(CachingIterator, count, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) 2963 PHP_FE_END 2964}; 2965 2966/* {{{ proto void RecursiveCachingIterator::__construct(RecursiveIterator it [, flags = CIT_CALL_TOSTRING]) 2967 Create an iterator from a RecursiveIterator */ 2968SPL_METHOD(RecursiveCachingIterator, __construct) 2969{ 2970 spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_RecursiveCachingIterator, spl_ce_RecursiveIterator, DIT_RecursiveCachingIterator); 2971} /* }}} */ 2972 2973/* {{{ proto bool RecursiveCachingIterator::hasChildren() 2974 Check whether the current element of the inner iterator has children */ 2975SPL_METHOD(RecursiveCachingIterator, hasChildren) 2976{ 2977 spl_dual_it_object *intern; 2978 2979 if (zend_parse_parameters_none() == FAILURE) { 2980 return; 2981 } 2982 2983 SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis()); 2984 2985 RETURN_BOOL(intern->u.caching.zchildren); 2986} /* }}} */ 2987 2988/* {{{ proto RecursiveCachingIterator RecursiveCachingIterator::getChildren() 2989 Return the inner iterator's children as a RecursiveCachingIterator */ 2990SPL_METHOD(RecursiveCachingIterator, getChildren) 2991{ 2992 spl_dual_it_object *intern; 2993 2994 if (zend_parse_parameters_none() == FAILURE) { 2995 return; 2996 } 2997 2998 SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis()); 2999 3000 if (intern->u.caching.zchildren) { 3001 RETURN_ZVAL(intern->u.caching.zchildren, 1, 0); 3002 } else { 3003 RETURN_NULL(); 3004 } 3005} /* }}} */ 3006 3007ZEND_BEGIN_ARG_INFO_EX(arginfo_caching_rec_it___construct, 0, ZEND_RETURN_VALUE, 1) 3008 ZEND_ARG_OBJ_INFO(0, iterator, Iterator, 0) 3009 ZEND_ARG_INFO(0, flags) 3010ZEND_END_ARG_INFO(); 3011 3012static const zend_function_entry spl_funcs_RecursiveCachingIterator[] = { 3013 SPL_ME(RecursiveCachingIterator, __construct, arginfo_caching_rec_it___construct, ZEND_ACC_PUBLIC) 3014 SPL_ME(RecursiveCachingIterator, hasChildren, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) 3015 SPL_ME(RecursiveCachingIterator, getChildren, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) 3016 PHP_FE_END 3017}; 3018 3019/* {{{ proto void IteratorIterator::__construct(Traversable it) 3020 Create an iterator from anything that is traversable */ 3021SPL_METHOD(IteratorIterator, __construct) 3022{ 3023 spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_IteratorIterator, zend_ce_traversable, DIT_IteratorIterator); 3024} /* }}} */ 3025 3026ZEND_BEGIN_ARG_INFO(arginfo_iterator_it___construct, 0) 3027 ZEND_ARG_OBJ_INFO(0, iterator, Traversable, 0) 3028ZEND_END_ARG_INFO(); 3029 3030static const zend_function_entry spl_funcs_IteratorIterator[] = { 3031 SPL_ME(IteratorIterator, __construct, arginfo_iterator_it___construct, ZEND_ACC_PUBLIC) 3032 SPL_ME(dual_it, rewind, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) 3033 SPL_ME(dual_it, valid, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) 3034 SPL_ME(dual_it, key, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) 3035 SPL_ME(dual_it, current, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) 3036 SPL_ME(dual_it, next, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) 3037 SPL_ME(dual_it, getInnerIterator, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) 3038 PHP_FE_END 3039}; 3040 3041/* {{{ proto void NoRewindIterator::__construct(Iterator it) 3042 Create an iterator from another iterator */ 3043SPL_METHOD(NoRewindIterator, __construct) 3044{ 3045 spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_NoRewindIterator, zend_ce_iterator, DIT_NoRewindIterator); 3046} /* }}} */ 3047 3048/* {{{ proto void NoRewindIterator::rewind() 3049 Prevent a call to inner iterators rewind() */ 3050SPL_METHOD(NoRewindIterator, rewind) 3051{ 3052 if (zend_parse_parameters_none() == FAILURE) { 3053 return; 3054 } 3055 /* nothing to do */ 3056} /* }}} */ 3057 3058/* {{{ proto bool NoRewindIterator::valid() 3059 Return inner iterators valid() */ 3060SPL_METHOD(NoRewindIterator, valid) 3061{ 3062 spl_dual_it_object *intern; 3063 3064 if (zend_parse_parameters_none() == FAILURE) { 3065 return; 3066 } 3067 3068 SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis()); 3069 RETURN_BOOL(intern->inner.iterator->funcs->valid(intern->inner.iterator TSRMLS_CC) == SUCCESS); 3070} /* }}} */ 3071 3072/* {{{ proto mixed NoRewindIterator::key() 3073 Return inner iterators key() */ 3074SPL_METHOD(NoRewindIterator, key) 3075{ 3076 spl_dual_it_object *intern; 3077 3078 if (zend_parse_parameters_none() == FAILURE) { 3079 return; 3080 } 3081 3082 SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis()); 3083 3084 if (intern->inner.iterator->funcs->get_current_key) { 3085 intern->inner.iterator->funcs->get_current_key(intern->inner.iterator, return_value TSRMLS_CC); 3086 } else { 3087 RETURN_NULL(); 3088 } 3089} /* }}} */ 3090 3091/* {{{ proto mixed NoRewindIterator::current() 3092 Return inner iterators current() */ 3093SPL_METHOD(NoRewindIterator, current) 3094{ 3095 spl_dual_it_object *intern; 3096 zval **data; 3097 3098 if (zend_parse_parameters_none() == FAILURE) { 3099 return; 3100 } 3101 3102 SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis()); 3103 intern->inner.iterator->funcs->get_current_data(intern->inner.iterator, &data TSRMLS_CC); 3104 if (data && *data) { 3105 RETURN_ZVAL(*data, 1, 0); 3106 } 3107} /* }}} */ 3108 3109/* {{{ proto void NoRewindIterator::next() 3110 Return inner iterators next() */ 3111SPL_METHOD(NoRewindIterator, next) 3112{ 3113 spl_dual_it_object *intern; 3114 3115 if (zend_parse_parameters_none() == FAILURE) { 3116 return; 3117 } 3118 3119 SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis()); 3120 intern->inner.iterator->funcs->move_forward(intern->inner.iterator TSRMLS_CC); 3121} /* }}} */ 3122 3123ZEND_BEGIN_ARG_INFO(arginfo_norewind_it___construct, 0) 3124 ZEND_ARG_OBJ_INFO(0, iterator, Iterator, 0) 3125ZEND_END_ARG_INFO(); 3126 3127static const zend_function_entry spl_funcs_NoRewindIterator[] = { 3128 SPL_ME(NoRewindIterator, __construct, arginfo_norewind_it___construct, ZEND_ACC_PUBLIC) 3129 SPL_ME(NoRewindIterator, rewind, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) 3130 SPL_ME(NoRewindIterator, valid, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) 3131 SPL_ME(NoRewindIterator, key, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) 3132 SPL_ME(NoRewindIterator, current, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) 3133 SPL_ME(NoRewindIterator, next, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) 3134 SPL_ME(dual_it, getInnerIterator, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) 3135 PHP_FE_END 3136}; 3137 3138/* {{{ proto void InfiniteIterator::__construct(Iterator it) 3139 Create an iterator from another iterator */ 3140SPL_METHOD(InfiniteIterator, __construct) 3141{ 3142 spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_InfiniteIterator, zend_ce_iterator, DIT_InfiniteIterator); 3143} /* }}} */ 3144 3145/* {{{ proto void InfiniteIterator::next() 3146 Prevent a call to inner iterators rewind() (internally the current data will be fetched if valid()) */ 3147SPL_METHOD(InfiniteIterator, next) 3148{ 3149 spl_dual_it_object *intern; 3150 3151 if (zend_parse_parameters_none() == FAILURE) { 3152 return; 3153 } 3154 3155 SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis()); 3156 3157 spl_dual_it_next(intern, 1 TSRMLS_CC); 3158 if (spl_dual_it_valid(intern TSRMLS_CC) == SUCCESS) { 3159 spl_dual_it_fetch(intern, 0 TSRMLS_CC); 3160 } else { 3161 spl_dual_it_rewind(intern TSRMLS_CC); 3162 if (spl_dual_it_valid(intern TSRMLS_CC) == SUCCESS) { 3163 spl_dual_it_fetch(intern, 0 TSRMLS_CC); 3164 } 3165 } 3166} /* }}} */ 3167 3168static const zend_function_entry spl_funcs_InfiniteIterator[] = { 3169 SPL_ME(InfiniteIterator, __construct, arginfo_norewind_it___construct, ZEND_ACC_PUBLIC) 3170 SPL_ME(InfiniteIterator, next, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) 3171 PHP_FE_END 3172}; 3173 3174/* {{{ proto void EmptyIterator::rewind() 3175 Does nothing */ 3176SPL_METHOD(EmptyIterator, rewind) 3177{ 3178 if (zend_parse_parameters_none() == FAILURE) { 3179 return; 3180 } 3181} /* }}} */ 3182 3183/* {{{ proto false EmptyIterator::valid() 3184 Return false */ 3185SPL_METHOD(EmptyIterator, valid) 3186{ 3187 if (zend_parse_parameters_none() == FAILURE) { 3188 return; 3189 } 3190 RETURN_FALSE; 3191} /* }}} */ 3192 3193/* {{{ proto void EmptyIterator::key() 3194 Throws exception BadMethodCallException */ 3195SPL_METHOD(EmptyIterator, key) 3196{ 3197 if (zend_parse_parameters_none() == FAILURE) { 3198 return; 3199 } 3200 zend_throw_exception(spl_ce_BadMethodCallException, "Accessing the key of an EmptyIterator", 0 TSRMLS_CC); 3201} /* }}} */ 3202 3203/* {{{ proto void EmptyIterator::current() 3204 Throws exception BadMethodCallException */ 3205SPL_METHOD(EmptyIterator, current) 3206{ 3207 if (zend_parse_parameters_none() == FAILURE) { 3208 return; 3209 } 3210 zend_throw_exception(spl_ce_BadMethodCallException, "Accessing the value of an EmptyIterator", 0 TSRMLS_CC); 3211} /* }}} */ 3212 3213/* {{{ proto void EmptyIterator::next() 3214 Does nothing */ 3215SPL_METHOD(EmptyIterator, next) 3216{ 3217 if (zend_parse_parameters_none() == FAILURE) { 3218 return; 3219 } 3220} /* }}} */ 3221 3222static const zend_function_entry spl_funcs_EmptyIterator[] = { 3223 SPL_ME(EmptyIterator, rewind, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) 3224 SPL_ME(EmptyIterator, valid, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) 3225 SPL_ME(EmptyIterator, key, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) 3226 SPL_ME(EmptyIterator, current, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) 3227 SPL_ME(EmptyIterator, next, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) 3228 PHP_FE_END 3229}; 3230 3231int spl_append_it_next_iterator(spl_dual_it_object *intern TSRMLS_DC) /* {{{*/ 3232{ 3233 spl_dual_it_free(intern TSRMLS_CC); 3234 3235 if (intern->inner.zobject) { 3236 zval_ptr_dtor(&intern->inner.zobject); 3237 intern->inner.zobject = NULL; 3238 intern->inner.ce = NULL; 3239 intern->inner.object = NULL; 3240 if (intern->inner.iterator) { 3241 intern->inner.iterator->funcs->dtor(intern->inner.iterator TSRMLS_CC); 3242 intern->inner.iterator = NULL; 3243 } 3244 } 3245 if (intern->u.append.iterator->funcs->valid(intern->u.append.iterator TSRMLS_CC) == SUCCESS) { 3246 zval **it; 3247 3248 intern->u.append.iterator->funcs->get_current_data(intern->u.append.iterator, &it TSRMLS_CC); 3249 Z_ADDREF_PP(it); 3250 intern->inner.zobject = *it; 3251 intern->inner.ce = Z_OBJCE_PP(it); 3252 intern->inner.object = zend_object_store_get_object(*it TSRMLS_CC); 3253 intern->inner.iterator = intern->inner.ce->get_iterator(intern->inner.ce, *it, 0 TSRMLS_CC); 3254 spl_dual_it_rewind(intern TSRMLS_CC); 3255 return SUCCESS; 3256 } else { 3257 return FAILURE; 3258 } 3259} /* }}} */ 3260 3261void spl_append_it_fetch(spl_dual_it_object *intern TSRMLS_DC) /* {{{*/ 3262{ 3263 while (spl_dual_it_valid(intern TSRMLS_CC) != SUCCESS) { 3264 intern->u.append.iterator->funcs->move_forward(intern->u.append.iterator TSRMLS_CC); 3265 if (spl_append_it_next_iterator(intern TSRMLS_CC) != SUCCESS) { 3266 return; 3267 } 3268 } 3269 spl_dual_it_fetch(intern, 0 TSRMLS_CC); 3270} /* }}} */ 3271 3272void spl_append_it_next(spl_dual_it_object *intern TSRMLS_DC) /* {{{ */ 3273{ 3274 if (spl_dual_it_valid(intern TSRMLS_CC) == SUCCESS) { 3275 spl_dual_it_next(intern, 1 TSRMLS_CC); 3276 } 3277 spl_append_it_fetch(intern TSRMLS_CC); 3278} /* }}} */ 3279 3280/* {{{ proto void AppendIterator::__construct() 3281 Create an AppendIterator */ 3282SPL_METHOD(AppendIterator, __construct) 3283{ 3284 spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_AppendIterator, zend_ce_iterator, DIT_AppendIterator); 3285} /* }}} */ 3286 3287/* {{{ proto void AppendIterator::append(Iterator it) 3288 Append an iterator */ 3289SPL_METHOD(AppendIterator, append) 3290{ 3291 spl_dual_it_object *intern; 3292 zval *it; 3293 3294 SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis()); 3295 3296 if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "O", &it, zend_ce_iterator) == FAILURE) { 3297 return; 3298 } 3299 spl_array_iterator_append(intern->u.append.zarrayit, it TSRMLS_CC); 3300 3301 if (!intern->inner.iterator || spl_dual_it_valid(intern TSRMLS_CC) != SUCCESS) { 3302 if (intern->u.append.iterator->funcs->valid(intern->u.append.iterator TSRMLS_CC) != SUCCESS) { 3303 intern->u.append.iterator->funcs->rewind(intern->u.append.iterator TSRMLS_CC); 3304 } 3305 do { 3306 spl_append_it_next_iterator(intern TSRMLS_CC); 3307 } while (intern->inner.zobject != it); 3308 spl_append_it_fetch(intern TSRMLS_CC); 3309 } 3310} /* }}} */ 3311 3312/* {{{ proto void AppendIterator::rewind() 3313 Rewind to the first iterator and rewind the first iterator, too */ 3314SPL_METHOD(AppendIterator, rewind) 3315{ 3316 spl_dual_it_object *intern; 3317 3318 if (zend_parse_parameters_none() == FAILURE) { 3319 return; 3320 } 3321 3322 SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis()); 3323 3324 intern->u.append.iterator->funcs->rewind(intern->u.append.iterator TSRMLS_CC); 3325 if (spl_append_it_next_iterator(intern TSRMLS_CC) == SUCCESS) { 3326 spl_append_it_fetch(intern TSRMLS_CC); 3327 } 3328} /* }}} */ 3329 3330/* {{{ proto bool AppendIterator::valid() 3331 Check if the current state is valid */ 3332SPL_METHOD(AppendIterator, valid) 3333{ 3334 spl_dual_it_object *intern; 3335 3336 if (zend_parse_parameters_none() == FAILURE) { 3337 return; 3338 } 3339 3340 SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis()); 3341 3342 RETURN_BOOL(intern->current.data); 3343} /* }}} */ 3344 3345/* {{{ proto void AppendIterator::next() 3346 Forward to next element */ 3347SPL_METHOD(AppendIterator, next) 3348{ 3349 spl_dual_it_object *intern; 3350 3351 if (zend_parse_parameters_none() == FAILURE) { 3352 return; 3353 } 3354 3355 SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis()); 3356 3357 spl_append_it_next(intern TSRMLS_CC); 3358} /* }}} */ 3359 3360/* {{{ proto int AppendIterator::getIteratorIndex() 3361 Get index of iterator */ 3362SPL_METHOD(AppendIterator, getIteratorIndex) 3363{ 3364 spl_dual_it_object *intern; 3365 3366 if (zend_parse_parameters_none() == FAILURE) { 3367 return; 3368 } 3369 3370 SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis()); 3371 3372 APPENDIT_CHECK_CTOR(intern); 3373 spl_array_iterator_key(intern->u.append.zarrayit, return_value TSRMLS_CC); 3374} /* }}} */ 3375 3376/* {{{ proto ArrayIterator AppendIterator::getArrayIterator() 3377 Get access to inner ArrayIterator */ 3378SPL_METHOD(AppendIterator, getArrayIterator) 3379{ 3380 spl_dual_it_object *intern; 3381 3382 if (zend_parse_parameters_none() == FAILURE) { 3383 return; 3384 } 3385 3386 SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis()); 3387 3388 RETURN_ZVAL(intern->u.append.zarrayit, 1, 0); 3389} /* }}} */ 3390 3391ZEND_BEGIN_ARG_INFO(arginfo_append_it_append, 0) 3392 ZEND_ARG_OBJ_INFO(0, iterator, Iterator, 0) 3393ZEND_END_ARG_INFO(); 3394 3395static const zend_function_entry spl_funcs_AppendIterator[] = { 3396 SPL_ME(AppendIterator, __construct, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) 3397 SPL_ME(AppendIterator, append, arginfo_append_it_append, ZEND_ACC_PUBLIC) 3398 SPL_ME(AppendIterator, rewind, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) 3399 SPL_ME(AppendIterator, valid, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) 3400 SPL_ME(dual_it, key, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) 3401 SPL_ME(dual_it, current, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) 3402 SPL_ME(AppendIterator, next, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) 3403 SPL_ME(dual_it, getInnerIterator, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) 3404 SPL_ME(AppendIterator, getIteratorIndex, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) 3405 SPL_ME(AppendIterator, getArrayIterator, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) 3406 PHP_FE_END 3407}; 3408 3409PHPAPI int spl_iterator_apply(zval *obj, spl_iterator_apply_func_t apply_func, void *puser TSRMLS_DC) 3410{ 3411 zend_object_iterator *iter; 3412 zend_class_entry *ce = Z_OBJCE_P(obj); 3413 3414 iter = ce->get_iterator(ce, obj, 0 TSRMLS_CC); 3415 3416 if (EG(exception)) { 3417 goto done; 3418 } 3419 3420 iter->index = 0; 3421 if (iter->funcs->rewind) { 3422 iter->funcs->rewind(iter TSRMLS_CC); 3423 if (EG(exception)) { 3424 goto done; 3425 } 3426 } 3427 3428 while (iter->funcs->valid(iter TSRMLS_CC) == SUCCESS) { 3429 if (EG(exception)) { 3430 goto done; 3431 } 3432 if (apply_func(iter, puser TSRMLS_CC) == ZEND_HASH_APPLY_STOP || EG(exception)) { 3433 goto done; 3434 } 3435 iter->index++; 3436 iter->funcs->move_forward(iter TSRMLS_CC); 3437 if (EG(exception)) { 3438 goto done; 3439 } 3440 } 3441 3442done: 3443 if (iter) { 3444 iter->funcs->dtor(iter TSRMLS_CC); 3445 } 3446 return EG(exception) ? FAILURE : SUCCESS; 3447} 3448/* }}} */ 3449 3450static int spl_iterator_to_array_apply(zend_object_iterator *iter, void *puser TSRMLS_DC) /* {{{ */ 3451{ 3452 zval **data, *return_value = (zval*)puser; 3453 3454 iter->funcs->get_current_data(iter, &data TSRMLS_CC); 3455 if (EG(exception)) { 3456 return ZEND_HASH_APPLY_STOP; 3457 } 3458 if (data == NULL || *data == NULL) { 3459 return ZEND_HASH_APPLY_STOP; 3460 } 3461 if (iter->funcs->get_current_key) { 3462 zval key; 3463 iter->funcs->get_current_key(iter, &key TSRMLS_CC); 3464 if (EG(exception)) { 3465 return ZEND_HASH_APPLY_STOP; 3466 } 3467 array_set_zval_key(Z_ARRVAL_P(return_value), &key, *data); 3468 zval_dtor(&key); 3469 } else { 3470 Z_ADDREF_PP(data); 3471 add_next_index_zval(return_value, *data); 3472 } 3473 return ZEND_HASH_APPLY_KEEP; 3474} 3475/* }}} */ 3476 3477static int spl_iterator_to_values_apply(zend_object_iterator *iter, void *puser TSRMLS_DC) /* {{{ */ 3478{ 3479 zval **data, *return_value = (zval*)puser; 3480 3481 iter->funcs->get_current_data(iter, &data TSRMLS_CC); 3482 if (EG(exception)) { 3483 return ZEND_HASH_APPLY_STOP; 3484 } 3485 if (data == NULL || *data == NULL) { 3486 return ZEND_HASH_APPLY_STOP; 3487 } 3488 Z_ADDREF_PP(data); 3489 add_next_index_zval(return_value, *data); 3490 return ZEND_HASH_APPLY_KEEP; 3491} 3492/* }}} */ 3493 3494/* {{{ proto array iterator_to_array(Traversable it [, bool use_keys = true]) 3495 Copy the iterator into an array */ 3496PHP_FUNCTION(iterator_to_array) 3497{ 3498 zval *obj; 3499 zend_bool use_keys = 1; 3500 3501 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O|b", &obj, zend_ce_traversable, &use_keys) == FAILURE) { 3502 RETURN_FALSE; 3503 } 3504 3505 array_init(return_value); 3506 3507 if (spl_iterator_apply(obj, use_keys ? spl_iterator_to_array_apply : spl_iterator_to_values_apply, (void*)return_value TSRMLS_CC) != SUCCESS) { 3508 zval_dtor(return_value); 3509 RETURN_NULL(); 3510 } 3511} /* }}} */ 3512 3513static int spl_iterator_count_apply(zend_object_iterator *iter, void *puser TSRMLS_DC) /* {{{ */ 3514{ 3515 (*(long*)puser)++; 3516 return ZEND_HASH_APPLY_KEEP; 3517} 3518/* }}} */ 3519 3520/* {{{ proto int iterator_count(Traversable it) 3521 Count the elements in an iterator */ 3522PHP_FUNCTION(iterator_count) 3523{ 3524 zval *obj; 3525 long count = 0; 3526 3527 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &obj, zend_ce_traversable) == FAILURE) { 3528 RETURN_FALSE; 3529 } 3530 3531 if (spl_iterator_apply(obj, spl_iterator_count_apply, (void*)&count TSRMLS_CC) == SUCCESS) { 3532 RETURN_LONG(count); 3533 } 3534} 3535/* }}} */ 3536 3537typedef struct { 3538 zval *obj; 3539 zval *args; 3540 long count; 3541 zend_fcall_info fci; 3542 zend_fcall_info_cache fcc; 3543} spl_iterator_apply_info; 3544 3545static int spl_iterator_func_apply(zend_object_iterator *iter, void *puser TSRMLS_DC) /* {{{ */ 3546{ 3547 zval *retval; 3548 spl_iterator_apply_info *apply_info = (spl_iterator_apply_info*)puser; 3549 int result; 3550 3551 apply_info->count++; 3552 zend_fcall_info_call(&apply_info->fci, &apply_info->fcc, &retval, NULL TSRMLS_CC); 3553 if (retval) { 3554 result = zend_is_true(retval) ? ZEND_HASH_APPLY_KEEP : ZEND_HASH_APPLY_STOP; 3555 zval_ptr_dtor(&retval); 3556 } else { 3557 result = ZEND_HASH_APPLY_STOP; 3558 } 3559 return result; 3560} 3561/* }}} */ 3562 3563/* {{{ proto int iterator_apply(Traversable it, mixed function [, mixed params]) 3564 Calls a function for every element in an iterator */ 3565PHP_FUNCTION(iterator_apply) 3566{ 3567 spl_iterator_apply_info apply_info; 3568 3569 apply_info.args = NULL; 3570 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) { 3571 return; 3572 } 3573 3574 apply_info.count = 0; 3575 zend_fcall_info_args(&apply_info.fci, apply_info.args TSRMLS_CC); 3576 if (spl_iterator_apply(apply_info.obj, spl_iterator_func_apply, (void*)&apply_info TSRMLS_CC) == SUCCESS) { 3577 RETVAL_LONG(apply_info.count); 3578 } else { 3579 RETVAL_FALSE; 3580 } 3581 zend_fcall_info_args(&apply_info.fci, NULL TSRMLS_CC); 3582} 3583/* }}} */ 3584 3585static const zend_function_entry spl_funcs_OuterIterator[] = { 3586 SPL_ABSTRACT_ME(OuterIterator, getInnerIterator, arginfo_recursive_it_void) 3587 PHP_FE_END 3588}; 3589 3590static const zend_function_entry spl_funcs_Countable[] = { 3591 SPL_ABSTRACT_ME(Countable, count, arginfo_recursive_it_void) 3592 PHP_FE_END 3593}; 3594 3595/* {{{ PHP_MINIT_FUNCTION(spl_iterators) 3596 */ 3597PHP_MINIT_FUNCTION(spl_iterators) 3598{ 3599 REGISTER_SPL_INTERFACE(RecursiveIterator); 3600 REGISTER_SPL_ITERATOR(RecursiveIterator); 3601 3602 REGISTER_SPL_STD_CLASS_EX(RecursiveIteratorIterator, spl_RecursiveIteratorIterator_new, spl_funcs_RecursiveIteratorIterator); 3603 REGISTER_SPL_ITERATOR(RecursiveIteratorIterator); 3604 3605 memcpy(&spl_handlers_rec_it_it, zend_get_std_object_handlers(), sizeof(zend_object_handlers)); 3606 spl_handlers_rec_it_it.get_method = spl_recursive_it_get_method; 3607 spl_handlers_rec_it_it.clone_obj = NULL; 3608 3609 memcpy(&spl_handlers_dual_it, zend_get_std_object_handlers(), sizeof(zend_object_handlers)); 3610 spl_handlers_dual_it.get_method = spl_dual_it_get_method; 3611 /*spl_handlers_dual_it.call_method = spl_dual_it_call_method;*/ 3612 spl_handlers_dual_it.clone_obj = NULL; 3613 3614 spl_ce_RecursiveIteratorIterator->get_iterator = spl_recursive_it_get_iterator; 3615 spl_ce_RecursiveIteratorIterator->iterator_funcs.funcs = &spl_recursive_it_iterator_funcs; 3616 3617 REGISTER_SPL_CLASS_CONST_LONG(RecursiveIteratorIterator, "LEAVES_ONLY", RIT_LEAVES_ONLY); 3618 REGISTER_SPL_CLASS_CONST_LONG(RecursiveIteratorIterator, "SELF_FIRST", RIT_SELF_FIRST); 3619 REGISTER_SPL_CLASS_CONST_LONG(RecursiveIteratorIterator, "CHILD_FIRST", RIT_CHILD_FIRST); 3620 REGISTER_SPL_CLASS_CONST_LONG(RecursiveIteratorIterator, "CATCH_GET_CHILD", RIT_CATCH_GET_CHILD); 3621 3622 REGISTER_SPL_INTERFACE(OuterIterator); 3623 REGISTER_SPL_ITERATOR(OuterIterator); 3624 3625 REGISTER_SPL_STD_CLASS_EX(IteratorIterator, spl_dual_it_new, spl_funcs_IteratorIterator); 3626 REGISTER_SPL_ITERATOR(IteratorIterator); 3627 REGISTER_SPL_IMPLEMENTS(IteratorIterator, OuterIterator); 3628 3629 REGISTER_SPL_SUB_CLASS_EX(FilterIterator, IteratorIterator, spl_dual_it_new, spl_funcs_FilterIterator); 3630 spl_ce_FilterIterator->ce_flags |= ZEND_ACC_EXPLICIT_ABSTRACT_CLASS; 3631 3632 REGISTER_SPL_SUB_CLASS_EX(RecursiveFilterIterator, FilterIterator, spl_dual_it_new, spl_funcs_RecursiveFilterIterator); 3633 REGISTER_SPL_IMPLEMENTS(RecursiveFilterIterator, RecursiveIterator); 3634 3635 REGISTER_SPL_SUB_CLASS_EX(CallbackFilterIterator, FilterIterator, spl_dual_it_new, spl_funcs_CallbackFilterIterator); 3636 3637 REGISTER_SPL_SUB_CLASS_EX(RecursiveCallbackFilterIterator, CallbackFilterIterator, spl_dual_it_new, spl_funcs_RecursiveCallbackFilterIterator); 3638 REGISTER_SPL_IMPLEMENTS(RecursiveCallbackFilterIterator, RecursiveIterator); 3639 3640 3641 REGISTER_SPL_SUB_CLASS_EX(ParentIterator, RecursiveFilterIterator, spl_dual_it_new, spl_funcs_ParentIterator); 3642 3643 REGISTER_SPL_INTERFACE(Countable); 3644 REGISTER_SPL_INTERFACE(SeekableIterator); 3645 REGISTER_SPL_ITERATOR(SeekableIterator); 3646 3647 REGISTER_SPL_SUB_CLASS_EX(LimitIterator, IteratorIterator, spl_dual_it_new, spl_funcs_LimitIterator); 3648 3649 REGISTER_SPL_SUB_CLASS_EX(CachingIterator, IteratorIterator, spl_dual_it_new, spl_funcs_CachingIterator); 3650 REGISTER_SPL_IMPLEMENTS(CachingIterator, ArrayAccess); 3651 REGISTER_SPL_IMPLEMENTS(CachingIterator, Countable); 3652 3653 REGISTER_SPL_CLASS_CONST_LONG(CachingIterator, "CALL_TOSTRING", CIT_CALL_TOSTRING); 3654 REGISTER_SPL_CLASS_CONST_LONG(CachingIterator, "CATCH_GET_CHILD", CIT_CATCH_GET_CHILD); 3655 REGISTER_SPL_CLASS_CONST_LONG(CachingIterator, "TOSTRING_USE_KEY", CIT_TOSTRING_USE_KEY); 3656 REGISTER_SPL_CLASS_CONST_LONG(CachingIterator, "TOSTRING_USE_CURRENT", CIT_TOSTRING_USE_CURRENT); 3657 REGISTER_SPL_CLASS_CONST_LONG(CachingIterator, "TOSTRING_USE_INNER", CIT_TOSTRING_USE_INNER); 3658 REGISTER_SPL_CLASS_CONST_LONG(CachingIterator, "FULL_CACHE", CIT_FULL_CACHE); 3659 3660 REGISTER_SPL_SUB_CLASS_EX(RecursiveCachingIterator, CachingIterator, spl_dual_it_new, spl_funcs_RecursiveCachingIterator); 3661 REGISTER_SPL_IMPLEMENTS(RecursiveCachingIterator, RecursiveIterator); 3662 3663 REGISTER_SPL_SUB_CLASS_EX(NoRewindIterator, IteratorIterator, spl_dual_it_new, spl_funcs_NoRewindIterator); 3664 3665 REGISTER_SPL_SUB_CLASS_EX(AppendIterator, IteratorIterator, spl_dual_it_new, spl_funcs_AppendIterator); 3666 3667 REGISTER_SPL_IMPLEMENTS(RecursiveIteratorIterator, OuterIterator); 3668 3669 REGISTER_SPL_SUB_CLASS_EX(InfiniteIterator, IteratorIterator, spl_dual_it_new, spl_funcs_InfiniteIterator); 3670#if HAVE_PCRE || HAVE_BUNDLED_PCRE 3671 REGISTER_SPL_SUB_CLASS_EX(RegexIterator, FilterIterator, spl_dual_it_new, spl_funcs_RegexIterator); 3672 REGISTER_SPL_CLASS_CONST_LONG(RegexIterator, "USE_KEY", REGIT_USE_KEY); 3673 REGISTER_SPL_CLASS_CONST_LONG(RegexIterator, "MATCH", REGIT_MODE_MATCH); 3674 REGISTER_SPL_CLASS_CONST_LONG(RegexIterator, "GET_MATCH", REGIT_MODE_GET_MATCH); 3675 REGISTER_SPL_CLASS_CONST_LONG(RegexIterator, "ALL_MATCHES", REGIT_MODE_ALL_MATCHES); 3676 REGISTER_SPL_CLASS_CONST_LONG(RegexIterator, "SPLIT", REGIT_MODE_SPLIT); 3677 REGISTER_SPL_CLASS_CONST_LONG(RegexIterator, "REPLACE", REGIT_MODE_REPLACE); 3678 REGISTER_SPL_PROPERTY(RegexIterator, "replacement", 0); 3679 REGISTER_SPL_SUB_CLASS_EX(RecursiveRegexIterator, RegexIterator, spl_dual_it_new, spl_funcs_RecursiveRegexIterator); 3680 REGISTER_SPL_IMPLEMENTS(RecursiveRegexIterator, RecursiveIterator); 3681#else 3682 spl_ce_RegexIterator = NULL; 3683 spl_ce_RecursiveRegexIterator = NULL; 3684#endif 3685 3686 REGISTER_SPL_STD_CLASS_EX(EmptyIterator, NULL, spl_funcs_EmptyIterator); 3687 REGISTER_SPL_ITERATOR(EmptyIterator); 3688 3689 REGISTER_SPL_SUB_CLASS_EX(RecursiveTreeIterator, RecursiveIteratorIterator, spl_RecursiveTreeIterator_new, spl_funcs_RecursiveTreeIterator); 3690 REGISTER_SPL_CLASS_CONST_LONG(RecursiveTreeIterator, "BYPASS_CURRENT", RTIT_BYPASS_CURRENT); 3691 REGISTER_SPL_CLASS_CONST_LONG(RecursiveTreeIterator, "BYPASS_KEY", RTIT_BYPASS_KEY); 3692 REGISTER_SPL_CLASS_CONST_LONG(RecursiveTreeIterator, "PREFIX_LEFT", 0); 3693 REGISTER_SPL_CLASS_CONST_LONG(RecursiveTreeIterator, "PREFIX_MID_HAS_NEXT", 1); 3694 REGISTER_SPL_CLASS_CONST_LONG(RecursiveTreeIterator, "PREFIX_MID_LAST", 2); 3695 REGISTER_SPL_CLASS_CONST_LONG(RecursiveTreeIterator, "PREFIX_END_HAS_NEXT", 3); 3696 REGISTER_SPL_CLASS_CONST_LONG(RecursiveTreeIterator, "PREFIX_END_LAST", 4); 3697 REGISTER_SPL_CLASS_CONST_LONG(RecursiveTreeIterator, "PREFIX_RIGHT", 5); 3698 3699 return SUCCESS; 3700} 3701/* }}} */ 3702 3703/* 3704 * Local variables: 3705 * tab-width: 4 3706 * c-basic-offset: 4 3707 * End: 3708 * vim600: fdm=marker 3709 * vim: noet sw=4 ts=4 3710 */ 3711