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

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

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