Back to index

php5  5.3.10
spl_iterators.c
Go to the documentation of this file.
00001 /*
00002    +----------------------------------------------------------------------+
00003    | PHP Version 5                                                        |
00004    +----------------------------------------------------------------------+
00005    | Copyright (c) 1997-2012 The PHP Group                                |
00006    +----------------------------------------------------------------------+
00007    | This source file is subject to version 3.01 of the PHP license,      |
00008    | that is bundled with this package in the file LICENSE, and is        |
00009    | available through the world-wide-web at the following url:           |
00010    | http://www.php.net/license/3_01.txt                                  |
00011    | If you did not receive a copy of the PHP license and are unable to   |
00012    | obtain it through the world-wide-web, please send a note to          |
00013    | license@php.net so we can mail you a copy immediately.               |
00014    +----------------------------------------------------------------------+
00015    | Authors: Marcus Boerger <helly@php.net>                              |
00016    +----------------------------------------------------------------------+
00017  */
00018 
00019 /* $Id: spl_iterators.c 321634 2012-01-01 13:15:04Z felipe $ */
00020 
00021 #ifdef HAVE_CONFIG_H
00022 # include "config.h"
00023 #endif
00024 
00025 #include "php.h"
00026 #include "php_ini.h"
00027 #include "ext/standard/info.h"
00028 #include "zend_exceptions.h"
00029 #include "zend_interfaces.h"
00030 
00031 #include "php_spl.h"
00032 #include "spl_functions.h"
00033 #include "spl_engine.h"
00034 #include "spl_iterators.h"
00035 #include "spl_directory.h"
00036 #include "spl_array.h"
00037 #include "spl_exceptions.h"
00038 #include "ext/standard/php_smart_str.h"
00039 
00040 #ifdef accept
00041 #undef accept
00042 #endif
00043 
00044 PHPAPI zend_class_entry *spl_ce_RecursiveIterator;
00045 PHPAPI zend_class_entry *spl_ce_RecursiveIteratorIterator;
00046 PHPAPI zend_class_entry *spl_ce_FilterIterator;
00047 PHPAPI zend_class_entry *spl_ce_RecursiveFilterIterator;
00048 PHPAPI zend_class_entry *spl_ce_ParentIterator;
00049 PHPAPI zend_class_entry *spl_ce_SeekableIterator;
00050 PHPAPI zend_class_entry *spl_ce_LimitIterator;
00051 PHPAPI zend_class_entry *spl_ce_CachingIterator;
00052 PHPAPI zend_class_entry *spl_ce_RecursiveCachingIterator;
00053 PHPAPI zend_class_entry *spl_ce_OuterIterator;
00054 PHPAPI zend_class_entry *spl_ce_IteratorIterator;
00055 PHPAPI zend_class_entry *spl_ce_NoRewindIterator;
00056 PHPAPI zend_class_entry *spl_ce_InfiniteIterator;
00057 PHPAPI zend_class_entry *spl_ce_EmptyIterator;
00058 PHPAPI zend_class_entry *spl_ce_AppendIterator;
00059 PHPAPI zend_class_entry *spl_ce_RegexIterator;
00060 PHPAPI zend_class_entry *spl_ce_RecursiveRegexIterator;
00061 PHPAPI zend_class_entry *spl_ce_Countable;
00062 PHPAPI zend_class_entry *spl_ce_RecursiveTreeIterator;
00063 
00064 ZEND_BEGIN_ARG_INFO(arginfo_recursive_it_void, 0)
00065 ZEND_END_ARG_INFO()
00066 
00067 const zend_function_entry spl_funcs_RecursiveIterator[] = {
00068        SPL_ABSTRACT_ME(RecursiveIterator, hasChildren,  arginfo_recursive_it_void)
00069        SPL_ABSTRACT_ME(RecursiveIterator, getChildren,  arginfo_recursive_it_void)
00070        PHP_FE_END
00071 };
00072 
00073 typedef enum {
00074        RIT_LEAVES_ONLY = 0,
00075        RIT_SELF_FIRST  = 1,
00076        RIT_CHILD_FIRST = 2
00077 } RecursiveIteratorMode;
00078 
00079 #define RIT_CATCH_GET_CHILD CIT_CATCH_GET_CHILD
00080 
00081 typedef enum {
00082        RTIT_BYPASS_CURRENT = 4,
00083        RTIT_BYPASS_KEY          = 8
00084 } RecursiveTreeIteratorFlags;
00085 
00086 typedef enum {
00087        RS_NEXT  = 0,
00088        RS_TEST  = 1,
00089        RS_SELF  = 2,
00090        RS_CHILD = 3,
00091        RS_START = 4
00092 } RecursiveIteratorState;
00093 
00094 typedef struct _spl_sub_iterator {
00095        zend_object_iterator    *iterator;
00096        zval                    *zobject;
00097        zend_class_entry        *ce;
00098        RecursiveIteratorState  state;
00099 } spl_sub_iterator;
00100 
00101 typedef struct _spl_recursive_it_object {
00102        zend_object              std;
00103        spl_sub_iterator         *iterators;
00104        int                      level;
00105        RecursiveIteratorMode    mode;
00106        int                      flags;
00107        int                      max_depth;
00108        zend_bool                in_iteration;
00109        zend_function            *beginIteration;
00110        zend_function            *endIteration;
00111        zend_function            *callHasChildren;
00112        zend_function            *callGetChildren;
00113        zend_function            *beginChildren;
00114        zend_function            *endChildren;
00115        zend_function            *nextElement;
00116        zend_class_entry         *ce;
00117        smart_str                prefix[6];
00118 } spl_recursive_it_object;
00119 
00120 typedef struct _spl_recursive_it_iterator {
00121        zend_object_iterator   intern;
00122        zval                   *zobject;
00123 } spl_recursive_it_iterator;
00124 
00125 static zend_object_handlers spl_handlers_rec_it_it;
00126 static zend_object_handlers spl_handlers_dual_it;
00127 
00128 #define SPL_FETCH_AND_CHECK_DUAL_IT(var, objzval) \
00129        do { \
00130               spl_dual_it_object *it = zend_object_store_get_object((objzval) TSRMLS_CC); \
00131               if (it->dit_type == DIT_Unknown) { \
00132                      zend_throw_exception_ex(spl_ce_LogicException, 0 TSRMLS_CC, \
00133                             "The object is in an invalid state as the parent constructor was not called"); \
00134                      return; \
00135               } \
00136               (var) = it; \
00137        } while (0)
00138 
00139 static void spl_recursive_it_dtor(zend_object_iterator *_iter TSRMLS_DC)
00140 {
00141        spl_recursive_it_iterator *iter   = (spl_recursive_it_iterator*)_iter;
00142        spl_recursive_it_object   *object = (spl_recursive_it_object*)_iter->data;
00143        zend_object_iterator      *sub_iter;
00144 
00145        while (object->level > 0) {
00146               sub_iter = object->iterators[object->level].iterator;
00147               sub_iter->funcs->dtor(sub_iter TSRMLS_CC);
00148               zval_ptr_dtor(&object->iterators[object->level--].zobject);
00149        }
00150        object->iterators = erealloc(object->iterators, sizeof(spl_sub_iterator));
00151        object->level = 0;
00152 
00153        zval_ptr_dtor(&iter->zobject);
00154        efree(iter);
00155 }
00156 
00157 static int spl_recursive_it_valid_ex(spl_recursive_it_object *object, zval *zthis TSRMLS_DC)
00158 {
00159        zend_object_iterator      *sub_iter;
00160        int                       level = object->level;
00161        
00162        while (level >=0) {
00163               sub_iter = object->iterators[level].iterator;
00164               if (sub_iter->funcs->valid(sub_iter TSRMLS_CC) == SUCCESS) {
00165                      return SUCCESS;
00166               }
00167               level--;
00168        }
00169        if (object->endIteration && object->in_iteration) {
00170               zend_call_method_with_0_params(&zthis, object->ce, &object->endIteration, "endIteration", NULL);
00171        }
00172        object->in_iteration = 0;
00173        return FAILURE;
00174 }
00175 
00176 static int spl_recursive_it_valid(zend_object_iterator *iter TSRMLS_DC)
00177 {
00178        spl_recursive_it_object   *object = (spl_recursive_it_object*)iter->data;
00179        
00180        return spl_recursive_it_valid_ex(object, ((spl_recursive_it_iterator*)iter)->zobject TSRMLS_CC);
00181 }
00182 
00183 static void spl_recursive_it_get_current_data(zend_object_iterator *iter, zval ***data TSRMLS_DC)
00184 {
00185        spl_recursive_it_object   *object = (spl_recursive_it_object*)iter->data;
00186        zend_object_iterator      *sub_iter = object->iterators[object->level].iterator;
00187        
00188        sub_iter->funcs->get_current_data(sub_iter, data TSRMLS_CC);
00189 }
00190 
00191 static int spl_recursive_it_get_current_key(zend_object_iterator *iter, char **str_key, uint *str_key_len, ulong *int_key TSRMLS_DC)
00192 {
00193        spl_recursive_it_object   *object = (spl_recursive_it_object*)iter->data;
00194        zend_object_iterator      *sub_iter = object->iterators[object->level].iterator;
00195 
00196        if (sub_iter->funcs->get_current_key) {
00197               return sub_iter->funcs->get_current_key(sub_iter, str_key, str_key_len, int_key TSRMLS_CC);
00198        } else {
00199               *int_key = iter->index;
00200               return HASH_KEY_IS_LONG;
00201        }
00202 }
00203 
00204 static void spl_recursive_it_move_forward_ex(spl_recursive_it_object *object, zval *zthis TSRMLS_DC)
00205 {
00206        zend_object_iterator      *iterator;
00207        zval                      *zobject;
00208        zend_class_entry          *ce;
00209        zval                      *retval, *child;
00210        zend_object_iterator      *sub_iter;
00211        int                       has_children;
00212 
00213        while (!EG(exception)) {
00214 next_step:
00215               iterator = object->iterators[object->level].iterator;
00216               switch (object->iterators[object->level].state) {
00217                      case RS_NEXT:
00218                             iterator->funcs->move_forward(iterator TSRMLS_CC);
00219                             if (EG(exception)) {
00220                                    if (!(object->flags & RIT_CATCH_GET_CHILD)) {
00221                                           return;
00222                                    } else {
00223                                           zend_clear_exception(TSRMLS_C);
00224                                    }
00225                             }
00226                      case RS_START:
00227                             if (iterator->funcs->valid(iterator TSRMLS_CC) == FAILURE) {
00228                                    break;
00229                             }
00230                             object->iterators[object->level].state = RS_TEST;                                   
00231                             /* break; */
00232                      case RS_TEST:
00233                             ce = object->iterators[object->level].ce;
00234                             zobject = object->iterators[object->level].zobject;
00235                             if (object->callHasChildren) {
00236                                    zend_call_method_with_0_params(&zthis, object->ce, &object->callHasChildren, "callHasChildren", &retval);
00237                             } else {
00238                                    zend_call_method_with_0_params(&zobject, ce, NULL, "haschildren", &retval);
00239                             }
00240                             if (EG(exception)) {
00241                                    if (!(object->flags & RIT_CATCH_GET_CHILD)) {
00242                                           object->iterators[object->level].state = RS_NEXT;
00243                                           return;
00244                                    } else {
00245                                           zend_clear_exception(TSRMLS_C);
00246                                    }
00247                             }
00248                             if (retval) {
00249                                    has_children = zend_is_true(retval);
00250                                    zval_ptr_dtor(&retval);
00251                                    if (has_children) {
00252                                           if (object->max_depth == -1 || object->max_depth > object->level) {
00253                                                  switch (object->mode) {
00254                                                  case RIT_LEAVES_ONLY:
00255                                                  case RIT_CHILD_FIRST:
00256                                                         object->iterators[object->level].state = RS_CHILD;
00257                                                         goto next_step;
00258                                                  case RIT_SELF_FIRST:
00259                                                         object->iterators[object->level].state = RS_SELF;
00260                                                         goto next_step;
00261                                                  }
00262                                           } else {
00263                                                  /* do not recurse into */
00264                                                  if (object->mode == RIT_LEAVES_ONLY) {
00265                                                         /* this is not a leave, so skip it */
00266                                                         object->iterators[object->level].state = RS_NEXT;
00267                                                         goto next_step;
00268                                                  }
00269                                           }
00270                                    }
00271                             }
00272                             if (object->nextElement) {
00273                                    zend_call_method_with_0_params(&zthis, object->ce, &object->nextElement, "nextelement", NULL);
00274                             }
00275                             object->iterators[object->level].state = RS_NEXT;
00276                             if (EG(exception)) {
00277                                    if (!(object->flags & RIT_CATCH_GET_CHILD)) {
00278                                           return;
00279                                    } else {
00280                                           zend_clear_exception(TSRMLS_C);
00281                                    }
00282                             }
00283                             return /* self */;
00284                      case RS_SELF:
00285                             if (object->nextElement && (object->mode == RIT_SELF_FIRST || object->mode == RIT_CHILD_FIRST)) {
00286                                    zend_call_method_with_0_params(&zthis, object->ce, &object->nextElement, "nextelement", NULL);
00287                             }
00288                             if (object->mode == RIT_SELF_FIRST) {
00289                                    object->iterators[object->level].state = RS_CHILD;
00290                             } else {
00291                                    object->iterators[object->level].state = RS_NEXT;
00292                             }
00293                             return /* self */;
00294                      case RS_CHILD:
00295                             ce = object->iterators[object->level].ce;
00296                             zobject = object->iterators[object->level].zobject;
00297                             if (object->callGetChildren) {
00298                                    zend_call_method_with_0_params(&zthis, object->ce, &object->callGetChildren, "callGetChildren", &child);
00299                             } else {
00300                                    zend_call_method_with_0_params(&zobject, ce, NULL, "getchildren", &child);
00301                             }
00302 
00303                             if (EG(exception)) {
00304                                    if (!(object->flags & RIT_CATCH_GET_CHILD)) {
00305                                           return;
00306                                    } else {
00307                                           zend_clear_exception(TSRMLS_C);
00308                                           if (child) {
00309                                                  zval_ptr_dtor(&child);
00310                                           }
00311                                           object->iterators[object->level].state = RS_NEXT;
00312                                           goto next_step;
00313                                    }
00314                             }
00315 
00316                             ce = child && Z_TYPE_P(child) == IS_OBJECT ? Z_OBJCE_P(child) : NULL;
00317                             if (!ce || !instanceof_function(ce, spl_ce_RecursiveIterator TSRMLS_CC)) {
00318                                    if (child) {
00319                                           zval_ptr_dtor(&child);
00320                                    }
00321                                    zend_throw_exception(spl_ce_UnexpectedValueException, "Objects returned by RecursiveIterator::getChildren() must implement RecursiveIterator", 0 TSRMLS_CC);
00322                                    return;
00323                             }
00324                             if (object->mode == RIT_CHILD_FIRST) {
00325                                    object->iterators[object->level].state = RS_SELF;
00326                             } else {
00327                                    object->iterators[object->level].state = RS_NEXT;
00328                             }
00329                             object->iterators = erealloc(object->iterators, sizeof(spl_sub_iterator) * (++object->level+1));
00330                             sub_iter = ce->get_iterator(ce, child, 0 TSRMLS_CC);
00331                             object->iterators[object->level].iterator = sub_iter;
00332                             object->iterators[object->level].zobject = child;
00333                             object->iterators[object->level].ce = ce;
00334                             object->iterators[object->level].state = RS_START;
00335                             if (sub_iter->funcs->rewind) {
00336                                    sub_iter->funcs->rewind(sub_iter TSRMLS_CC);
00337                             }
00338                             if (object->beginChildren) {
00339                                    zend_call_method_with_0_params(&zthis, object->ce, &object->beginChildren, "beginchildren", NULL);
00340                                    if (EG(exception)) {
00341                                           if (!(object->flags & RIT_CATCH_GET_CHILD)) {
00342                                                  return;
00343                                           } else {
00344                                                  zend_clear_exception(TSRMLS_C);
00345                                           }
00346                                    }
00347                             }
00348                             goto next_step;
00349               }
00350               /* no more elements */
00351               if (object->level > 0) {
00352                      if (object->endChildren) {
00353                             zend_call_method_with_0_params(&zthis, object->ce, &object->endChildren, "endchildren", NULL);
00354                             if (EG(exception)) {
00355                                    if (!(object->flags & RIT_CATCH_GET_CHILD)) {
00356                                           return;
00357                                    } else {
00358                                           zend_clear_exception(TSRMLS_C);
00359                                    }
00360                             }
00361                      }
00362                      iterator->funcs->dtor(iterator TSRMLS_CC);
00363                      zval_ptr_dtor(&object->iterators[object->level].zobject);
00364                      object->level--;
00365               } else {
00366                      return; /* done completeley */
00367               }
00368        }
00369 }
00370 
00371 static void spl_recursive_it_rewind_ex(spl_recursive_it_object *object, zval *zthis TSRMLS_DC)
00372 {
00373        zend_object_iterator      *sub_iter;
00374        
00375        if (!object->iterators) {
00376               php_error_docref(NULL TSRMLS_CC, E_ERROR, "The %s instance wasn't initialized properly", Z_OBJCE_P(zthis)->name);
00377        }
00378 
00379        while (object->level) {
00380               sub_iter = object->iterators[object->level].iterator;
00381               sub_iter->funcs->dtor(sub_iter TSRMLS_CC);
00382               zval_ptr_dtor(&object->iterators[object->level--].zobject);
00383               if (!EG(exception) && (!object->endChildren || object->endChildren->common.scope != spl_ce_RecursiveIteratorIterator)) {
00384                      zend_call_method_with_0_params(&zthis, object->ce, &object->endChildren, "endchildren", NULL);
00385               }
00386        }
00387        object->iterators = erealloc(object->iterators, sizeof(spl_sub_iterator));
00388        object->iterators[0].state = RS_START;
00389        sub_iter = object->iterators[0].iterator;
00390        if (sub_iter->funcs->rewind) {
00391               sub_iter->funcs->rewind(sub_iter TSRMLS_CC);
00392        }
00393        if (!EG(exception) && object->beginIteration && !object->in_iteration) {
00394               zend_call_method_with_0_params(&zthis, object->ce, &object->beginIteration, "beginIteration", NULL);
00395        }
00396        object->in_iteration = 1;
00397        spl_recursive_it_move_forward_ex(object, zthis TSRMLS_CC);
00398 }
00399 
00400 static void spl_recursive_it_move_forward(zend_object_iterator *iter TSRMLS_DC)
00401 {
00402        spl_recursive_it_move_forward_ex((spl_recursive_it_object*)iter->data, ((spl_recursive_it_iterator*)iter)->zobject TSRMLS_CC);
00403 }
00404 
00405 static void spl_recursive_it_rewind(zend_object_iterator *iter TSRMLS_DC)
00406 {
00407        spl_recursive_it_rewind_ex((spl_recursive_it_object*)iter->data, ((spl_recursive_it_iterator*)iter)->zobject TSRMLS_CC);
00408 }
00409 
00410 static zend_object_iterator *spl_recursive_it_get_iterator(zend_class_entry *ce, zval *zobject, int by_ref TSRMLS_DC)
00411 {
00412        spl_recursive_it_iterator *iterator;
00413        spl_recursive_it_object   *object;
00414 
00415        if (by_ref) {
00416               zend_error(E_ERROR, "An iterator cannot be used with foreach by reference");
00417        }
00418        iterator = emalloc(sizeof(spl_recursive_it_iterator));
00419        object   = (spl_recursive_it_object*)zend_object_store_get_object(zobject TSRMLS_CC);
00420        if (object->iterators == NULL) {
00421               zend_error(E_ERROR, "The object to be iterated is in an invalid state: "
00422                             "the parent constructor has not been called");
00423        }
00424 
00425        Z_ADDREF_P(zobject);
00426        iterator->intern.data = (void*)object;
00427        iterator->intern.funcs = ce->iterator_funcs.funcs;
00428        iterator->zobject = zobject;
00429        return (zend_object_iterator*)iterator;
00430 }
00431 
00432 zend_object_iterator_funcs spl_recursive_it_iterator_funcs = {
00433        spl_recursive_it_dtor,
00434        spl_recursive_it_valid,
00435        spl_recursive_it_get_current_data,
00436        spl_recursive_it_get_current_key,
00437        spl_recursive_it_move_forward,
00438        spl_recursive_it_rewind
00439 };
00440 
00441 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)
00442 {
00443        zval                      *object = getThis();
00444        spl_recursive_it_object   *intern;
00445        zval                      *iterator;
00446        zend_class_entry          *ce_iterator;
00447        long                       mode, flags;
00448        int                        inc_refcount = 1;
00449        zend_error_handling        error_handling;
00450 
00451        zend_replace_error_handling(EH_THROW, spl_ce_InvalidArgumentException, &error_handling TSRMLS_CC);
00452 
00453        switch(rit_type) {
00454               case RIT_RecursiveTreeIterator: {
00455 
00456                      zval *caching_it, *caching_it_flags, *user_caching_it_flags = NULL;
00457                      mode = RIT_SELF_FIRST;
00458                      flags = RTIT_BYPASS_KEY;
00459 
00460                      if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "o|lzl", &iterator, &flags, &user_caching_it_flags, &mode) == SUCCESS) {
00461                             if (instanceof_function(Z_OBJCE_P(iterator), zend_ce_aggregate TSRMLS_CC)) {
00462                                    zval *aggregate = iterator;
00463                                    zend_call_method_with_0_params(&aggregate, Z_OBJCE_P(aggregate), &Z_OBJCE_P(aggregate)->iterator_funcs.zf_new_iterator, "getiterator", &iterator);
00464                                    inc_refcount = 0;
00465                             }
00466 
00467                             MAKE_STD_ZVAL(caching_it_flags);
00468                             if (user_caching_it_flags) {
00469                                    ZVAL_ZVAL(caching_it_flags, user_caching_it_flags, 1, 0);
00470                             } else {
00471                                    ZVAL_LONG(caching_it_flags, CIT_CATCH_GET_CHILD);
00472                             }
00473                             spl_instantiate_arg_ex2(spl_ce_RecursiveCachingIterator, &caching_it, 1, iterator, caching_it_flags TSRMLS_CC);
00474                             zval_ptr_dtor(&caching_it_flags);
00475                             if (inc_refcount == 0 && iterator) {
00476                                    zval_ptr_dtor(&iterator);
00477                             }
00478                             iterator = caching_it;
00479                             inc_refcount = 0;
00480                      } else {
00481                             iterator = NULL;
00482                      }
00483                      break;
00484               }
00485               case RIT_RecursiveIteratorIterator:
00486               default: {
00487                      mode = RIT_LEAVES_ONLY;
00488                      flags = 0;
00489 
00490                      if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "o|ll", &iterator, &mode, &flags) == SUCCESS) {
00491                             if (instanceof_function(Z_OBJCE_P(iterator), zend_ce_aggregate TSRMLS_CC)) {
00492                                    zval *aggregate = iterator;
00493                                    zend_call_method_with_0_params(&aggregate, Z_OBJCE_P(aggregate), &Z_OBJCE_P(aggregate)->iterator_funcs.zf_new_iterator, "getiterator", &iterator);
00494                                    inc_refcount = 0;
00495                             }
00496                      } else {
00497                             iterator = NULL;
00498                      }
00499                      break;
00500               }
00501        }
00502        if (!iterator || !instanceof_function(Z_OBJCE_P(iterator), spl_ce_RecursiveIterator TSRMLS_CC)) {
00503               if (iterator && !inc_refcount) {
00504                      zval_ptr_dtor(&iterator);
00505               }
00506               zend_throw_exception(spl_ce_InvalidArgumentException, "An instance of RecursiveIterator or IteratorAggregate creating it is required", 0 TSRMLS_CC);
00507               zend_restore_error_handling(&error_handling TSRMLS_CC);
00508               return;
00509        }
00510 
00511        intern = (spl_recursive_it_object*)zend_object_store_get_object(object TSRMLS_CC);
00512        intern->iterators = emalloc(sizeof(spl_sub_iterator));
00513        intern->level = 0;
00514        intern->mode = mode;
00515        intern->flags = flags;
00516        intern->max_depth = -1;
00517        intern->in_iteration = 0;
00518        intern->ce = Z_OBJCE_P(object);
00519 
00520        zend_hash_find(&intern->ce->function_table, "beginiteration", sizeof("beginiteration"), (void **) &intern->beginIteration);
00521        if (intern->beginIteration->common.scope == ce_base) {
00522               intern->beginIteration = NULL;
00523        }
00524        zend_hash_find(&intern->ce->function_table, "enditeration", sizeof("enditeration"), (void **) &intern->endIteration);
00525        if (intern->endIteration->common.scope == ce_base) {
00526               intern->endIteration = NULL;
00527        }
00528        zend_hash_find(&intern->ce->function_table, "callhaschildren", sizeof("callHasChildren"), (void **) &intern->callHasChildren);
00529        if (intern->callHasChildren->common.scope == ce_base) {
00530               intern->callHasChildren = NULL;
00531        }
00532        zend_hash_find(&intern->ce->function_table, "callgetchildren", sizeof("callGetChildren"), (void **) &intern->callGetChildren);
00533        if (intern->callGetChildren->common.scope == ce_base) {
00534               intern->callGetChildren = NULL;
00535        }
00536        zend_hash_find(&intern->ce->function_table, "beginchildren", sizeof("beginchildren"), (void **) &intern->beginChildren);
00537        if (intern->beginChildren->common.scope == ce_base) {
00538               intern->beginChildren = NULL;
00539        }
00540        zend_hash_find(&intern->ce->function_table, "endchildren", sizeof("endchildren"), (void **) &intern->endChildren);
00541        if (intern->endChildren->common.scope == ce_base) {
00542               intern->endChildren = NULL;
00543        }
00544        zend_hash_find(&intern->ce->function_table, "nextelement", sizeof("nextElement"), (void **) &intern->nextElement);
00545        if (intern->nextElement->common.scope == ce_base) {
00546               intern->nextElement = NULL;
00547        }
00548        ce_iterator = Z_OBJCE_P(iterator); /* respect inheritance, don't use spl_ce_RecursiveIterator */
00549        intern->iterators[0].iterator = ce_iterator->get_iterator(ce_iterator, iterator, 0 TSRMLS_CC);
00550        if (inc_refcount) {
00551               Z_ADDREF_P(iterator);
00552        }
00553        intern->iterators[0].zobject = iterator;
00554        intern->iterators[0].ce = ce_iterator;
00555        intern->iterators[0].state = RS_START;
00556 
00557        zend_restore_error_handling(&error_handling TSRMLS_CC);
00558 
00559        if (EG(exception)) {
00560               zend_object_iterator *sub_iter;
00561 
00562               while (intern->level >= 0) {
00563                      sub_iter = intern->iterators[intern->level].iterator;
00564                      sub_iter->funcs->dtor(sub_iter TSRMLS_CC);
00565                      zval_ptr_dtor(&intern->iterators[intern->level--].zobject);
00566               }
00567               efree(intern->iterators);
00568               intern->iterators = NULL;
00569        }
00570 }
00571 
00572 /* {{{ proto void RecursiveIteratorIterator::__construct(RecursiveIterator|IteratorAggregate it [, int mode = RIT_LEAVES_ONLY [, int flags = 0]]) throws InvalidArgumentException
00573    Creates a RecursiveIteratorIterator from a RecursiveIterator. */
00574 SPL_METHOD(RecursiveIteratorIterator, __construct)
00575 {
00576        spl_recursive_it_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_RecursiveIteratorIterator, zend_ce_iterator, RIT_RecursiveIteratorIterator);
00577 } /* }}} */
00578 
00579 /* {{{ proto void RecursiveIteratorIterator::rewind()
00580    Rewind the iterator to the first element of the top level inner iterator. */
00581 SPL_METHOD(RecursiveIteratorIterator, rewind)
00582 {
00583        spl_recursive_it_object   *object = (spl_recursive_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
00584        
00585        if (zend_parse_parameters_none() == FAILURE) {
00586               return;
00587        }
00588 
00589        spl_recursive_it_rewind_ex(object, getThis() TSRMLS_CC);
00590 } /* }}} */
00591 
00592 /* {{{ proto bool RecursiveIteratorIterator::valid()
00593    Check whether the current position is valid */
00594 SPL_METHOD(RecursiveIteratorIterator, valid)
00595 {
00596        spl_recursive_it_object   *object = (spl_recursive_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
00597        
00598        if (zend_parse_parameters_none() == FAILURE) {
00599               return;
00600        }
00601 
00602        RETURN_BOOL(spl_recursive_it_valid_ex(object, getThis() TSRMLS_CC) == SUCCESS);
00603 } /* }}} */
00604 
00605 /* {{{ proto mixed RecursiveIteratorIterator::key()
00606    Access the current key */
00607 SPL_METHOD(RecursiveIteratorIterator, key)
00608 {
00609        spl_recursive_it_object   *object = (spl_recursive_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
00610        zend_object_iterator      *iterator = object->iterators[object->level].iterator;
00611        
00612        if (zend_parse_parameters_none() == FAILURE) {
00613               return;
00614        }
00615 
00616        if (iterator->funcs->get_current_key) {
00617               char *str_key;
00618               uint str_key_len;
00619               ulong int_key;
00620 
00621               switch (iterator->funcs->get_current_key(iterator, &str_key, &str_key_len, &int_key TSRMLS_CC)) {
00622                      case HASH_KEY_IS_LONG:
00623                             RETURN_LONG(int_key);
00624                             break;
00625                      case HASH_KEY_IS_STRING:
00626                             RETURN_STRINGL(str_key, str_key_len-1, 0);
00627                             break;
00628                      default:
00629                             RETURN_NULL();
00630               }
00631        } else {
00632               RETURN_NULL();
00633        }
00634 } /* }}} */
00635 
00636 /* {{{ proto mixed RecursiveIteratorIterator::current()
00637    Access the current element value */
00638 SPL_METHOD(RecursiveIteratorIterator, current)
00639 {
00640        spl_recursive_it_object   *object = (spl_recursive_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
00641        zend_object_iterator      *iterator = object->iterators[object->level].iterator;
00642        zval                      **data;
00643        
00644        if (zend_parse_parameters_none() == FAILURE) {
00645               return;
00646        }
00647 
00648        iterator->funcs->get_current_data(iterator, &data TSRMLS_CC);
00649        if (data && *data) {
00650               RETURN_ZVAL(*data, 1, 0);
00651        }
00652 } /* }}} */
00653 
00654 /* {{{ proto void RecursiveIteratorIterator::next()
00655    Move forward to the next element */
00656 SPL_METHOD(RecursiveIteratorIterator, next)
00657 {
00658        spl_recursive_it_object   *object = (spl_recursive_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
00659        
00660        if (zend_parse_parameters_none() == FAILURE) {
00661               return;
00662        }
00663 
00664        spl_recursive_it_move_forward_ex(object, getThis() TSRMLS_CC);
00665 } /* }}} */
00666 
00667 /* {{{ proto int RecursiveIteratorIterator::getDepth()
00668    Get the current depth of the recursive iteration */
00669 SPL_METHOD(RecursiveIteratorIterator, getDepth)
00670 {
00671        spl_recursive_it_object   *object = (spl_recursive_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
00672        
00673        if (zend_parse_parameters_none() == FAILURE) {
00674               return;
00675        }
00676        
00677        RETURN_LONG(object->level);
00678 } /* }}} */
00679 
00680 /* {{{ proto RecursiveIterator RecursiveIteratorIterator::getSubIterator([int level])
00681    The current active sub iterator or the iterator at specified level */
00682 SPL_METHOD(RecursiveIteratorIterator, getSubIterator)
00683 {
00684        spl_recursive_it_object   *object = (spl_recursive_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
00685        long  level = object->level;
00686        
00687        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &level) == FAILURE) {
00688               return;
00689        }
00690        if (level < 0 || level > object->level) {
00691               RETURN_NULL();
00692        }
00693        RETURN_ZVAL(object->iterators[level].zobject, 1, 0);
00694 } /* }}} */
00695 
00696 /* {{{ proto RecursiveIterator RecursiveIteratorIterator::getInnerIterator()
00697    The current active sub iterator */
00698 SPL_METHOD(RecursiveIteratorIterator, getInnerIterator)
00699 {
00700        spl_recursive_it_object   *object = (spl_recursive_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
00701        long  level = object->level;
00702        
00703        if (zend_parse_parameters_none() == FAILURE) {
00704               return;
00705        }
00706        
00707        RETURN_ZVAL(object->iterators[level].zobject, 1, 0);
00708 } /* }}} */
00709 
00710 /* {{{ proto RecursiveIterator RecursiveIteratorIterator::beginIteration()
00711    Called when iteration begins (after first rewind() call) */
00712 SPL_METHOD(RecursiveIteratorIterator, beginIteration)
00713 {
00714        if (zend_parse_parameters_none() == FAILURE) {
00715               return;
00716        }
00717        /* nothing to do */
00718 } /* }}} */
00719 
00720 /* {{{ proto RecursiveIterator RecursiveIteratorIterator::endIteration()
00721    Called when iteration ends (when valid() first returns false */
00722 SPL_METHOD(RecursiveIteratorIterator, endIteration)
00723 {
00724        if (zend_parse_parameters_none() == FAILURE) {
00725               return;
00726        }
00727        /* nothing to do */
00728 } /* }}} */
00729 
00730 /* {{{ proto bool RecursiveIteratorIterator::callHasChildren()
00731    Called for each element to test whether it has children */
00732 SPL_METHOD(RecursiveIteratorIterator, callHasChildren)
00733 {
00734        spl_recursive_it_object   *object = (spl_recursive_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
00735        zend_class_entry *ce = object->iterators[object->level].ce;
00736        zval *retval, *zobject;
00737        
00738        if (zend_parse_parameters_none() == FAILURE) {
00739               return;
00740        }
00741 
00742        zobject = object->iterators[object->level].zobject;
00743        if (!zobject) {
00744               RETURN_FALSE;
00745        } else {
00746               zend_call_method_with_0_params(&zobject, ce, NULL, "haschildren", &retval);
00747               if (retval) {
00748                      RETURN_ZVAL(retval, 0, 1);
00749               } else {
00750                      RETURN_FALSE;
00751               }
00752        }
00753 } /* }}} */
00754 
00755 /* {{{ proto RecursiveIterator RecursiveIteratorIterator::callGetChildren()
00756    Return children of current element */
00757 SPL_METHOD(RecursiveIteratorIterator, callGetChildren)
00758 {
00759        spl_recursive_it_object   *object = (spl_recursive_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
00760        zend_class_entry *ce = object->iterators[object->level].ce;
00761        zval *retval, *zobject;
00762        
00763        if (zend_parse_parameters_none() == FAILURE) {
00764               return;
00765        }
00766 
00767        zobject = object->iterators[object->level].zobject;
00768        if (!zobject) {
00769               return;
00770        } else {
00771               zend_call_method_with_0_params(&zobject, ce, NULL, "getchildren", &retval);
00772               if (retval) {
00773                      RETURN_ZVAL(retval, 0, 1);
00774               }
00775        }
00776 } /* }}} */
00777 
00778 /* {{{ proto void RecursiveIteratorIterator::beginChildren()
00779    Called when recursing one level down */
00780 SPL_METHOD(RecursiveIteratorIterator, beginChildren)
00781 {
00782        if (zend_parse_parameters_none() == FAILURE) {
00783               return;
00784        }
00785        /* nothing to do */
00786 } /* }}} */
00787 
00788 /* {{{ proto void RecursiveIteratorIterator::endChildren()
00789    Called when end recursing one level */
00790 SPL_METHOD(RecursiveIteratorIterator, endChildren)
00791 {
00792        if (zend_parse_parameters_none() == FAILURE) {
00793               return;
00794        }
00795        /* nothing to do */
00796 } /* }}} */
00797 
00798 /* {{{ proto void RecursiveIteratorIterator::nextElement()
00799    Called when the next element is available */
00800 SPL_METHOD(RecursiveIteratorIterator, nextElement)
00801 {
00802        if (zend_parse_parameters_none() == FAILURE) {
00803               return;
00804        }
00805        /* nothing to do */
00806 } /* }}} */
00807 
00808 /* {{{ proto void RecursiveIteratorIterator::setMaxDepth([$max_depth = -1])
00809    Set the maximum allowed depth (or any depth if pmax_depth = -1] */
00810 SPL_METHOD(RecursiveIteratorIterator, setMaxDepth)
00811 {
00812        spl_recursive_it_object   *object = (spl_recursive_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
00813        long  max_depth = -1;
00814        
00815        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &max_depth) == FAILURE) {
00816               return;
00817        }
00818        if (max_depth < -1) {
00819               zend_throw_exception(spl_ce_OutOfRangeException, "Parameter max_depth must be >= -1", 0 TSRMLS_CC);
00820               return;
00821        }
00822        object->max_depth = max_depth;
00823 } /* }}} */
00824 
00825 /* {{{ proto int|false RecursiveIteratorIterator::getMaxDepth()
00826    Return the maximum accepted depth or false if any depth is allowed */
00827 SPL_METHOD(RecursiveIteratorIterator, getMaxDepth)
00828 {
00829        spl_recursive_it_object   *object = (spl_recursive_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
00830 
00831        if (zend_parse_parameters_none() == FAILURE) {
00832               return;
00833        }
00834        
00835        if (object->max_depth == -1) {
00836               RETURN_FALSE;
00837        } else {
00838               RETURN_LONG(object->max_depth);
00839        }
00840 } /* }}} */
00841 
00842 static union _zend_function *spl_recursive_it_get_method(zval **object_ptr, char *method, int method_len TSRMLS_DC)
00843 {
00844        union _zend_function    *function_handler;
00845        spl_recursive_it_object *object = (spl_recursive_it_object*)zend_object_store_get_object(*object_ptr TSRMLS_CC);
00846        long                     level = object->level;
00847        zval                    *zobj;
00848 
00849        if (!object->iterators) {
00850               php_error_docref(NULL TSRMLS_CC, E_ERROR, "The %s instance wasn't initialized properly", Z_OBJCE_PP(object_ptr)->name);
00851        }
00852        zobj = object->iterators[level].zobject;
00853 
00854        function_handler = std_object_handlers.get_method(object_ptr, method, method_len TSRMLS_CC);
00855        if (!function_handler) {
00856               if (zend_hash_find(&Z_OBJCE_P(zobj)->function_table, method, method_len+1, (void **) &function_handler) == FAILURE) {
00857                      if (Z_OBJ_HT_P(zobj)->get_method) {
00858                             *object_ptr = zobj;
00859                             function_handler = Z_OBJ_HT_P(*object_ptr)->get_method(object_ptr, method, method_len TSRMLS_CC);
00860                      }
00861               }
00862        }
00863        return function_handler;
00864 }
00865 
00866 /* {{{ spl_RecursiveIteratorIterator_dtor */
00867 static void spl_RecursiveIteratorIterator_dtor(zend_object *_object, zend_object_handle handle TSRMLS_DC)
00868 {
00869        spl_recursive_it_object   *object = (spl_recursive_it_object *)_object;
00870        zend_object_iterator      *sub_iter;
00871 
00872        /* call standard dtor */
00873        zend_objects_destroy_object(_object, handle TSRMLS_CC);
00874 
00875        if (object->iterators) {
00876               while (object->level >= 0) {
00877                      sub_iter = object->iterators[object->level].iterator;
00878                      sub_iter->funcs->dtor(sub_iter TSRMLS_CC);
00879                      zval_ptr_dtor(&object->iterators[object->level--].zobject);
00880               }
00881               efree(object->iterators);
00882               object->iterators = NULL;
00883        }
00884 }
00885 /* }}} */
00886 
00887 /* {{{ spl_RecursiveIteratorIterator_dtor */
00888 static void spl_RecursiveIteratorIterator_free_storage(void *_object TSRMLS_DC)
00889 {
00890        spl_recursive_it_object   *object = (spl_recursive_it_object *)_object;
00891 
00892        zend_object_std_dtor(&object->std TSRMLS_CC);
00893        smart_str_free(&object->prefix[0]);
00894        smart_str_free(&object->prefix[1]);
00895        smart_str_free(&object->prefix[2]);
00896        smart_str_free(&object->prefix[3]);
00897        smart_str_free(&object->prefix[4]);
00898        smart_str_free(&object->prefix[5]);
00899 
00900        efree(object);
00901 }
00902 /* }}} */
00903 
00904 /* {{{ spl_RecursiveIteratorIterator_new_ex */
00905 static zend_object_value spl_RecursiveIteratorIterator_new_ex(zend_class_entry *class_type, int init_prefix TSRMLS_DC)
00906 {
00907        zend_object_value retval;
00908        spl_recursive_it_object *intern;
00909        zval *tmp;
00910 
00911        intern = emalloc(sizeof(spl_recursive_it_object));
00912        memset(intern, 0, sizeof(spl_recursive_it_object));
00913 
00914        if (init_prefix) {
00915               smart_str_appendl(&intern->prefix[0], "",    0);
00916               smart_str_appendl(&intern->prefix[1], "| ",  2);
00917               smart_str_appendl(&intern->prefix[2], "  ",  2);
00918               smart_str_appendl(&intern->prefix[3], "|-",  2);
00919               smart_str_appendl(&intern->prefix[4], "\\-", 2);
00920               smart_str_appendl(&intern->prefix[5], "",    0);
00921        }
00922 
00923        zend_object_std_init(&intern->std, class_type TSRMLS_CC);
00924        zend_hash_copy(intern->std.properties, &class_type->default_properties, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *));
00925 
00926        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);
00927        retval.handlers = &spl_handlers_rec_it_it;
00928        return retval;
00929 }
00930 /* }}} */
00931 
00932 /* {{{ spl_RecursiveIteratorIterator_new */
00933 static zend_object_value spl_RecursiveIteratorIterator_new(zend_class_entry *class_type TSRMLS_DC)
00934 {
00935        return spl_RecursiveIteratorIterator_new_ex(class_type, 0 TSRMLS_CC);
00936 }
00937 /* }}} */
00938 
00939 /* {{{ spl_RecursiveTreeIterator_new */
00940 static zend_object_value spl_RecursiveTreeIterator_new(zend_class_entry *class_type TSRMLS_DC)
00941 {
00942        return spl_RecursiveIteratorIterator_new_ex(class_type, 1 TSRMLS_CC);
00943 }
00944 /* }}} */
00945 
00946 ZEND_BEGIN_ARG_INFO_EX(arginfo_recursive_it___construct, 0, 0, 1) 
00947        ZEND_ARG_OBJ_INFO(0, iterator, Traversable, 0)
00948        ZEND_ARG_INFO(0, mode)
00949        ZEND_ARG_INFO(0, flags)
00950 ZEND_END_ARG_INFO();
00951 
00952 ZEND_BEGIN_ARG_INFO_EX(arginfo_recursive_it_getSubIterator, 0, 0, 0)
00953        ZEND_ARG_INFO(0, level)
00954 ZEND_END_ARG_INFO();
00955 
00956 ZEND_BEGIN_ARG_INFO_EX(arginfo_recursive_it_setMaxDepth, 0, 0, 0)
00957        ZEND_ARG_INFO(0, max_depth)
00958 ZEND_END_ARG_INFO();
00959 
00960 static const zend_function_entry spl_funcs_RecursiveIteratorIterator[] = {
00961        SPL_ME(RecursiveIteratorIterator, __construct,       arginfo_recursive_it___construct,    ZEND_ACC_PUBLIC)
00962        SPL_ME(RecursiveIteratorIterator, rewind,            arginfo_recursive_it_void,           ZEND_ACC_PUBLIC)
00963        SPL_ME(RecursiveIteratorIterator, valid,             arginfo_recursive_it_void,           ZEND_ACC_PUBLIC)
00964        SPL_ME(RecursiveIteratorIterator, key,               arginfo_recursive_it_void,           ZEND_ACC_PUBLIC)
00965        SPL_ME(RecursiveIteratorIterator, current,           arginfo_recursive_it_void,           ZEND_ACC_PUBLIC)
00966        SPL_ME(RecursiveIteratorIterator, next,              arginfo_recursive_it_void,           ZEND_ACC_PUBLIC)
00967        SPL_ME(RecursiveIteratorIterator, getDepth,          arginfo_recursive_it_void,           ZEND_ACC_PUBLIC)
00968        SPL_ME(RecursiveIteratorIterator, getSubIterator,    arginfo_recursive_it_getSubIterator, ZEND_ACC_PUBLIC)
00969        SPL_ME(RecursiveIteratorIterator, getInnerIterator,  arginfo_recursive_it_void,           ZEND_ACC_PUBLIC)
00970        SPL_ME(RecursiveIteratorIterator, beginIteration,    arginfo_recursive_it_void,           ZEND_ACC_PUBLIC)
00971        SPL_ME(RecursiveIteratorIterator, endIteration,      arginfo_recursive_it_void,           ZEND_ACC_PUBLIC)
00972        SPL_ME(RecursiveIteratorIterator, callHasChildren,   arginfo_recursive_it_void,           ZEND_ACC_PUBLIC)
00973        SPL_ME(RecursiveIteratorIterator, callGetChildren,   arginfo_recursive_it_void,           ZEND_ACC_PUBLIC)
00974        SPL_ME(RecursiveIteratorIterator, beginChildren,     arginfo_recursive_it_void,           ZEND_ACC_PUBLIC)
00975        SPL_ME(RecursiveIteratorIterator, endChildren,       arginfo_recursive_it_void,           ZEND_ACC_PUBLIC)
00976        SPL_ME(RecursiveIteratorIterator, nextElement,       arginfo_recursive_it_void,           ZEND_ACC_PUBLIC)
00977        SPL_ME(RecursiveIteratorIterator, setMaxDepth,       arginfo_recursive_it_setMaxDepth,    ZEND_ACC_PUBLIC)
00978        SPL_ME(RecursiveIteratorIterator, getMaxDepth,       arginfo_recursive_it_void,           ZEND_ACC_PUBLIC)
00979        PHP_FE_END
00980 };
00981 
00982 static void spl_recursive_tree_iterator_get_prefix(spl_recursive_it_object *object, zval *return_value TSRMLS_DC)
00983 {
00984        smart_str  str = {0};
00985        zval      *has_next;
00986        int        level;
00987 
00988        smart_str_appendl(&str, object->prefix[0].c, object->prefix[0].len);
00989        
00990        for (level = 0; level < object->level; ++level) {
00991               zend_call_method_with_0_params(&object->iterators[level].zobject, object->iterators[level].ce, NULL, "hasnext", &has_next);
00992               if (has_next) {
00993                      if (Z_LVAL_P(has_next)) {
00994                             smart_str_appendl(&str, object->prefix[1].c, object->prefix[1].len);
00995                      } else {
00996                             smart_str_appendl(&str, object->prefix[2].c, object->prefix[2].len);
00997                      }
00998                      zval_ptr_dtor(&has_next);
00999               }
01000        }
01001        zend_call_method_with_0_params(&object->iterators[level].zobject, object->iterators[level].ce, NULL, "hasnext", &has_next);
01002        if (has_next) {
01003               if (Z_LVAL_P(has_next)) {
01004                      smart_str_appendl(&str, object->prefix[3].c, object->prefix[3].len);
01005               } else {
01006                      smart_str_appendl(&str, object->prefix[4].c, object->prefix[4].len);
01007               }
01008               zval_ptr_dtor(&has_next);
01009        }
01010 
01011        smart_str_appendl(&str, object->prefix[5].c, object->prefix[5].len);
01012        smart_str_0(&str);
01013 
01014        RETVAL_STRINGL(str.c, str.len, 0);
01015 }
01016 
01017 static void spl_recursive_tree_iterator_get_entry(spl_recursive_it_object * object, zval * return_value TSRMLS_DC)
01018 {
01019        zend_object_iterator      *iterator = object->iterators[object->level].iterator;
01020        zval                     **data;
01021        zend_error_handling        error_handling;
01022 
01023        iterator->funcs->get_current_data(iterator, &data TSRMLS_CC);
01024 
01025        zend_replace_error_handling(EH_THROW, spl_ce_UnexpectedValueException, &error_handling TSRMLS_CC);
01026        if (data && *data) {
01027               RETVAL_ZVAL(*data, 1, 0);
01028        }
01029        if (Z_TYPE_P(return_value) == IS_ARRAY) {
01030               zval_dtor(return_value);
01031               ZVAL_STRINGL(return_value, "Array", sizeof("Array")-1, 1);
01032        } else {
01033               convert_to_string(return_value);
01034        }
01035        zend_restore_error_handling(&error_handling TSRMLS_CC);
01036 }
01037 
01038 static void spl_recursive_tree_iterator_get_postfix(spl_recursive_it_object * object, zval * return_value TSRMLS_DC)
01039 {
01040        RETVAL_STRINGL("", 0, 1);
01041 }
01042 
01043 /* {{{ 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
01044    RecursiveIteratorIterator to generate ASCII graphic trees for the entries in a RecursiveIterator */
01045 SPL_METHOD(RecursiveTreeIterator, __construct)
01046 {
01047        spl_recursive_it_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_RecursiveTreeIterator, zend_ce_iterator, RIT_RecursiveTreeIterator);
01048 } /* }}} */
01049 
01050 /* {{{ proto void RecursiveTreeIterator::setPrefixPart(int part, string prefix) throws OutOfRangeException
01051    Sets prefix parts as used in getPrefix() */
01052 SPL_METHOD(RecursiveTreeIterator, setPrefixPart)
01053 {
01054        spl_recursive_it_object   *object = (spl_recursive_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
01055        long  part;
01056        char* prefix;
01057        int   prefix_len;
01058        
01059        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ls", &part, &prefix, &prefix_len) == FAILURE) {
01060               return;
01061        }
01062        if (0 > part || part > 5) {
01063               zend_throw_exception_ex(spl_ce_OutOfRangeException, 0 TSRMLS_CC, "Use RecursiveTreeIterator::PREFIX_* constant");
01064               return;
01065        }
01066        
01067        smart_str_free(&object->prefix[part]);
01068        smart_str_appendl(&object->prefix[part], prefix, prefix_len);
01069 } /* }}} */
01070 
01071 /* {{{ proto string RecursiveTreeIterator::getPrefix()
01072    Returns the string to place in front of current element */
01073 SPL_METHOD(RecursiveTreeIterator, getPrefix)
01074 {
01075        spl_recursive_it_object   *object = (spl_recursive_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
01076 
01077        if (zend_parse_parameters_none() == FAILURE) {
01078               return;
01079        }
01080        spl_recursive_tree_iterator_get_prefix(object, return_value TSRMLS_CC);
01081 } /* }}} */
01082 
01083 /* {{{ proto string RecursiveTreeIterator::getEntry()
01084    Returns the string presentation built for current element */
01085 SPL_METHOD(RecursiveTreeIterator, getEntry)
01086 {
01087        spl_recursive_it_object   *object = (spl_recursive_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
01088 
01089        if (zend_parse_parameters_none() == FAILURE) {
01090               return;
01091        }
01092        
01093        spl_recursive_tree_iterator_get_entry(object, return_value TSRMLS_CC);
01094 } /* }}} */
01095 
01096 /* {{{ proto string RecursiveTreeIterator::getPostfix()
01097    Returns the string to place after the current element */
01098 SPL_METHOD(RecursiveTreeIterator, getPostfix)
01099 {
01100        spl_recursive_it_object   *object = (spl_recursive_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
01101 
01102        if (zend_parse_parameters_none() == FAILURE) {
01103               return;
01104        }
01105        
01106        spl_recursive_tree_iterator_get_postfix(object, return_value TSRMLS_CC);
01107 } /* }}} */
01108 
01109 /* {{{ proto mixed RecursiveTreeIterator::current()
01110    Returns the current element prefixed and postfixed */
01111 SPL_METHOD(RecursiveTreeIterator, current)
01112 {
01113        spl_recursive_it_object   *object = (spl_recursive_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
01114        zval                       prefix, entry, postfix;
01115        char                      *str, *ptr;
01116        size_t                     str_len;
01117        
01118        if (zend_parse_parameters_none() == FAILURE) {
01119               return;
01120        }
01121 
01122        if (object->flags & RTIT_BYPASS_CURRENT) {
01123               zend_object_iterator      *iterator = object->iterators[object->level].iterator;
01124               zval                      **data;
01125 
01126               iterator->funcs->get_current_data(iterator, &data TSRMLS_CC);
01127               if (data && *data) {
01128                      RETURN_ZVAL(*data, 1, 0);
01129               } else {
01130                      RETURN_NULL();
01131               }
01132        }
01133 
01134        spl_recursive_tree_iterator_get_prefix(object, &prefix TSRMLS_CC);
01135        spl_recursive_tree_iterator_get_entry(object, &entry TSRMLS_CC);
01136        spl_recursive_tree_iterator_get_postfix(object, &postfix TSRMLS_CC);
01137 
01138        str_len = Z_STRLEN(prefix) + Z_STRLEN(entry) + Z_STRLEN(postfix);
01139        str = (char *) emalloc(str_len + 1U);
01140        ptr = str;
01141 
01142        memcpy(ptr, Z_STRVAL(prefix), Z_STRLEN(prefix));
01143        ptr += Z_STRLEN(prefix);
01144        memcpy(ptr, Z_STRVAL(entry), Z_STRLEN(entry));
01145        ptr += Z_STRLEN(entry);
01146        memcpy(ptr, Z_STRVAL(postfix), Z_STRLEN(postfix));
01147        ptr += Z_STRLEN(postfix);
01148        *ptr = 0;
01149 
01150        zval_dtor(&prefix);
01151        zval_dtor(&entry);
01152        zval_dtor(&postfix);
01153 
01154        RETURN_STRINGL(str, str_len, 0);
01155 } /* }}} */
01156 
01157 /* {{{ proto mixed RecursiveTreeIterator::key()
01158    Returns the current key prefixed and postfixed */
01159 SPL_METHOD(RecursiveTreeIterator, key)
01160 {
01161        spl_recursive_it_object   *object = (spl_recursive_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
01162        zend_object_iterator      *iterator = object->iterators[object->level].iterator;
01163        zval                       prefix, key, postfix, key_copy;
01164        char                      *str, *ptr;
01165        size_t                     str_len;
01166        
01167        if (zend_parse_parameters_none() == FAILURE) {
01168               return;
01169        }
01170 
01171        if (iterator->funcs->get_current_key) {
01172               char *str_key;
01173               uint str_key_len;
01174               ulong int_key;
01175 
01176               switch (iterator->funcs->get_current_key(iterator, &str_key, &str_key_len, &int_key TSRMLS_CC)) {
01177                      case HASH_KEY_IS_LONG:
01178                             ZVAL_LONG(&key, int_key);
01179                             break;
01180                      case HASH_KEY_IS_STRING:
01181                             ZVAL_STRINGL(&key, str_key, str_key_len-1, 0);
01182                             break;
01183                      default:
01184                             ZVAL_NULL(&key);
01185               }
01186        } else {
01187               ZVAL_NULL(&key);
01188        }
01189 
01190        if (object->flags & RTIT_BYPASS_KEY) {
01191               zval *key_ptr = &key;
01192               RETVAL_ZVAL(key_ptr, 1, 0);
01193               zval_dtor(&key);
01194               return;
01195        }
01196 
01197        if (Z_TYPE(key) != IS_STRING) {
01198               int use_copy;
01199               zend_make_printable_zval(&key, &key_copy, &use_copy);
01200               if (use_copy) {
01201                      key = key_copy;
01202               }
01203        }
01204 
01205        spl_recursive_tree_iterator_get_prefix(object, &prefix TSRMLS_CC);
01206        spl_recursive_tree_iterator_get_postfix(object, &postfix TSRMLS_CC);
01207 
01208        str_len = Z_STRLEN(prefix) + Z_STRLEN(key) + Z_STRLEN(postfix);
01209        str = (char *) emalloc(str_len + 1U);
01210        ptr = str;
01211 
01212        memcpy(ptr, Z_STRVAL(prefix), Z_STRLEN(prefix));
01213        ptr += Z_STRLEN(prefix);
01214        memcpy(ptr, Z_STRVAL(key), Z_STRLEN(key));
01215        ptr += Z_STRLEN(key);
01216        memcpy(ptr, Z_STRVAL(postfix), Z_STRLEN(postfix));
01217        ptr += Z_STRLEN(postfix);
01218        *ptr = 0;
01219 
01220        zval_dtor(&prefix);
01221        zval_dtor(&key);
01222        zval_dtor(&postfix);
01223 
01224        RETVAL_STRINGL(str, str_len, 0);
01225 } /* }}} */
01226 
01227 ZEND_BEGIN_ARG_INFO_EX(arginfo_recursive_tree_it___construct, 0, 0, 1) 
01228        ZEND_ARG_OBJ_INFO(0, iterator, Traversable, 0)
01229        ZEND_ARG_INFO(0, flags)
01230        ZEND_ARG_INFO(0, caching_it_flags)
01231        ZEND_ARG_INFO(0, mode)
01232 ZEND_END_ARG_INFO();
01233 
01234 ZEND_BEGIN_ARG_INFO_EX(arginfo_recursive_tree_it_setPrefixPart, 0, 0, 2)
01235        ZEND_ARG_INFO(0, part)
01236        ZEND_ARG_INFO(0, value)
01237 ZEND_END_ARG_INFO();
01238 
01239 static const zend_function_entry spl_funcs_RecursiveTreeIterator[] = {
01240        SPL_ME(RecursiveTreeIterator,     __construct,       arginfo_recursive_tree_it___construct,   ZEND_ACC_PUBLIC)
01241        SPL_ME(RecursiveIteratorIterator, rewind,            arginfo_recursive_it_void,               ZEND_ACC_PUBLIC)
01242        SPL_ME(RecursiveIteratorIterator, valid,             arginfo_recursive_it_void,               ZEND_ACC_PUBLIC)
01243        SPL_ME(RecursiveTreeIterator,     key,               arginfo_recursive_it_void,               ZEND_ACC_PUBLIC)
01244        SPL_ME(RecursiveTreeIterator,     current,           arginfo_recursive_it_void,               ZEND_ACC_PUBLIC)
01245        SPL_ME(RecursiveIteratorIterator, next,              arginfo_recursive_it_void,               ZEND_ACC_PUBLIC)
01246        SPL_ME(RecursiveIteratorIterator, beginIteration,    arginfo_recursive_it_void,               ZEND_ACC_PUBLIC)
01247        SPL_ME(RecursiveIteratorIterator, endIteration,      arginfo_recursive_it_void,               ZEND_ACC_PUBLIC)
01248        SPL_ME(RecursiveIteratorIterator, callHasChildren,   arginfo_recursive_it_void,               ZEND_ACC_PUBLIC)
01249        SPL_ME(RecursiveIteratorIterator, callGetChildren,   arginfo_recursive_it_void,               ZEND_ACC_PUBLIC)
01250        SPL_ME(RecursiveIteratorIterator, beginChildren,     arginfo_recursive_it_void,               ZEND_ACC_PUBLIC)
01251        SPL_ME(RecursiveIteratorIterator, endChildren,       arginfo_recursive_it_void,               ZEND_ACC_PUBLIC)
01252        SPL_ME(RecursiveIteratorIterator, nextElement,       arginfo_recursive_it_void,               ZEND_ACC_PUBLIC)
01253        SPL_ME(RecursiveTreeIterator,     getPrefix,         arginfo_recursive_it_void,               ZEND_ACC_PUBLIC)
01254        SPL_ME(RecursiveTreeIterator,     setPrefixPart,     arginfo_recursive_tree_it_setPrefixPart, ZEND_ACC_PUBLIC)
01255        SPL_ME(RecursiveTreeIterator,     getEntry,          arginfo_recursive_it_void,               ZEND_ACC_PUBLIC)
01256        SPL_ME(RecursiveTreeIterator,     getPostfix,        arginfo_recursive_it_void,               ZEND_ACC_PUBLIC)
01257        PHP_FE_END
01258 };
01259 
01260 #if MBO_0
01261 static int spl_dual_it_gets_implemented(zend_class_entry *interface, zend_class_entry *class_type TSRMLS_DC)
01262 {
01263        class_type->iterator_funcs.zf_valid = NULL;
01264        class_type->iterator_funcs.zf_current = NULL;
01265        class_type->iterator_funcs.zf_key = NULL;
01266        class_type->iterator_funcs.zf_next = NULL;
01267        class_type->iterator_funcs.zf_rewind = NULL;
01268        if (!class_type->iterator_funcs.funcs) {
01269               class_type->iterator_funcs.funcs = &zend_interface_iterator_funcs_iterator;
01270        }
01271 
01272        return SUCCESS;
01273 }
01274 #endif
01275 
01276 static union _zend_function *spl_dual_it_get_method(zval **object_ptr, char *method, int method_len TSRMLS_DC)
01277 {
01278        union _zend_function *function_handler;
01279        spl_dual_it_object   *intern;
01280 
01281        intern = (spl_dual_it_object*)zend_object_store_get_object(*object_ptr TSRMLS_CC);
01282 
01283        function_handler = std_object_handlers.get_method(object_ptr, method, method_len TSRMLS_CC);
01284        if (!function_handler && intern->inner.ce) {
01285               if (zend_hash_find(&intern->inner.ce->function_table, method, method_len+1, (void **) &function_handler) == FAILURE) {
01286                      if (Z_OBJ_HT_P(intern->inner.zobject)->get_method) {
01287                             *object_ptr = intern->inner.zobject;
01288                             function_handler = Z_OBJ_HT_P(*object_ptr)->get_method(object_ptr, method, method_len TSRMLS_CC);
01289                      }
01290               }
01291        }
01292        return function_handler;
01293 }
01294 
01295 #if MBO_0
01296 int spl_dual_it_call_method(char *method, INTERNAL_FUNCTION_PARAMETERS)
01297 {
01298        zval ***func_params, func;
01299        zval *retval_ptr;
01300        int arg_count;
01301        int current = 0;
01302        int success;
01303        void **p;
01304        spl_dual_it_object   *intern;
01305 
01306        intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
01307 
01308        ZVAL_STRING(&func, method, 0);
01309        if (!zend_is_callable(&func, 0, &method TSRMLS_CC)) {
01310               php_error_docref(NULL TSRMLS_CC, E_ERROR, "Method %s::%s() does not exist", intern->inner.ce->name, method);
01311               return FAILURE;
01312        }
01313 
01314        p = EG(argument_stack).top_element-2;
01315        arg_count = (ulong) *p;
01316 
01317        func_params = safe_emalloc(sizeof(zval **), arg_count, 0);
01318 
01319        current = 0;
01320        while (arg_count-- > 0) {
01321               func_params[current] = (zval **) p - (arg_count-current);
01322               current++;
01323        }
01324        arg_count = current; /* restore */
01325 
01326        if (call_user_function_ex(EG(function_table), NULL, &func, &retval_ptr, arg_count, func_params, 0, NULL TSRMLS_CC) == SUCCESS && retval_ptr) {
01327               RETURN_ZVAL(retval_ptr, 0, 1);
01328               
01329               success = SUCCESS;
01330        } else {
01331               php_error_docref(NULL TSRMLS_CC, E_ERROR, "Unable to call %s::%s()", intern->inner.ce->name, method);
01332               success = FAILURE;
01333        }
01334 
01335        efree(func_params); 
01336        return success;
01337 }
01338 #endif
01339 
01340 #define SPL_CHECK_CTOR(intern, classname) \
01341        if (intern->dit_type == DIT_Unknown) { \
01342               zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "Classes derived from %s must call %s::__construct()", \
01343                             (spl_ce_##classname)->name, (spl_ce_##classname)->name); \
01344               return; \
01345        }
01346 
01347 #define APPENDIT_CHECK_CTOR(intern) SPL_CHECK_CTOR(intern, AppendIterator)
01348 
01349 static inline int spl_dual_it_fetch(spl_dual_it_object *intern, int check_more TSRMLS_DC);
01350 
01351 static inline int spl_cit_check_flags(int flags)
01352 {
01353        int cnt = 0;
01354 
01355        cnt += (flags & CIT_CALL_TOSTRING) ? 1 : 0;
01356        cnt += (flags & CIT_TOSTRING_USE_KEY) ? 1 : 0;
01357        cnt += (flags & CIT_TOSTRING_USE_CURRENT) ? 1 : 0;
01358        cnt += (flags & CIT_TOSTRING_USE_INNER) ? 1 : 0;
01359        
01360        return cnt <= 1 ? SUCCESS : FAILURE;
01361 }
01362 
01363 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)
01364 {
01365        zval                 *zobject, *retval;
01366        spl_dual_it_object   *intern;
01367        zend_class_entry     *ce = NULL;
01368        int                   inc_refcount = 1;
01369        zend_error_handling   error_handling;
01370 
01371        intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
01372        
01373        if (intern->dit_type != DIT_Unknown) {
01374               zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "%s::getIterator() must be called exactly once per instance", ce_base->name);
01375               return NULL;
01376        }
01377 
01378        zend_replace_error_handling(EH_THROW, spl_ce_InvalidArgumentException, &error_handling TSRMLS_CC);
01379 
01380        intern->dit_type = dit_type;
01381        switch (dit_type) {
01382               case DIT_LimitIterator: {
01383                      intern->u.limit.offset = 0; /* start at beginning */
01384                      intern->u.limit.count = -1; /* get all */
01385                      if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O|ll", &zobject, ce_inner, &intern->u.limit.offset, &intern->u.limit.count) == FAILURE) {
01386                             zend_restore_error_handling(&error_handling TSRMLS_CC);
01387                             return NULL;
01388                      }
01389                      if (intern->u.limit.offset < 0) {
01390                             zend_throw_exception(spl_ce_OutOfRangeException, "Parameter offset must be >= 0", 0 TSRMLS_CC);
01391                             zend_restore_error_handling(&error_handling TSRMLS_CC);
01392                             return NULL;
01393                      }
01394                      if (intern->u.limit.count < 0 && intern->u.limit.count != -1) {
01395                             zend_throw_exception(spl_ce_OutOfRangeException, "Parameter count must either be -1 or a value greater than or equal 0", 0 TSRMLS_CC);
01396                             zend_restore_error_handling(&error_handling TSRMLS_CC);
01397                             return NULL;
01398                      }
01399                      break;
01400               }
01401               case DIT_CachingIterator:
01402               case DIT_RecursiveCachingIterator: {
01403                      long flags = CIT_CALL_TOSTRING;
01404                      if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O|l", &zobject, ce_inner, &flags) == FAILURE) {
01405                             zend_restore_error_handling(&error_handling TSRMLS_CC);
01406                             return NULL;
01407                      }
01408                      if (spl_cit_check_flags(flags) != SUCCESS) {
01409                             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);
01410                             zend_restore_error_handling(&error_handling TSRMLS_CC);
01411                             return NULL;
01412                      }
01413                      intern->u.caching.flags |= flags & CIT_PUBLIC;
01414                      MAKE_STD_ZVAL(intern->u.caching.zcache);
01415                      array_init(intern->u.caching.zcache);
01416                      break;
01417               }
01418               case DIT_IteratorIterator: {
01419                      zend_class_entry **pce_cast;
01420                      char * class_name = NULL;
01421                      int class_name_len = 0;
01422 
01423                      if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O|s", &zobject, ce_inner, &class_name, &class_name_len) == FAILURE) {
01424                             zend_restore_error_handling(&error_handling TSRMLS_CC);
01425                             return NULL;
01426                      }
01427                      ce = Z_OBJCE_P(zobject);
01428                      if (!instanceof_function(ce, zend_ce_iterator TSRMLS_CC)) {
01429                             if (ZEND_NUM_ARGS() > 1) {
01430                                    if (zend_lookup_class(class_name, class_name_len, &pce_cast TSRMLS_CC) == FAILURE 
01431                                    || !instanceof_function(ce, *pce_cast TSRMLS_CC)
01432                                    || !(*pce_cast)->get_iterator
01433                                    ) {
01434                                           zend_throw_exception(spl_ce_LogicException, "Class to downcast to not found or not base class or does not implement Traversable", 0 TSRMLS_CC);
01435                                           zend_restore_error_handling(&error_handling TSRMLS_CC);
01436                                           return NULL;
01437                                    }
01438                                    ce = *pce_cast;
01439                             }
01440                             if (instanceof_function(ce, zend_ce_aggregate TSRMLS_CC)) {
01441                                    zend_call_method_with_0_params(&zobject, ce, &ce->iterator_funcs.zf_new_iterator, "getiterator", &retval);
01442                                    if (EG(exception)) {
01443                                           if (retval) {
01444                                                  zval_ptr_dtor(&retval);
01445                                           }
01446                                           zend_restore_error_handling(&error_handling TSRMLS_CC);
01447                                           return NULL;
01448                                    }
01449                                    if (!retval || Z_TYPE_P(retval) != IS_OBJECT || !instanceof_function(Z_OBJCE_P(retval), zend_ce_traversable TSRMLS_CC)) {
01450                                           zend_throw_exception_ex(spl_ce_LogicException, 0 TSRMLS_CC, "%s::getIterator() must return an object that implements Traversable", ce->name);
01451                                           zend_restore_error_handling(&error_handling TSRMLS_CC);
01452                                           return NULL;
01453                                    }
01454                                    zobject = retval;
01455                                    ce = Z_OBJCE_P(zobject);
01456                                    inc_refcount = 0;
01457                             }
01458                      }
01459                      break;
01460               }
01461               case DIT_AppendIterator:
01462                      spl_instantiate(spl_ce_ArrayIterator, &intern->u.append.zarrayit, 1 TSRMLS_CC);
01463                      zend_call_method_with_0_params(&intern->u.append.zarrayit, spl_ce_ArrayIterator, &spl_ce_ArrayIterator->constructor, "__construct", NULL);
01464                      intern->u.append.iterator = spl_ce_ArrayIterator->get_iterator(spl_ce_ArrayIterator, intern->u.append.zarrayit, 0 TSRMLS_CC);
01465                      zend_restore_error_handling(&error_handling TSRMLS_CC);
01466                      return intern;
01467 #if HAVE_PCRE || HAVE_BUNDLED_PCRE
01468               case DIT_RegexIterator:
01469               case DIT_RecursiveRegexIterator: {
01470                      char *regex;
01471                      int regex_len;
01472                      long mode = REGIT_MODE_MATCH;
01473 
01474                      intern->u.regex.use_flags = ZEND_NUM_ARGS() >= 5;
01475                      intern->u.regex.flags = 0;
01476                      intern->u.regex.preg_flags = 0;
01477                      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) {
01478                             zend_restore_error_handling(&error_handling TSRMLS_CC);
01479                             return NULL;
01480                      }
01481                      if (mode < 0 || mode >= REGIT_MODE_MAX) {
01482                             zend_throw_exception_ex(spl_ce_InvalidArgumentException, 0 TSRMLS_CC, "Illegal mode %ld", mode);
01483                             zend_restore_error_handling(&error_handling TSRMLS_CC);
01484                             return NULL;
01485                      }
01486                      intern->u.regex.mode = mode;
01487                      intern->u.regex.regex = estrndup(regex, regex_len);
01488                      intern->u.regex.pce = pcre_get_compiled_regex_cache(regex, regex_len TSRMLS_CC);
01489                      if (intern->u.regex.pce == NULL) {
01490                             /* pcre_get_compiled_regex_cache has already sent error */
01491                             zend_restore_error_handling(&error_handling TSRMLS_CC);
01492                             return NULL;
01493                      }
01494                      intern->u.regex.pce->refcount++;
01495                      break;
01496               }
01497 #endif
01498               default:
01499                      if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &zobject, ce_inner) == FAILURE) {
01500                             zend_restore_error_handling(&error_handling TSRMLS_CC);
01501                             return NULL;
01502                      }
01503                      break;
01504        }
01505 
01506        zend_restore_error_handling(&error_handling TSRMLS_CC);
01507 
01508        if (inc_refcount) {
01509               Z_ADDREF_P(zobject);
01510        }
01511        intern->inner.zobject = zobject;
01512        intern->inner.ce = dit_type == DIT_IteratorIterator ? ce : Z_OBJCE_P(zobject);
01513        intern->inner.object = zend_object_store_get_object(zobject TSRMLS_CC);
01514        intern->inner.iterator = intern->inner.ce->get_iterator(intern->inner.ce, zobject, 0 TSRMLS_CC);
01515 
01516        return intern;
01517 }
01518 
01519 /* {{{ proto void FilterIterator::__construct(Iterator it) 
01520    Create an Iterator from another iterator */
01521 SPL_METHOD(FilterIterator, __construct)
01522 {
01523        spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_FilterIterator, zend_ce_iterator, DIT_FilterIterator);
01524 } /* }}} */
01525 
01526 /* {{{ proto Iterator FilterIterator::getInnerIterator() 
01527        proto Iterator CachingIterator::getInnerIterator()
01528        proto Iterator LimitIterator::getInnerIterator()
01529        proto Iterator ParentIterator::getInnerIterator()
01530    Get the inner iterator */
01531 SPL_METHOD(dual_it, getInnerIterator)
01532 {
01533        spl_dual_it_object   *intern;
01534        
01535        if (zend_parse_parameters_none() == FAILURE) {
01536               return;
01537        }
01538        
01539        SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
01540 
01541        if (intern->inner.zobject) {
01542               RETVAL_ZVAL(intern->inner.zobject, 1, 0);
01543        } else {
01544               RETURN_NULL();
01545        }
01546 } /* }}} */
01547 
01548 static inline void spl_dual_it_require(spl_dual_it_object *intern TSRMLS_DC)
01549 {
01550        if (!intern->inner.iterator) {
01551               php_error_docref(NULL TSRMLS_CC, E_ERROR, "The inner constructor wasn't initialized with an iterator instance");
01552        }
01553 }
01554 
01555 static inline void spl_dual_it_free(spl_dual_it_object *intern TSRMLS_DC)
01556 {
01557        if (intern->inner.iterator && intern->inner.iterator->funcs->invalidate_current) {
01558               intern->inner.iterator->funcs->invalidate_current(intern->inner.iterator TSRMLS_CC);
01559        }
01560        if (intern->current.data) {
01561               zval_ptr_dtor(&intern->current.data);
01562               intern->current.data = NULL;
01563        }
01564        if (intern->current.str_key) {
01565               efree(intern->current.str_key);
01566               intern->current.str_key = NULL;
01567        }
01568        if (intern->dit_type == DIT_CachingIterator || intern->dit_type == DIT_RecursiveCachingIterator) {
01569               if (intern->u.caching.zstr) {
01570                      zval_ptr_dtor(&intern->u.caching.zstr);
01571                      intern->u.caching.zstr = NULL;
01572               }
01573               if (intern->u.caching.zchildren) {
01574                      zval_ptr_dtor(&intern->u.caching.zchildren);
01575                      intern->u.caching.zchildren = NULL;
01576               }
01577        }
01578 }
01579 
01580 static inline void spl_dual_it_rewind(spl_dual_it_object *intern TSRMLS_DC)
01581 {
01582        spl_dual_it_free(intern TSRMLS_CC);
01583        intern->current.pos = 0;
01584        if (intern->inner.iterator->funcs->rewind) {
01585               intern->inner.iterator->funcs->rewind(intern->inner.iterator TSRMLS_CC);
01586        }
01587 }
01588 
01589 static inline int spl_dual_it_valid(spl_dual_it_object *intern TSRMLS_DC)
01590 {
01591        if (!intern->inner.iterator) {
01592               return FAILURE;
01593        }
01594        /* FAILURE / SUCCESS */
01595        return intern->inner.iterator->funcs->valid(intern->inner.iterator TSRMLS_CC);
01596 }
01597 
01598 static inline int spl_dual_it_fetch(spl_dual_it_object *intern, int check_more TSRMLS_DC)
01599 {
01600        zval **data;
01601 
01602        spl_dual_it_free(intern TSRMLS_CC);
01603        if (!check_more || spl_dual_it_valid(intern TSRMLS_CC) == SUCCESS) {
01604               intern->inner.iterator->funcs->get_current_data(intern->inner.iterator, &data TSRMLS_CC);
01605               if (data && *data) {
01606                      intern->current.data = *data;
01607                      Z_ADDREF_P(intern->current.data);
01608               }
01609               if (intern->inner.iterator->funcs->get_current_key) {
01610                      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);
01611               } else {
01612                      intern->current.key_type = HASH_KEY_IS_LONG;
01613                      intern->current.int_key = intern->current.pos;
01614               }
01615               return EG(exception) ? FAILURE : SUCCESS;
01616        }
01617        return FAILURE;
01618 }
01619 
01620 static inline void spl_dual_it_next(spl_dual_it_object *intern, int do_free TSRMLS_DC)
01621 {
01622        if (do_free) {
01623               spl_dual_it_free(intern TSRMLS_CC);
01624        } else {
01625               spl_dual_it_require(intern TSRMLS_CC);
01626        }
01627        intern->inner.iterator->funcs->move_forward(intern->inner.iterator TSRMLS_CC);
01628        intern->current.pos++;
01629 }
01630 
01631 /* {{{ proto void ParentIterator::rewind()
01632        proto void IteratorIterator::rewind()
01633    Rewind the iterator
01634    */
01635 SPL_METHOD(dual_it, rewind)
01636 {
01637        spl_dual_it_object   *intern;
01638        
01639        if (zend_parse_parameters_none() == FAILURE) {
01640               return;
01641        }
01642        
01643        SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
01644        
01645        spl_dual_it_rewind(intern TSRMLS_CC);
01646        spl_dual_it_fetch(intern, 1 TSRMLS_CC);
01647 } /* }}} */
01648 
01649 /* {{{ proto bool FilterIterator::valid()
01650        proto bool ParentIterator::valid()
01651        proto bool IteratorIterator::valid()
01652        proto bool NoRewindIterator::valid()
01653    Check whether the current element is valid */
01654 SPL_METHOD(dual_it, valid)
01655 {
01656        spl_dual_it_object   *intern;
01657 
01658        if (zend_parse_parameters_none() == FAILURE) {
01659               return;
01660        }
01661        
01662        SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
01663 
01664        RETURN_BOOL(intern->current.data);
01665 } /* }}} */
01666 
01667 /* {{{ proto mixed FilterIterator::key()
01668        proto mixed CachingIterator::key()
01669        proto mixed LimitIterator::key()
01670        proto mixed ParentIterator::key()
01671        proto mixed IteratorIterator::key()
01672        proto mixed NoRewindIterator::key()
01673        proto mixed AppendIterator::key()
01674    Get the current key */
01675 SPL_METHOD(dual_it, key)
01676 {
01677        spl_dual_it_object   *intern;
01678 
01679        if (zend_parse_parameters_none() == FAILURE) {
01680               return;
01681        }
01682        
01683        SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
01684 
01685        if (intern->current.data) {
01686               if (intern->current.key_type == HASH_KEY_IS_STRING) {
01687                      RETURN_STRINGL(intern->current.str_key, intern->current.str_key_len-1, 1);
01688               } else {
01689                      RETURN_LONG(intern->current.int_key);
01690               }
01691        }
01692        RETURN_NULL();
01693 } /* }}} */
01694 
01695 /* {{{ proto mixed FilterIterator::current()
01696        proto mixed CachingIterator::current()
01697        proto mixed LimitIterator::current()
01698        proto mixed ParentIterator::current()
01699        proto mixed IteratorIterator::current()
01700        proto mixed NoRewindIterator::current()
01701        proto mixed AppendIterator::current()
01702    Get the current element value */
01703 SPL_METHOD(dual_it, current)
01704 {
01705        spl_dual_it_object   *intern;
01706        
01707        if (zend_parse_parameters_none() == FAILURE) {
01708               return;
01709        }
01710 
01711        SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
01712 
01713        if (intern->current.data) {
01714               RETVAL_ZVAL(intern->current.data, 1, 0);
01715        } else {
01716               RETURN_NULL();
01717        }
01718 } /* }}} */
01719 
01720 /* {{{ proto void ParentIterator::next()
01721        proto void IteratorIterator::next()
01722        proto void NoRewindIterator::next()
01723    Move the iterator forward */
01724 SPL_METHOD(dual_it, next)
01725 {
01726        spl_dual_it_object   *intern;
01727        
01728        if (zend_parse_parameters_none() == FAILURE) {
01729               return;
01730        }
01731 
01732        SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
01733 
01734        spl_dual_it_next(intern, 1 TSRMLS_CC);
01735        spl_dual_it_fetch(intern, 1 TSRMLS_CC);
01736 } /* }}} */
01737 
01738 static inline void spl_filter_it_fetch(zval *zthis, spl_dual_it_object *intern TSRMLS_DC)
01739 {
01740        zval *retval;
01741 
01742        while (spl_dual_it_fetch(intern, 1 TSRMLS_CC) == SUCCESS) {
01743               zend_call_method_with_0_params(&zthis, intern->std.ce, NULL, "accept", &retval);
01744               if (retval) {
01745                      if (zend_is_true(retval)) {
01746                             zval_ptr_dtor(&retval);
01747                             return;
01748                      }
01749                      zval_ptr_dtor(&retval);
01750               }
01751               if (EG(exception)) {
01752                      return;
01753               }
01754               intern->inner.iterator->funcs->move_forward(intern->inner.iterator TSRMLS_CC);
01755        }
01756        spl_dual_it_free(intern TSRMLS_CC);
01757 }
01758 
01759 static inline void spl_filter_it_rewind(zval *zthis, spl_dual_it_object *intern TSRMLS_DC)
01760 {
01761        spl_dual_it_rewind(intern TSRMLS_CC);
01762        spl_filter_it_fetch(zthis, intern TSRMLS_CC);
01763 }
01764 
01765 static inline void spl_filter_it_next(zval *zthis, spl_dual_it_object *intern TSRMLS_DC)
01766 {
01767        spl_dual_it_next(intern, 1 TSRMLS_CC);
01768        spl_filter_it_fetch(zthis, intern TSRMLS_CC);
01769 }
01770 
01771 /* {{{ proto void FilterIterator::rewind()
01772    Rewind the iterator */
01773 SPL_METHOD(FilterIterator, rewind)
01774 {
01775        spl_dual_it_object   *intern;
01776        
01777        if (zend_parse_parameters_none() == FAILURE) {
01778               return;
01779        }
01780 
01781        SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
01782        spl_filter_it_rewind(getThis(), intern TSRMLS_CC);
01783 } /* }}} */
01784 
01785 /* {{{ proto void FilterIterator::next()
01786    Move the iterator forward */
01787 SPL_METHOD(FilterIterator, next)
01788 {
01789        spl_dual_it_object   *intern;
01790        
01791        if (zend_parse_parameters_none() == FAILURE) {
01792               return;
01793        }
01794 
01795        SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
01796        spl_filter_it_next(getThis(), intern TSRMLS_CC);
01797 } /* }}} */
01798 
01799 /* {{{ proto void RecursiveFilterIterator::__construct(RecursiveIterator it)
01800    Create a RecursiveFilterIterator from a RecursiveIterator */
01801 SPL_METHOD(RecursiveFilterIterator, __construct)
01802 {
01803        spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_RecursiveFilterIterator, spl_ce_RecursiveIterator, DIT_RecursiveFilterIterator);
01804 } /* }}} */
01805 
01806 /* {{{ proto bool RecursiveFilterIterator::hasChildren()
01807    Check whether the inner iterator's current element has children */
01808 SPL_METHOD(RecursiveFilterIterator, hasChildren)
01809 {
01810        spl_dual_it_object   *intern;
01811        zval                 *retval;
01812        
01813        if (zend_parse_parameters_none() == FAILURE) {
01814               return;
01815        }
01816 
01817        SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
01818 
01819        zend_call_method_with_0_params(&intern->inner.zobject, intern->inner.ce, NULL, "haschildren", &retval);
01820        if (retval) {
01821               RETURN_ZVAL(retval, 0, 1);
01822        } else {
01823               RETURN_FALSE;
01824        }
01825 } /* }}} */
01826 
01827 /* {{{ proto RecursiveFilterIterator RecursiveFilterIterator::getChildren()
01828    Return the inner iterator's children contained in a RecursiveFilterIterator */
01829 SPL_METHOD(RecursiveFilterIterator, getChildren)
01830 {
01831        spl_dual_it_object   *intern;
01832        zval                 *retval;
01833        
01834        if (zend_parse_parameters_none() == FAILURE) {
01835               return;
01836        }
01837 
01838        SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
01839 
01840        zend_call_method_with_0_params(&intern->inner.zobject, intern->inner.ce, NULL, "getchildren", &retval);
01841        if (!EG(exception) && retval) {
01842               spl_instantiate_arg_ex1(Z_OBJCE_P(getThis()), &return_value, 0, retval TSRMLS_CC);
01843        }
01844        if (retval) {
01845               zval_ptr_dtor(&retval);
01846        }
01847 } /* }}} */
01848 
01849 /* {{{ proto void ParentIterator::__construct(RecursiveIterator it)
01850    Create a ParentIterator from a RecursiveIterator */
01851 SPL_METHOD(ParentIterator, __construct)
01852 {
01853        spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_ParentIterator, spl_ce_RecursiveIterator, DIT_ParentIterator);
01854 } /* }}} */
01855 
01856 #if HAVE_PCRE || HAVE_BUNDLED_PCRE
01857 /* {{{ proto void RegexIterator::__construct(Iterator it, string regex [, int mode [, int flags [, int preg_flags]]]) 
01858    Create an RegexIterator from another iterator and a regular expression */
01859 SPL_METHOD(RegexIterator, __construct)
01860 {
01861        spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_RegexIterator, zend_ce_iterator, DIT_RegexIterator);
01862 } /* }}} */
01863 
01864 /* {{{ proto bool RegexIterator::accept()
01865    Match (string)current() against regular expression */
01866 SPL_METHOD(RegexIterator, accept)
01867 {
01868        spl_dual_it_object *intern;
01869        char       *subject, tmp[32], *result;
01870        int        subject_len, use_copy, count = 0, result_len;
01871        zval       subject_copy, zcount, *replacement, tmp_replacement;
01872        
01873        if (zend_parse_parameters_none() == FAILURE) {
01874               return;
01875        }
01876        
01877        SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
01878        
01879        if (intern->current.data == NULL) {
01880               RETURN_FALSE;
01881        }
01882        
01883        if (intern->u.regex.flags & REGIT_USE_KEY) {
01884               if (intern->current.key_type == HASH_KEY_IS_LONG) {
01885                      subject_len = slprintf(tmp, sizeof(tmp), "%ld", intern->current.int_key);
01886                      subject = &tmp[0];
01887                      use_copy = 0;
01888               } else {
01889                      subject_len = intern->current.str_key_len - 1;
01890                      subject = estrndup(intern->current.str_key, subject_len);
01891                      use_copy = 1;
01892               }
01893        } else {
01894               zend_make_printable_zval(intern->current.data, &subject_copy, &use_copy);
01895               if (use_copy) {
01896                      subject = Z_STRVAL(subject_copy);
01897                      subject_len = Z_STRLEN(subject_copy);
01898               } else {
01899                      subject = Z_STRVAL_P(intern->current.data);
01900                      subject_len = Z_STRLEN_P(intern->current.data);
01901               }
01902        }
01903 
01904        switch (intern->u.regex.mode)
01905        {
01906        case REGIT_MODE_MAX: /* won't happen but makes compiler happy */
01907        case REGIT_MODE_MATCH:
01908               count = pcre_exec(intern->u.regex.pce->re, intern->u.regex.pce->extra, subject, subject_len, 0, 0, NULL, 0);
01909               RETVAL_BOOL(count >= 0);
01910               break;
01911 
01912        case REGIT_MODE_ALL_MATCHES:
01913        case REGIT_MODE_GET_MATCH:
01914               if (!use_copy) {
01915                      subject = estrndup(subject, subject_len);
01916                      use_copy = 1;
01917               }
01918               zval_ptr_dtor(&intern->current.data);
01919               ALLOC_INIT_ZVAL(intern->current.data);
01920               php_pcre_match_impl(intern->u.regex.pce, subject, subject_len, &zcount, 
01921                      intern->current.data, intern->u.regex.mode == REGIT_MODE_ALL_MATCHES, intern->u.regex.use_flags, intern->u.regex.preg_flags, 0 TSRMLS_CC);
01922               count = zend_hash_num_elements(Z_ARRVAL_P(intern->current.data));
01923               RETVAL_BOOL(count > 0);
01924               break;
01925 
01926        case REGIT_MODE_SPLIT:
01927               if (!use_copy) {
01928                      subject = estrndup(subject, subject_len);
01929                      use_copy = 1;
01930               }
01931               zval_ptr_dtor(&intern->current.data);
01932               ALLOC_INIT_ZVAL(intern->current.data);
01933               php_pcre_split_impl(intern->u.regex.pce, subject, subject_len, intern->current.data, -1, intern->u.regex.preg_flags TSRMLS_CC);
01934               count = zend_hash_num_elements(Z_ARRVAL_P(intern->current.data));
01935               RETVAL_BOOL(count > 1);
01936               break;
01937 
01938        case REGIT_MODE_REPLACE:
01939               replacement = zend_read_property(intern->std.ce, getThis(), "replacement", sizeof("replacement")-1, 1 TSRMLS_CC);
01940               if (Z_TYPE_P(replacement) != IS_STRING) {
01941                      tmp_replacement = *replacement;
01942                      zval_copy_ctor(&tmp_replacement);
01943                      convert_to_string(&tmp_replacement);
01944                      replacement = &tmp_replacement;
01945               }
01946               result = php_pcre_replace_impl(intern->u.regex.pce, subject, subject_len, replacement, 0, &result_len, -1, &count TSRMLS_CC);
01947               
01948               if (intern->u.regex.flags & REGIT_USE_KEY) {
01949                      if (intern->current.key_type != HASH_KEY_IS_LONG) {
01950                             efree(intern->current.str_key);
01951                      }
01952                      intern->current.key_type = HASH_KEY_IS_STRING;
01953                      intern->current.str_key = result;
01954                      intern->current.str_key_len = result_len + 1;
01955               } else {
01956                      zval_ptr_dtor(&intern->current.data);
01957                      MAKE_STD_ZVAL(intern->current.data);
01958                      ZVAL_STRINGL(intern->current.data, result, result_len, 0);
01959               }
01960 
01961               if (replacement == &tmp_replacement) {
01962                      zval_dtor(replacement);
01963               }
01964               RETVAL_BOOL(count > 0);
01965        }
01966 
01967        if (intern->u.regex.flags & REGIT_INVERTED) {
01968               RETVAL_BOOL(Z_LVAL_P(return_value));
01969        }
01970 
01971        if (use_copy) {
01972               efree(subject);
01973        }
01974 } /* }}} */
01975 
01976 /* {{{ proto bool RegexIterator::getMode()
01977    Returns current operation mode */
01978 SPL_METHOD(RegexIterator, getMode)
01979 {
01980        spl_dual_it_object *intern;
01981 
01982        if (zend_parse_parameters_none() == FAILURE) {
01983               return;
01984        }
01985        
01986        SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
01987        
01988        RETURN_LONG(intern->u.regex.mode);
01989 } /* }}} */
01990 
01991 /* {{{ proto bool RegexIterator::setMode(int new_mode)
01992    Set new operation mode */
01993 SPL_METHOD(RegexIterator, setMode)
01994 {
01995        spl_dual_it_object *intern;
01996        long mode;
01997 
01998        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &mode) == FAILURE) {
01999               return;
02000        }
02001 
02002        if (mode < 0 || mode >= REGIT_MODE_MAX) {
02003               zend_throw_exception_ex(spl_ce_InvalidArgumentException, 0 TSRMLS_CC, "Illegal mode %ld", mode);
02004               return;/* NULL */
02005        }
02006        
02007        SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
02008 
02009        intern->u.regex.mode = mode;
02010 } /* }}} */
02011 
02012 /* {{{ proto bool RegexIterator::getFlags()
02013    Returns current operation flags */
02014 SPL_METHOD(RegexIterator, getFlags)
02015 {
02016        spl_dual_it_object *intern;
02017 
02018        if (zend_parse_parameters_none() == FAILURE) {
02019               return;
02020        }
02021        
02022        SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
02023        
02024        RETURN_LONG(intern->u.regex.flags);
02025 } /* }}} */
02026 
02027 /* {{{ proto bool RegexIterator::setFlags(int new_flags)
02028    Set operation flags */
02029 SPL_METHOD(RegexIterator, setFlags)
02030 {
02031        spl_dual_it_object *intern;
02032        long flags;
02033 
02034        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &flags) == FAILURE) {
02035               return;
02036        }
02037        
02038        SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
02039 
02040        intern->u.regex.flags = flags;
02041 } /* }}} */
02042 
02043 /* {{{ proto bool RegexIterator::getFlags()
02044    Returns current PREG flags (if in use or NULL) */
02045 SPL_METHOD(RegexIterator, getPregFlags)
02046 {
02047        spl_dual_it_object *intern;
02048        
02049        if (zend_parse_parameters_none() == FAILURE) {
02050               return;
02051        }
02052        
02053        SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
02054 
02055        if (intern->u.regex.use_flags) {
02056               RETURN_LONG(intern->u.regex.preg_flags);
02057        } else {
02058               return;
02059        }
02060 } /* }}} */
02061 
02062 /* {{{ proto bool RegexIterator::setPregFlags(int new_flags)
02063    Set PREG flags */
02064 SPL_METHOD(RegexIterator, setPregFlags)
02065 {
02066        spl_dual_it_object *intern;
02067        long preg_flags;
02068 
02069        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &preg_flags) == FAILURE) {
02070               return;
02071        }
02072        
02073        SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
02074 
02075        intern->u.regex.preg_flags = preg_flags;
02076        intern->u.regex.use_flags = 1;
02077 } /* }}} */
02078 
02079 /* {{{ proto void RecursiveRegexIterator::__construct(RecursiveIterator it, string regex [, int mode [, int flags [, int preg_flags]]]) 
02080    Create an RecursiveRegexIterator from another recursive iterator and a regular expression */
02081 SPL_METHOD(RecursiveRegexIterator, __construct)
02082 {
02083        spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_RecursiveRegexIterator, spl_ce_RecursiveIterator, DIT_RecursiveRegexIterator);
02084 } /* }}} */
02085 
02086 /* {{{ proto RecursiveRegexIterator RecursiveRegexIterator::getChildren()
02087    Return the inner iterator's children contained in a RecursiveRegexIterator */
02088 SPL_METHOD(RecursiveRegexIterator, getChildren)
02089 {
02090        spl_dual_it_object   *intern;
02091        zval                 *retval, *regex;
02092        
02093        if (zend_parse_parameters_none() == FAILURE) {
02094               return;
02095        }
02096 
02097        SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
02098 
02099        zend_call_method_with_0_params(&intern->inner.zobject, intern->inner.ce, NULL, "getchildren", &retval);
02100        if (!EG(exception)) {
02101               MAKE_STD_ZVAL(regex);
02102               ZVAL_STRING(regex, intern->u.regex.regex, 1);
02103               spl_instantiate_arg_ex2(Z_OBJCE_P(getThis()), &return_value, 0, retval, regex TSRMLS_CC);
02104               zval_ptr_dtor(&regex);
02105        }
02106        if (retval) {
02107               zval_ptr_dtor(&retval);
02108        }
02109 } /* }}} */
02110 
02111 #endif
02112 
02113 /* {{{ spl_dual_it_dtor */
02114 static void spl_dual_it_dtor(zend_object *_object, zend_object_handle handle TSRMLS_DC)
02115 {
02116        spl_dual_it_object        *object = (spl_dual_it_object *)_object;
02117 
02118        /* call standard dtor */
02119        zend_objects_destroy_object(_object, handle TSRMLS_CC);
02120 
02121        spl_dual_it_free(object TSRMLS_CC);
02122 
02123        if (object->inner.iterator) {
02124               object->inner.iterator->funcs->dtor(object->inner.iterator TSRMLS_CC);
02125        }
02126 }
02127 /* }}} */
02128 
02129 /* {{{ spl_dual_it_free_storage */
02130 static void spl_dual_it_free_storage(void *_object TSRMLS_DC)
02131 {
02132        spl_dual_it_object        *object = (spl_dual_it_object *)_object;
02133 
02134        if (object->inner.zobject) {
02135               zval_ptr_dtor(&object->inner.zobject);
02136        }
02137        
02138        if (object->dit_type == DIT_AppendIterator) {
02139               object->u.append.iterator->funcs->dtor(object->u.append.iterator TSRMLS_CC);
02140               if (object->u.append.zarrayit) {
02141                      zval_ptr_dtor(&object->u.append.zarrayit);
02142               }
02143        }
02144 
02145        if (object->dit_type == DIT_CachingIterator || object->dit_type == DIT_RecursiveCachingIterator) {
02146               if (object->u.caching.zcache) {
02147                      zval_ptr_dtor(&object->u.caching.zcache);
02148                      object->u.caching.zcache = NULL;
02149               }
02150        }
02151 
02152 #if HAVE_PCRE || HAVE_BUNDLED_PCRE
02153        if (object->dit_type == DIT_RegexIterator || object->dit_type == DIT_RecursiveRegexIterator) {
02154               if (object->u.regex.pce) {
02155                      object->u.regex.pce->refcount--;
02156               }
02157               if (object->u.regex.regex) {
02158                      efree(object->u.regex.regex);
02159               }
02160        }
02161 #endif
02162 
02163        zend_object_std_dtor(&object->std TSRMLS_CC);
02164 
02165        efree(object);
02166 }
02167 /* }}} */
02168 
02169 /* {{{ spl_dual_it_new */
02170 static zend_object_value spl_dual_it_new(zend_class_entry *class_type TSRMLS_DC)
02171 {
02172        zend_object_value retval;
02173        spl_dual_it_object *intern;
02174        zval *tmp;
02175 
02176        intern = emalloc(sizeof(spl_dual_it_object));
02177        memset(intern, 0, sizeof(spl_dual_it_object));
02178        intern->dit_type = DIT_Unknown;
02179 
02180        zend_object_std_init(&intern->std, class_type TSRMLS_CC);
02181        zend_hash_copy(intern->std.properties, &class_type->default_properties, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *));
02182 
02183        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);
02184        retval.handlers = &spl_handlers_dual_it;
02185        return retval;
02186 }
02187 /* }}} */
02188 
02189 ZEND_BEGIN_ARG_INFO(arginfo_filter_it___construct, 0) 
02190        ZEND_ARG_OBJ_INFO(0, iterator, Iterator, 0)
02191 ZEND_END_ARG_INFO();
02192 
02193 static const zend_function_entry spl_funcs_FilterIterator[] = {
02194        SPL_ME(FilterIterator,  __construct,      arginfo_filter_it___construct, ZEND_ACC_PUBLIC)
02195        SPL_ME(FilterIterator,  rewind,           arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
02196        SPL_ME(dual_it,         valid,            arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
02197        SPL_ME(dual_it,         key,              arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
02198        SPL_ME(dual_it,         current,          arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
02199        SPL_ME(FilterIterator,  next,             arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
02200        SPL_ME(dual_it,         getInnerIterator, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
02201        SPL_ABSTRACT_ME(FilterIterator, accept,   arginfo_recursive_it_void)
02202        PHP_FE_END
02203 };
02204 
02205 ZEND_BEGIN_ARG_INFO(arginfo_parent_it___construct, 0) 
02206        ZEND_ARG_OBJ_INFO(0, iterator, RecursiveIterator, 0)
02207 ZEND_END_ARG_INFO();
02208 
02209 static const zend_function_entry spl_funcs_RecursiveFilterIterator[] = {
02210        SPL_ME(RecursiveFilterIterator,  __construct,      arginfo_parent_it___construct, ZEND_ACC_PUBLIC)
02211        SPL_ME(RecursiveFilterIterator,  hasChildren,      arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
02212        SPL_ME(RecursiveFilterIterator,  getChildren,      arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
02213        PHP_FE_END
02214 };
02215 
02216 static const zend_function_entry spl_funcs_ParentIterator[] = {
02217        SPL_ME(ParentIterator,  __construct,      arginfo_parent_it___construct, ZEND_ACC_PUBLIC)
02218        SPL_MA(ParentIterator,  accept,           RecursiveFilterIterator, hasChildren, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
02219        PHP_FE_END
02220 };
02221 
02222 #if HAVE_PCRE || HAVE_BUNDLED_PCRE
02223 ZEND_BEGIN_ARG_INFO_EX(arginfo_regex_it___construct, 0, 0, 2) 
02224        ZEND_ARG_OBJ_INFO(0, iterator, Iterator, 0)
02225        ZEND_ARG_INFO(0, regex)
02226        ZEND_ARG_INFO(0, mode)
02227        ZEND_ARG_INFO(0, flags)
02228        ZEND_ARG_INFO(0, preg_flags)
02229 ZEND_END_ARG_INFO();
02230 
02231 ZEND_BEGIN_ARG_INFO_EX(arginfo_regex_it_set_mode, 0, 0, 1) 
02232        ZEND_ARG_INFO(0, mode)
02233 ZEND_END_ARG_INFO();
02234 
02235 ZEND_BEGIN_ARG_INFO_EX(arginfo_regex_it_set_flags, 0, 0, 1) 
02236        ZEND_ARG_INFO(0, flags)
02237 ZEND_END_ARG_INFO();
02238 
02239 ZEND_BEGIN_ARG_INFO_EX(arginfo_regex_it_set_preg_flags, 0, 0, 1) 
02240        ZEND_ARG_INFO(0, preg_flags)
02241 ZEND_END_ARG_INFO();
02242 
02243 static const zend_function_entry spl_funcs_RegexIterator[] = {
02244        SPL_ME(RegexIterator,   __construct,      arginfo_regex_it___construct,    ZEND_ACC_PUBLIC)
02245        SPL_ME(RegexIterator,   accept,           arginfo_recursive_it_void,       ZEND_ACC_PUBLIC)
02246        SPL_ME(RegexIterator,   getMode,          arginfo_recursive_it_void,       ZEND_ACC_PUBLIC)
02247        SPL_ME(RegexIterator,   setMode,          arginfo_regex_it_set_mode,       ZEND_ACC_PUBLIC)
02248        SPL_ME(RegexIterator,   getFlags,         arginfo_recursive_it_void,       ZEND_ACC_PUBLIC)
02249        SPL_ME(RegexIterator,   setFlags,         arginfo_regex_it_set_flags,      ZEND_ACC_PUBLIC)
02250        SPL_ME(RegexIterator,   getPregFlags,     arginfo_recursive_it_void,       ZEND_ACC_PUBLIC)
02251        SPL_ME(RegexIterator,   setPregFlags,     arginfo_regex_it_set_preg_flags, ZEND_ACC_PUBLIC)
02252        PHP_FE_END
02253 };
02254 
02255 ZEND_BEGIN_ARG_INFO_EX(arginfo_rec_regex_it___construct, 0, 0, 2) 
02256        ZEND_ARG_OBJ_INFO(0, iterator, RecursiveIterator, 0)
02257        ZEND_ARG_INFO(0, regex)
02258        ZEND_ARG_INFO(0, mode)
02259        ZEND_ARG_INFO(0, flags)
02260        ZEND_ARG_INFO(0, preg_flags)
02261 ZEND_END_ARG_INFO();
02262 
02263 static const zend_function_entry spl_funcs_RecursiveRegexIterator[] = {
02264        SPL_ME(RecursiveRegexIterator,  __construct,      arginfo_rec_regex_it___construct, ZEND_ACC_PUBLIC)
02265        SPL_ME(RecursiveFilterIterator, hasChildren,      arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
02266        SPL_ME(RecursiveRegexIterator,  getChildren,      arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
02267        PHP_FE_END
02268 };
02269 #endif
02270 
02271 static inline int spl_limit_it_valid(spl_dual_it_object *intern TSRMLS_DC)
02272 {
02273        /* FAILURE / SUCCESS */
02274        if (intern->u.limit.count != -1 && intern->current.pos >= intern->u.limit.offset + intern->u.limit.count) {
02275               return FAILURE;
02276        } else {
02277               return spl_dual_it_valid(intern TSRMLS_CC);
02278        }
02279 }
02280 
02281 static inline void spl_limit_it_seek(spl_dual_it_object *intern, long pos TSRMLS_DC)
02282 {
02283        zval  *zpos;
02284 
02285        spl_dual_it_free(intern TSRMLS_CC);
02286        if (pos < intern->u.limit.offset) {
02287               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);
02288               return;
02289        }
02290        if (pos >= intern->u.limit.offset + intern->u.limit.count && intern->u.limit.count != -1) {
02291               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);
02292               return;
02293        }
02294        if (pos != intern->current.pos && instanceof_function(intern->inner.ce, spl_ce_SeekableIterator TSRMLS_CC)) {
02295               MAKE_STD_ZVAL(zpos);
02296               ZVAL_LONG(zpos, pos);
02297               spl_dual_it_free(intern TSRMLS_CC);
02298               zend_call_method_with_1_params(&intern->inner.zobject, intern->inner.ce, NULL, "seek", NULL, zpos);
02299               zval_ptr_dtor(&zpos);
02300               if (!EG(exception)) {
02301                      intern->current.pos = pos;
02302                      if (spl_limit_it_valid(intern TSRMLS_CC) == SUCCESS) {
02303                             spl_dual_it_fetch(intern, 0 TSRMLS_CC);
02304                      }
02305               }
02306        } else {
02307               /* emulate the forward seek, by next() calls */
02308               /* a back ward seek is done by a previous rewind() */
02309               if (pos < intern->current.pos) {
02310                      spl_dual_it_rewind(intern TSRMLS_CC);
02311               }
02312               while (pos > intern->current.pos && spl_dual_it_valid(intern TSRMLS_CC) == SUCCESS) {
02313                      spl_dual_it_next(intern, 1 TSRMLS_CC);
02314               }
02315               if (spl_dual_it_valid(intern TSRMLS_CC) == SUCCESS) {
02316                      spl_dual_it_fetch(intern, 1 TSRMLS_CC);
02317               }
02318        }
02319 }
02320 
02321 /* {{{ proto LimitIterator::__construct(Iterator it [, int offset, int count])
02322    Construct a LimitIterator from an Iterator with a given starting offset and optionally a maximum count */
02323 SPL_METHOD(LimitIterator, __construct)
02324 {
02325        spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_LimitIterator, zend_ce_iterator, DIT_LimitIterator);
02326 } /* }}} */
02327 
02328 /* {{{ proto void LimitIterator::rewind() 
02329    Rewind the iterator to the specified starting offset */
02330 SPL_METHOD(LimitIterator, rewind)
02331 {
02332        spl_dual_it_object   *intern;
02333 
02334        SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
02335        spl_dual_it_rewind(intern TSRMLS_CC);
02336        spl_limit_it_seek(intern, intern->u.limit.offset TSRMLS_CC);
02337 } /* }}} */
02338 
02339 /* {{{ proto bool LimitIterator::valid()
02340    Check whether the current element is valid */
02341 SPL_METHOD(LimitIterator, valid)
02342 {
02343        spl_dual_it_object   *intern;
02344 
02345        SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
02346 
02347 /*     RETURN_BOOL(spl_limit_it_valid(intern TSRMLS_CC) == SUCCESS);*/
02348        RETURN_BOOL((intern->u.limit.count == -1 || intern->current.pos < intern->u.limit.offset + intern->u.limit.count) && intern->current.data);
02349 } /* }}} */
02350 
02351 /* {{{ proto void LimitIterator::next()
02352    Move the iterator forward */
02353 SPL_METHOD(LimitIterator, next)
02354 {
02355        spl_dual_it_object   *intern;
02356 
02357        SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
02358 
02359        spl_dual_it_next(intern, 1 TSRMLS_CC);
02360        if (intern->u.limit.count == -1 || intern->current.pos < intern->u.limit.offset + intern->u.limit.count) {
02361               spl_dual_it_fetch(intern, 1 TSRMLS_CC);
02362        }
02363 } /* }}} */
02364 
02365 /* {{{ proto void LimitIterator::seek(int position)
02366    Seek to the given position */
02367 SPL_METHOD(LimitIterator, seek)
02368 {
02369        spl_dual_it_object   *intern;
02370        long                 pos;
02371 
02372        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &pos) == FAILURE) {
02373               return;
02374        }
02375 
02376        SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
02377        spl_limit_it_seek(intern, pos TSRMLS_CC);
02378        RETURN_LONG(intern->current.pos);
02379 } /* }}} */
02380 
02381 /* {{{ proto int LimitIterator::getPosition()
02382    Return the current position */
02383 SPL_METHOD(LimitIterator, getPosition)
02384 {
02385        spl_dual_it_object   *intern;
02386        SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
02387        RETURN_LONG(intern->current.pos);
02388 } /* }}} */
02389 
02390 ZEND_BEGIN_ARG_INFO(arginfo_seekable_it_seek, 0) 
02391        ZEND_ARG_INFO(0, position)
02392 ZEND_END_ARG_INFO();
02393 
02394 static const zend_function_entry spl_funcs_SeekableIterator[] = {
02395        SPL_ABSTRACT_ME(SeekableIterator, seek, arginfo_seekable_it_seek)
02396        PHP_FE_END
02397 };
02398 
02399 ZEND_BEGIN_ARG_INFO_EX(arginfo_limit_it___construct, 0, 0, 1) 
02400        ZEND_ARG_OBJ_INFO(0, iterator, Iterator, 0)
02401        ZEND_ARG_INFO(0, offset)
02402        ZEND_ARG_INFO(0, count)
02403 ZEND_END_ARG_INFO();
02404 
02405 ZEND_BEGIN_ARG_INFO(arginfo_limit_it_seek, 0) 
02406        ZEND_ARG_INFO(0, position)
02407 ZEND_END_ARG_INFO();
02408 
02409 static const zend_function_entry spl_funcs_LimitIterator[] = {
02410        SPL_ME(LimitIterator,   __construct,      arginfo_limit_it___construct, ZEND_ACC_PUBLIC)
02411        SPL_ME(LimitIterator,   rewind,           arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
02412        SPL_ME(LimitIterator,   valid,            arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
02413        SPL_ME(dual_it,         key,              arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
02414        SPL_ME(dual_it,         current,          arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
02415        SPL_ME(LimitIterator,   next,             arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
02416        SPL_ME(LimitIterator,   seek,             arginfo_limit_it_seek, ZEND_ACC_PUBLIC)
02417        SPL_ME(LimitIterator,   getPosition,      arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
02418        SPL_ME(dual_it,         getInnerIterator, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
02419        PHP_FE_END
02420 };
02421 
02422 static inline int spl_caching_it_valid(spl_dual_it_object *intern TSRMLS_DC)
02423 {
02424        return intern->u.caching.flags & CIT_VALID ? SUCCESS : FAILURE;
02425 }
02426 
02427 static inline int spl_caching_it_has_next(spl_dual_it_object *intern TSRMLS_DC)
02428 {
02429        return spl_dual_it_valid(intern TSRMLS_CC);
02430 }
02431 
02432 static inline void spl_caching_it_next(spl_dual_it_object *intern TSRMLS_DC)
02433 {
02434        if (spl_dual_it_fetch(intern, 1 TSRMLS_CC) == SUCCESS) {
02435               intern->u.caching.flags |= CIT_VALID;
02436               /* Full cache ? */
02437               if (intern->u.caching.flags & CIT_FULL_CACHE) {
02438                      zval *zcacheval;
02439                      
02440                      MAKE_STD_ZVAL(zcacheval);
02441                      ZVAL_ZVAL(zcacheval, intern->current.data, 1, 0);
02442                      if (intern->current.key_type == HASH_KEY_IS_LONG) {
02443                             add_index_zval(intern->u.caching.zcache, intern->current.int_key, zcacheval);
02444                      } else {
02445                             zend_symtable_update(HASH_OF(intern->u.caching.zcache), intern->current.str_key, intern->current.str_key_len, &zcacheval, sizeof(void*), NULL);
02446                      }
02447               }
02448               /* Recursion ? */
02449               if (intern->dit_type == DIT_RecursiveCachingIterator) {
02450                      zval *retval, *zchildren, zflags;
02451                      zend_call_method_with_0_params(&intern->inner.zobject, intern->inner.ce, NULL, "haschildren", &retval);
02452                      if (EG(exception)) {
02453                             if (retval) {
02454                                    zval_ptr_dtor(&retval);
02455                             }
02456                             if (intern->u.caching.flags & CIT_CATCH_GET_CHILD) {
02457                                    zend_clear_exception(TSRMLS_C);
02458                             } else {
02459                                    return;
02460                             }
02461                      } else {
02462                             if (zend_is_true(retval)) {
02463                                    zend_call_method_with_0_params(&intern->inner.zobject, intern->inner.ce, NULL, "getchildren", &zchildren);
02464                                    if (EG(exception)) {
02465                                           if (zchildren) {
02466                                                  zval_ptr_dtor(&zchildren);
02467                                           }
02468                                           if (intern->u.caching.flags & CIT_CATCH_GET_CHILD) {
02469                                                  zend_clear_exception(TSRMLS_C);
02470                                           } else {
02471                                                  zval_ptr_dtor(&retval);
02472                                                  return;
02473                                           }
02474                                    } else {
02475                                           INIT_PZVAL(&zflags);
02476                                           ZVAL_LONG(&zflags, intern->u.caching.flags & CIT_PUBLIC);
02477                                           spl_instantiate_arg_ex2(spl_ce_RecursiveCachingIterator, &intern->u.caching.zchildren, 1, zchildren, &zflags TSRMLS_CC);
02478                                           zval_ptr_dtor(&zchildren);
02479                                    }
02480                             }
02481                             zval_ptr_dtor(&retval);
02482                             if (EG(exception)) {
02483                                    if (intern->u.caching.flags & CIT_CATCH_GET_CHILD) {
02484                                           zend_clear_exception(TSRMLS_C);
02485                                    } else {
02486                                           return;
02487                                    }
02488                             }
02489                      }
02490               }
02491               if (intern->u.caching.flags & (CIT_TOSTRING_USE_INNER|CIT_CALL_TOSTRING)) {
02492                      int  use_copy;
02493                      zval expr_copy;
02494                      ALLOC_ZVAL(intern->u.caching.zstr);
02495                      if (intern->u.caching.flags & CIT_TOSTRING_USE_INNER) {
02496                             *intern->u.caching.zstr = *intern->inner.zobject;
02497                      } else {
02498                             *intern->u.caching.zstr = *intern->current.data;
02499                      }
02500                      zend_make_printable_zval(intern->u.caching.zstr, &expr_copy, &use_copy);
02501                      if (use_copy) {
02502                             *intern->u.caching.zstr = expr_copy;
02503                             INIT_PZVAL(intern->u.caching.zstr);
02504                             zval_copy_ctor(intern->u.caching.zstr);
02505                             zval_dtor(&expr_copy);
02506                      } else {
02507                             INIT_PZVAL(intern->u.caching.zstr);
02508                             zval_copy_ctor(intern->u.caching.zstr);
02509                      }
02510               }
02511               spl_dual_it_next(intern, 0 TSRMLS_CC);    
02512        } else {
02513               intern->u.caching.flags &= ~CIT_VALID;
02514        }
02515 }
02516 
02517 static inline void spl_caching_it_rewind(spl_dual_it_object *intern TSRMLS_DC)
02518 {
02519        spl_dual_it_rewind(intern TSRMLS_CC);
02520        zend_hash_clean(HASH_OF(intern->u.caching.zcache));
02521        spl_caching_it_next(intern TSRMLS_CC);
02522 }
02523 
02524 /* {{{ proto void CachingIterator::__construct(Iterator it [, flags = CIT_CALL_TOSTRING])
02525    Construct a CachingIterator from an Iterator */
02526 SPL_METHOD(CachingIterator, __construct)
02527 {
02528        spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_CachingIterator, zend_ce_iterator, DIT_CachingIterator);
02529 } /* }}} */
02530 
02531 /* {{{ proto void CachingIterator::rewind()
02532    Rewind the iterator */
02533 SPL_METHOD(CachingIterator, rewind)
02534 {
02535        spl_dual_it_object   *intern;
02536        
02537        if (zend_parse_parameters_none() == FAILURE) {
02538               return;
02539        }
02540 
02541        SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
02542 
02543        spl_caching_it_rewind(intern TSRMLS_CC);
02544 } /* }}} */
02545 
02546 /* {{{ proto bool CachingIterator::valid()
02547    Check whether the current element is valid */
02548 SPL_METHOD(CachingIterator, valid)
02549 {
02550        spl_dual_it_object   *intern;
02551        
02552        if (zend_parse_parameters_none() == FAILURE) {
02553               return;
02554        }
02555 
02556        SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
02557 
02558        RETURN_BOOL(spl_caching_it_valid(intern TSRMLS_CC) == SUCCESS);
02559 } /* }}} */
02560 
02561 /* {{{ proto void CachingIterator::next()
02562    Move the iterator forward */
02563 SPL_METHOD(CachingIterator, next)
02564 {
02565        spl_dual_it_object   *intern;
02566        
02567        if (zend_parse_parameters_none() == FAILURE) {
02568               return;
02569        }
02570 
02571        SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
02572 
02573        spl_caching_it_next(intern TSRMLS_CC);
02574 } /* }}} */
02575 
02576 /* {{{ proto bool CachingIterator::hasNext()
02577    Check whether the inner iterator has a valid next element */
02578 SPL_METHOD(CachingIterator, hasNext)
02579 {
02580        spl_dual_it_object   *intern;
02581        
02582        if (zend_parse_parameters_none() == FAILURE) {
02583               return;
02584        }
02585 
02586        SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
02587 
02588        RETURN_BOOL(spl_caching_it_has_next(intern TSRMLS_CC) == SUCCESS);
02589 } /* }}} */
02590 
02591 /* {{{ proto string CachingIterator::__toString()
02592    Return the string representation of the current element */
02593 SPL_METHOD(CachingIterator, __toString)
02594 {
02595        spl_dual_it_object   *intern;
02596 
02597        SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
02598 
02599        if (!(intern->u.caching.flags & (CIT_CALL_TOSTRING|CIT_TOSTRING_USE_KEY|CIT_TOSTRING_USE_CURRENT|CIT_TOSTRING_USE_INNER)))    {
02600               zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "%s does not fetch string value (see CachingIterator::__construct)", Z_OBJCE_P(getThis())->name);
02601               return;
02602        }
02603        if (intern->u.caching.flags & CIT_TOSTRING_USE_KEY) {
02604               if (intern->current.key_type == HASH_KEY_IS_STRING) {
02605                      RETURN_STRINGL(intern->current.str_key, intern->current.str_key_len-1, 1);
02606               } else {
02607                      RETVAL_LONG(intern->current.int_key);
02608                      convert_to_string(return_value);
02609                      return;
02610               }
02611        } else if (intern->u.caching.flags & CIT_TOSTRING_USE_CURRENT) {
02612               MAKE_COPY_ZVAL(&intern->current.data, return_value);
02613               convert_to_string(return_value);
02614               return;
02615        }
02616        if (intern->u.caching.zstr) {
02617               RETURN_STRINGL(Z_STRVAL_P(intern->u.caching.zstr), Z_STRLEN_P(intern->u.caching.zstr), 1);
02618        } else {
02619               RETURN_NULL();
02620        }
02621 } /* }}} */
02622 
02623 /* {{{ proto void CachingIterator::offsetSet(mixed index, mixed newval)
02624    Set given index in cache */
02625 SPL_METHOD(CachingIterator, offsetSet)
02626 {
02627        spl_dual_it_object   *intern;
02628        char *arKey;
02629        uint nKeyLength;
02630        zval *value;
02631 
02632        SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
02633 
02634        if (!(intern->u.caching.flags & CIT_FULL_CACHE)) {
02635               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);
02636               return;
02637        }
02638 
02639        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz", &arKey, &nKeyLength, &value) == FAILURE) {
02640               return;
02641        }
02642 
02643        Z_ADDREF_P(value);
02644        zend_symtable_update(HASH_OF(intern->u.caching.zcache), arKey, nKeyLength+1, &value, sizeof(value), NULL);
02645 }
02646 /* }}} */
02647 
02648 /* {{{ proto string CachingIterator::offsetGet(mixed index)
02649    Return the internal cache if used */
02650 SPL_METHOD(CachingIterator, offsetGet)
02651 {
02652        spl_dual_it_object   *intern;
02653        char *arKey;
02654        uint nKeyLength;
02655        zval **value;
02656 
02657        SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
02658 
02659        if (!(intern->u.caching.flags & CIT_FULL_CACHE)) {
02660               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);
02661               return;
02662        }
02663 
02664        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &arKey, &nKeyLength) == FAILURE) {
02665               return;
02666        }
02667 
02668        if (zend_symtable_find(HASH_OF(intern->u.caching.zcache), arKey, nKeyLength+1, (void**)&value) == FAILURE) {
02669               zend_error(E_NOTICE, "Undefined index:  %s", arKey);
02670               return;
02671        }
02672        
02673        RETURN_ZVAL(*value, 1, 0);
02674 }
02675 /* }}} */
02676 
02677 /* {{{ proto void CachingIterator::offsetUnset(mixed index)
02678    Unset given index in cache */
02679 SPL_METHOD(CachingIterator, offsetUnset)
02680 {
02681        spl_dual_it_object   *intern;
02682        char *arKey;
02683        uint nKeyLength;
02684 
02685        SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
02686 
02687        if (!(intern->u.caching.flags & CIT_FULL_CACHE)) {
02688               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);
02689               return;
02690        }
02691 
02692        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &arKey, &nKeyLength) == FAILURE) {
02693               return;
02694        }
02695 
02696        zend_symtable_del(HASH_OF(intern->u.caching.zcache), arKey, nKeyLength+1);
02697 }
02698 /* }}} */
02699 
02700 /* {{{ proto bool CachingIterator::offsetExists(mixed index)
02701    Return whether the requested index exists */
02702 SPL_METHOD(CachingIterator, offsetExists)
02703 {
02704        spl_dual_it_object   *intern;
02705        char *arKey;
02706        uint nKeyLength;
02707        
02708        SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
02709 
02710        if (!(intern->u.caching.flags & CIT_FULL_CACHE)) {
02711               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);
02712               return;
02713        }
02714        
02715        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &arKey, &nKeyLength) == FAILURE) {
02716               return;
02717        }
02718 
02719        RETURN_BOOL(zend_symtable_exists(HASH_OF(intern->u.caching.zcache), arKey, nKeyLength+1));
02720 }
02721 /* }}} */
02722 
02723 /* {{{ proto bool CachingIterator::getCache()
02724    Return the cache */
02725 SPL_METHOD(CachingIterator, getCache)
02726 {
02727        spl_dual_it_object   *intern;
02728        
02729        if (zend_parse_parameters_none() == FAILURE) {
02730               return;
02731        }
02732        
02733        SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
02734 
02735        if (!(intern->u.caching.flags & CIT_FULL_CACHE)) {
02736               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);
02737               return;
02738        }
02739 
02740        RETURN_ZVAL(intern->u.caching.zcache, 1, 0);
02741 }
02742 /* }}} */
02743 
02744 /* {{{ proto int CachingIterator::getFlags()
02745    Return the internal flags */
02746 SPL_METHOD(CachingIterator, getFlags)
02747 {
02748        spl_dual_it_object   *intern;
02749 
02750        if (zend_parse_parameters_none() == FAILURE) {
02751               return;
02752        }
02753        
02754        SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
02755 
02756        RETURN_LONG(intern->u.caching.flags);
02757 }
02758 /* }}} */
02759 
02760 /* {{{ proto void CachingIterator::setFlags(int flags)
02761    Set the internal flags */
02762 SPL_METHOD(CachingIterator, setFlags)
02763 {
02764        spl_dual_it_object   *intern;
02765        long flags;
02766 
02767        SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
02768 
02769        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &flags) == FAILURE) {
02770               return;
02771        }
02772 
02773        if (spl_cit_check_flags(flags) != SUCCESS) {
02774               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);
02775               return;
02776        }
02777        if ((intern->u.caching.flags & CIT_CALL_TOSTRING) != 0 && (flags & CIT_CALL_TOSTRING) == 0) {
02778               zend_throw_exception(spl_ce_InvalidArgumentException, "Unsetting flag CALL_TO_STRING is not possible", 0 TSRMLS_CC);
02779               return;
02780        }
02781        if ((intern->u.caching.flags & CIT_TOSTRING_USE_INNER) != 0 && (flags & CIT_TOSTRING_USE_INNER) == 0) {
02782               zend_throw_exception(spl_ce_InvalidArgumentException, "Unsetting flag TOSTRING_USE_INNER is not possible", 0 TSRMLS_CC);
02783               return;
02784        }
02785        if ((flags & CIT_FULL_CACHE) != 0 && (intern->u.caching.flags & CIT_FULL_CACHE) == 0) {
02786               /* clear on (re)enable */
02787               zend_hash_clean(HASH_OF(intern->u.caching.zcache));
02788        }
02789        intern->u.caching.flags = (intern->u.caching.flags & ~CIT_PUBLIC) | (flags & CIT_PUBLIC);
02790 }
02791 /* }}} */
02792 
02793 /* {{{ proto void CachingIterator::count()
02794    Number of cached elements */
02795 SPL_METHOD(CachingIterator, count)
02796 {
02797        spl_dual_it_object   *intern;
02798 
02799        if (zend_parse_parameters_none() == FAILURE) {
02800               return;
02801        }
02802        
02803        SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
02804 
02805        if (!(intern->u.caching.flags & CIT_FULL_CACHE)) {
02806               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);
02807               return;
02808        }
02809 
02810        RETURN_LONG(zend_hash_num_elements(HASH_OF(intern->u.caching.zcache)));
02811 }
02812 /* }}} */
02813 
02814 ZEND_BEGIN_ARG_INFO_EX(arginfo_caching_it___construct, 0, 0, 1) 
02815        ZEND_ARG_OBJ_INFO(0, iterator, Iterator, 0)
02816        ZEND_ARG_INFO(0, flags)
02817 ZEND_END_ARG_INFO();
02818 
02819 ZEND_BEGIN_ARG_INFO(arginfo_caching_it_setFlags, 0) 
02820        ZEND_ARG_INFO(0, flags)
02821 ZEND_END_ARG_INFO();
02822 
02823 ZEND_BEGIN_ARG_INFO(arginfo_caching_it_offsetGet, 0)
02824        ZEND_ARG_INFO(0, index)
02825 ZEND_END_ARG_INFO();
02826 
02827 ZEND_BEGIN_ARG_INFO(arginfo_caching_it_offsetSet, 0)
02828        ZEND_ARG_INFO(0, index)
02829        ZEND_ARG_INFO(0, newval)
02830 ZEND_END_ARG_INFO();
02831 
02832 static const zend_function_entry spl_funcs_CachingIterator[] = {
02833        SPL_ME(CachingIterator, __construct,      arginfo_caching_it___construct, ZEND_ACC_PUBLIC)
02834        SPL_ME(CachingIterator, rewind,           arginfo_recursive_it_void,      ZEND_ACC_PUBLIC)
02835        SPL_ME(CachingIterator, valid,            arginfo_recursive_it_void,      ZEND_ACC_PUBLIC)
02836        SPL_ME(dual_it,         key,              arginfo_recursive_it_void,      ZEND_ACC_PUBLIC)
02837        SPL_ME(dual_it,         current,          arginfo_recursive_it_void,      ZEND_ACC_PUBLIC)
02838        SPL_ME(CachingIterator, next,             arginfo_recursive_it_void,      ZEND_ACC_PUBLIC)
02839        SPL_ME(CachingIterator, hasNext,          arginfo_recursive_it_void,      ZEND_ACC_PUBLIC)
02840        SPL_ME(CachingIterator, __toString,       arginfo_recursive_it_void,      ZEND_ACC_PUBLIC)
02841        SPL_ME(dual_it,         getInnerIterator, arginfo_recursive_it_void,      ZEND_ACC_PUBLIC)
02842        SPL_ME(CachingIterator, getFlags,         arginfo_recursive_it_void,      ZEND_ACC_PUBLIC)
02843        SPL_ME(CachingIterator, setFlags,         arginfo_caching_it_setFlags,    ZEND_ACC_PUBLIC)
02844        SPL_ME(CachingIterator, offsetGet,        arginfo_caching_it_offsetGet,   ZEND_ACC_PUBLIC)
02845        SPL_ME(CachingIterator, offsetSet,        arginfo_caching_it_offsetSet,   ZEND_ACC_PUBLIC)
02846        SPL_ME(CachingIterator, offsetUnset,      arginfo_caching_it_offsetGet,   ZEND_ACC_PUBLIC)
02847        SPL_ME(CachingIterator, offsetExists,     arginfo_caching_it_offsetGet,   ZEND_ACC_PUBLIC)
02848        SPL_ME(CachingIterator, getCache,         arginfo_recursive_it_void,      ZEND_ACC_PUBLIC)
02849        SPL_ME(CachingIterator, count,            arginfo_recursive_it_void,      ZEND_ACC_PUBLIC)
02850        PHP_FE_END
02851 };
02852 
02853 /* {{{ proto void RecursiveCachingIterator::__construct(RecursiveIterator it [, flags = CIT_CALL_TOSTRING])
02854    Create an iterator from a RecursiveIterator */
02855 SPL_METHOD(RecursiveCachingIterator, __construct)
02856 {
02857        spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_RecursiveCachingIterator, spl_ce_RecursiveIterator, DIT_RecursiveCachingIterator);
02858 } /* }}} */
02859 
02860 /* {{{ proto bool RecursiveCachingIterator::hasChildren()
02861    Check whether the current element of the inner iterator has children */
02862 SPL_METHOD(RecursiveCachingIterator, hasChildren)
02863 {
02864        spl_dual_it_object   *intern;
02865 
02866        if (zend_parse_parameters_none() == FAILURE) {
02867               return;
02868        }
02869        
02870        SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
02871 
02872        RETURN_BOOL(intern->u.caching.zchildren);
02873 } /* }}} */
02874 
02875 /* {{{ proto RecursiveCachingIterator RecursiveCachingIterator::getChildren()
02876   Return the inner iterator's children as a RecursiveCachingIterator */
02877 SPL_METHOD(RecursiveCachingIterator, getChildren)
02878 {
02879        spl_dual_it_object   *intern;
02880        
02881        if (zend_parse_parameters_none() == FAILURE) {
02882               return;
02883        }
02884 
02885        SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
02886 
02887        if (intern->u.caching.zchildren) {
02888               RETURN_ZVAL(intern->u.caching.zchildren, 1, 0);
02889        } else {
02890               RETURN_NULL();
02891        }
02892 } /* }}} */
02893 
02894 ZEND_BEGIN_ARG_INFO_EX(arginfo_caching_rec_it___construct, 0, ZEND_RETURN_VALUE, 1) 
02895        ZEND_ARG_OBJ_INFO(0, iterator, Iterator, 0)
02896        ZEND_ARG_INFO(0, flags)
02897 ZEND_END_ARG_INFO();
02898 
02899 static const zend_function_entry spl_funcs_RecursiveCachingIterator[] = {
02900        SPL_ME(RecursiveCachingIterator, __construct,   arginfo_caching_rec_it___construct, ZEND_ACC_PUBLIC)
02901        SPL_ME(RecursiveCachingIterator, hasChildren,   arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
02902        SPL_ME(RecursiveCachingIterator, getChildren,   arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
02903        PHP_FE_END
02904 };
02905 
02906 /* {{{ proto void IteratorIterator::__construct(Traversable it)
02907    Create an iterator from anything that is traversable */
02908 SPL_METHOD(IteratorIterator, __construct)
02909 {
02910        spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_IteratorIterator, zend_ce_traversable, DIT_IteratorIterator);
02911 } /* }}} */
02912 
02913 ZEND_BEGIN_ARG_INFO(arginfo_iterator_it___construct, 0) 
02914        ZEND_ARG_OBJ_INFO(0, iterator, Traversable, 0)
02915 ZEND_END_ARG_INFO();
02916 
02917 static const zend_function_entry spl_funcs_IteratorIterator[] = {
02918        SPL_ME(IteratorIterator, __construct,      arginfo_iterator_it___construct, ZEND_ACC_PUBLIC)
02919        SPL_ME(dual_it,          rewind,           arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
02920        SPL_ME(dual_it,          valid,            arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
02921        SPL_ME(dual_it,          key,              arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
02922        SPL_ME(dual_it,          current,          arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
02923        SPL_ME(dual_it,          next,             arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
02924        SPL_ME(dual_it,          getInnerIterator, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
02925        PHP_FE_END
02926 };
02927 
02928 /* {{{ proto void NoRewindIterator::__construct(Iterator it)
02929    Create an iterator from another iterator */
02930 SPL_METHOD(NoRewindIterator, __construct)
02931 {
02932        spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_NoRewindIterator, zend_ce_iterator, DIT_NoRewindIterator);
02933 } /* }}} */
02934 
02935 /* {{{ proto void NoRewindIterator::rewind()
02936    Prevent a call to inner iterators rewind() */
02937 SPL_METHOD(NoRewindIterator, rewind)
02938 {
02939        if (zend_parse_parameters_none() == FAILURE) {
02940               return;
02941        }
02942        /* nothing to do */
02943 } /* }}} */
02944 
02945 /* {{{ proto bool NoRewindIterator::valid()
02946    Return inner iterators valid() */
02947 SPL_METHOD(NoRewindIterator, valid)
02948 {
02949        spl_dual_it_object   *intern;
02950        
02951        if (zend_parse_parameters_none() == FAILURE) {
02952               return;
02953        }
02954 
02955        SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
02956        RETURN_BOOL(intern->inner.iterator->funcs->valid(intern->inner.iterator TSRMLS_CC) == SUCCESS);
02957 } /* }}} */
02958 
02959 /* {{{ proto mixed NoRewindIterator::key()
02960    Return inner iterators key() */
02961 SPL_METHOD(NoRewindIterator, key)
02962 {
02963        spl_dual_it_object   *intern;
02964        
02965        if (zend_parse_parameters_none() == FAILURE) {
02966               return;
02967        }
02968 
02969        SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
02970 
02971        if (intern->inner.iterator->funcs->get_current_key) {
02972               char *str_key;
02973               uint str_key_len;
02974               ulong int_key;
02975               switch (intern->inner.iterator->funcs->get_current_key(intern->inner.iterator, &str_key, &str_key_len, &int_key TSRMLS_CC)) {
02976                      case HASH_KEY_IS_LONG:
02977                             RETURN_LONG(int_key);
02978                             break;
02979                      case HASH_KEY_IS_STRING:
02980                             RETURN_STRINGL(str_key, str_key_len-1, 0);
02981                             break;
02982                      default:
02983                             RETURN_NULL();
02984               }
02985        } else {
02986               RETURN_NULL();
02987        }
02988 } /* }}} */
02989 
02990 /* {{{ proto mixed NoRewindIterator::current()
02991    Return inner iterators current() */
02992 SPL_METHOD(NoRewindIterator, current)
02993 {
02994        spl_dual_it_object   *intern;
02995        zval **data;
02996        
02997        if (zend_parse_parameters_none() == FAILURE) {
02998               return;
02999        }
03000 
03001        SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
03002        intern->inner.iterator->funcs->get_current_data(intern->inner.iterator, &data TSRMLS_CC);
03003        if (data && *data) {
03004               RETURN_ZVAL(*data, 1, 0);
03005        }
03006 } /* }}} */
03007 
03008 /* {{{ proto void NoRewindIterator::next()
03009    Return inner iterators next() */
03010 SPL_METHOD(NoRewindIterator, next)
03011 {
03012        spl_dual_it_object   *intern;
03013        
03014        if (zend_parse_parameters_none() == FAILURE) {
03015               return;
03016        }
03017 
03018        SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
03019        intern->inner.iterator->funcs->move_forward(intern->inner.iterator TSRMLS_CC);
03020 } /* }}} */
03021 
03022 ZEND_BEGIN_ARG_INFO(arginfo_norewind_it___construct, 0) 
03023        ZEND_ARG_OBJ_INFO(0, iterator, Iterator, 0)
03024 ZEND_END_ARG_INFO();
03025 
03026 static const zend_function_entry spl_funcs_NoRewindIterator[] = {
03027        SPL_ME(NoRewindIterator, __construct,      arginfo_norewind_it___construct, ZEND_ACC_PUBLIC)
03028        SPL_ME(NoRewindIterator, rewind,           arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
03029        SPL_ME(NoRewindIterator, valid,            arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
03030        SPL_ME(NoRewindIterator, key,              arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
03031        SPL_ME(NoRewindIterator, current,          arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
03032        SPL_ME(NoRewindIterator, next,             arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
03033        SPL_ME(dual_it,          getInnerIterator, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
03034        PHP_FE_END
03035 };
03036 
03037 /* {{{ proto void InfiniteIterator::__construct(Iterator it)
03038    Create an iterator from another iterator */
03039 SPL_METHOD(InfiniteIterator, __construct)
03040 {
03041        spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_InfiniteIterator, zend_ce_iterator, DIT_InfiniteIterator);
03042 } /* }}} */
03043 
03044 /* {{{ proto void InfiniteIterator::next()
03045    Prevent a call to inner iterators rewind() (internally the current data will be fetched if valid()) */
03046 SPL_METHOD(InfiniteIterator, next)
03047 {
03048        spl_dual_it_object   *intern;
03049        
03050        if (zend_parse_parameters_none() == FAILURE) {
03051               return;
03052        }
03053 
03054        SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
03055 
03056        spl_dual_it_next(intern, 1 TSRMLS_CC);
03057        if (spl_dual_it_valid(intern TSRMLS_CC) == SUCCESS) {
03058               spl_dual_it_fetch(intern, 0 TSRMLS_CC);
03059        } else {
03060               spl_dual_it_rewind(intern TSRMLS_CC);
03061               if (spl_dual_it_valid(intern TSRMLS_CC) == SUCCESS) {
03062                      spl_dual_it_fetch(intern, 0 TSRMLS_CC);
03063               }
03064        }
03065 } /* }}} */
03066 
03067 static const zend_function_entry spl_funcs_InfiniteIterator[] = {
03068        SPL_ME(InfiniteIterator, __construct,      arginfo_norewind_it___construct, ZEND_ACC_PUBLIC)
03069        SPL_ME(InfiniteIterator, next,             arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
03070        PHP_FE_END
03071 };
03072 
03073 /* {{{ proto void EmptyIterator::rewind()
03074    Does nothing  */
03075 SPL_METHOD(EmptyIterator, rewind)
03076 {
03077        if (zend_parse_parameters_none() == FAILURE) {
03078               return;
03079        }
03080 } /* }}} */
03081 
03082 /* {{{ proto false EmptyIterator::valid()
03083    Return false */
03084 SPL_METHOD(EmptyIterator, valid)
03085 {
03086        if (zend_parse_parameters_none() == FAILURE) {
03087               return;
03088        }
03089        RETURN_FALSE;
03090 } /* }}} */
03091 
03092 /* {{{ proto void EmptyIterator::key()
03093    Throws exception BadMethodCallException */
03094 SPL_METHOD(EmptyIterator, key)
03095 {
03096        if (zend_parse_parameters_none() == FAILURE) {
03097               return;
03098        }
03099        zend_throw_exception(spl_ce_BadMethodCallException, "Accessing the key of an EmptyIterator", 0 TSRMLS_CC);
03100 } /* }}} */
03101 
03102 /* {{{ proto void EmptyIterator::current()
03103    Throws exception BadMethodCallException */
03104 SPL_METHOD(EmptyIterator, current)
03105 {
03106        if (zend_parse_parameters_none() == FAILURE) {
03107               return;
03108        }
03109        zend_throw_exception(spl_ce_BadMethodCallException, "Accessing the value of an EmptyIterator", 0 TSRMLS_CC);
03110 } /* }}} */
03111 
03112 /* {{{ proto void EmptyIterator::next()
03113    Does nothing */
03114 SPL_METHOD(EmptyIterator, next)
03115 {
03116        if (zend_parse_parameters_none() == FAILURE) {
03117               return;
03118        }
03119 } /* }}} */
03120 
03121 static const zend_function_entry spl_funcs_EmptyIterator[] = {
03122        SPL_ME(EmptyIterator, rewind,           arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
03123        SPL_ME(EmptyIterator, valid,            arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
03124        SPL_ME(EmptyIterator, key,              arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
03125        SPL_ME(EmptyIterator, current,          arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
03126        SPL_ME(EmptyIterator, next,             arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
03127        PHP_FE_END
03128 };
03129 
03130 int spl_append_it_next_iterator(spl_dual_it_object *intern TSRMLS_DC) /* {{{*/
03131 {
03132        spl_dual_it_free(intern TSRMLS_CC);
03133 
03134        if (intern->inner.zobject) {
03135               zval_ptr_dtor(&intern->inner.zobject);
03136               intern->inner.zobject = NULL;
03137               intern->inner.ce = NULL;
03138               intern->inner.object = NULL;
03139               if (intern->inner.iterator) {
03140                      intern->inner.iterator->funcs->dtor(intern->inner.iterator TSRMLS_CC);
03141                      intern->inner.iterator = NULL;
03142               }
03143        }
03144        if (intern->u.append.iterator->funcs->valid(intern->u.append.iterator TSRMLS_CC) == SUCCESS) {
03145               zval **it;
03146 
03147               intern->u.append.iterator->funcs->get_current_data(intern->u.append.iterator, &it TSRMLS_CC);
03148               Z_ADDREF_PP(it);
03149               intern->inner.zobject = *it;
03150               intern->inner.ce = Z_OBJCE_PP(it);
03151               intern->inner.object = zend_object_store_get_object(*it TSRMLS_CC);
03152               intern->inner.iterator = intern->inner.ce->get_iterator(intern->inner.ce, *it, 0 TSRMLS_CC);
03153               spl_dual_it_rewind(intern TSRMLS_CC);
03154               return SUCCESS;
03155        } else {
03156               return FAILURE;
03157        }
03158 } /* }}} */
03159 
03160 void spl_append_it_fetch(spl_dual_it_object *intern TSRMLS_DC) /* {{{*/
03161 {
03162        while (spl_dual_it_valid(intern TSRMLS_CC) != SUCCESS) {
03163               intern->u.append.iterator->funcs->move_forward(intern->u.append.iterator TSRMLS_CC);
03164               if (spl_append_it_next_iterator(intern TSRMLS_CC) != SUCCESS) {
03165                      return;
03166               }
03167        }
03168        spl_dual_it_fetch(intern, 0 TSRMLS_CC);
03169 } /* }}} */
03170 
03171 void spl_append_it_next(spl_dual_it_object *intern TSRMLS_DC) /* {{{ */
03172 {
03173        if (spl_dual_it_valid(intern TSRMLS_CC) == SUCCESS) {
03174               spl_dual_it_next(intern, 1 TSRMLS_CC);
03175        }
03176        spl_append_it_fetch(intern TSRMLS_CC);
03177 } /* }}} */
03178 
03179 /* {{{ proto void AppendIterator::__construct()
03180    Create an AppendIterator */
03181 SPL_METHOD(AppendIterator, __construct)
03182 {
03183        spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_AppendIterator, zend_ce_iterator, DIT_AppendIterator);
03184 } /* }}} */
03185 
03186 /* {{{ proto void AppendIterator::append(Iterator it)
03187    Append an iterator */
03188 SPL_METHOD(AppendIterator, append)
03189 {
03190        spl_dual_it_object   *intern;
03191        zval *it;
03192 
03193        SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
03194 
03195        if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "O", &it, zend_ce_iterator) == FAILURE) {
03196               return;
03197        }
03198        spl_array_iterator_append(intern->u.append.zarrayit, it TSRMLS_CC);
03199 
03200        if (!intern->inner.iterator || spl_dual_it_valid(intern TSRMLS_CC) != SUCCESS) {
03201               if (intern->u.append.iterator->funcs->valid(intern->u.append.iterator TSRMLS_CC) != SUCCESS) {
03202                      intern->u.append.iterator->funcs->rewind(intern->u.append.iterator TSRMLS_CC);
03203               }
03204               do {
03205                      spl_append_it_next_iterator(intern TSRMLS_CC);
03206               } while (intern->inner.zobject != it);
03207               spl_append_it_fetch(intern TSRMLS_CC);
03208        }
03209 } /* }}} */
03210 
03211 /* {{{ proto void AppendIterator::rewind()
03212    Rewind to the first iterator and rewind the first iterator, too */
03213 SPL_METHOD(AppendIterator, rewind)
03214 {
03215        spl_dual_it_object   *intern;
03216        
03217        if (zend_parse_parameters_none() == FAILURE) {
03218               return;
03219        }
03220 
03221        SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
03222        
03223        intern->u.append.iterator->funcs->rewind(intern->u.append.iterator TSRMLS_CC);
03224        if (spl_append_it_next_iterator(intern TSRMLS_CC) == SUCCESS) {
03225               spl_append_it_fetch(intern TSRMLS_CC);
03226        }
03227 } /* }}} */
03228 
03229 /* {{{ proto bool AppendIterator::valid()
03230    Check if the current state is valid */
03231 SPL_METHOD(AppendIterator, valid)
03232 {
03233        spl_dual_it_object   *intern;
03234 
03235        if (zend_parse_parameters_none() == FAILURE) {
03236               return;
03237        }
03238        
03239        SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
03240 
03241        RETURN_BOOL(intern->current.data);
03242 } /* }}} */
03243 
03244 /* {{{ proto void AppendIterator::next()
03245    Forward to next element */
03246 SPL_METHOD(AppendIterator, next)
03247 {
03248        spl_dual_it_object   *intern;
03249        
03250        if (zend_parse_parameters_none() == FAILURE) {
03251               return;
03252        }
03253 
03254        SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
03255        
03256        spl_append_it_next(intern TSRMLS_CC);
03257 } /* }}} */
03258 
03259 /* {{{ proto int AppendIterator::getIteratorIndex()
03260    Get index of iterator */
03261 SPL_METHOD(AppendIterator, getIteratorIndex)
03262 {
03263        spl_dual_it_object   *intern;
03264        
03265        if (zend_parse_parameters_none() == FAILURE) {
03266               return;
03267        }
03268 
03269        SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
03270 
03271        APPENDIT_CHECK_CTOR(intern);
03272        spl_array_iterator_key(intern->u.append.zarrayit, return_value TSRMLS_CC);
03273 } /* }}} */
03274 
03275 /* {{{ proto ArrayIterator AppendIterator::getArrayIterator()
03276    Get access to inner ArrayIterator */
03277 SPL_METHOD(AppendIterator, getArrayIterator)
03278 {
03279        spl_dual_it_object   *intern;
03280        
03281        if (zend_parse_parameters_none() == FAILURE) {
03282               return;
03283        }
03284 
03285        SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis());
03286 
03287        RETURN_ZVAL(intern->u.append.zarrayit, 1, 0);
03288 } /* }}} */
03289 
03290 ZEND_BEGIN_ARG_INFO(arginfo_append_it_append, 0) 
03291        ZEND_ARG_OBJ_INFO(0, iterator, Iterator, 0)
03292 ZEND_END_ARG_INFO();
03293 
03294 static const zend_function_entry spl_funcs_AppendIterator[] = {
03295        SPL_ME(AppendIterator, __construct,      arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
03296        SPL_ME(AppendIterator, append,           arginfo_append_it_append, ZEND_ACC_PUBLIC)
03297        SPL_ME(AppendIterator, rewind,           arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
03298        SPL_ME(AppendIterator, valid,            arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
03299        SPL_ME(dual_it,        key,              arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
03300        SPL_ME(dual_it,        current,          arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
03301        SPL_ME(AppendIterator, next,             arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
03302        SPL_ME(dual_it,        getInnerIterator, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
03303        SPL_ME(AppendIterator, getIteratorIndex, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
03304        SPL_ME(AppendIterator, getArrayIterator, arginfo_recursive_it_void, ZEND_ACC_PUBLIC)
03305        PHP_FE_END
03306 };
03307 
03308 PHPAPI int spl_iterator_apply(zval *obj, spl_iterator_apply_func_t apply_func, void *puser TSRMLS_DC)
03309 {
03310        zend_object_iterator   *iter;
03311        zend_class_entry       *ce = Z_OBJCE_P(obj);
03312 
03313        iter = ce->get_iterator(ce, obj, 0 TSRMLS_CC);
03314 
03315        if (EG(exception)) {
03316               goto done;
03317        }
03318 
03319        iter->index = 0;
03320        if (iter->funcs->rewind) {
03321               iter->funcs->rewind(iter TSRMLS_CC);
03322               if (EG(exception)) {
03323                      goto done;
03324               }
03325        }
03326 
03327        while (iter->funcs->valid(iter TSRMLS_CC) == SUCCESS) {
03328               if (EG(exception)) {
03329                      goto done;
03330               }
03331               if (apply_func(iter, puser TSRMLS_CC) == ZEND_HASH_APPLY_STOP || EG(exception)) {
03332                      goto done;
03333               }
03334               iter->index++;
03335               iter->funcs->move_forward(iter TSRMLS_CC);
03336               if (EG(exception)) {
03337                      goto done;
03338               }
03339        }
03340 
03341 done:
03342        if (iter) {
03343               iter->funcs->dtor(iter TSRMLS_CC);
03344        }
03345        return EG(exception) ? FAILURE : SUCCESS;
03346 }
03347 /* }}} */
03348 
03349 static int spl_iterator_to_array_apply(zend_object_iterator *iter, void *puser TSRMLS_DC) /* {{{ */
03350 {
03351        zval                    **data, *return_value = (zval*)puser;
03352        char                    *str_key;
03353        uint                    str_key_len;
03354        ulong                   int_key;
03355        int                     key_type;
03356 
03357        iter->funcs->get_current_data(iter, &data TSRMLS_CC);
03358        if (EG(exception)) {
03359               return ZEND_HASH_APPLY_STOP;
03360        }
03361        if (data == NULL || *data == NULL) {
03362               return ZEND_HASH_APPLY_STOP;
03363        }
03364        if (iter->funcs->get_current_key) {
03365               key_type = iter->funcs->get_current_key(iter, &str_key, &str_key_len, &int_key TSRMLS_CC);
03366               if (EG(exception)) {
03367                      return ZEND_HASH_APPLY_STOP;
03368               }
03369               Z_ADDREF_PP(data);
03370               switch(key_type) {
03371                      case HASH_KEY_IS_STRING:
03372                             add_assoc_zval_ex(return_value, str_key, str_key_len, *data);
03373                             efree(str_key);
03374                             break;
03375                      case HASH_KEY_IS_LONG:
03376                             add_index_zval(return_value, int_key, *data);
03377                             break;
03378               }
03379        } else {
03380               Z_ADDREF_PP(data);
03381               add_next_index_zval(return_value, *data);
03382        }
03383        return ZEND_HASH_APPLY_KEEP;
03384 }
03385 /* }}} */
03386 
03387 static int spl_iterator_to_values_apply(zend_object_iterator *iter, void *puser TSRMLS_DC) /* {{{ */
03388 {
03389        zval **data, *return_value = (zval*)puser;
03390 
03391        iter->funcs->get_current_data(iter, &data TSRMLS_CC);
03392        if (EG(exception)) {
03393               return ZEND_HASH_APPLY_STOP;
03394        }
03395        if (data == NULL || *data == NULL) {
03396               return ZEND_HASH_APPLY_STOP;
03397        }
03398        Z_ADDREF_PP(data);
03399        add_next_index_zval(return_value, *data);
03400        return ZEND_HASH_APPLY_KEEP;
03401 }
03402 /* }}} */
03403 
03404 /* {{{ proto array iterator_to_array(Traversable it [, bool use_keys = true]) 
03405    Copy the iterator into an array */
03406 PHP_FUNCTION(iterator_to_array)
03407 {
03408        zval  *obj;
03409        zend_bool use_keys = 1;
03410 
03411        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O|b", &obj, zend_ce_traversable, &use_keys) == FAILURE) {
03412               RETURN_FALSE;
03413        }
03414 
03415        array_init(return_value);
03416 
03417        if (spl_iterator_apply(obj, use_keys ? spl_iterator_to_array_apply : spl_iterator_to_values_apply, (void*)return_value TSRMLS_CC) != SUCCESS) {
03418               zval_dtor(return_value);
03419               RETURN_NULL();
03420        }
03421 } /* }}} */
03422 
03423 static int spl_iterator_count_apply(zend_object_iterator *iter, void *puser TSRMLS_DC) /* {{{ */
03424 {
03425        (*(long*)puser)++;
03426        return ZEND_HASH_APPLY_KEEP;
03427 }
03428 /* }}} */
03429 
03430 /* {{{ proto int iterator_count(Traversable it) 
03431    Count the elements in an iterator */
03432 PHP_FUNCTION(iterator_count)
03433 {
03434        zval  *obj;
03435        long  count = 0;
03436 
03437        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &obj, zend_ce_traversable) == FAILURE) {
03438               RETURN_FALSE;
03439        }
03440        
03441        if (spl_iterator_apply(obj, spl_iterator_count_apply, (void*)&count TSRMLS_CC) == SUCCESS) {
03442               RETURN_LONG(count);
03443        }
03444 }
03445 /* }}} */
03446 
03447 typedef struct {
03448        zval                   *obj;
03449        zval                   *args;
03450        long                   count;
03451        zend_fcall_info        fci;
03452        zend_fcall_info_cache  fcc;
03453 } spl_iterator_apply_info;
03454 
03455 static int spl_iterator_func_apply(zend_object_iterator *iter, void *puser TSRMLS_DC) /* {{{ */
03456 {
03457        zval *retval;
03458        spl_iterator_apply_info  *apply_info = (spl_iterator_apply_info*)puser;
03459        int result;
03460 
03461        apply_info->count++;
03462        zend_fcall_info_call(&apply_info->fci, &apply_info->fcc, &retval, NULL TSRMLS_CC);
03463        if (retval) {
03464               result = zend_is_true(retval) ? ZEND_HASH_APPLY_KEEP : ZEND_HASH_APPLY_STOP;
03465               zval_ptr_dtor(&retval);
03466        } else {
03467               result = ZEND_HASH_APPLY_STOP;
03468        }
03469        return result;
03470 }
03471 /* }}} */
03472 
03473 /* {{{ proto int iterator_apply(Traversable it, mixed function [, mixed params])
03474    Calls a function for every element in an iterator */
03475 PHP_FUNCTION(iterator_apply)
03476 {
03477        spl_iterator_apply_info  apply_info;
03478 
03479        apply_info.args = NULL;
03480        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) {
03481               return;
03482        }
03483 
03484        apply_info.count = 0;
03485        zend_fcall_info_args(&apply_info.fci, apply_info.args TSRMLS_CC);
03486        if (spl_iterator_apply(apply_info.obj, spl_iterator_func_apply, (void*)&apply_info TSRMLS_CC) == SUCCESS) {
03487               RETVAL_LONG(apply_info.count);
03488        } else {
03489               RETVAL_FALSE;
03490        }
03491        zend_fcall_info_args(&apply_info.fci, NULL TSRMLS_CC);
03492 }
03493 /* }}} */
03494 
03495 static const zend_function_entry spl_funcs_OuterIterator[] = {
03496        SPL_ABSTRACT_ME(OuterIterator, getInnerIterator,   arginfo_recursive_it_void)
03497        PHP_FE_END
03498 };
03499 
03500 static const zend_function_entry spl_funcs_Countable[] = {
03501        SPL_ABSTRACT_ME(Countable, count,   arginfo_recursive_it_void)
03502        PHP_FE_END
03503 };
03504 
03505 /* {{{ PHP_MINIT_FUNCTION(spl_iterators)
03506  */
03507 PHP_MINIT_FUNCTION(spl_iterators)
03508 {
03509        REGISTER_SPL_INTERFACE(RecursiveIterator);
03510        REGISTER_SPL_ITERATOR(RecursiveIterator);
03511 
03512        REGISTER_SPL_STD_CLASS_EX(RecursiveIteratorIterator, spl_RecursiveIteratorIterator_new, spl_funcs_RecursiveIteratorIterator);
03513        REGISTER_SPL_ITERATOR(RecursiveIteratorIterator);
03514 
03515        memcpy(&spl_handlers_rec_it_it, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
03516        spl_handlers_rec_it_it.get_method = spl_recursive_it_get_method;
03517        spl_handlers_rec_it_it.clone_obj = NULL;
03518 
03519        memcpy(&spl_handlers_dual_it, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
03520        spl_handlers_dual_it.get_method = spl_dual_it_get_method;
03521        /*spl_handlers_dual_it.call_method = spl_dual_it_call_method;*/
03522        spl_handlers_dual_it.clone_obj = NULL;
03523        
03524        spl_ce_RecursiveIteratorIterator->get_iterator = spl_recursive_it_get_iterator;
03525        spl_ce_RecursiveIteratorIterator->iterator_funcs.funcs = &spl_recursive_it_iterator_funcs;
03526 
03527        REGISTER_SPL_CLASS_CONST_LONG(RecursiveIteratorIterator, "LEAVES_ONLY",     RIT_LEAVES_ONLY);
03528        REGISTER_SPL_CLASS_CONST_LONG(RecursiveIteratorIterator, "SELF_FIRST",      RIT_SELF_FIRST);
03529        REGISTER_SPL_CLASS_CONST_LONG(RecursiveIteratorIterator, "CHILD_FIRST",     RIT_CHILD_FIRST);
03530        REGISTER_SPL_CLASS_CONST_LONG(RecursiveIteratorIterator, "CATCH_GET_CHILD", RIT_CATCH_GET_CHILD);
03531 
03532        REGISTER_SPL_INTERFACE(OuterIterator);
03533        REGISTER_SPL_ITERATOR(OuterIterator);
03534 
03535        REGISTER_SPL_STD_CLASS_EX(IteratorIterator, spl_dual_it_new, spl_funcs_IteratorIterator);
03536        REGISTER_SPL_ITERATOR(IteratorIterator);
03537        REGISTER_SPL_IMPLEMENTS(IteratorIterator, OuterIterator);
03538 
03539        REGISTER_SPL_SUB_CLASS_EX(FilterIterator, IteratorIterator, spl_dual_it_new, spl_funcs_FilterIterator);
03540        spl_ce_FilterIterator->ce_flags |= ZEND_ACC_EXPLICIT_ABSTRACT_CLASS;
03541 
03542        REGISTER_SPL_SUB_CLASS_EX(RecursiveFilterIterator, FilterIterator, spl_dual_it_new, spl_funcs_RecursiveFilterIterator);
03543        REGISTER_SPL_IMPLEMENTS(RecursiveFilterIterator, RecursiveIterator);
03544 
03545        REGISTER_SPL_SUB_CLASS_EX(ParentIterator, RecursiveFilterIterator, spl_dual_it_new, spl_funcs_ParentIterator);
03546 
03547        REGISTER_SPL_INTERFACE(Countable);
03548        REGISTER_SPL_INTERFACE(SeekableIterator);
03549        REGISTER_SPL_ITERATOR(SeekableIterator);
03550 
03551        REGISTER_SPL_SUB_CLASS_EX(LimitIterator, IteratorIterator, spl_dual_it_new, spl_funcs_LimitIterator);
03552 
03553        REGISTER_SPL_SUB_CLASS_EX(CachingIterator, IteratorIterator, spl_dual_it_new, spl_funcs_CachingIterator);
03554        REGISTER_SPL_IMPLEMENTS(CachingIterator, ArrayAccess);
03555        REGISTER_SPL_IMPLEMENTS(CachingIterator, Countable);
03556 
03557        REGISTER_SPL_CLASS_CONST_LONG(CachingIterator, "CALL_TOSTRING",        CIT_CALL_TOSTRING); 
03558        REGISTER_SPL_CLASS_CONST_LONG(CachingIterator, "CATCH_GET_CHILD",      CIT_CATCH_GET_CHILD); 
03559        REGISTER_SPL_CLASS_CONST_LONG(CachingIterator, "TOSTRING_USE_KEY",     CIT_TOSTRING_USE_KEY);
03560        REGISTER_SPL_CLASS_CONST_LONG(CachingIterator, "TOSTRING_USE_CURRENT", CIT_TOSTRING_USE_CURRENT);
03561        REGISTER_SPL_CLASS_CONST_LONG(CachingIterator, "TOSTRING_USE_INNER",   CIT_TOSTRING_USE_INNER);
03562        REGISTER_SPL_CLASS_CONST_LONG(CachingIterator, "FULL_CACHE",           CIT_FULL_CACHE); 
03563 
03564        REGISTER_SPL_SUB_CLASS_EX(RecursiveCachingIterator, CachingIterator, spl_dual_it_new, spl_funcs_RecursiveCachingIterator);
03565        REGISTER_SPL_IMPLEMENTS(RecursiveCachingIterator, RecursiveIterator);
03566        
03567        REGISTER_SPL_SUB_CLASS_EX(NoRewindIterator, IteratorIterator, spl_dual_it_new, spl_funcs_NoRewindIterator);
03568 
03569        REGISTER_SPL_SUB_CLASS_EX(AppendIterator, IteratorIterator, spl_dual_it_new, spl_funcs_AppendIterator);
03570 
03571        REGISTER_SPL_IMPLEMENTS(RecursiveIteratorIterator, OuterIterator);
03572 
03573        REGISTER_SPL_SUB_CLASS_EX(InfiniteIterator, IteratorIterator, spl_dual_it_new, spl_funcs_InfiniteIterator);
03574 #if HAVE_PCRE || HAVE_BUNDLED_PCRE
03575        REGISTER_SPL_SUB_CLASS_EX(RegexIterator, FilterIterator, spl_dual_it_new, spl_funcs_RegexIterator);
03576        REGISTER_SPL_CLASS_CONST_LONG(RegexIterator, "USE_KEY",     REGIT_USE_KEY);
03577        REGISTER_SPL_CLASS_CONST_LONG(RegexIterator, "MATCH",       REGIT_MODE_MATCH);
03578        REGISTER_SPL_CLASS_CONST_LONG(RegexIterator, "GET_MATCH",   REGIT_MODE_GET_MATCH);
03579        REGISTER_SPL_CLASS_CONST_LONG(RegexIterator, "ALL_MATCHES", REGIT_MODE_ALL_MATCHES);
03580        REGISTER_SPL_CLASS_CONST_LONG(RegexIterator, "SPLIT",       REGIT_MODE_SPLIT);
03581        REGISTER_SPL_CLASS_CONST_LONG(RegexIterator, "REPLACE",     REGIT_MODE_REPLACE);
03582        REGISTER_SPL_PROPERTY(RegexIterator, "replacement", 0);
03583        REGISTER_SPL_SUB_CLASS_EX(RecursiveRegexIterator, RegexIterator, spl_dual_it_new, spl_funcs_RecursiveRegexIterator);
03584        REGISTER_SPL_IMPLEMENTS(RecursiveRegexIterator, RecursiveIterator);
03585 #else
03586        spl_ce_RegexIterator = NULL;
03587        spl_ce_RecursiveRegexIterator = NULL;
03588 #endif
03589 
03590        REGISTER_SPL_STD_CLASS_EX(EmptyIterator, NULL, spl_funcs_EmptyIterator);
03591        REGISTER_SPL_ITERATOR(EmptyIterator);
03592 
03593        REGISTER_SPL_SUB_CLASS_EX(RecursiveTreeIterator, RecursiveIteratorIterator, spl_RecursiveTreeIterator_new, spl_funcs_RecursiveTreeIterator);
03594        REGISTER_SPL_CLASS_CONST_LONG(RecursiveTreeIterator, "BYPASS_CURRENT",      RTIT_BYPASS_CURRENT);
03595        REGISTER_SPL_CLASS_CONST_LONG(RecursiveTreeIterator, "BYPASS_KEY",          RTIT_BYPASS_KEY);
03596        REGISTER_SPL_CLASS_CONST_LONG(RecursiveTreeIterator, "PREFIX_LEFT",         0);
03597        REGISTER_SPL_CLASS_CONST_LONG(RecursiveTreeIterator, "PREFIX_MID_HAS_NEXT", 1);
03598        REGISTER_SPL_CLASS_CONST_LONG(RecursiveTreeIterator, "PREFIX_MID_LAST",     2);
03599        REGISTER_SPL_CLASS_CONST_LONG(RecursiveTreeIterator, "PREFIX_END_HAS_NEXT", 3);
03600        REGISTER_SPL_CLASS_CONST_LONG(RecursiveTreeIterator, "PREFIX_END_LAST",     4);
03601        REGISTER_SPL_CLASS_CONST_LONG(RecursiveTreeIterator, "PREFIX_RIGHT",        5);
03602 
03603        return SUCCESS;
03604 }
03605 /* }}} */
03606 
03607 /*
03608  * Local variables:
03609  * tab-width: 4
03610  * c-basic-offset: 4
03611  * End:
03612  * vim600: fdm=marker
03613  * vim: noet sw=4 ts=4
03614  */