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