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