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

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

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