helly           Sat Jul 19 15:49:21 2008 UTC

  Added files:                 (Branch: PHP_5_3)
    /php-src/ext/spl/tests      recursive_tree_iterator_001.phpt 
                                recursive_tree_iterator_002.phpt 
                                recursive_tree_iterator_003.phpt 
                                recursive_tree_iterator_004.phpt 
                                recursive_tree_iterator_005.phpt 
                                recursive_tree_iterator_006.phpt 
                                recursive_tree_iterator_007.phpt 
                                recursive_tree_iterator_008.phpt 
    /php-src/ext/spl/internal   recursivetreeiterator.inc 

  Removed files:               
    /php-src/ext/spl/examples   recursivetreeiterator.inc 

  Modified files:              
    /php-src    NEWS 
    /php-src/ext/spl    spl_iterators.c spl_iterators.h spl.php 
  Log:
  - MFH Added RecursiveTreeIterator
  
  
http://cvs.php.net/viewvc.cgi/php-src/NEWS?r1=1.2027.2.547.2.965.2.203&r2=1.2027.2.547.2.965.2.204&diff_format=u
Index: php-src/NEWS
diff -u php-src/NEWS:1.2027.2.547.2.965.2.203 
php-src/NEWS:1.2027.2.547.2.965.2.204
--- php-src/NEWS:1.2027.2.547.2.965.2.203       Fri Jul 18 17:55:59 2008
+++ php-src/NEWS        Sat Jul 19 15:49:20 2008
@@ -117,6 +117,7 @@
   . Added new parameter $prepend to spl_autoload_register(). (Etienne)
   . Added FixedArray. (Etienne, Tony)
   . Added delaying exceptions in SPL's autoload mechanism. (Marcus)
+  . Added RecursiveTreeIterator. (Arnaud, Marcus)
 
 - Improved Zend Engine:
   . Added "compact" handler for Zend MM storage. (Dmitry)
http://cvs.php.net/viewvc.cgi/php-src/ext/spl/spl_iterators.c?r1=1.73.2.30.2.28.2.7&r2=1.73.2.30.2.28.2.8&diff_format=u
Index: php-src/ext/spl/spl_iterators.c
diff -u php-src/ext/spl/spl_iterators.c:1.73.2.30.2.28.2.7 
php-src/ext/spl/spl_iterators.c:1.73.2.30.2.28.2.8
--- php-src/ext/spl/spl_iterators.c:1.73.2.30.2.28.2.7  Wed Mar 12 13:34:47 2008
+++ php-src/ext/spl/spl_iterators.c     Sat Jul 19 15:49:21 2008
@@ -16,7 +16,7 @@
    +----------------------------------------------------------------------+
  */
 
-/* $Id: spl_iterators.c,v 1.73.2.30.2.28.2.7 2008/03/12 13:34:47 colder Exp $ 
*/
+/* $Id: spl_iterators.c,v 1.73.2.30.2.28.2.8 2008/07/19 15:49:21 helly Exp $ */
 
 #ifdef HAVE_CONFIG_H
 # include "config.h"
@@ -35,6 +35,7 @@
 #include "spl_directory.h"
 #include "spl_array.h"
 #include "spl_exceptions.h"
+#include "ext/standard/php_smart_str.h"
 
 #ifdef accept
 #undef accept
@@ -58,6 +59,7 @@
 PHPAPI zend_class_entry *spl_ce_RegexIterator;
 PHPAPI zend_class_entry *spl_ce_RecursiveRegexIterator;
 PHPAPI zend_class_entry *spl_ce_Countable;
+PHPAPI zend_class_entry *spl_ce_RecursiveTreeIterator;
 
 const zend_function_entry spl_funcs_RecursiveIterator[] = {
        SPL_ABSTRACT_ME(RecursiveIterator, hasChildren,  NULL)
@@ -74,6 +76,11 @@
 #define RIT_CATCH_GET_CHILD CIT_CATCH_GET_CHILD
 
 typedef enum {
+       RTIT_BYPASS_CURRENT = 4,
+       RTIT_BYPASS_KEY     = 8
+} RecursiveTreeIteratorFlags;
+
+typedef enum {
        RS_NEXT  = 0,
        RS_TEST  = 1,
        RS_SELF  = 2,
@@ -104,6 +111,7 @@
        zend_function            *endChildren;
        zend_function            *nextElement;
        zend_class_entry         *ce;
+       smart_str                prefix[6];
 } spl_recursive_it_object;
 
 typedef struct _spl_recursive_it_iterator {
@@ -408,27 +416,65 @@
        spl_recursive_it_rewind
 };
 
-/* {{{ proto void 
RecursiveIteratorIterator::__construct(RecursiveIterator|IteratorAggregate it 
[, int mode = RIT_LEAVES_ONLY [, int flags = 0]]) throws 
InvalidArgumentException
-   Creates a RecursiveIteratorIterator from a RecursiveIterator. */
-SPL_METHOD(RecursiveIteratorIterator, __construct)
+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 TSRMLS_DC)
 {
        zval                      *object = getThis();
        spl_recursive_it_object   *intern;
        zval                      *iterator;
        zend_class_entry          *ce_iterator;
-       long                       mode = RIT_LEAVES_ONLY, flags = 0;
+       long                       mode, flags;
        int                        inc_refcount = 1;
 
        php_set_error_handling(EH_THROW, spl_ce_InvalidArgumentException 
TSRMLS_CC);
 
-       if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() 
TSRMLS_CC, "o|ll", &iterator, &mode, &flags) == SUCCESS) {
-               if (instanceof_function(Z_OBJCE_P(iterator), zend_ce_aggregate 
TSRMLS_CC)) {
-                       zval *aggregate = iterator;
-                       zend_call_method_with_0_params(&aggregate, 
Z_OBJCE_P(aggregate), &Z_OBJCE_P(aggregate)->iterator_funcs.zf_new_iterator, 
"getiterator", &iterator);
-                       inc_refcount = 0;
+       switch(rit_type) {
+               case RIT_RecursiveTreeIterator: {
+
+                       zval *caching_it, *caching_it_flags, 
*user_caching_it_flags = NULL;
+                       mode = RIT_SELF_FIRST;
+                       flags = RTIT_BYPASS_KEY;
+
+                       if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, 
ZEND_NUM_ARGS() TSRMLS_CC, "o|lzl", &iterator, &flags, &user_caching_it_flags, 
&mode) == SUCCESS) {
+                               if (instanceof_function(Z_OBJCE_P(iterator), 
zend_ce_aggregate TSRMLS_CC)) {
+                                       zval *aggregate = iterator;
+                                       
zend_call_method_with_0_params(&aggregate, Z_OBJCE_P(aggregate), 
&Z_OBJCE_P(aggregate)->iterator_funcs.zf_new_iterator, "getiterator", 
&iterator);
+                                       inc_refcount = 0;
+                               }
+
+                               MAKE_STD_ZVAL(caching_it_flags);
+                               if (user_caching_it_flags) {
+                                       ZVAL_ZVAL(caching_it_flags, 
user_caching_it_flags, 1, 0);
+                               } else {
+                                       ZVAL_LONG(caching_it_flags, 
CIT_CATCH_GET_CHILD);
+                               }
+                               
spl_instantiate_arg_ex2(spl_ce_RecursiveCachingIterator, &caching_it, 1, 
iterator, caching_it_flags);
+                               zval_ptr_dtor(&caching_it_flags);
+                               if (inc_refcount == 0 && iterator) {
+                                       zval_ptr_dtor(&iterator);
+                               }
+                               iterator = caching_it;
+                               inc_refcount = 0;
+                       } else {
+                               iterator = NULL;
+                       }
+                       break;
+               }
+               case RIT_RecursiveIteratorIterator:
+               default: {
+                       mode = RIT_LEAVES_ONLY;
+                       flags = 0;
+
+                       if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, 
ZEND_NUM_ARGS() TSRMLS_CC, "o|ll", &iterator, &mode, &flags) == SUCCESS) {
+                               if (instanceof_function(Z_OBJCE_P(iterator), 
zend_ce_aggregate TSRMLS_CC)) {
+                                       zval *aggregate = iterator;
+                                       
zend_call_method_with_0_params(&aggregate, Z_OBJCE_P(aggregate), 
&Z_OBJCE_P(aggregate)->iterator_funcs.zf_new_iterator, "getiterator", 
&iterator);
+                                       inc_refcount = 0;
+                               }
+                       } else {
+                               iterator = NULL;
+                       }
+                       break;
                }
-       } else {
-               iterator = NULL;
        }
        if (!iterator || !instanceof_function(Z_OBJCE_P(iterator), 
spl_ce_RecursiveIterator TSRMLS_CC)) {
                if (iterator && !inc_refcount) {
@@ -449,31 +495,31 @@
        intern->ce = Z_OBJCE_P(object);
 
        zend_hash_find(&intern->ce->function_table, "beginiteration", 
sizeof("beginiteration"), (void **) &intern->beginIteration);
-       if (intern->beginIteration->common.scope == 
spl_ce_RecursiveIteratorIterator) {
+       if (intern->beginIteration->common.scope == ce_base) {
                intern->beginIteration = NULL;
        }
        zend_hash_find(&intern->ce->function_table, "enditeration", 
sizeof("enditeration"), (void **) &intern->endIteration);
-       if (intern->endIteration->common.scope == 
spl_ce_RecursiveIteratorIterator) {
+       if (intern->endIteration->common.scope == ce_base) {
                intern->endIteration = NULL;
        }
        zend_hash_find(&intern->ce->function_table, "callhaschildren", 
sizeof("callHasChildren"), (void **) &intern->callHasChildren);
-       if (intern->callHasChildren->common.scope == 
spl_ce_RecursiveIteratorIterator) {
+       if (intern->callHasChildren->common.scope == ce_base) {
                intern->callHasChildren = NULL;
        }
        zend_hash_find(&intern->ce->function_table, "callgetchildren", 
sizeof("callGetChildren"), (void **) &intern->callGetChildren);
-       if (intern->callGetChildren->common.scope == 
spl_ce_RecursiveIteratorIterator) {
+       if (intern->callGetChildren->common.scope == ce_base) {
                intern->callGetChildren = NULL;
        }
        zend_hash_find(&intern->ce->function_table, "beginchildren", 
sizeof("beginchildren"), (void **) &intern->beginChildren);
-       if (intern->beginChildren->common.scope == 
spl_ce_RecursiveIteratorIterator) {
+       if (intern->beginChildren->common.scope == ce_base) {
                intern->beginChildren = NULL;
        }
        zend_hash_find(&intern->ce->function_table, "endchildren", 
sizeof("endchildren"), (void **) &intern->endChildren);
-       if (intern->endChildren->common.scope == 
spl_ce_RecursiveIteratorIterator) {
+       if (intern->endChildren->common.scope == ce_base) {
                intern->endChildren = NULL;
        }
        zend_hash_find(&intern->ce->function_table, "nextelement", 
sizeof("nextElement"), (void **) &intern->nextElement);
-       if (intern->nextElement->common.scope == 
spl_ce_RecursiveIteratorIterator) {
+       if (intern->nextElement->common.scope == ce_base) {
                intern->nextElement = NULL;
        }
        ce_iterator = Z_OBJCE_P(iterator); /* respect inheritance, don't use 
spl_ce_RecursiveIterator */
@@ -486,6 +532,13 @@
        intern->iterators[0].state = RS_START;
 
        php_set_error_handling(EH_NORMAL, NULL TSRMLS_CC);
+}
+
+/* {{{ proto void 
RecursiveIteratorIterator::__construct(RecursiveIterator|IteratorAggregate it 
[, int mode = RIT_LEAVES_ONLY [, int flags = 0]]) throws 
InvalidArgumentException
+   Creates a RecursiveIteratorIterator from a RecursiveIterator. */
+SPL_METHOD(RecursiveIteratorIterator, __construct)
+{
+       spl_recursive_it_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, 
spl_ce_RecursiveIteratorIterator, zend_ce_iterator, 
RIT_RecursiveIteratorIterator TSRMLS_CC);
 } /* }}} */
 
 /* {{{ proto void RecursiveIteratorIterator::rewind()
@@ -735,13 +788,19 @@
        }
 
        zend_object_std_dtor(&object->std TSRMLS_CC);
+       smart_str_free(&object->prefix[0]);
+       smart_str_free(&object->prefix[1]);
+       smart_str_free(&object->prefix[2]);
+       smart_str_free(&object->prefix[3]);
+       smart_str_free(&object->prefix[4]);
+       smart_str_free(&object->prefix[5]);
 
        efree(object);
 }
 /* }}} */
 
-/* {{{ spl_RecursiveIteratorIterator_new */
-static zend_object_value spl_RecursiveIteratorIterator_new(zend_class_entry 
*class_type TSRMLS_DC)
+/* {{{ spl_RecursiveIteratorIterator_new_ex */
+static zend_object_value spl_RecursiveIteratorIterator_new_ex(zend_class_entry 
*class_type, int init_prefix TSRMLS_DC)
 {
        zend_object_value retval;
        spl_recursive_it_object *intern;
@@ -750,6 +809,15 @@
        intern = emalloc(sizeof(spl_recursive_it_object));
        memset(intern, 0, sizeof(spl_recursive_it_object));
 
+       if (init_prefix) {
+               smart_str_appendl(&intern->prefix[0], "",    0);
+               smart_str_appendl(&intern->prefix[1], "| ",  2);
+               smart_str_appendl(&intern->prefix[2], "  ",  2);
+               smart_str_appendl(&intern->prefix[3], "|-",  2);
+               smart_str_appendl(&intern->prefix[4], "\\-", 2);
+               smart_str_appendl(&intern->prefix[5], "",    0);
+       }
+
        zend_object_std_init(&intern->std, class_type TSRMLS_CC);
        zend_hash_copy(intern->std.properties, &class_type->default_properties, 
(copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *));
 
@@ -759,6 +827,20 @@
 }
 /* }}} */
 
+/* {{{ spl_RecursiveIteratorIterator_new */
+static zend_object_value spl_RecursiveIteratorIterator_new(zend_class_entry 
*class_type TSRMLS_DC)
+{
+       return spl_RecursiveIteratorIterator_new_ex(class_type, 0 TSRMLS_CC);
+}
+/* }}} */
+
+/* {{{ spl_RecursiveTreeIterator_new */
+static zend_object_value spl_RecursiveTreeIterator_new(zend_class_entry 
*class_type TSRMLS_DC)
+{
+       return spl_RecursiveIteratorIterator_new_ex(class_type, 1 TSRMLS_CC);
+}
+/* }}} */
+
 static
 ZEND_BEGIN_ARG_INFO_EX(arginfo_recursive_it___construct, 0, 0, 1) 
        ZEND_ARG_OBJ_INFO(0, iterator, Traversable, 0)
@@ -798,6 +880,255 @@
        {NULL, NULL, NULL}
 };
 
+static void spl_recursive_tree_iterator_get_prefix(spl_recursive_it_object 
*object, zval *return_value TSRMLS_DC)
+{
+       smart_str  str = {0};
+       zval      *has_next;
+       int        level;
+
+       smart_str_appendl(&str, object->prefix[0].c, object->prefix[0].len);
+       
+       for (level = 0; level < object->level; ++level) {
+               
zend_call_method_with_0_params(&object->iterators[level].zobject, 
object->iterators[level].ce, NULL, "hasnext", &has_next);
+               if (has_next) {
+                       if (Z_LVAL_P(has_next)) {
+                               smart_str_appendl(&str, object->prefix[1].c, 
object->prefix[1].len);
+                       } else {
+                               smart_str_appendl(&str, object->prefix[2].c, 
object->prefix[2].len);
+                       }
+                       zval_ptr_dtor(&has_next);
+               }
+       }
+       zend_call_method_with_0_params(&object->iterators[level].zobject, 
object->iterators[level].ce, NULL, "hasnext", &has_next);
+       if (has_next) {
+               if (Z_LVAL_P(has_next)) {
+                       smart_str_appendl(&str, object->prefix[3].c, 
object->prefix[3].len);
+               } else {
+                       smart_str_appendl(&str, object->prefix[4].c, 
object->prefix[4].len);
+               }
+               zval_ptr_dtor(&has_next);
+       }
+
+       smart_str_appendl(&str, object->prefix[5].c, object->prefix[5].len);
+       smart_str_0(&str);
+
+       RETVAL_STRINGL(str.c, str.len, 0);
+}
+
+static void spl_recursive_tree_iterator_get_entry(spl_recursive_it_object * 
object, zval * return_value TSRMLS_DC)
+{
+       zend_object_iterator      *iterator = 
object->iterators[object->level].iterator;
+       zval                      **data;
+
+       iterator->funcs->get_current_data(iterator, &data TSRMLS_CC);
+
+       php_set_error_handling(EH_THROW, spl_ce_UnexpectedValueException 
TSRMLS_CC);
+       RETVAL_ZVAL(*data, 1, 0);
+       convert_to_string(return_value);
+       php_set_error_handling(EH_NORMAL, NULL TSRMLS_CC);
+}
+
+static void spl_recursive_tree_iterator_get_postfix(spl_recursive_it_object * 
object, zval * return_value TSRMLS_DC)
+{
+       RETVAL_STRINGL("", 0, 1);
+}
+
+/* {{{ 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
+   RecursiveIteratorIterator to generate ASCII graphic trees for the entries 
in a RecursiveIterator */
+SPL_METHOD(RecursiveTreeIterator, __construct)
+{
+       spl_recursive_it_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, 
spl_ce_RecursiveTreeIterator, zend_ce_iterator, RIT_RecursiveTreeIterator 
TSRMLS_CC);
+} /* }}} */
+
+/* {{{ proto void RecursiveTreeIterator::setPrefixPart() throws 
OutOfRangeException
+   Sets prefix parts as used in getPrefix() */
+SPL_METHOD(RecursiveTreeIterator, setPrefixPart)
+{
+       spl_recursive_it_object   *object = 
(spl_recursive_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
+       long  part;
+       char* prefix;
+       int   prefix_len;
+       
+       if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ls", &part, 
&prefix, &prefix_len) == FAILURE) {
+               return;
+       }
+       if (0 > part || part > 5) {
+               zend_throw_exception_ex(spl_ce_OutOfRangeException, 0 
TSRMLS_CC, "Use RecursiveTreeIterator::PREFIX_* constant");
+               return;
+       }
+       
+       smart_str_free(&object->prefix[part]);
+       smart_str_appendl(&object->prefix[part], prefix, prefix_len);
+} /* }}} */
+
+/* {{{ proto string RecursiveTreeIterator::getPrefix()
+   Returns the string to place in front of current element */
+SPL_METHOD(RecursiveTreeIterator, getPrefix)
+{
+       spl_recursive_it_object   *object = 
(spl_recursive_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
+
+       spl_recursive_tree_iterator_get_prefix(object, return_value TSRMLS_CC);
+} /* }}} */
+
+/* {{{ proto string RecursiveTreeIterator::getEntry()
+   Returns the string presentation built for current element */
+SPL_METHOD(RecursiveTreeIterator, getEntry)
+{
+       spl_recursive_it_object   *object = 
(spl_recursive_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
+
+       spl_recursive_tree_iterator_get_entry(object, return_value TSRMLS_CC);
+} /* }}} */
+
+/* {{{ proto string RecursiveTreeIterator::getPostfix()
+   Returns the string to place after the current element */
+SPL_METHOD(RecursiveTreeIterator, getPostfix)
+{
+       spl_recursive_it_object   *object = 
(spl_recursive_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
+
+       spl_recursive_tree_iterator_get_postfix(object, return_value TSRMLS_CC);
+} /* }}} */
+
+/* {{{ proto mixed RecursiveTreeIterator::current()
+   Returns the current element prefixed and postfixed */
+SPL_METHOD(RecursiveTreeIterator, current)
+{
+       spl_recursive_it_object   *object = 
(spl_recursive_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
+       zval                       prefix, entry, postfix;
+       char                      *str, *ptr;
+       size_t                     str_len;
+
+       if (object->flags & RTIT_BYPASS_CURRENT) {
+               zend_object_iterator      *iterator = 
object->iterators[object->level].iterator;
+               zval                      **data;
+
+               iterator->funcs->get_current_data(iterator, &data TSRMLS_CC);
+               RETURN_ZVAL(*data, 1, 0);
+       }
+
+       spl_recursive_tree_iterator_get_prefix(object, &prefix TSRMLS_CC);
+       spl_recursive_tree_iterator_get_entry(object, &entry TSRMLS_CC);
+       spl_recursive_tree_iterator_get_postfix(object, &postfix TSRMLS_CC);
+
+       str_len = Z_STRLEN(prefix) + Z_STRLEN(entry) + Z_STRLEN(postfix);
+       str = (char *) emalloc(str_len + 1U);
+       ptr = str;
+
+       memcpy(ptr, Z_STRVAL(prefix), Z_STRLEN(prefix));
+       ptr += Z_STRLEN(prefix);
+       memcpy(ptr, Z_STRVAL(entry), Z_STRLEN(entry));
+       ptr += Z_STRLEN(entry);
+       memcpy(ptr, Z_STRVAL(postfix), Z_STRLEN(postfix));
+       ptr += Z_STRLEN(postfix);
+       *ptr = 0;
+
+       zval_dtor(&prefix);
+       zval_dtor(&entry);
+       zval_dtor(&postfix);
+
+       RETURN_STRINGL(str, str_len, 0);
+} /* }}} */
+
+/* {{{ proto mixed RecursiveTreeIterator::key()
+   Returns the current key prefixed and postfixed */
+SPL_METHOD(RecursiveTreeIterator, key)
+{
+       spl_recursive_it_object   *object = 
(spl_recursive_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
+       zend_object_iterator      *iterator = 
object->iterators[object->level].iterator;
+       zval                       prefix, key, postfix, key_copy;
+       char                      *str, *ptr;
+       size_t                     str_len;
+
+       if (iterator->funcs->get_current_key) {
+               char *str_key;
+               uint str_key_len;
+               ulong int_key;
+
+               switch (iterator->funcs->get_current_key(iterator, &str_key, 
&str_key_len, &int_key TSRMLS_CC)) {
+                       case HASH_KEY_IS_LONG:
+                               ZVAL_LONG(&key, int_key);
+                               break;
+                       case HASH_KEY_IS_STRING:
+                               ZVAL_STRINGL(&key, str_key, str_key_len-1, 0);
+                               break;
+                       default:
+                               ZVAL_NULL(&key);
+               }
+       } else {
+               ZVAL_NULL(&key);
+       }
+
+       if (object->flags & RTIT_BYPASS_KEY) {
+               zval *key_ptr = &key;
+               RETVAL_ZVAL(key_ptr, 1, 0);
+               zval_dtor(&key);
+               return;
+       }
+
+       if (Z_TYPE(key) != IS_STRING) {
+               int use_copy;
+               zend_make_printable_zval(&key, &key_copy, &use_copy);
+               if (use_copy) {
+                       key = key_copy;
+               }
+       }
+
+       spl_recursive_tree_iterator_get_prefix(object, &prefix TSRMLS_CC);
+       spl_recursive_tree_iterator_get_postfix(object, &postfix TSRMLS_CC);
+
+       str_len = Z_STRLEN(prefix) + Z_STRLEN(key) + Z_STRLEN(postfix);
+       str = (char *) emalloc(str_len + 1U);
+       ptr = str;
+
+       memcpy(ptr, Z_STRVAL(prefix), Z_STRLEN(prefix));
+       ptr += Z_STRLEN(prefix);
+       memcpy(ptr, Z_STRVAL(key), Z_STRLEN(key));
+       ptr += Z_STRLEN(key);
+       memcpy(ptr, Z_STRVAL(postfix), Z_STRLEN(postfix));
+       ptr += Z_STRLEN(postfix);
+       *ptr = 0;
+
+       zval_dtor(&prefix);
+       zval_dtor(&key);
+       zval_dtor(&postfix);
+
+       RETVAL_STRINGL(str, str_len, 0);
+} /* }}} */
+
+static
+ZEND_BEGIN_ARG_INFO_EX(arginfo_recursive_tree_it___construct, 0, 0, 1) 
+       ZEND_ARG_OBJ_INFO(0, iterator, Traversable, 0)
+       ZEND_ARG_INFO(0, flags)
+       ZEND_ARG_INFO(0, caching_it_flags)
+       ZEND_ARG_INFO(0, mode)
+ZEND_END_ARG_INFO();
+
+static
+ZEND_BEGIN_ARG_INFO_EX(arginfo_recursive_tree_it_setPrefixPart, 0, 0, 2)
+       ZEND_ARG_INFO(0, part)
+       ZEND_ARG_INFO(0, value)
+ZEND_END_ARG_INFO();
+
+static const zend_function_entry spl_funcs_RecursiveTreeIterator[] = {
+       SPL_ME(RecursiveTreeIterator,     __construct,       
arginfo_recursive_tree_it___construct,   ZEND_ACC_PUBLIC)
+       SPL_ME(RecursiveIteratorIterator, rewind,            NULL,              
                      ZEND_ACC_PUBLIC)
+       SPL_ME(RecursiveIteratorIterator, valid,             NULL,              
                      ZEND_ACC_PUBLIC)
+       SPL_ME(RecursiveTreeIterator,     key,               NULL,              
                      ZEND_ACC_PUBLIC)
+       SPL_ME(RecursiveTreeIterator,     current,           NULL,              
                      ZEND_ACC_PUBLIC)
+       SPL_ME(RecursiveIteratorIterator, next,              NULL,              
                      ZEND_ACC_PUBLIC)
+       SPL_ME(RecursiveIteratorIterator, beginIteration,    NULL,              
                      ZEND_ACC_PUBLIC)
+       SPL_ME(RecursiveIteratorIterator, endIteration,      NULL,              
                      ZEND_ACC_PUBLIC)
+       SPL_ME(RecursiveIteratorIterator, callHasChildren,   NULL,              
                      ZEND_ACC_PUBLIC)
+       SPL_ME(RecursiveIteratorIterator, callGetChildren,   NULL,              
                      ZEND_ACC_PUBLIC)
+       SPL_ME(RecursiveIteratorIterator, beginChildren,     NULL,              
                      ZEND_ACC_PUBLIC)
+       SPL_ME(RecursiveIteratorIterator, endChildren,       NULL,              
                      ZEND_ACC_PUBLIC)
+       SPL_ME(RecursiveIteratorIterator, nextElement,       NULL,              
                      ZEND_ACC_PUBLIC)
+       SPL_ME(RecursiveTreeIterator,     getPrefix,         NULL,              
                      ZEND_ACC_PUBLIC)
+       SPL_ME(RecursiveTreeIterator,     setPrefixPart,     
arginfo_recursive_tree_it_setPrefixPart, ZEND_ACC_PUBLIC)
+       SPL_ME(RecursiveTreeIterator,     getEntry,          NULL,              
                      ZEND_ACC_PUBLIC)
+       SPL_ME(RecursiveTreeIterator,     getPostfix,        NULL,              
                      ZEND_ACC_PUBLIC)
+       {NULL, NULL, NULL}
+};
+
 #if MBO_0
 static int spl_dual_it_gets_implemented(zend_class_entry *interface, 
zend_class_entry *class_type TSRMLS_DC)
 {
@@ -2940,6 +3271,16 @@
        REGISTER_SPL_STD_CLASS_EX(EmptyIterator, NULL, spl_funcs_EmptyIterator);
        REGISTER_SPL_ITERATOR(EmptyIterator);
 
+       REGISTER_SPL_SUB_CLASS_EX(RecursiveTreeIterator, 
RecursiveIteratorIterator, spl_RecursiveTreeIterator_new, 
spl_funcs_RecursiveTreeIterator);
+       REGISTER_SPL_CLASS_CONST_LONG(RecursiveTreeIterator, "BYPASS_CURRENT",  
    RTIT_BYPASS_CURRENT);
+       REGISTER_SPL_CLASS_CONST_LONG(RecursiveTreeIterator, "BYPASS_KEY",      
    RTIT_BYPASS_KEY);
+       REGISTER_SPL_CLASS_CONST_LONG(RecursiveTreeIterator, "PREFIX_LEFT",     
    0);
+       REGISTER_SPL_CLASS_CONST_LONG(RecursiveTreeIterator, 
"PREFIX_MID_HAS_NEXT", 1);
+       REGISTER_SPL_CLASS_CONST_LONG(RecursiveTreeIterator, "PREFIX_MID_LAST", 
    2);
+       REGISTER_SPL_CLASS_CONST_LONG(RecursiveTreeIterator, 
"PREFIX_END_HAS_NEXT", 3);
+       REGISTER_SPL_CLASS_CONST_LONG(RecursiveTreeIterator, "PREFIX_END_LAST", 
    4);
+       REGISTER_SPL_CLASS_CONST_LONG(RecursiveTreeIterator, "PREFIX_RIGHT",    
    5);
+
        return SUCCESS;
 }
 /* }}} */
http://cvs.php.net/viewvc.cgi/php-src/ext/spl/spl_iterators.h?r1=1.18.2.7.2.12.2.2&r2=1.18.2.7.2.12.2.3&diff_format=u
Index: php-src/ext/spl/spl_iterators.h
diff -u php-src/ext/spl/spl_iterators.h:1.18.2.7.2.12.2.2 
php-src/ext/spl/spl_iterators.h:1.18.2.7.2.12.2.3
--- php-src/ext/spl/spl_iterators.h:1.18.2.7.2.12.2.2   Mon Dec 31 07:17:14 2007
+++ php-src/ext/spl/spl_iterators.h     Sat Jul 19 15:49:21 2008
@@ -16,7 +16,7 @@
    +----------------------------------------------------------------------+
  */
 
-/* $Id: spl_iterators.h,v 1.18.2.7.2.12.2.2 2007/12/31 07:17:14 sebastian Exp 
$ */
+/* $Id: spl_iterators.h,v 1.18.2.7.2.12.2.3 2008/07/19 15:49:21 helly Exp $ */
 
 #ifndef SPL_ITERATORS_H
 #define SPL_ITERATORS_H
@@ -77,6 +77,13 @@
        DIT_Unknown = ~0
 } dual_it_type;
 
+typedef enum {
+       RIT_Default = 0,
+       RIT_RecursiveIteratorIterator = RIT_Default,
+       RIT_RecursiveTreeIterator,
+       RIT_Unknow = ~0
+} recursive_it_it_type;
+
 enum {
        /* public */
        CIT_CALL_TOSTRING        = 0x00000001,
http://cvs.php.net/viewvc.cgi/php-src/ext/spl/spl.php?r1=1.49.2.11.2.7.2.4&r2=1.49.2.11.2.7.2.5&diff_format=u
Index: php-src/ext/spl/spl.php
diff -u php-src/ext/spl/spl.php:1.49.2.11.2.7.2.4 
php-src/ext/spl/spl.php:1.49.2.11.2.7.2.5
--- php-src/ext/spl/spl.php:1.49.2.11.2.7.2.4   Wed Feb 13 12:05:34 2008
+++ php-src/ext/spl/spl.php     Sat Jul 19 15:49:21 2008
@@ -35,6 +35,7 @@
  * - interface RecursiveIterator extends Iterator
  * - interface OuterIterator extends Iterator
  * - class RecursiveIteratorIterator implements OuterIterator
+ * - class RecursiveTreeIterator extends RecursiveIteratorIterator
  * - abstract class FilterIterator implements OuterIterator
  * - class ParentIterator extends FilterIterator implements RecursiveIterator
  * - interface SeekableIterator extends Iterator
@@ -55,7 +56,7 @@
  *
  * - class SplFileInfo
  * - class DirectoryIterator extends SplFileInfo implements Iterator
- * - class filesystemIterator extends DirectoryIterator
+ * - class FilesystemIterator extends DirectoryIterator
  * - class RecursiveDirectoryIterator extends FilesystemIterator implements 
RecursiveIterator
  * - class GlobIterator extends FilesystemIterator implements Countable
  * - class SplFileObject extends SplFileInfo implements RecursiveIterator, 
SeekableIterator
@@ -1132,7 +1133,7 @@
 {
        /** Called from the subject (i.e. when it's value has changed).
         * @param $subject the callee
-        :*/
+        */
        function update(SplSubject $subject);
 }
 

http://cvs.php.net/viewvc.cgi/php-src/ext/spl/tests/recursive_tree_iterator_001.phpt?view=markup&rev=1.1
Index: php-src/ext/spl/tests/recursive_tree_iterator_001.phpt
+++ php-src/ext/spl/tests/recursive_tree_iterator_001.phpt
--TEST--
SPL: RecursiveTreeIterator
--INI--
error_reporting=E_ALL&~E_NOTICE
--FILE--
<?php

$ary = array(
        0 => array(
                "a",
                1,
        ),
        "a" => array(
                2,
                "b",
                3 => array(
                        4,
                        "c",
                ),
                "3" => array(
                        4,
                        "c",
                ),
        ),
);

$it = new RecursiveArrayIterator($ary);
echo "-- flags = BYPASS_KEY --\n";
foreach(new RecursiveTreeIterator($it) as $k => $v) {
        echo "[$k] => $v\n";
}
echo "-- flags = BYPASS_CURRENT --\n";
foreach(new RecursiveTreeIterator($it, RecursiveTreeIterator::BYPASS_CURRENT) 
as $k => $v) {
        echo "[$k] => $v\n";
}
echo "-- flags = BYPASS_KEY|BYPASS_KEY --\n";
foreach(new RecursiveTreeIterator($it, 
RecursiveTreeIterator::BYPASS_CURRENT|RecursiveTreeIterator::BYPASS_KEY) as $k 
=> $v) {
        echo "[$k] => $v\n";
}
echo "-- flags = 0 --\n";
foreach(new RecursiveTreeIterator($it, 0) as $k => $v) {
        echo "[$k] => $v\n";
}
echo "-- flags = 0, caching_it_flags = CachingIterator::CATCH_GET_CHILD --\n";
foreach(new RecursiveTreeIterator($it, 0, CachingIterator::CATCH_GET_CHILD) as 
$k => $v) {
        echo "[$k] => $v\n";
}

?>
===DONE===
--EXPECTF--
-- flags = BYPASS_KEY --
[0] => |-Array
[0] => | |-a
[1] => | \-1
[a] => \-Array
[0] =>   |-2
[1] =>   |-b
[3] =>   \-Array
[0] =>     |-4
[1] =>     \-c
-- flags = BYPASS_CURRENT --
[|-0] => Array
[| |-0] => a
[| \-1] => 1
[\-a] => Array
[  |-0] => 2
[  |-1] => b
[  \-3] => Array
[    |-0] => 4
[    \-1] => c
-- flags = BYPASS_KEY|BYPASS_KEY --
[0] => Array
[0] => a
[1] => 1
[a] => Array
[0] => 2
[1] => b
[3] => Array
[0] => 4
[1] => c
-- flags = 0 --
[|-0] => |-Array
[| |-0] => | |-a
[| \-1] => | \-1
[\-a] => \-Array
[  |-0] =>   |-2
[  |-1] =>   |-b
[  \-3] =>   \-Array
[    |-0] =>     |-4
[    \-1] =>     \-c
-- flags = 0, caching_it_flags = CachingIterator::CATCH_GET_CHILD --
[|-0] => |-Array
[| |-0] => | |-a
[| \-1] => | \-1
[\-a] => \-Array
[  |-0] =>   |-2
[  |-1] =>   |-b
[  \-3] =>   \-Array
[    |-0] =>     |-4
[    \-1] =>     \-c
===DONE===

http://cvs.php.net/viewvc.cgi/php-src/ext/spl/tests/recursive_tree_iterator_002.phpt?view=markup&rev=1.1
Index: php-src/ext/spl/tests/recursive_tree_iterator_002.phpt
+++ php-src/ext/spl/tests/recursive_tree_iterator_002.phpt
--TEST--
SPL: RecursiveTreeIterator(void)
--INI--
error_reporting=E_ALL&~E_NOTICE
--FILE--
<?php
try {
        new RecursiveTreeIterator();
} catch (InvalidArgumentException $e) {
        echo "InvalidArgumentException thrown\n";
}
?>
===DONE===
--EXPECTF--
InvalidArgumentException thrown
===DONE===

http://cvs.php.net/viewvc.cgi/php-src/ext/spl/tests/recursive_tree_iterator_003.phpt?view=markup&rev=1.1
Index: php-src/ext/spl/tests/recursive_tree_iterator_003.phpt
+++ php-src/ext/spl/tests/recursive_tree_iterator_003.phpt
--TEST--
SPL: RecursiveTreeIterator(non-traversable)
--INI--
error_reporting=E_ALL&~E_NOTICE
--FILE--
<?php
try {
        new RecursiveTreeIterator(new ArrayIterator(array()));
} catch (InvalidArgumentException $e) {
        echo "InvalidArgumentException thrown\n";
}
?>
===DONE===
--EXPECTF--
InvalidArgumentException thrown
===DONE===

http://cvs.php.net/viewvc.cgi/php-src/ext/spl/tests/recursive_tree_iterator_004.phpt?view=markup&rev=1.1
Index: php-src/ext/spl/tests/recursive_tree_iterator_004.phpt
+++ php-src/ext/spl/tests/recursive_tree_iterator_004.phpt
--TEST--
SPL: RecursiveTreeIterator methods
--INI--
error_reporting=E_ALL&~E_NOTICE
--FILE--
<?php

$ary = array(
        0 => array(
                "a",
                1,
        ),
        "a" => array(
                2,
                "b",
                3 => array(
                        4,
                        "c",
                ),
                "3" => array(
                        4,
                        "c",
                ),
        ),
);

$it = new RecursiveTreeIterator(new RecursiveArrayIterator($ary));
foreach($it as $k => $v) {
        echo '[' . $it->key() . '] => ' . $it->getPrefix() . $it->getEntry() . 
$it->getPostfix() . "\n";
}
?>
===DONE===
--EXPECTF--
[0] => |-Array
[0] => | |-a
[1] => | \-1
[a] => \-Array
[0] =>   |-2
[1] =>   |-b
[3] =>   \-Array
[0] =>     |-4
[1] =>     \-c
===DONE===

http://cvs.php.net/viewvc.cgi/php-src/ext/spl/tests/recursive_tree_iterator_005.phpt?view=markup&rev=1.1
Index: php-src/ext/spl/tests/recursive_tree_iterator_005.phpt
+++ php-src/ext/spl/tests/recursive_tree_iterator_005.phpt
--TEST--
SPL: RecursiveTreeIterator and binary vs unicode (PHP 6.0+) 
--INI--
error_reporting=E_ALL&~E_NOTICE
--FILE--
<?php

$ary = array(
        0 => array(
                (binary) "binary",
                "abc2",
                1,
        ),
        (binary) "binary" => array(
                2,
                "b",
                3 => array(
                        4,
                        "c",
                ),
                "4abc" => array(
                        4,
                        "c",
                ),
        ),
);

$it = new RecursiveTreeIterator(new RecursiveArrayIterator($ary), 0);
foreach($it as $k => $v) {
        var_dump($v);
}
echo "\n----------------\n\n";
foreach($it as $k => $v) {
        var_dump($k);
}
echo "\n----------------\n\n";
echo "key, getEntry, current:\n";
foreach($it as $k => $v) {
        var_dump($it->key(), $it->getEntry(), $it->current());
}
?>
===DONE===
--EXPECT--
unicode(7) "|-Array"
string(10) "| |-binary"
unicode(8) "| |-abc2"
unicode(5) "| \-1"
unicode(7) "\-Array"
unicode(5) "  |-2"
unicode(5) "  |-b"
unicode(9) "  |-Array"
unicode(7) "  | |-4"
unicode(7) "  | \-c"
unicode(9) "  \-Array"
unicode(7) "    |-4"
unicode(7) "    \-c"

----------------

unicode(3) "|-0"
unicode(5) "| |-0"
unicode(5) "| |-1"
unicode(5) "| \-2"
string(8) "\-binary"
unicode(5) "  |-0"
unicode(5) "  |-1"
unicode(5) "  |-3"
unicode(7) "  | |-0"
unicode(7) "  | \-1"
unicode(8) "  \-4abc"
unicode(7) "    |-0"
unicode(7) "    \-1"

----------------

key, getEntry, current:
unicode(3) "|-0"
unicode(5) "Array"
unicode(7) "|-Array"
unicode(5) "| |-0"
string(6) "binary"
string(10) "| |-binary"
unicode(5) "| |-1"
unicode(4) "abc2"
unicode(8) "| |-abc2"
unicode(5) "| \-2"
unicode(1) "1"
unicode(5) "| \-1"
string(8) "\-binary"
unicode(5) "Array"
unicode(7) "\-Array"
unicode(5) "  |-0"
unicode(1) "2"
unicode(5) "  |-2"
unicode(5) "  |-1"
unicode(1) "b"
unicode(5) "  |-b"
unicode(5) "  |-3"
unicode(5) "Array"
unicode(9) "  |-Array"
unicode(7) "  | |-0"
unicode(1) "4"
unicode(7) "  | |-4"
unicode(7) "  | \-1"
unicode(1) "c"
unicode(7) "  | \-c"
unicode(8) "  \-4abc"
unicode(5) "Array"
unicode(9) "  \-Array"
unicode(7) "    |-0"
unicode(1) "4"
unicode(7) "    |-4"
unicode(7) "    \-1"
unicode(1) "c"
unicode(7) "    \-c"
===DONE===

http://cvs.php.net/viewvc.cgi/php-src/ext/spl/tests/recursive_tree_iterator_006.phpt?view=markup&rev=1.1
Index: php-src/ext/spl/tests/recursive_tree_iterator_006.phpt
+++ php-src/ext/spl/tests/recursive_tree_iterator_006.phpt
--TEST--
SPL: RecursiveTreeIterator and IteratorAggregate
--INI--
error_reporting=E_ALL&~E_NOTICE
--FILE--
<?php

$ary = array(
        0 => array(
                "a",
                1,
        ),
        "a" => array(
                2,
                "b",
                3 => array(
                        4,
                        "c",
                ),
                "3" => array(
                        4,
                        "c",
                ),
        ),
);

class RecursiveArrayIteratorAggregated implements IteratorAggregate {
        public $it;
        function __construct($it) {
                $this->it = new RecursiveArrayIterator($it);
        }
        function getIterator() {
                return $this->it;
        }
}

$it = new RecursiveArrayIteratorAggregated($ary);
echo "-- flags = BYPASS_KEY --\n";
foreach(new RecursiveTreeIterator($it) as $k => $v) {
        echo "[$k] => $v\n";
}
echo "-- flags = BYPASS_CURRENT --\n";
foreach(new RecursiveTreeIterator($it, RecursiveTreeIterator::BYPASS_CURRENT) 
as $k => $v) {
        echo "[$k] => $v\n";
}
echo "-- flags = BYPASS_KEY|BYPASS_KEY --\n";
foreach(new RecursiveTreeIterator($it, 
RecursiveTreeIterator::BYPASS_CURRENT|RecursiveTreeIterator::BYPASS_KEY) as $k 
=> $v) {
        echo "[$k] => $v\n";
}
echo "-- flags = 0 --\n";
foreach(new RecursiveTreeIterator($it, 0) as $k => $v) {
        echo "[$k] => $v\n";
}
echo "-- flags = 0, caching_it_flags = CachingIterator::CATCH_GET_CHILD --\n";
foreach(new RecursiveTreeIterator($it, 0, CachingIterator::CATCH_GET_CHILD) as 
$k => $v) {
        echo "[$k] => $v\n";
}

?>
===DONE===
--EXPECTF--
-- flags = BYPASS_KEY --
[0] => |-Array
[0] => | |-a
[1] => | \-1
[a] => \-Array
[0] =>   |-2
[1] =>   |-b
[3] =>   \-Array
[0] =>     |-4
[1] =>     \-c
-- flags = BYPASS_CURRENT --
[|-0] => Array
[| |-0] => a
[| \-1] => 1
[\-a] => Array
[  |-0] => 2
[  |-1] => b
[  \-3] => Array
[    |-0] => 4
[    \-1] => c
-- flags = BYPASS_KEY|BYPASS_KEY --
[0] => Array
[0] => a
[1] => 1
[a] => Array
[0] => 2
[1] => b
[3] => Array
[0] => 4
[1] => c
-- flags = 0 --
[|-0] => |-Array
[| |-0] => | |-a
[| \-1] => | \-1
[\-a] => \-Array
[  |-0] =>   |-2
[  |-1] =>   |-b
[  \-3] =>   \-Array
[    |-0] =>     |-4
[    \-1] =>     \-c
-- flags = 0, caching_it_flags = CachingIterator::CATCH_GET_CHILD --
[|-0] => |-Array
[| |-0] => | |-a
[| \-1] => | \-1
[\-a] => \-Array
[  |-0] =>   |-2
[  |-1] =>   |-b
[  \-3] =>   \-Array
[    |-0] =>     |-4
[    \-1] =>     \-c
===DONE===

http://cvs.php.net/viewvc.cgi/php-src/ext/spl/tests/recursive_tree_iterator_007.phpt?view=markup&rev=1.1
Index: php-src/ext/spl/tests/recursive_tree_iterator_007.phpt
+++ php-src/ext/spl/tests/recursive_tree_iterator_007.phpt
--TEST--
SPL: RecursiveTreeIterator and Exception from getEntry()
--INI--
error_reporting=E_ALL&~E_NOTICE
--FILE--
<?php

$ary = array(new stdClass);

class RecursiveArrayIteratorAggregated implements IteratorAggregate {
        public $it;
        function __construct($it) {
                $this->it = new RecursiveArrayIterator($it);
        }
        function getIterator() {
                return $this->it;
        }
}

$it = new RecursiveArrayIteratorAggregated($ary);
try {
        foreach(new RecursiveTreeIterator($it) as $k => $v) {
                echo "[$k] => $v\n";
        }
} catch (UnexpectedValueException $e) {
        echo "UnexpectedValueException thrown\n";
}

?>
===DONE===
--EXPECTF--
UnexpectedValueException thrown
===DONE===

http://cvs.php.net/viewvc.cgi/php-src/ext/spl/tests/recursive_tree_iterator_008.phpt?view=markup&rev=1.1
Index: php-src/ext/spl/tests/recursive_tree_iterator_008.phpt
+++ php-src/ext/spl/tests/recursive_tree_iterator_008.phpt
--TEST--
SPL: RecursiveTreeIterator::setPrefixPart()
--INI--
error_reporting=E_ALL&~E_NOTICE
--FILE--
<?php

$ary = array(
        "a" => array("b"),
        "c" => array("d"),
);

$it = new RecursiveArrayIterator($ary);
$it = new RecursiveTreeIterator($it);
for($i = 0; $i < 6; ++$i) {
        $it->setPrefixPart($i, $i);
}
foreach($it as $k => $v) {
        echo "[$k] => $v\n";
}
try {
        $it->setPrefixPart(-1, "");
        $it->setPrefixPart(6, "");
} catch (OutOfRangeException $e) {
        echo "OutOfRangeException thrown\n";
}
try {
        $it->setPrefixPart(6, "");
} catch (OutOfRangeException $e) {
        echo "OutOfRangeException thrown\n";
}
?>
===DONE===
--EXPECTF--
[a] => 035Array
[0] => 0145b
[c] => 045Array
[0] => 0245d
OutOfRangeException thrown
OutOfRangeException thrown
===DONE===

http://cvs.php.net/viewvc.cgi/php-src/ext/spl/internal/recursivetreeiterator.inc?view=markup&rev=1.1
Index: php-src/ext/spl/internal/recursivetreeiterator.inc
+++ php-src/ext/spl/internal/recursivetreeiterator.inc
<?php

/** @file recursivetreeiterator.inc
 * @ingroup Examples
 * @brief   class RecursiveTreeIterator
 * @author  Marcus Boerger, Johannes Schlueter
 * @date    2005
 *
 * SPL - Standard PHP Library
 */


/** @ingroup SPL
 * @brief   RecursiveIteratorIterator to generate ASCII graphic trees for the
 *          entries in a RecursiveIterator
 * @author  Marcus Boerger, Johannes Schlueter
 * @version 1.1
 */
class RecursiveTreeIterator extends RecursiveIteratorIterator
{
        const BYPASS_CURRENT = 0x00000004;
        const BYPASS_KEY     = 0x00000008;

        private $rit_flags;

        /**
         * @param it         iterator to use as inner iterator
         * @param rit_flags  flags passed to RecursiveIteratoIterator (parent)
         * @param cit_flags  flags passed to RecursiveCachingIterator (for 
hasNext)
         * @param mode       mode  passed to RecursiveIteratoIterator (parent)
         */
        function __construct(RecursiveIterator $it, $rit_flags = 
self::BYPASS_KEY, $cit_flags = CachingIterator::CATCH_GET_CHILD, $mode = 
self::SELF_FIRST)
        {
                parent::__construct(new RecursiveCachingIterator($it, 
$cit_flags), $mode, $rit_flags);
                $this->rit_flags = $rit_flags;
        }

        private $prefix = array(0=>'', 1=>'| ', 2=>'  ', 3=>'|-', 4=>'\-', 
5=>'');

        /** Prefix used to start elements. */
        const PREFIX_LEFT         = 0;
        /** Prefix used if $level < depth and hasNext($level) == true. */
        const PREFIX_MID_HAS_NEXT = 1;
        /** Prefix used if $level < depth and hasNext($level) == false. */
        const PREFIX_MID_LAST     = 2;
        /** Prefix used if $level == depth and hasNext($level) == true. */
        const PREFIX_END_HAS_NEXT = 3;
        /** Prefix used if $level == depth and hasNext($level) == false. */
        const PREFIX_END_LAST     = 4;
        /** Prefix used right in front of the current element. */
        const PREFIX_RIGHT        = 5;

        /**
         * Set prefix part as used in getPrefix() and stored in $prefix.
         * @param $part   any PREFIX_* const.
         * @param $value  new prefix string for specified part.
         * @throws OutOfRangeException if 0 > $part or $part > 5.
         */
        function setPrefixPart($part, $value)
        {
                if (0 > $part || $part > 5) {
                        throw new OutOfRangeException();
                }
                $this->prefix[$part] = (string)$value;
        }

        /** @return string to place in front of current element
         */
        function getPrefix()
        {
                $tree = '';
                for ($level = 0; $level < $this->getDepth(); $level++)
                {
                        $tree .= $this->getSubIterator($level)->hasNext() ? 
$this->prefix[1] : $this->prefix[2];
                }
                $tree .= $this->getSubIterator($level)->hasNext() ? 
$this->prefix[3] : $this->prefix[4];

                return $this->prefix[0] . $tree . $this->prefix[5];
        }

        /** @return string presentation build for current element
         */
        function getEntry()
        {
                return @(string)parent::current();
        }

        /** @return string to place after the current element
         */
        function getPostfix()
        {
                return '';
        }

        /** @return the current element prefixed and postfixed
         */
        function current()
        {
                if ($this->rit_flags & self::BYPASS_CURRENT)
                {
                        return parent::current();
                }
                else
                {
                        return $this->getPrefix() . $this->getEntry() .  
$this->getPostfix();
                }
        }

        /** @return the current key prefixed and postfixed
         */
        function key()
        {
                if ($this->rit_flags & self::BYPASS_KEY)
                {
                        return parent::key();
                }
                else
                {
                        return $this->getPrefix() . parent::key() .  
$this->getPostfix();
                }
        }

        /** Aggregates the inner iterator
         */
        function __call($func, $params)
        {
                return call_user_func_array(array($this->getSubIterator(), 
$func), $params);
        }
}

?>
-- 
PHP CVS Mailing List (http://www.php.net/)
To unsubscribe, visit: http://www.php.net/unsub.php

Reply via email to