Annotation of embedaddon/php/ext/spl/spl_iterators.c, revision 1.1.1.1

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, &regex, &regex_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(&regex);
                   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:  */

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>