diff options
author | Marcus Boerger <helly@php.net> | 2003-11-09 14:05:36 +0000 |
---|---|---|
committer | Marcus Boerger <helly@php.net> | 2003-11-09 14:05:36 +0000 |
commit | 159c538bcf7cc649410a7e91b11584dcebcf1b55 (patch) | |
tree | 2e5d3063aaf3733744fa81a1614fd526f9881be1 | |
parent | 44dc9eb3e4ae8be3d3d187b8e6335d768447fed5 (diff) | |
download | php-git-159c538bcf7cc649410a7e91b11584dcebcf1b55.tar.gz |
Major update:
- Remove all overloading hooks -> array_read/array_access must be rewritten
- Remove all basic iterators
- Remove all 'spl_' prefixing exposed to user level
- Add RecursiveIterator, RecursiveIteratorIterator
- Add DirectoryIterator, DirectoryTreeIterator
- Add some examples
-rwxr-xr-x | ext/spl/config.m4 | 35 | ||||
-rwxr-xr-x | ext/spl/examples/directoryfilterdots.inc | 26 | ||||
-rwxr-xr-x | ext/spl/examples/directorytree.inc | 10 | ||||
-rwxr-xr-x | ext/spl/examples/directorytree.php | 17 | ||||
-rwxr-xr-x | ext/spl/examples/filter.inc | 16 | ||||
-rwxr-xr-x | ext/spl/examples/filteriterator.inc | 89 | ||||
-rwxr-xr-x | ext/spl/examples/findfile.php | 17 | ||||
-rwxr-xr-x | ext/spl/examples/limititerator.inc | 48 | ||||
-rwxr-xr-x | ext/spl/examples/recursiveiteratoriterator.inc | 87 | ||||
-rwxr-xr-x | ext/spl/examples/searchiterator.inc | 16 | ||||
-rwxr-xr-x | ext/spl/php_spl.c | 124 | ||||
-rwxr-xr-x | ext/spl/php_spl.h | 12 | ||||
-rwxr-xr-x | ext/spl/spl_array.c | 402 | ||||
-rwxr-xr-x | ext/spl/spl_array.h | 14 | ||||
-rwxr-xr-x | ext/spl/spl_directory.c | 577 | ||||
-rwxr-xr-x | ext/spl/spl_directory.h (renamed from ext/spl/spl_foreach.h) | 12 | ||||
-rwxr-xr-x | ext/spl/spl_engine.c | 200 | ||||
-rwxr-xr-x | ext/spl/spl_engine.h | 53 | ||||
-rwxr-xr-x | ext/spl/spl_foreach.c | 269 | ||||
-rwxr-xr-x | ext/spl/spl_functions.c | 20 | ||||
-rwxr-xr-x | ext/spl/spl_functions.h | 22 | ||||
-rwxr-xr-x | ext/spl/spl_iterators.c | 399 | ||||
-rwxr-xr-x | ext/spl/spl_iterators.h | 39 |
23 files changed, 1405 insertions, 1099 deletions
diff --git a/ext/spl/config.m4 b/ext/spl/config.m4 index bce2b4f43a..95bffc35c1 100755 --- a/ext/spl/config.m4 +++ b/ext/spl/config.m4 @@ -4,40 +4,7 @@ dnl config.m4 for extension SPL PHP_ARG_ENABLE(spl, enable SPL suppport, [ --disable-spl Enable Standard PHP Library], yes) -dnl first enable/disable all hooks - -PHP_ARG_ENABLE(spl-hook-all, enable all hooks, -[ --enable-spl-hook-all SPL: Enable all hooks]) - -dnl now all single enable/disable for hooks - -PHP_ARG_ENABLE(spl-foreach, enable hook on foreach, -[ --disable-spl-foreach SPL: Disable hook on forach], yes) - -PHP_ARG_ENABLE(spl-array-read, enable hook on array read, -[ --enable-spl-array-read SPL: Enable hook on array read]) - -PHP_ARG_ENABLE(spl-array-write, enable hook on array write, -[ --enable-spl-array-write SPL: Enable hook on array write (+read)]) - -dnl last do checks on hooks - -if test "$PHP_SPL" != "no"; then - if test "$PHP_SPL_HOOK_ALL" != "no" -o "$PHP_SPL_FOREACH" != "no"; then - AC_DEFINE(SPL_FOREACH, 1, [Activate opcode hook on foreach]) - PHP_SPL="yes" - fi - if test "$PHP_SPL_HOOK_ALL" != "no" -o "$PHP_SPL_ARRAY_READ" != "no" -o "$PHP_SPL_ARRAY_WRITE" != "no"; then - AC_DEFINE(SPL_ARRAY_READ, 1, [Activate opcode hook on array read]) - PHP_SPL="yes" - fi - if test "$PHP_SPL_HOOK_ALL" != "no" -o "$PHP_SPL_ARRAY_WRITE" != "no"; then - AC_DEFINE(SPL_ARRAY_WRITE, 1, [Activate opcode hook on array write]) - PHP_SPL="yes" - fi -fi - if test "$PHP_SPL" != "no"; then AC_DEFINE(HAVE_SPL, 1, [Whether you want SPL (Standard Php Library) support]) - PHP_NEW_EXTENSION(spl, php_spl.c spl_functions.c spl_engine.c spl_foreach.c spl_array.c spl_directory.c, $ext_shared) + PHP_NEW_EXTENSION(spl, php_spl.c spl_functions.c spl_engine.c spl_iterators.c spl_array.c spl_directory.c, $ext_shared) fi diff --git a/ext/spl/examples/directoryfilterdots.inc b/ext/spl/examples/directoryfilterdots.inc new file mode 100755 index 0000000000..3ca0e6a2f8 --- /dev/null +++ b/ext/spl/examples/directoryfilterdots.inc @@ -0,0 +1,26 @@ +<?php + +class DirectoryFilterDots extends FilterIterator implements RecursiveIterator +{ + function __construct($path) { + parent::__construct(new DirectoryIterator($path)); + } + + function accept() { + return !$this->it->isDot(); + } + + function hasChildren() { + return $this->it->hasChildren(); + } + + function getChildren() { + return new DirectoryFilterDots($this->it->getPathname()); + } + + function key() { + return $this->it->getPathname(); + } +} + +?>
\ No newline at end of file diff --git a/ext/spl/examples/directorytree.inc b/ext/spl/examples/directorytree.inc new file mode 100755 index 0000000000..218ca513d9 --- /dev/null +++ b/ext/spl/examples/directorytree.inc @@ -0,0 +1,10 @@ +<?php + +class DirectoryTree extends RecursiveIteratorIterator +{ + function __construct($path) { + parent::__construct(new DirectoryFilterDots($path)); + } +} + +?>
\ No newline at end of file diff --git a/ext/spl/examples/directorytree.php b/ext/spl/examples/directorytree.php new file mode 100755 index 0000000000..744a17a99a --- /dev/null +++ b/ext/spl/examples/directorytree.php @@ -0,0 +1,17 @@ +<?php + +/** tree view example + * + * Usage: php DirectoryTree.php <path> + * + * Simply specify the path to tree with parameter <path>. + * + * (c) Marcus Boerger + */ + +$length = $argc > 3 ? $argv[3] : NULL; +foreach(new LimitIterator(new DirectoryTree($argv[1]), @$argv[2], $length) as $pathname => $file) { + echo "$pathname\n"; +} + +?>
\ No newline at end of file diff --git a/ext/spl/examples/filter.inc b/ext/spl/examples/filter.inc index 1cab580edd..d01dd62845 100755 --- a/ext/spl/examples/filter.inc +++ b/ext/spl/examples/filter.inc @@ -22,7 +22,7 @@ class filter implements spl_forward * method is called. * * @param it Object that implements at least spl_forward - * @patam regex Regular expression used as a filter. + * @param regex Regular expression used as a filter. */ function __construct(spl_forward $it, $regex) { if ($it instanceof spl_sequence) { @@ -40,14 +40,18 @@ class filter implements spl_forward unset($this->it); } - protected function accept($curr) { - return ereg($this->regex, $curr); + /** + * Check whether a value can be accepted. + * + * @param value used to test + * @return whether input is acceptable + */ + protected function accept($value) { + return ereg($this->regex, $value); } /** * Fetch next element and store it. - * - * @return void */ protected function fetch() { $this->curr = false; @@ -63,8 +67,6 @@ class filter implements spl_forward /** * Move to next element - * - * @return void */ function next() { $this->it->next(); diff --git a/ext/spl/examples/filteriterator.inc b/ext/spl/examples/filteriterator.inc new file mode 100755 index 0000000000..43f8515c2f --- /dev/null +++ b/ext/spl/examples/filteriterator.inc @@ -0,0 +1,89 @@ +<?php + +/** + * @brief Regular expression filter for string iterators + * @author Marcus Boerger + * @version 1.0 + * + * Instances of this class act as a filter around iterators whose elements + * are strings. In other words you can put an iterator into the constructor + * and the instance will only return elements which match the given regular + * expression. + */ +abstract class FilterIterator implements Iterator +{ + protected $it; + + /** + * Constructs a filter around an iterator whose elemnts are strings. + * If the given iterator is of type spl_sequence then its rewind() + * method is called. + * + * @param it Object that implements at least spl_forward + * @patam regex Regular expression used as a filter. + */ + function __construct(Iterator $it) { + $this->it = $it; + } + + function rewind() { + $this->it->rewind(); + $this->fetch(); + } + + abstract function accept(); + + /** + * Fetch next element and store it. + * + * @return void + */ + protected function fetch() { + while ($this->it->hasMore()) { + if ($this->accept()) { + return; + } + $this->it->next(); + }; + } + + /** + * Move to next element + * + * @return void + */ + function next() { + $this->it->next(); + $this->fetch(); + } + + /** + * @return Whether more elements are available + */ + function hasMore() { + return $this->it->hasMore(); + } + + /** + * @return The current key + */ + function key() { + return $this->it->key(); + } + + /** + * @return The current value + */ + function current() { + return $this->it->current(); + } + + /** + * hidden __clone + */ + protected function __clone() { + // disallow clone + } +} + +?>
\ No newline at end of file diff --git a/ext/spl/examples/findfile.php b/ext/spl/examples/findfile.php new file mode 100755 index 0000000000..003111e272 --- /dev/null +++ b/ext/spl/examples/findfile.php @@ -0,0 +1,17 @@ +<?php + +class FindFile extends SearchIterator +{ + protected $file; + + function __construct($path, $file) { + $this->file = $file; + parent::__construct(new DirectoryTree($path)); + } + function accept() { + return !strcmp($this->it->current(), $this->file); + } +} + +foreach(new FindFile($argv[1], $argv[2]) as $pathname => $file) echo "$pathname\n"; +?>
\ No newline at end of file diff --git a/ext/spl/examples/limititerator.inc b/ext/spl/examples/limititerator.inc new file mode 100755 index 0000000000..c1a19fedd9 --- /dev/null +++ b/ext/spl/examples/limititerator.inc @@ -0,0 +1,48 @@ +<?php + +class LimitIterator implements Iterator +{ + protected $it; + protected $offset; + protected $count; + protected $index; + + // negative offset is respected + // count === NULL means all + function __construct(Iterator $it, $offset = 0, $count = NULL) + { + $this->it = $it; + $this->offset = $offset; + $this->count = $count; + $this->index = 0; + } + + function rewind() + { + $this->it->rewind(); + $this->index = 0; + while($this->index < $this->offset && $this->it->hasMore()) { + $this->next(); + } + } + + function hasMore() { + return (is_null($this->count) || $this->index < $this->offset + $this->count) + && $this->it->hasMore(); + } + + function key() { + return $this->it->key(); + } + + function current() { + return $this->it->current(); + } + + function next() { + $this->it->next(); + $this->index++; + } +} + +?>
\ No newline at end of file diff --git a/ext/spl/examples/recursiveiteratoriterator.inc b/ext/spl/examples/recursiveiteratoriterator.inc new file mode 100755 index 0000000000..95d52d7f76 --- /dev/null +++ b/ext/spl/examples/recursiveiteratoriterator.inc @@ -0,0 +1,87 @@ +<?php + +/** + * @brief Iterates through recursive iterators + * @author Marcus Boerger + * @version 1.0 + * + */ +class RecursiveIteratorIterator implements Iterator +{ + protected $ait = array(); + protected $count = 0; + + function __construct(RecursiveIterator $it) { + $this->count = 1; + $this->ait[0] = $it; + } + + + function rewind() { + while ($this->count > 1) { + unset($this->ait[--$this->count]); + } + $this->ait[0]->rewind(); + $this->ait[0]->recursed = false; + } + + function hasMore() { + $count = $this->count; + while ($count--) { + $it = $this->ait[$count]; + if ($it->hasMore()) {// || (!$it->recursed && $it->isRecursive())) { + return true; + } + } + return false; + } + + function key() { + $it = $this->ait[$this->count-1]; + return $it->key(); + } + + function current() { + $it = $this->ait[$this->count-1]; + return $it->current(); + } + + function next() { + while ($this->count) { + $it = $this->ait[$this->count-1]; + if ($it->hasMore()) { + if (!$it->recursed && $it->hasChildren()) { + $it->recursed = true; + $sub = $it->getChildren(); + $sub->recursed = false; + $sub->rewind(); + if ($sub->hasMore()) { + $this->ait[$this->count++] = $sub; + if (!is_a($sub, 'RecursiveIterator')) { + throw new Exception(get_class($sub).'::getChildren() must return an object that implements RecursiveIterator'); + } + return; + } + unset($sub); + } + $it->next(); + $it->recursed = false; + if ($it->hasMore()) { + return; + } + $it->recursed = false; + } + if ($this->count <= 1) { + return; + } + unset($this->ait[--$this->count]); + $it = $this->ait[$this->count-1]; + } + } + + function getCurrentIterator() { + return $this->ait[$this->count-1]; + } +} + +?>
\ No newline at end of file diff --git a/ext/spl/examples/searchiterator.inc b/ext/spl/examples/searchiterator.inc new file mode 100755 index 0000000000..42c249be9b --- /dev/null +++ b/ext/spl/examples/searchiterator.inc @@ -0,0 +1,16 @@ +<?php + +abstract class SearchIterator extends FilterIterator +{ + private $done = false; + + function hasMore() { + return !$this->done && parent::hasMore(); + } + + function next() { + $this->done = true; + } +} + +?>
\ No newline at end of file diff --git a/ext/spl/php_spl.c b/ext/spl/php_spl.c index 7617f3fa9e..c5941d7c07 100755 --- a/ext/spl/php_spl.c +++ b/ext/spl/php_spl.c @@ -26,8 +26,9 @@ #include "php_spl.h" #include "spl_functions.h" #include "spl_engine.h" -#include "spl_foreach.h" #include "spl_array.h" +#include "spl_directory.h" +#include "spl_iterators.h" #ifdef COMPILE_DL_SPL ZEND_GET_MODULE(spl) @@ -61,12 +62,8 @@ zend_module_entry spl_module_entry = { }; /* }}} */ -zend_class_entry *spl_ce_iterator; -zend_class_entry *spl_ce_forward; -zend_class_entry *spl_ce_assoc; -zend_class_entry *spl_ce_sequence; -zend_class_entry *spl_ce_forward_assoc; -zend_class_entry *spl_ce_sequence_assoc; +zend_class_entry *spl_ce_recursive_it; +zend_class_entry *spl_ce_recursive_it_it; zend_class_entry *spl_ce_array_read; zend_class_entry *spl_ce_array_access; @@ -81,106 +78,16 @@ function_entry spl_functions_none[] = { */ static void spl_init_globals(zend_spl_globals *spl_globals) { -#ifdef SPL_FOREACH - ZEND_EXECUTE_HOOK(ZEND_FE_RESET); - ZEND_EXECUTE_HOOK(ZEND_FE_FETCH); - ZEND_EXECUTE_HOOK(ZEND_SWITCH_FREE); -#endif - -#if defined(SPL_ARRAY_READ) | defined(SPL_ARRAY_WRITE) - ZEND_EXECUTE_HOOK(ZEND_FETCH_DIM_R); - ZEND_EXECUTE_HOOK(ZEND_FETCH_DIM_W); - ZEND_EXECUTE_HOOK(ZEND_FETCH_DIM_RW); -#endif - -#ifdef SPL_ARRAY_WRITE - ZEND_EXECUTE_HOOK(ZEND_ASSIGN_DIM); - ZEND_EXECUTE_HOOK(ZEND_UNSET_DIM_OBJ); -#endif /* SPL_ARRAY_WRITE */ } /* }}} */ -PHP_FUNCTION(spl_abstract) {} - -#define SPL_ABSTRACT_FE(class, name, arg_info) \ - { #name, ZEND_FN(spl_abstract), arg_info, sizeof(arg_info)/sizeof(struct _zend_arg_info)-1, ZEND_ACC_ABSTRACT|ZEND_ACC_PUBLIC }, - -static -ZEND_BEGIN_ARG_INFO(arginfo_one_param, 0) - ZEND_ARG_INFO(0, index) -ZEND_END_ARG_INFO(); - -static -ZEND_BEGIN_ARG_INFO(arginfo_two_params, 0) - ZEND_ARG_INFO(0, index) - ZEND_ARG_INFO(0, value) -ZEND_END_ARG_INFO(); - -function_entry spl_funcs_iterator[] = { - SPL_ABSTRACT_FE(iterator, newIterator, NULL) - {NULL, NULL, NULL} -}; - -function_entry spl_funcs_forward[] = { - SPL_ABSTRACT_FE(forward, current, NULL) - SPL_ABSTRACT_FE(forward, next, NULL) - SPL_ABSTRACT_FE(forward, hasMore, NULL) - {NULL, NULL, NULL} -}; - -function_entry spl_funcs_sequence[] = { - SPL_ABSTRACT_FE(sequence, rewind, NULL) - {NULL, NULL, NULL} -}; - -function_entry spl_funcs_assoc[] = { - SPL_ABSTRACT_FE(assoc, key, NULL) - {NULL, NULL, NULL} -}; - -function_entry *spl_funcs_forward_assoc = NULL; -function_entry *spl_funcs_sequence_assoc = NULL; - -function_entry spl_funcs_array_read[] = { - SPL_ABSTRACT_FE(array_read, get, arginfo_one_param) - SPL_ABSTRACT_FE(array_read, exists, arginfo_one_param) - {NULL, NULL, NULL} -}; - -function_entry spl_funcs_array_access[] = { - SPL_ABSTRACT_FE(array_access, set, arginfo_two_params) - SPL_ABSTRACT_FE(array_access, del, arginfo_one_param) - {NULL, NULL, NULL} -}; - /* {{{ PHP_MINIT_FUNCTION(spl) */ PHP_MINIT_FUNCTION(spl) { ZEND_INIT_MODULE_GLOBALS(spl, spl_init_globals, NULL); - REGISTER_SPL_INTERFACE(iterator); - - REGISTER_SPL_INTERFACE(forward); - - REGISTER_SPL_INTERFACE(sequence); - REGISTER_SPL_IMPLEMENT(sequence, forward); - - REGISTER_SPL_INTERFACE(assoc); - - REGISTER_SPL_INTERFACE(forward_assoc); - REGISTER_SPL_IMPLEMENT(forward_assoc, assoc); - REGISTER_SPL_IMPLEMENT(forward_assoc, forward); - - REGISTER_SPL_INTERFACE(sequence_assoc); - REGISTER_SPL_IMPLEMENT(sequence_assoc, forward_assoc); - REGISTER_SPL_IMPLEMENT(sequence_assoc, sequence); - - REGISTER_SPL_INTERFACE(array_read); - - REGISTER_SPL_INTERFACE(array_access); - REGISTER_SPL_IMPLEMENT(array_access, array_read); - + PHP_MINIT(spl_iterators)(INIT_FUNC_ARGS_PASSTHRU); PHP_MINIT(spl_array)(INIT_FUNC_ARGS_PASSTHRU); PHP_MINIT(spl_directory)(INIT_FUNC_ARGS_PASSTHRU); @@ -256,10 +163,8 @@ PHP_MINFO_FUNCTION(spl) php_info_print_table_row(2, "forward", foreach); php_info_print_table_row(2, "sequence", foreach); php_info_print_table_row(2, "assoc", foreach); - php_info_print_table_row(2, "forward_assoc", foreach); - php_info_print_table_row(2, "sequence_assoc", foreach); - php_info_print_table_row(2, "array_read", array_read); - php_info_print_table_row(2, "array_access", array_write); + php_info_print_table_row(2, "ArrayRead", array_read); + php_info_print_table_row(2, "ArrayAccess", array_write); php_info_print_table_end(); } /* }}} */ @@ -305,14 +210,13 @@ PHP_FUNCTION(spl_classes) { array_init(return_value); - SPL_ADD_CLASS(iterator); - SPL_ADD_CLASS(forward); - SPL_ADD_CLASS(sequence); - SPL_ADD_CLASS(assoc); - SPL_ADD_CLASS(forward_assoc); - SPL_ADD_CLASS(sequence_assoc); - SPL_ADD_CLASS(array_read); - SPL_ADD_CLASS(array_access); + SPL_ADD_CLASS(ArrayAccess); + SPL_ADD_CLASS(ArrayClass); + SPL_ADD_CLASS(ArrayIterator); + SPL_ADD_CLASS(ArrayRead); + SPL_ADD_CLASS(DirectoryIterator); + SPL_ADD_CLASS(RecursiveIterator); + SPL_ADD_CLASS(RecursiveIteratorIterator); } /* }}} */ diff --git a/ext/spl/php_spl.h b/ext/spl/php_spl.h index b8de833022..474da85c01 100755 --- a/ext/spl/php_spl.h +++ b/ext/spl/php_spl.h @@ -83,22 +83,10 @@ extern int spl_globals_id; extern zend_spl_globals spl_globals; #endif -extern zend_class_entry *spl_ce_iterator; -extern zend_class_entry *spl_ce_forward; -extern zend_class_entry *spl_ce_sequence; -extern zend_class_entry *spl_ce_assoc; -extern zend_class_entry *spl_ce_forward_assoc; -extern zend_class_entry *spl_ce_sequence_assoc; -extern zend_class_entry *spl_ce_array_read; -extern zend_class_entry *spl_ce_array_access; - PHP_FUNCTION(spl_classes); PHP_FUNCTION(class_parents); PHP_FUNCTION(class_implements); -PHP_MINIT_FUNCTION(spl_array); -PHP_MINIT_FUNCTION(spl_directory); - #endif /* PHP_SPL_H */ /* diff --git a/ext/spl/spl_array.c b/ext/spl/spl_array.c index 95132cb6c2..6df776ac6c 100755 --- a/ext/spl/spl_array.c +++ b/ext/spl/spl_array.c @@ -23,317 +23,74 @@ #include "php.h" #include "php_ini.h" #include "ext/standard/info.h" -#include "zend_compile.h" +#include "zend_interfaces.h" #include "php_spl.h" #include "spl_functions.h" #include "spl_engine.h" #include "spl_array.h" -#define DELETE_ZVAL(z) \ - if ((z)->refcount < 2) { \ - zval_dtor(z); \ - FREE_ZVAL(z); /* maybe safe_free_zval_ptr is needed for the uninitialised things */ \ - } - -#define DELETE_RET_ZVAL(z) \ - if ((z)->refcount < 3) { \ - zval_dtor(z); \ - FREE_ZVAL(z); /* maybe safe_free_zval_ptr is needed for the uninitialised things */ \ - } - -#define AI_PTR_2_PTR_PTR(ai) \ - (ai).ptr_ptr = &((ai).ptr) - -/* {{{ spl_fetch_dimension_address */ -int spl_fetch_dimension_address(znode *result, znode *op1, znode *op2, temp_variable *Ts, int type TSRMLS_DC) -{ - zval **obj; - zend_class_entry *obj_ce; - spl_is_a is_a; - - obj = spl_get_zval_ptr_ptr(op1, Ts TSRMLS_CC); - - if (!obj || (obj_ce = spl_get_class_entry(*obj TSRMLS_CC)) == NULL) { - return 1; - } - - is_a = spl_implements(obj_ce); - - if (is_a & SPL_IS_A_ARRAY_READ) { - zval **retval = &(T(result->u.var).var.ptr); - zval *dim = spl_get_zval_ptr(op2, Ts, &EG(free_op2) TSRMLS_CC); - zval *exists; - - spl_call_method_1(obj, obj_ce, NULL, "exists", sizeof("exists")-1, &exists, dim); - if (!i_zend_is_true(exists)) { - if (type == BP_VAR_R || type == BP_VAR_RW) { - SEPARATE_ZVAL(&dim); - convert_to_string_ex(&dim); - zend_error(E_NOTICE, "Undefined index: %s", Z_STRVAL_P(dim)); - DELETE_ZVAL(dim); - } - if (type == BP_VAR_R || type == BP_VAR_IS) { - DELETE_RET_ZVAL(exists); - *retval = &EG(error_zval); - (*retval)->refcount++; - FREE_OP(Ts, op2, EG(free_op2)); - SELECTIVE_PZVAL_LOCK(*retval, result); - return 0; - } - } - DELETE_RET_ZVAL(exists); - if (type == BP_VAR_R || type == BP_VAR_IS) { - spl_call_method_1(obj, obj_ce, NULL, "get", sizeof("get")-1, retval, dim); - } - FREE_OP(Ts, op2, EG(free_op2)); - return 0; - } - return 1; -} -/* }}} */ - -/* {{{ ZEND_EXECUTE_HOOK_FUNCTION(ZEND_FETCH_DIM_R) */ -#ifdef SPL_ARRAY_READ -ZEND_EXECUTE_HOOK_FUNCTION(ZEND_FETCH_DIM_R) -{ - if (!spl_fetch_dimension_address(&EX(opline)->result, &EX(opline)->op1, &EX(opline)->op2, EX(Ts), BP_VAR_R TSRMLS_CC)) - { - if (EX(opline)->extended_value == ZEND_FETCH_ADD_LOCK) { - spl_pzval_lock_func(*EX_T(EX(opline)->op1.u.var).var.ptr_ptr); - } - spl_unlock_zval_ptr_ptr(&EX(opline)->op1, EX(Ts) TSRMLS_CC); - - AI_PTR_2_PTR_PTR(EX_T(EX(opline)->result.u.var).var); - NEXT_OPCODE(); - } - ZEND_EXECUTE_HOOK_ORIGINAL(ZEND_FETCH_DIM_R); -} -#endif -/* }}} */ - -/* {{{ ZEND_EXECUTE_HOOK_FUNCTION(ZEND_FETCH_DIM_W) */ -#ifdef SPL_ARRAY_READ -ZEND_EXECUTE_HOOK_FUNCTION(ZEND_FETCH_DIM_W) -{ - if (!spl_fetch_dimension_address(&EX(opline)->result, &EX(opline)->op1, &EX(opline)->op2, EX(Ts), BP_VAR_W TSRMLS_CC)) - { - spl_unlock_zval_ptr_ptr(&EX(opline)->op1, EX(Ts) TSRMLS_CC); - NEXT_OPCODE(); - } - ZEND_EXECUTE_HOOK_ORIGINAL(ZEND_FETCH_DIM_W); -} -#endif -/* }}} */ - -/* {{{ ZEND_EXECUTE_HOOK_FUNCTION(ZEND_FETCH_DIM_RW) */ -#ifdef SPL_ARRAY_READ -ZEND_EXECUTE_HOOK_FUNCTION(ZEND_FETCH_DIM_RW) -{ - if (!spl_fetch_dimension_address(&EX(opline)->result, &EX(opline)->op1, &EX(opline)->op2, EX(Ts), BP_VAR_RW TSRMLS_CC)) - { - spl_unlock_zval_ptr_ptr(&EX(opline)->op1, EX(Ts) TSRMLS_CC); - - NEXT_OPCODE(); - } - ZEND_EXECUTE_HOOK_ORIGINAL(ZEND_FETCH_DIM_RW); -} -#endif -/* }}} */ - -static inline zval **spl_get_obj_zval_ptr_ptr(znode *op, temp_variable *Ts, int type TSRMLS_DC) -{ - if (op->op_type == IS_UNUSED) { - if (EG(This)) { - /* this should actually never be modified, _ptr_ptr is modified only when - the object is empty */ - return &EG(This); - } else { - zend_error(E_ERROR, "Using $this when not in object context"); - } - } - return spl_get_zval_ptr_ptr(op, Ts TSRMLS_CC); -} - -/* {{{ ZEND_EXECUTE_HOOK_FUNCTION(ZEND_ASSIGN_DIM) */ -#ifdef SPL_ARRAY_WRITE -ZEND_EXECUTE_HOOK_FUNCTION(ZEND_ASSIGN_DIM) -{ - zval **obj; - zend_class_entry *obj_ce; - spl_is_a is_a; - - obj = spl_get_obj_zval_ptr_ptr(&EX(opline)->op1, EX(Ts), 0 TSRMLS_CC); - - if (!obj || (obj_ce = spl_get_class_entry(*obj TSRMLS_CC)) == NULL) { - ZEND_EXECUTE_HOOK_ORIGINAL(ZEND_ASSIGN_DIM); - } - - is_a = spl_implements(obj_ce); - - if (is_a & SPL_IS_A_ARRAY_ACCESS) { - znode *op2 = &EX(opline)->op2; - zval *index = spl_get_zval_ptr(op2, EX(Ts), &EG(free_op2), BP_VAR_R); - zval *free_value; - zend_op *value_op = EX(opline)+1; - zval *value = spl_get_zval_ptr(&value_op->op1, EX(Ts), &free_value, BP_VAR_R); - zval tmp; - zval *retval; - - spl_unlock_zval_ptr_ptr(&EX(opline)->op1, EX(Ts) TSRMLS_CC); - - /* here we are sure we are dealing with an object */ - switch (op2->op_type) { - case IS_CONST: - /* already a constant string */ - break; - case IS_VAR: - tmp = *index; - zval_copy_ctor(&tmp); - convert_to_string(&tmp); - index = &tmp; - break; - case IS_TMP_VAR: - convert_to_string(index); - break; - } - - /* separate our value if necessary */ - if (value_op->op1.op_type == IS_TMP_VAR) { - zval *orig_value = value; - - ALLOC_ZVAL(value); - *value = *orig_value; - value->is_ref = 0; - value->refcount = 0; - } - - spl_call_method_2(obj, obj_ce, NULL, "set", sizeof("set")-1, &retval, index, value); - - if (index == &tmp) { - zval_dtor(index); - } - - FREE_OP(Ts, op2, EG(free_op2)); - if (&EX(opline)->result) { - if (retval->refcount < 2) { - zend_error(E_WARNING, "Method %s::set() did not return a value, using input value", obj_ce->name); - EX_T(EX(opline)->result.u.var).var.ptr = value; - SELECTIVE_PZVAL_LOCK(value, &EX(opline)->result); - DELETE_RET_ZVAL(retval); - } else { - SELECTIVE_PZVAL_LOCK(retval, &EX(opline)->result); - EX_T(EX(opline)->result.u.var).var.ptr = retval; - retval->refcount--; - } - EX_T(EX(opline)->result.u.var).var.ptr_ptr = NULL; - } else { - DELETE_RET_ZVAL(retval); - } - - EX(opline)++; - NEXT_OPCODE(); - } - ZEND_EXECUTE_HOOK_ORIGINAL(ZEND_ASSIGN_DIM); -} -#endif -/* }}} */ - -/* {{{ ZEND_EXECUTE_HOOK_FUNCTION(ZEND_UNSET_DIM_OBJ) */ -#ifdef SPL_ARRAY_WRITE -ZEND_EXECUTE_HOOK_FUNCTION(ZEND_UNSET_DIM_OBJ) -{ - zval **obj; - zend_class_entry *obj_ce; - spl_is_a is_a; - - if (EX(opline)->extended_value != ZEND_UNSET_DIM) { - ZEND_EXECUTE_HOOK_ORIGINAL(ZEND_UNSET_DIM_OBJ); - } - - obj = spl_get_obj_zval_ptr_ptr(&EX(opline)->op1, EX(Ts), 0 TSRMLS_CC); - - if (!obj || (obj_ce = spl_get_class_entry(*obj TSRMLS_CC)) == NULL) { - ZEND_EXECUTE_HOOK_ORIGINAL(ZEND_UNSET_DIM_OBJ); - } - - is_a = spl_implements(obj_ce); - - if (is_a & SPL_IS_A_ARRAY_ACCESS) { - znode *op2 = &EX(opline)->op2; - zval *index = spl_get_zval_ptr(op2, EX(Ts), &EG(free_op2), BP_VAR_R); - zval tmp; - zval *retval; - - spl_unlock_zval_ptr_ptr(&EX(opline)->op1, EX(Ts) TSRMLS_CC); - - /* here we are sure we are dealing with an object */ - switch (op2->op_type) { - case IS_CONST: - /* already a constant string */ - break; - case IS_VAR: - tmp = *index; - zval_copy_ctor(&tmp); - convert_to_string(&tmp); - index = &tmp; - break; - case IS_TMP_VAR: - convert_to_string(index); - break; - } - - spl_call_method_1(obj, obj_ce, NULL, "del", sizeof("del")-1, &retval, index); +static +ZEND_BEGIN_ARG_INFO(arginfo_one_param, 0) + ZEND_ARG_INFO(0, index) +ZEND_END_ARG_INFO(); - if (index == &tmp) { - zval_dtor(index); - } +static +ZEND_BEGIN_ARG_INFO(arginfo_two_params, 0) + ZEND_ARG_INFO(0, index) + ZEND_ARG_INFO(0, value) +ZEND_END_ARG_INFO(); - FREE_OP(Ts, op2, EG(free_op2)); - DELETE_RET_ZVAL(retval); +function_entry spl_funcs_ArrayRead[] = { + SPL_ABSTRACT_ME(ArrayRead, get, arginfo_one_param) + SPL_ABSTRACT_ME(ArrayRead, exists, arginfo_one_param) + {NULL, NULL, NULL} +}; - NEXT_OPCODE(); - } - ZEND_EXECUTE_HOOK_ORIGINAL(ZEND_UNSET_DIM_OBJ); -} -#endif -/* }}} */ +function_entry spl_funcs_ArrayAccess[] = { + SPL_ABSTRACT_ME(ArrayAccess, set, arginfo_two_params) + SPL_ABSTRACT_ME(ArrayAccess, del, arginfo_one_param) + {NULL, NULL, NULL} +}; -SPL_CLASS_FUNCTION(array, __construct); -SPL_CLASS_FUNCTION(array, newIterator); -SPL_CLASS_FUNCTION(array, rewind); -SPL_CLASS_FUNCTION(array, current); -SPL_CLASS_FUNCTION(array, key); -SPL_CLASS_FUNCTION(array, next); -SPL_CLASS_FUNCTION(array, hasMore); +SPL_METHOD(Array, __construct); +SPL_METHOD(Array, getIterator); +SPL_METHOD(Array, rewind); +SPL_METHOD(Array, current); +SPL_METHOD(Array, key); +SPL_METHOD(Array, next); +SPL_METHOD(Array, hasMore); static ZEND_BEGIN_ARG_INFO(arginfo_array___construct, 0) ZEND_ARG_INFO(0, array) ZEND_END_ARG_INFO(); -static zend_function_entry spl_array_class_functions[] = { - SPL_CLASS_FE(array, __construct, arginfo_array___construct, ZEND_ACC_PUBLIC) - SPL_CLASS_FE(array, newIterator, NULL, ZEND_ACC_PUBLIC) +static zend_function_entry spl_funcs_ArrayClass[] = { + SPL_ME(Array, __construct, arginfo_array___construct, ZEND_ACC_PUBLIC) + SPL_ME(Array, getIterator, NULL, ZEND_ACC_PUBLIC) {NULL, NULL, NULL} }; -static zend_function_entry spl_array_it_class_functions[] = { - SPL_CLASS_FE(array, __construct, arginfo_array___construct, ZEND_ACC_PRIVATE) - SPL_CLASS_FE(array, rewind, NULL, ZEND_ACC_PUBLIC) - SPL_CLASS_FE(array, current, NULL, ZEND_ACC_PUBLIC) - SPL_CLASS_FE(array, key, NULL, ZEND_ACC_PUBLIC) - SPL_CLASS_FE(array, next, NULL, ZEND_ACC_PUBLIC) - SPL_CLASS_FE(array, hasMore, NULL, ZEND_ACC_PUBLIC) +static zend_function_entry spl_funcs_ArrayIterator[] = { + SPL_ME(Array, __construct, arginfo_array___construct, ZEND_ACC_PRIVATE) + SPL_ME(Array, rewind, NULL, ZEND_ACC_PUBLIC) + SPL_ME(Array, current, NULL, ZEND_ACC_PUBLIC) + SPL_ME(Array, key, NULL, ZEND_ACC_PUBLIC) + SPL_ME(Array, next, NULL, ZEND_ACC_PUBLIC) + SPL_ME(Array, hasMore, NULL, ZEND_ACC_PUBLIC) {NULL, NULL, NULL} }; -static zend_object_handlers spl_array_handlers; -static zend_class_entry * spl_ce_array; +zend_class_entry * spl_ce_ArrayRead; +zend_class_entry * spl_ce_ArrayAccess; -static zend_object_handlers spl_array_it_handlers; -static zend_class_entry * spl_ce_array_it; +zend_object_handlers spl_handler_ArrayClass; +zend_class_entry * spl_ce_ArrayClass; + +zend_object_handlers spl_handler_ArrayIterator; +zend_class_entry * spl_ce_ArrayIterator; typedef struct _spl_array_object { zend_object std; @@ -384,10 +141,10 @@ static zend_object_value spl_array_object_new_ex(zend_class_entry *class_type, s zend_hash_internal_pointer_reset_ex(HASH_OF(intern->array), &intern->pos); retval.handle = zend_objects_store_put(intern, spl_array_object_dtor, NULL TSRMLS_CC); - if (class_type == spl_ce_array_it) { - retval.handlers = &spl_array_it_handlers; + if (class_type == spl_ce_ArrayIterator) { + retval.handlers = &spl_handler_ArrayIterator; } else { - retval.handlers = &spl_array_handlers; + retval.handlers = &spl_handler_ArrayClass; } return retval; } @@ -420,20 +177,6 @@ static zend_object_value spl_array_object_clone(zval *zobject TSRMLS_DC) } /* }}} */ -/* {{{ spl_array_get_ce */ -static zend_class_entry *spl_array_get_ce(zval *object TSRMLS_DC) -{ - return spl_ce_array; -} -/* }}} */ - -/* {{{ spl_array_it_get_ce */ -static zend_class_entry *spl_array_it_get_ce(zval *object TSRMLS_DC) -{ - return spl_ce_array_it; -} -/* }}} */ - /* {{{ spl_array_read_dimension */ static zval *spl_array_read_dimension(zval *object, zval *offset TSRMLS_DC) { @@ -544,20 +287,23 @@ static HashTable *spl_array_get_properties(zval *object TSRMLS_DC) /* {{{ PHP_MINIT_FUNCTION(spl_array) */ PHP_MINIT_FUNCTION(spl_array) { - REGISTER_SPL_STD_CLASS_EX(array, spl_array_object_new, spl_array_class_functions); - REGISTER_SPL_IMPLEMENT(array, iterator); - memcpy(&spl_array_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers)); - spl_array_handlers.clone_obj = spl_array_object_clone; - spl_array_handlers.get_class_entry = spl_array_get_ce; - spl_array_handlers.read_dimension = spl_array_read_dimension; - spl_array_handlers.write_dimension = spl_array_write_dimension; - spl_array_handlers.unset_dimension = spl_array_unset_dimension; - spl_array_handlers.get_properties = spl_array_get_properties; - - REGISTER_SPL_STD_CLASS_EX(array_it, spl_array_object_new, spl_array_it_class_functions); - REGISTER_SPL_IMPLEMENT(array_it, sequence_assoc); - memcpy(&spl_array_it_handlers, &spl_array_handlers, sizeof(zend_object_handlers)); - spl_array_it_handlers.get_class_entry = spl_array_it_get_ce; + REGISTER_SPL_INTERFACE(ArrayRead); + + REGISTER_SPL_INTERFACE(ArrayAccess); + zend_class_implements(spl_ce_ArrayAccess TSRMLS_CC, 1, spl_ce_ArrayRead); + + REGISTER_SPL_STD_CLASS_EX(ArrayClass, spl_array_object_new, spl_funcs_ArrayClass); + zend_class_implements(spl_ce_ArrayClass TSRMLS_CC, 1, zend_ce_aggregate); + memcpy(&spl_handler_ArrayClass, zend_get_std_object_handlers(), sizeof(zend_object_handlers)); + spl_handler_ArrayClass.clone_obj = spl_array_object_clone; + spl_handler_ArrayClass.read_dimension = spl_array_read_dimension; + spl_handler_ArrayClass.write_dimension = spl_array_write_dimension; + spl_handler_ArrayClass.unset_dimension = spl_array_unset_dimension; + spl_handler_ArrayClass.get_properties = spl_array_get_properties; + + REGISTER_SPL_STD_CLASS_EX(ArrayIterator, spl_array_object_new, spl_funcs_ArrayIterator); + zend_class_implements(spl_ce_ArrayIterator TSRMLS_CC, 1, zend_ce_iterator); + memcpy(&spl_handler_ArrayIterator, &spl_handler_ArrayClass, sizeof(zend_object_handlers)); return SUCCESS; } @@ -566,7 +312,7 @@ PHP_MINIT_FUNCTION(spl_array) /* {{{ proto void spl_array::__construct(array|object ar = array()) proto void spl_array_it::__construct(array|object ar = array()) Cronstructs a new array iterator from a path. */ -SPL_CLASS_FUNCTION(array, __construct) +SPL_METHOD(Array, __construct) { zval *object = getThis(); spl_array_object *intern; @@ -598,9 +344,9 @@ SPL_CLASS_FUNCTION(array, __construct) } /* }}} */ -/* {{{ proto spl_array_it|NULL spl_array::newIterator() - Create a new iterator from a spl_array instance */ -SPL_CLASS_FUNCTION(array, newIterator) +/* {{{ proto spl_array_it|NULL ArrayClass::getIterator() + Create a new iterator from a ArrayClass instance */ +SPL_METHOD(Array, getIterator) { zval *object = getThis(); spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC); @@ -613,7 +359,7 @@ SPL_CLASS_FUNCTION(array, newIterator) } return_value->type = IS_OBJECT; - return_value->value.obj = spl_array_object_new_ex(spl_ce_array_it, &iterator, intern TSRMLS_CC); + return_value->value.obj = spl_array_object_new_ex(spl_ce_ArrayIterator, &iterator, intern TSRMLS_CC); return_value->refcount = 1; return_value->is_ref = 1; } @@ -643,7 +389,7 @@ ZEND_API int spl_hash_pos_exists(spl_array_object * intern TSRMLS_DC) /* {{{ proto void spl_array_it::rewind() Rewind array back to the start */ -SPL_CLASS_FUNCTION(array, rewind) +SPL_METHOD(Array, rewind) { zval *object = getThis(); spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC); @@ -660,7 +406,7 @@ SPL_CLASS_FUNCTION(array, rewind) /* {{{ proto mixed|false spl_array_it::current() Return current array entry */ -SPL_CLASS_FUNCTION(array, current) +SPL_METHOD(Array, current) { zval *object = getThis(); spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC); @@ -687,7 +433,7 @@ SPL_CLASS_FUNCTION(array, current) /* {{{ proto mixed|false spl_array_it::key() Return current array key */ -SPL_CLASS_FUNCTION(array, key) +SPL_METHOD(Array, key) { zval *object = getThis(); spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC); @@ -721,7 +467,7 @@ SPL_CLASS_FUNCTION(array, key) /* {{{ proto void spl_array_it::next() Move to next entry */ -SPL_CLASS_FUNCTION(array, next) +SPL_METHOD(Array, next) { zval *object = getThis(); spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC); @@ -742,7 +488,7 @@ SPL_CLASS_FUNCTION(array, next) /* {{{ proto bool spl_array_it::hasMore() Check whether array contains more entries */ -SPL_CLASS_FUNCTION(array, hasMore) +SPL_METHOD(Array, hasMore) { zval *object = getThis(); spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC); diff --git a/ext/spl/spl_array.h b/ext/spl/spl_array.h index 840a9627eb..d4bc03d876 100755 --- a/ext/spl/spl_array.h +++ b/ext/spl/spl_array.h @@ -22,16 +22,12 @@ #include "php.h" #include "php_spl.h" -#ifdef SPL_ARRAY_READ -ZEND_EXECUTE_HOOK_FUNCTION(ZEND_FETCH_DIM_R); -ZEND_EXECUTE_HOOK_FUNCTION(ZEND_FETCH_DIM_W); -ZEND_EXECUTE_HOOK_FUNCTION(ZEND_FETCH_DIM_RW); -#endif +extern zend_class_entry *spl_ce_ArrayRead; +extern zend_class_entry *spl_ce_ArrayAccess; +extern zend_class_entry *spl_ce_ArrayClass; +extern zend_class_entry *spl_ce_ArrayIterator; -#ifdef SPL_ARRAY_WRITE -ZEND_EXECUTE_HOOK_FUNCTION(ZEND_ASSIGN_DIM); -ZEND_EXECUTE_HOOK_FUNCTION(ZEND_UNSET_DIM_OBJ); -#endif +PHP_MINIT_FUNCTION(spl_array); #endif /* SPL_ARRAY_H */ diff --git a/ext/spl/spl_directory.c b/ext/spl/spl_directory.c index 045e5d4368..444ac26704 100755 --- a/ext/spl/spl_directory.c +++ b/ext/spl/spl_directory.c @@ -27,51 +27,97 @@ #include "ext/standard/info.h" #include "zend_compile.h" #include "zend_default_classes.h" +#include "zend_interfaces.h" #include "php_spl.h" #include "spl_functions.h" #include "spl_engine.h" -#include "spl_foreach.h" +#include "spl_iterators.h" #include "php.h" #include "fopen_wrappers.h" -SPL_CLASS_FUNCTION(dir, __construct); -SPL_CLASS_FUNCTION(dir, rewind); -SPL_CLASS_FUNCTION(dir, current); -SPL_CLASS_FUNCTION(dir, next); -SPL_CLASS_FUNCTION(dir, hasMore); -SPL_CLASS_FUNCTION(dir, getPath); - +#include "ext/standard/basic_functions.h" +#include "ext/standard/php_filestat.h" + +/* forward declaration for all methods use (class-name, method-name) */ +SPL_METHOD(DirectoryIterator, __construct); +SPL_METHOD(DirectoryIterator, rewind); +SPL_METHOD(DirectoryIterator, hasMore); +SPL_METHOD(DirectoryIterator, key); +SPL_METHOD(DirectoryIterator, current); +SPL_METHOD(DirectoryIterator, next); +SPL_METHOD(DirectoryIterator, getPath); +SPL_METHOD(DirectoryIterator, getFilename); +SPL_METHOD(DirectoryIterator, getPathname); +SPL_METHOD(DirectoryIterator, isDot); +SPL_METHOD(DirectoryIterator, isDir); + +SPL_METHOD(DirectoryTreeIterator, key); +SPL_METHOD(DirectoryTreeIterator, hasChildren); +SPL_METHOD(DirectoryTreeIterator, getChildren); + + +/* declare method parameters */ +/* supply a name and default to call by parameter */ static -ZEND_BEGIN_ARG_INFO(arginfo_dir___construct, 0) - ZEND_ARG_INFO(0, path) +ZEND_BEGIN_ARG_INFO(arginfo_dir___construct, 0) + ZEND_ARG_INFO(0, path) /* parameter name */ ZEND_END_ARG_INFO(); -static zend_function_entry spl_dir_class_functions[] = { - SPL_CLASS_FE(dir, __construct, arginfo_dir___construct, ZEND_ACC_PUBLIC) - SPL_CLASS_FE(dir, rewind, NULL, ZEND_ACC_PUBLIC) - SPL_CLASS_FE(dir, current, NULL, ZEND_ACC_PUBLIC) - SPL_CLASS_FE(dir, next, NULL, ZEND_ACC_PUBLIC) - SPL_CLASS_FE(dir, hasMore, NULL, ZEND_ACC_PUBLIC) - SPL_CLASS_FE(dir, getPath, NULL, ZEND_ACC_PUBLIC) + +/* the method table */ +/* each method can have its own parameters and visibility */ +static zend_function_entry spl_ce_dir_class_functions[] = { + SPL_ME(DirectoryIterator, __construct, arginfo_dir___construct, ZEND_ACC_PUBLIC) + SPL_ME(DirectoryIterator, rewind, NULL, ZEND_ACC_PUBLIC) + SPL_ME(DirectoryIterator, hasMore, NULL, ZEND_ACC_PUBLIC) + SPL_ME(DirectoryIterator, key, NULL, ZEND_ACC_PUBLIC) + SPL_ME(DirectoryIterator, current, NULL, ZEND_ACC_PUBLIC) + SPL_ME(DirectoryIterator, next, NULL, ZEND_ACC_PUBLIC) + SPL_ME(DirectoryIterator, getPath, NULL, ZEND_ACC_PUBLIC) + SPL_ME(DirectoryIterator, getFilename, NULL, ZEND_ACC_PUBLIC) + SPL_ME(DirectoryIterator, getPathname, NULL, ZEND_ACC_PUBLIC) + SPL_ME(DirectoryIterator, isDot, NULL, ZEND_ACC_PUBLIC) + SPL_ME(DirectoryIterator, isDir, NULL, ZEND_ACC_PUBLIC) + {NULL, NULL, NULL} +}; + +static zend_function_entry spl_ce_dir_tree_class_functions[] = { + SPL_ME(DirectoryTreeIterator, key, NULL, ZEND_ACC_PUBLIC) + SPL_ME(DirectoryTreeIterator, hasChildren, NULL, ZEND_ACC_PUBLIC) + SPL_ME(DirectoryTreeIterator, getChildren, NULL, ZEND_ACC_PUBLIC) {NULL, NULL, NULL} }; -static zend_object_handlers spl_dir_handlers; -static zend_class_entry *spl_ce_dir; -typedef struct _spl_dir_object { +/* declare the class handlers */ +static zend_object_handlers spl_ce_dir_handlers; + + +/* decalre the class entry */ +zend_class_entry *spl_ce_DirectoryIterator; +zend_class_entry *spl_ce_DirectoryTreeIterator; + + +/* the overloaded class structure */ + +/* overloading the structure results in the need of having + dedicated creatin/cloning/destruction functions */ +typedef struct _spl_ce_dir_object { zend_object std; php_stream *dirp; php_stream_dirent entry; char *path; -} spl_dir_object; + int index; +} spl_ce_dir_object; + -/* {{{ spl_dir_object_dtor */ -static void spl_dir_object_dtor(void *object, zend_object_handle handle TSRMLS_DC) +/* {{{ spl_ce_dir_object_dtor */ +/* close all resources and the memory allocated for the object */ +static void spl_ce_dir_object_dtor(void *object, zend_object_handle handle TSRMLS_DC) { - spl_dir_object *intern = (spl_dir_object *)object; + spl_ce_dir_object *intern = (spl_ce_dir_object *)object; zend_hash_destroy(intern->std.properties); FREE_HASHTABLE(intern->std.properties); @@ -86,15 +132,26 @@ static void spl_dir_object_dtor(void *object, zend_object_handle handle TSRMLS_D } /* }}} */ -/* {{{ spl_dir_object_new */ -static zend_object_value spl_dir_object_new_ex(zend_class_entry *class_type, spl_dir_object **obj TSRMLS_DC) + +/* {{{ spl_ce_dir_object_new */ +/* creates the object by + - allocating memory + - initializing the object members + - storing the object + - setting it's handlers + + called from + - clone + - new + */ +static zend_object_value spl_ce_dir_object_new_ex(zend_class_entry *class_type, spl_ce_dir_object **obj TSRMLS_DC) { zend_object_value retval; - spl_dir_object *intern; + spl_ce_dir_object *intern; zval *tmp; - intern = emalloc(sizeof(spl_dir_object)); - memset(intern, 0, sizeof(spl_dir_object)); + intern = emalloc(sizeof(spl_ce_dir_object)); + memset(intern, 0, sizeof(spl_ce_dir_object)); intern->std.ce = class_type; *obj = intern; @@ -102,27 +159,31 @@ static zend_object_value spl_dir_object_new_ex(zend_class_entry *class_type, spl zend_hash_init(intern->std.properties, 0, NULL, ZVAL_PTR_DTOR, 0); zend_hash_copy(intern->std.properties, &class_type->default_properties, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *)); - retval.handle = zend_objects_store_put(intern, spl_dir_object_dtor, NULL TSRMLS_CC); - retval.handlers = &spl_dir_handlers; + retval.handle = zend_objects_store_put(intern, spl_ce_dir_object_dtor, NULL TSRMLS_CC); + retval.handlers = &spl_ce_dir_handlers; return retval; } /* }}} */ -/* {{{ spl_dir_object_new */ -static zend_object_value spl_dir_object_new(zend_class_entry *class_type TSRMLS_DC) + +/* {{{ spl_ce_dir_object_new */ +/* See spl_ce_dir_object_new_ex */ +static zend_object_value spl_ce_dir_object_new(zend_class_entry *class_type TSRMLS_DC) { - spl_dir_object *tmp; - return spl_dir_object_new_ex(class_type, &tmp TSRMLS_CC); + spl_ce_dir_object *tmp; + return spl_ce_dir_object_new_ex(class_type, &tmp TSRMLS_CC); } /* }}} */ -/* {{{ spl_dir_open */ -static void spl_dir_open(spl_dir_object* intern, char *path TSRMLS_DC) + +/* {{{ spl_ce_dir_open */ +/* open a directory resource */ +static void spl_ce_dir_open(spl_ce_dir_object* intern, char *path TSRMLS_DC) { - /* we are using EH_THORW so REPORT_ERRORS results in exceptions */ intern->dirp = php_stream_opendir(path, ENFORCE_SAFE_MODE|REPORT_ERRORS, NULL); intern->path = estrdup(path); + intern->index = 0; if (intern->dirp == NULL) { /* throw exception: should've been already happened */ @@ -135,20 +196,26 @@ static void spl_dir_open(spl_dir_object* intern, char *path TSRMLS_DC) } /* }}} */ -/* {{{ spl_dir_object_clone */ -static zend_object_value spl_dir_object_clone(zval *zobject TSRMLS_DC) +/* {{{ spl_ce_dir_object_clone */ +/* Local zend_object_value creation (on stack) + Load the 'other' object + Create a new empty object (See spl_ce_dir_object_new_ex) + Open the directory + Clone other members (properties) + */ +static zend_object_value spl_ce_dir_object_clone(zval *zobject TSRMLS_DC) { zend_object_value new_obj_val; zend_object *old_object; zend_object *new_object; zend_object_handle handle = Z_OBJ_HANDLE_P(zobject); - spl_dir_object *intern; + spl_ce_dir_object *intern; old_object = zend_objects_get_address(zobject TSRMLS_CC); - new_obj_val = spl_dir_object_new_ex(old_object->ce, &intern TSRMLS_CC); + new_obj_val = spl_ce_dir_object_new_ex(old_object->ce, &intern TSRMLS_CC); new_object = &intern->std; - spl_dir_open(intern, ((spl_dir_object*)old_object)->path TSRMLS_CC); + spl_ce_dir_open(intern, ((spl_ce_dir_object*)old_object)->path TSRMLS_CC); zend_objects_clone_members(new_object, new_obj_val, old_object, handle TSRMLS_CC); @@ -156,32 +223,19 @@ static zend_object_value spl_dir_object_clone(zval *zobject TSRMLS_DC) } /* }}} */ -/* {{{ spl_dir_get_ce */ -static zend_class_entry *spl_dir_get_ce(zval *object TSRMLS_DC) -{ - return spl_ce_dir; -} -/* }}} */ - -/* {{{ PHP_MINIT_FUNCTION(spl_directory) */ -PHP_MINIT_FUNCTION(spl_directory) -{ - REGISTER_SPL_STD_CLASS_EX(dir, spl_dir_object_new, spl_dir_class_functions); - REGISTER_SPL_IMPLEMENT(dir, sequence); - memcpy(&spl_dir_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers)); - spl_dir_handlers.clone_obj = spl_dir_object_clone; - spl_dir_handlers.get_class_entry = spl_dir_get_ce; - - return SUCCESS; -} -/* }}} */ - -/* {{{ proto void __construct(string path) +/* {{{ proto void DirectoryIterator::__construct(string path) Cronstructs a new dir iterator from a path. */ -SPL_CLASS_FUNCTION(dir, __construct) +/* php_set_error_handling() is used to throw exceptions in case + the constructor fails. Here we use this to ensure the object + has a valid directory resource. + + When the constructor gets called the object is already created + by the engine, so we must only call 'additional' initializations. + */ +SPL_METHOD(DirectoryIterator, __construct) { zval *object = getThis(); - spl_dir_object *intern; + spl_ce_dir_object *intern; char *path; long len; @@ -192,20 +246,21 @@ SPL_CLASS_FUNCTION(dir, __construct) return; } - intern = (spl_dir_object*)zend_object_store_get_object(object TSRMLS_CC); - spl_dir_open(intern, path TSRMLS_CC); + intern = (spl_ce_dir_object*)zend_object_store_get_object(object TSRMLS_CC); + spl_ce_dir_open(intern, path TSRMLS_CC); php_set_error_handling(EH_NORMAL, NULL TSRMLS_CC); } /* }}} */ -/* {{{ proto void rewind() +/* {{{ proto void DirectoryIterator::rewind() Rewind dir back to the start */ -SPL_CLASS_FUNCTION(dir, rewind) +SPL_METHOD(DirectoryIterator, rewind) { zval *object = getThis(); - spl_dir_object *intern = (spl_dir_object*)zend_object_store_get_object(object TSRMLS_CC); + spl_ce_dir_object *intern = (spl_ce_dir_object*)zend_object_store_get_object(object TSRMLS_CC); + intern->index = 0; if (intern->dirp) { php_stream_rewinddir(intern->dirp); } @@ -215,14 +270,29 @@ SPL_CLASS_FUNCTION(dir, rewind) } /* }}} */ -/* {{{ proto string current() +/* {{{ proto string DirectoryIterator::key() Return current dir entry */ -SPL_CLASS_FUNCTION(dir, current) +SPL_METHOD(DirectoryIterator, key) { zval *object = getThis(); - spl_dir_object *intern = (spl_dir_object*)zend_object_store_get_object(object TSRMLS_CC); + spl_ce_dir_object *intern = (spl_ce_dir_object*)zend_object_store_get_object(object TSRMLS_CC); if (intern->dirp) { + RETURN_LONG(intern->index); + } else { + RETURN_FALSE; + } +} +/* }}} */ + +/* {{{ proto string|false DirectoryIterator::current() + Return this (needed for Iterator interface) */ +SPL_METHOD(DirectoryIterator, current) +{ + zval *object = getThis(); + spl_ce_dir_object *intern = (spl_ce_dir_object*)zend_object_store_get_object(object TSRMLS_CC); + + if (intern->entry.d_name[0]) { RETURN_STRING(intern->entry.d_name, 1); } else { RETURN_FALSE; @@ -230,46 +300,383 @@ SPL_CLASS_FUNCTION(dir, current) } /* }}} */ -/* {{{ proto void next() +/* {{{ proto void DirectoryIterator::next() Move to next entry */ -SPL_CLASS_FUNCTION(dir, next) +SPL_METHOD(DirectoryIterator, next) { zval *object = getThis(); - spl_dir_object *intern = (spl_dir_object*)zend_object_store_get_object(object TSRMLS_CC); + spl_ce_dir_object *intern = (spl_ce_dir_object*)zend_object_store_get_object(object TSRMLS_CC); + intern->index++; if (!intern->dirp || !php_stream_readdir(intern->dirp, &intern->entry)) { intern->entry.d_name[0] = '\0'; } } /* }}} */ -/* {{{ proto string hasMore() +/* {{{ proto string DirectoryIterator::hasMore() Check whether dir contains more entries */ -SPL_CLASS_FUNCTION(dir, hasMore) +SPL_METHOD(DirectoryIterator, hasMore) { zval *object = getThis(); - spl_dir_object *intern = (spl_dir_object*)zend_object_store_get_object(object TSRMLS_CC); + spl_ce_dir_object *intern = (spl_ce_dir_object*)zend_object_store_get_object(object TSRMLS_CC); RETURN_BOOL(intern->entry.d_name[0] != '\0'); } /* }}} */ -/* {{{ proto string getPath() +/* {{{ proto string DirectoryIterator::getPath() Return directory path */ -SPL_CLASS_FUNCTION(dir, getPath) +SPL_METHOD(DirectoryIterator, getPath) { zval *object = getThis(); - spl_dir_object *intern = (spl_dir_object*)zend_object_store_get_object(object TSRMLS_CC); + spl_ce_dir_object *intern = (spl_ce_dir_object*)zend_object_store_get_object(object TSRMLS_CC); RETURN_STRING(intern->path, 1); } /* }}} */ +/* {{{ proto string DirectoryIterator::getFilename() + Return filename of current dir entry */ +SPL_METHOD(DirectoryIterator, getFilename) +{ + zval *object = getThis(); + spl_ce_dir_object *intern = (spl_ce_dir_object*)zend_object_store_get_object(object TSRMLS_CC); + + RETURN_STRING(intern->entry.d_name, 1); +} +/* }}} */ + +/* {{{ proto string DirectoryIterator::getPathname() + Return path and filename of current dir entry */ +SPL_METHOD(DirectoryIterator, getPathname) +{ + zval *object = getThis(); + spl_ce_dir_object *intern = (spl_ce_dir_object*)zend_object_store_get_object(object TSRMLS_CC); + + char *filename; + int filename_len = spprintf(&filename, 0, "%s/%s", intern->path, intern->entry.d_name); + RETURN_STRINGL(filename, filename_len, 0); +} +/* }}} */ + +/* {{{ proto string DirectoryTreeIterator::key() + Return path and filename of current dir entry */ +SPL_METHOD(DirectoryTreeIterator, key) +{ + zval *object = getThis(); + spl_ce_dir_object *intern = (spl_ce_dir_object*)zend_object_store_get_object(object TSRMLS_CC); + + char *filename; + int filename_len = spprintf(&filename, 0, "%s/%s", intern->path, intern->entry.d_name); + RETURN_STRINGL(filename, filename_len, 0); +} +/* }}} */ + +/* {{{ proto bool DirectoryIterator::isDot() + Returns true if current entry is '.' or '..' */ +SPL_METHOD(DirectoryIterator, isDot) +{ + zval *object = getThis(); + spl_ce_dir_object *intern = (spl_ce_dir_object*)zend_object_store_get_object(object TSRMLS_CC); + + RETURN_BOOL(!strcmp(intern->entry.d_name, ".") || !strcmp(intern->entry.d_name, "..")); +} +/* }}} */ + +/* {{{ proto bool DirectoryIterator::isDir() + Returns whether current entry is a directory */ +SPL_METHOD(DirectoryIterator, isDir) +{ + zval *object = getThis(); + spl_ce_dir_object *intern = (spl_ce_dir_object*)zend_object_store_get_object(object TSRMLS_CC); + char *filename; + + php_stat_len filename_len = spprintf(&filename, 0, "%s/%s", intern->path, intern->entry.d_name); + + php_stat(filename, filename_len, /*funcnum*/FS_IS_DIR, return_value TSRMLS_CC); + + efree(filename); +} +/* }}} */ + +/* {{{ proto bool DirectoryIterator::hasChildren() + Returns whether current entry is a directory and not '.' or '..' */ +SPL_METHOD(DirectoryTreeIterator, hasChildren) +{ + zval *object = getThis(); + spl_ce_dir_object *intern = (spl_ce_dir_object*)zend_object_store_get_object(object TSRMLS_CC); + + if (!strcmp(intern->entry.d_name, ".") || !strcmp(intern->entry.d_name, "..")) { + RETURN_BOOL(0); + } else { + char *filename; + php_stat_len filename_len = spprintf(&filename, 0, "%s/%s", intern->path, intern->entry.d_name); + + php_stat(filename, filename_len, FS_IS_DIR, return_value TSRMLS_CC); + efree(filename); + } +} +/* }}} */ + +/* {{{ proto DirectoryIterator DirectoryIterator::getChildren() + Returns an iterator fo rthe current entry if it is a directory */ +SPL_METHOD(DirectoryTreeIterator, getChildren) +{ + zval *object = getThis(), zpath; + spl_ce_dir_object *intern = (spl_ce_dir_object*)zend_object_store_get_object(object TSRMLS_CC); + + char *path; + int path_len = spprintf(&path, 0, "%s/%s", intern->path, intern->entry.d_name); + + ZVAL_STRINGL(&zpath, path, path_len, 0); + + spl_instantiate_arg_ex1(spl_ce_DirectoryTreeIterator, &return_value, 0, &zpath TSRMLS_CC); + zval_dtor(&zpath); +} +/* }}} */ + +/* define an overloaded iterator structure */ +typedef struct { + zend_object_iterator intern; + zval *current; + spl_ce_dir_object *object; +} spl_ce_dir_it; + +/* forward declarations to the iterator handlers */ +static void spl_ce_dir_it_dtor(zend_object_iterator *iter TSRMLS_DC); +static int spl_ce_dir_it_has_more(zend_object_iterator *iter TSRMLS_DC); +static void spl_ce_dir_it_current_data(zend_object_iterator *iter, zval ***data TSRMLS_DC); +static int spl_ce_dir_it_current_key(zend_object_iterator *iter, char **str_key, uint *str_key_len, ulong *int_key TSRMLS_DC); +static void spl_ce_dir_it_move_forward(zend_object_iterator *iter TSRMLS_DC); +static void spl_ce_dir_it_rewind(zend_object_iterator *iter TSRMLS_DC); + + +/* iterator handler table */ +zend_object_iterator_funcs spl_ce_dir_it_funcs = { + spl_ce_dir_it_dtor, + spl_ce_dir_it_has_more, + spl_ce_dir_it_current_data, + spl_ce_dir_it_current_key, + spl_ce_dir_it_move_forward, + spl_ce_dir_it_rewind +}; + + +/* {{{ spl_ce_dir_get_iterator */ +zend_object_iterator *spl_ce_dir_get_iterator(zend_class_entry *ce, zval *object TSRMLS_DC) +{ + spl_ce_dir_it *iterator = emalloc(sizeof(spl_ce_dir_it)); + spl_ce_dir_object *dir_object = (spl_ce_dir_object*)zend_object_store_get_object(object TSRMLS_CC); + + object->refcount++; + iterator->intern.data = (void*)object; + iterator->intern.funcs = &spl_ce_dir_it_funcs; + MAKE_STD_ZVAL(iterator->current); + iterator->object = dir_object; + + return (zend_object_iterator*)iterator; +} +/* }}} */ + + +/* {{{ spl_ce_dir_it_dtor */ +static void spl_ce_dir_it_dtor(zend_object_iterator *iter TSRMLS_DC) +{ + spl_ce_dir_it *iterator = (spl_ce_dir_it *)iter; + zval *intern = (zval*)iterator->intern.data; + + zval_ptr_dtor(&iterator->current); + zval_ptr_dtor(&intern); + + efree(iterator); +} +/* }}} */ + + +/* {{{ spl_ce_dir_it_has_more */ +static int spl_ce_dir_it_has_more(zend_object_iterator *iter TSRMLS_DC) +{ + spl_ce_dir_it *iterator = (spl_ce_dir_it *)iter; + spl_ce_dir_object *object = iterator->object; + + return object->entry.d_name[0] != '\0' ? SUCCESS : FAILURE; +} +/* }}} */ + + +/* {{{ spl_ce_dir_it_current_data */ +static void spl_ce_dir_it_current_data(zend_object_iterator *iter, zval ***data TSRMLS_DC) +{ + spl_ce_dir_it *iterator = (spl_ce_dir_it *)iter; + + *data = &iterator->current; +} +/* }}} */ + + +/* {{{ spl_ce_dir_it_current_key */ +static int spl_ce_dir_it_current_key(zend_object_iterator *iter, char **str_key, uint *str_key_len, ulong *int_key TSRMLS_DC) +{ + spl_ce_dir_it *iterator = (spl_ce_dir_it *)iter; + spl_ce_dir_object *object = iterator->object; + + *int_key = object->index; + return HASH_KEY_IS_LONG; +} +/* }}} */ + + +/* {{{ spl_ce_dir_it_move_forward */ +static void spl_ce_dir_it_move_forward(zend_object_iterator *iter TSRMLS_DC) +{ + spl_ce_dir_it *iterator = (spl_ce_dir_it *)iter; + spl_ce_dir_object *object = iterator->object; + + object->index++; + zval_dtor(iterator->current); + if (!object->dirp || !php_stream_readdir(object->dirp, &object->entry)) { + object->entry.d_name[0] = '\0'; + ZVAL_NULL(iterator->current); + } else { + ZVAL_STRING(iterator->current, object->entry.d_name, 1); + } +} +/* }}} */ + + +/* {{{ spl_ce_dir_it_rewind */ +static void spl_ce_dir_it_rewind(zend_object_iterator *iter TSRMLS_DC) +{ + spl_ce_dir_it *iterator = (spl_ce_dir_it *)iter; + spl_ce_dir_object *object = iterator->object; + + object->index = 0; + if (object->dirp) { + php_stream_rewinddir(object->dirp); + } + zval_dtor(iterator->current); + if (!object->dirp || !php_stream_readdir(object->dirp, &object->entry)) { + object->entry.d_name[0] = '\0'; + ZVAL_NULL(iterator->current); + } else { + ZVAL_STRING(iterator->current, object->entry.d_name, 1); + } +} +/* }}} */ + + +/* {{{ spl_ce_dir_tree_it_current_key */ +static int spl_ce_dir_tree_it_current_key(zend_object_iterator *iter, char **str_key, uint *str_key_len, ulong *int_key TSRMLS_DC) +{ + spl_ce_dir_it *iterator = (spl_ce_dir_it *)iter; + spl_ce_dir_object *object = iterator->object; + + *str_key_len = spprintf(str_key, 0, "%s/%s", object->path, object->entry.d_name) + 1; + return HASH_KEY_IS_STRING; +} +/* }}} */ + + +/* {{{ spl_ce_dir_tree_it_move_forward */ +static void spl_ce_dir_tree_it_move_forward(zend_object_iterator *iter TSRMLS_DC) +{ + spl_ce_dir_it *iterator = (spl_ce_dir_it *)iter; + spl_ce_dir_object *object = iterator->object; + + object->index++; + zval_dtor(iterator->current); +skip_dots: + if (!object->dirp || !php_stream_readdir(object->dirp, &object->entry)) { + object->entry.d_name[0] = '\0'; + ZVAL_NULL(iterator->current); + } else { + if (!strcmp(object->entry.d_name, ".") || !strcmp(object->entry.d_name, "..")) { + goto skip_dots; + } + ZVAL_STRING(iterator->current, object->entry.d_name, 1); + } +} +/* }}} */ + +/* {{{ spl_ce_dir_tree_it_rewind */ +static void spl_ce_dir_tree_it_rewind(zend_object_iterator *iter TSRMLS_DC) +{ + spl_ce_dir_it *iterator = (spl_ce_dir_it *)iter; + spl_ce_dir_object *object = iterator->object; + + object->index = 0; + if (object->dirp) { + php_stream_rewinddir(object->dirp); + } + zval_dtor(iterator->current); +skip_dots: + if (!object->dirp || !php_stream_readdir(object->dirp, &object->entry)) { + object->entry.d_name[0] = '\0'; + ZVAL_NULL(iterator->current); + } else { + if (!strcmp(object->entry.d_name, ".") || !strcmp(object->entry.d_name, "..")) { + goto skip_dots; + } + ZVAL_STRING(iterator->current, object->entry.d_name, 1); + } +} +/* }}} */ + + +/* iterator handler table */ +zend_object_iterator_funcs spl_ce_dir_tree_it_funcs = { + spl_ce_dir_it_dtor, + spl_ce_dir_it_has_more, + spl_ce_dir_it_current_data, + spl_ce_dir_tree_it_current_key, + spl_ce_dir_tree_it_move_forward, + spl_ce_dir_tree_it_rewind +}; + +/* {{{ spl_ce_dir_get_iterator */ +zend_object_iterator *spl_ce_dir_tree_get_iterator(zend_class_entry *ce, zval *object TSRMLS_DC) +{ + spl_ce_dir_it *iterator = emalloc(sizeof(spl_ce_dir_it)); + spl_ce_dir_object *dir_object = (spl_ce_dir_object*)zend_object_store_get_object(object TSRMLS_CC); + + object->refcount++; + iterator->intern.data = (void*)object; + iterator->intern.funcs = &spl_ce_dir_tree_it_funcs; + MAKE_STD_ZVAL(iterator->current); + iterator->object = dir_object; + + return (zend_object_iterator*)iterator; +} +/* }}} */ + + +/* {{{ PHP_MINIT_FUNCTION(spl_directory) + */ +PHP_MINIT_FUNCTION(spl_directory) +{ + REGISTER_SPL_STD_CLASS_EX(DirectoryIterator, spl_ce_dir_object_new, spl_ce_dir_class_functions); + zend_class_implements(spl_ce_DirectoryIterator TSRMLS_CC, 1, zend_ce_iterator); + memcpy(&spl_ce_dir_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers)); + spl_ce_dir_handlers.clone_obj = spl_ce_dir_object_clone; + + spl_ce_DirectoryIterator->get_iterator = spl_ce_dir_get_iterator; + + REGISTER_SPL_SUB_CLASS_EX(DirectoryTreeIterator, DirectoryIterator, spl_ce_dir_object_new, spl_ce_dir_tree_class_functions); + REGISTER_SPL_IMPLEMENTS(DirectoryTreeIterator, RecursiveIterator); + + spl_ce_DirectoryTreeIterator->get_iterator = spl_ce_dir_tree_get_iterator; + + return SUCCESS; +} +/* }}} */ + + /* * Local variables: * tab-width: 4 * c-basic-offset: 4 * End: - * vim600: sw=4 ts=4 fdm=marker - * vim<600: sw=4 ts=4 + * vim600: noet sw=4 ts=4 fdm=marker + * vim<600: noet sw=4 ts=4 */ diff --git a/ext/spl/spl_foreach.h b/ext/spl/spl_directory.h index e27f9e77de..987bf7b074 100755 --- a/ext/spl/spl_foreach.h +++ b/ext/spl/spl_directory.h @@ -16,17 +16,17 @@ +----------------------------------------------------------------------+ */ -#ifndef SPL_FOREACH_H -#define SPL_FOREACH_H +#ifndef SPL_DIRECTORY_H +#define SPL_DIRECTORY_H #include "php.h" #include "php_spl.h" -ZEND_EXECUTE_HOOK_FUNCTION(ZEND_FE_RESET); -ZEND_EXECUTE_HOOK_FUNCTION(ZEND_FE_FETCH); -ZEND_EXECUTE_HOOK_FUNCTION(ZEND_SWITCH_FREE); +extern zend_class_entry *spl_ce_DirectoryIterator; -#endif /* SPL_FOREACH_H */ +PHP_MINIT_FUNCTION(spl_directory); + +#endif /* SPL_DIRECTORY_H */ /* * Local Variables: diff --git a/ext/spl/spl_engine.c b/ext/spl/spl_engine.c index 349a599784..ec43c6fdd9 100755 --- a/ext/spl/spl_engine.c +++ b/ext/spl/spl_engine.c @@ -23,115 +23,53 @@ #include "php.h" #include "php_ini.h" #include "ext/standard/info.h" -#include "zend_compile.h" +#include "zend_interfaces.h" #include "php_spl.h" #include "spl_functions.h" #include "spl_engine.h" -/* {{{ spl_instanciate */ -void spl_instanciate(zend_class_entry *pce, zval **object TSRMLS_DC) +#include "spl_array.h" + +/* {{{ spl_instantiate */ +void spl_instantiate(zend_class_entry *pce, zval **object, int alloc TSRMLS_DC) { - ALLOC_ZVAL(*object); + if (alloc) { + ALLOC_ZVAL(*object); + } object_init_ex(*object, pce); (*object)->refcount = 1; (*object)->is_ref = 1; /* check if this can be hold always */ } /* }}} */ -/* {{{ spl_instanciate_arg_ex2 */ -int spl_instanciate_arg_ex2(zend_class_entry *pce, zval **retval, zval *arg1, zval *arg2 TSRMLS_DC) +/* {{{ spl_instantiate_arg_ex1 */ +int spl_instantiate_arg_ex1(zend_class_entry *pce, zval **retval, int alloc, zval *arg1 TSRMLS_DC) { - zval *object; - - spl_instanciate(pce, &object TSRMLS_CC); + zval *tmp; - retval = &EG(uninitialized_zval_ptr); + spl_instantiate(pce, retval, alloc TSRMLS_CC); - spl_call_method(&object, pce, &pce->constructor, pce->constructor->common.function_name, strlen(pce->constructor->common.function_name), retval, 2, arg1, arg2 TSRMLS_CC); - *retval = object; - return 0; -} -/* }}} */ - -/* {{{ spl_get_zval_ptr_ptr - Remember to call spl_unlock_ptr_ptr when needed */ -zval ** spl_get_zval_ptr_ptr(znode *node, temp_variable *Ts TSRMLS_DC) -{ - if (node->op_type==IS_VAR) { - return T(node->u.var).var.ptr_ptr; - } else { - return NULL; - } -} -/* }}} */ - -/* {{{ spl_unlock_zval_ptr_ptr */ -void spl_unlock_zval_ptr_ptr(znode *node, temp_variable *Ts TSRMLS_DC) -{ - if (node->op_type==IS_VAR) { - if (T(node->u.var).var.ptr_ptr) { - spl_pzval_unlock_func(*T(node->u.var).var.ptr_ptr TSRMLS_CC); - } else if (T(node->u.var).EA.type==IS_STRING_OFFSET) { - spl_pzval_unlock_func(T(node->u.var).EA.data.str_offset.str TSRMLS_CC); - } + zend_call_method(retval, pce, &pce->constructor, pce->constructor->common.function_name, strlen(pce->constructor->common.function_name), &tmp, 1, arg1, NULL TSRMLS_CC); + if (tmp) { + zval_ptr_dtor(&tmp); } + return 0; } /* }}} */ -/* {{{ spl_get_zval_ptr */ -zval * spl_get_zval_ptr(znode *node, temp_variable *Ts, zval **should_free TSRMLS_DC) +/* {{{ spl_instantiate_arg_ex2 */ +int spl_instantiate_arg_ex2(zend_class_entry *pce, zval **retval, int alloc, zval *arg1, zval *arg2 TSRMLS_DC) { - switch (node->op_type) { - case IS_CONST: - *should_free = 0; - return &node->u.constant; - break; - case IS_TMP_VAR: - return *should_free = &T(node->u.var).tmp_var; - break; - case IS_VAR: - if (T(node->u.var).var.ptr) { - spl_pzval_unlock_func(T(node->u.var).var.ptr TSRMLS_CC); - *should_free = 0; - return T(node->u.var).var.ptr; - } else { - *should_free = &T(node->u.var).tmp_var; - - switch (T(node->u.var).EA.type) { - case IS_STRING_OFFSET: { - temp_variable *T = &T(node->u.var); - zval *str = T->EA.data.str_offset.str; - - if (T->EA.data.str_offset.str->type != IS_STRING - || (T->EA.data.str_offset.offset<0) - || (T->EA.data.str_offset.str->value.str.len <= T->EA.data.str_offset.offset)) { - zend_error(E_NOTICE, "Uninitialized string offset: %d", T->EA.data.str_offset.offset); - T->tmp_var.value.str.val = empty_string; - T->tmp_var.value.str.len = 0; - } else { - char c = str->value.str.val[T->EA.data.str_offset.offset]; - - T->tmp_var.value.str.val = estrndup(&c, 1); - T->tmp_var.value.str.len = 1; - } - spl_pzval_unlock_func(str TSRMLS_CC); - T->tmp_var.refcount=1; - T->tmp_var.is_ref=1; - T->tmp_var.type = IS_STRING; - return &T->tmp_var; - } - break; - } - } - break; - case IS_UNUSED: - *should_free = 0; - return NULL; - break; - EMPTY_SWITCH_DEFAULT_CASE() + zval *tmp; + + spl_instantiate(pce, retval, alloc TSRMLS_CC); + + zend_call_method(retval, pce, &pce->constructor, pce->constructor->common.function_name, strlen(pce->constructor->common.function_name), &tmp, 2, arg1, arg2 TSRMLS_CC); + if (tmp) { + zval_ptr_dtor(&tmp); } - return NULL; + return 0; } /* }}} */ @@ -149,92 +87,6 @@ int spl_is_instance_of(zval **obj, zend_class_entry *ce TSRMLS_DC) } /* }}} */ -/* {{{ spl_implements */ -spl_is_a spl_implements(zend_class_entry *ce) -{ - register spl_is_a is_a = 0; - register int i = ce->num_interfaces; - register zend_class_entry **pce = ce->interfaces; - - while (i--) { - if (*pce == spl_ce_iterator) is_a |= SPL_IS_A_ITERATOR; - else if (*pce == spl_ce_forward) is_a |= SPL_IS_A_FORWARD; - else if (*pce == spl_ce_assoc) is_a |= SPL_IS_A_ASSOC; - else if (*pce == spl_ce_sequence) is_a |= SPL_IS_A_SEQUENCE; - else if (*pce == spl_ce_array_read) is_a |= SPL_IS_A_ARRAY_READ; - else if (*pce == spl_ce_array_access) is_a |= SPL_IS_A_ARRAY_ACCESS; - pce++; - } - return is_a; -} -/* }}} */ - -/* {{{ spl_call_method */ -zval * spl_call_method(zval **object_pp, zend_class_entry *obj_ce, zend_function **fn_proxy, char *function_name, int function_name_len, zval **retval_ptr, int param_count, zval* arg1, zval* arg2 TSRMLS_DC) -{ - int result; - zend_fcall_info fci; - zval z_fname; - zval *retval; - - zval **params[2]; - - params[0] = &arg1; - params[1] = &arg2; - - fci.size = sizeof(fci); - /*fci.function_table = NULL; will be read form zend_class_entry of object if needed */ - fci.object_pp = object_pp; - fci.function_name = &z_fname; - fci.retval_ptr_ptr = retval_ptr ? retval_ptr : &retval; - fci.param_count = param_count; - fci.params = params; - fci.no_separation = 1; - fci.symbol_table = NULL; - - if (!fn_proxy && !obj_ce) { - /* no interest in caching and no information already present that is - * needed later inside zend_call_function. */ - ZVAL_STRINGL(&z_fname, function_name, function_name_len, 0); - result = zend_call_function(&fci, NULL TSRMLS_CC); - } else { - zend_fcall_info_cache fcic; - - fcic.initialized = 1; - if (!obj_ce) { - obj_ce = Z_OBJCE_PP(object_pp); - } - if (!fn_proxy || !*fn_proxy) { - if (zend_hash_find(&obj_ce->function_table, function_name, function_name_len+1, (void **) &fcic.function_handler) == FAILURE) { - /* error at c-level */ - zend_error(E_CORE_ERROR, "Couldn't find implementation for method %s::%s\n", obj_ce->name, function_name); - } - if (fn_proxy) { - *fn_proxy = fcic.function_handler; - } - } else { - fcic.function_handler = *fn_proxy; - } - fcic.calling_scope = obj_ce; - fcic.object_pp = object_pp; - result = zend_call_function(&fci, &fcic TSRMLS_CC); - } - if (result == FAILURE) { - /* error at c-level */ - if (!obj_ce) { - obj_ce = Z_OBJCE_PP(object_pp); - } - zend_error(E_CORE_ERROR, "Couldn't execute method %s::%s\n", obj_ce->name, function_name); - } - if (!retval_ptr && retval) { - zval_dtor(retval); - FREE_ZVAL(retval); - return NULL; - } - return *retval_ptr; -} -/* }}} */ - /* * Local variables: * tab-width: 4 diff --git a/ext/spl/spl_engine.h b/ext/spl/spl_engine.h index 19f4ccc83b..a753a9339e 100755 --- a/ext/spl/spl_engine.h +++ b/ext/spl/spl_engine.h @@ -22,19 +22,6 @@ #include "php.h" #include "php_spl.h" -#include "zend_compile.h" - -#undef EX -#define EX(element) execute_data->element -#define EX_T(offset) (*(temp_variable *)((char *) EX(Ts) + offset)) -#define T(offset) (*(temp_variable *)((char *) Ts + offset)) - -#define NEXT_OPCODE() \ - EX(opline)++; \ - return 0; - -zval * spl_call_method(zval **object_pp, zend_class_entry *obj_ce, zend_function **fn_proxy, char *function_name, int function_name_len, zval **retval_ptr, int param_count, zval* arg1, zval* arg2 TSRMLS_DC); - /* {{{ zend_class_entry */ static inline zend_class_entry *spl_get_class_entry(zval *obj TSRMLS_DC) { @@ -55,46 +42,12 @@ static inline zend_class_entry *spl_get_class_entry(zval *obj TSRMLS_DC) #define spl_call_method_2(obj, obj_ce, fn_proxy, function_name, fname_len, retval, arg1, arg2) \ spl_call_method(obj, obj_ce, fn_proxy, function_name, fname_len, retval, 2, arg1, arg2 TSRMLS_CC) -void spl_instanciate(zend_class_entry *pce, zval **object TSRMLS_DC); -int spl_instanciate_arg_ex2(zend_class_entry *pce, zval **retval, zval *arg1, zval *arg2 TSRMLS_DC); - -zval ** spl_get_zval_ptr_ptr(znode *node, temp_variable *Ts TSRMLS_DC); -void spl_unlock_zval_ptr_ptr(znode *node, temp_variable *Ts TSRMLS_DC); -zval * spl_get_zval_ptr(znode *node, temp_variable *Ts, zval **should_free TSRMLS_DC); +void spl_instantiate(zend_class_entry *pce, zval **object, int alloc TSRMLS_DC); +int spl_instantiate_arg_ex1(zend_class_entry *pce, zval **retval, int alloc, zval *arg1 TSRMLS_DC); +int spl_instantiate_arg_ex2(zend_class_entry *pce, zval **retval, int alloc, zval *arg1, zval *arg2 TSRMLS_DC); int spl_is_instance_of(zval **obj, zend_class_entry *ce TSRMLS_DC); -typedef enum { - SPL_IS_A_ITERATOR = 0x01, - SPL_IS_A_FORWARD = 0x02, - SPL_IS_A_ASSOC = 0x04, - SPL_IS_A_SEQUENCE = 0x08, - SPL_IS_A_ARRAY_READ = 0x10, - SPL_IS_A_ARRAY_ACCESS = 0x20 -} spl_is_a; - -spl_is_a spl_implements(zend_class_entry *ce); - -/* Use this only insode OPCODE-Hooks */ -static inline void spl_pzval_unlock_func(zval *z TSRMLS_DC) -{ - z->refcount--; - if (!z->refcount) { - z->refcount = 1; - z->is_ref = 0; - EG(garbage)[EG(garbage_ptr)++] = z; - } -} - -/* Use this only insode OPCODE-Hooks */ -static inline void spl_pzval_lock_func(zval *z) -{ - z->refcount++; -} - -/* Use this only insode OPCODE-Hooks */ -#define SELECTIVE_PZVAL_LOCK(pzv, pzn) if (!((pzn)->u.EA.type & EXT_TYPE_UNUSED)) { spl_pzval_lock_func(pzv); } - #endif /* SPL_ENGINE_H */ /* diff --git a/ext/spl/spl_foreach.c b/ext/spl/spl_foreach.c deleted file mode 100755 index 90441415d8..0000000000 --- a/ext/spl/spl_foreach.c +++ /dev/null @@ -1,269 +0,0 @@ -/* - +----------------------------------------------------------------------+ - | PHP Version 5 | - +----------------------------------------------------------------------+ - | Copyright (c) 1997-2003 The PHP Group | - +----------------------------------------------------------------------+ - | This source file is subject to version 3.0 of the PHP license, | - | that is bundled with this package in the file LICENSE, and is | - | available through the world-wide-web at the following url: | - | http://www.php.net/license/3_0.txt. | - | If you did not receive a copy of the PHP license and are unable to | - | obtain it through the world-wide-web, please send a note to | - | license@php.net so we can mail you a copy immediately. | - +----------------------------------------------------------------------+ - | Authors: Marcus Boerger <helly@php.net> | - +----------------------------------------------------------------------+ - */ - -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#include "php.h" -#include "php_ini.h" -#include "ext/standard/info.h" -#include "zend_compile.h" - -#include "php_spl.h" -#include "spl_functions.h" -#include "spl_engine.h" -#include "spl_foreach.h" - -#define OPTIMIZED_ARRAY_CONSTRUCT - -typedef struct { - zend_function *next; - zend_function *rewind; - zend_function *more; - zend_function *current; - zend_function *key; -} spl_foreach_funcs; - -typedef struct { - zval *obj; - zend_class_entry *obj_ce; - zend_uint index; - spl_is_a is_a; - spl_foreach_funcs funcs; - char dummy; /* needed for '\0' but we can't set it due to compiler optimizations */ -} spl_foreach_proxy; - -/* {{{ ZEND_EXECUTE_HOOK_FUNCTION(ZEND_FE_RESET) */ -ZEND_EXECUTE_HOOK_FUNCTION(ZEND_FE_RESET) -{ - zval **obj, *retval; - spl_foreach_proxy *proxy; - zend_class_entry *instance_ce, *obj_ce; - spl_is_a is_a; - temp_variable *tmp; - - obj = spl_get_zval_ptr_ptr(&EX(opline)->op1, EX(Ts) TSRMLS_CC); - - if (!obj || (instance_ce = spl_get_class_entry(*obj TSRMLS_CC)) == NULL) { - ZEND_EXECUTE_HOOK_ORIGINAL(ZEND_FE_RESET); - } - - is_a = spl_implements(instance_ce); - - if (is_a & SPL_IS_A_ITERATOR) { - spl_unlock_zval_ptr_ptr(&EX(opline)->op1, EX(Ts) TSRMLS_CC); - obj_ce = instance_ce; - spl_call_method_0(obj, obj_ce, NULL, "newiterator", sizeof("newiterator")-1, &retval); - instance_ce = spl_get_class_entry(retval TSRMLS_CC); - is_a = spl_implements(instance_ce); - if (!(is_a & SPL_IS_A_FORWARD)) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Objects created by %s::newIterator() must implement spl_forward", obj_ce->name); - ZEND_EXECUTE_HOOK_ORIGINAL(ZEND_FE_RESET); - } - spl_pzval_lock_func(retval); - } else if (is_a & SPL_IS_A_FORWARD) { - spl_unlock_zval_ptr_ptr(&EX(opline)->op1, EX(Ts) TSRMLS_CC); - retval = *obj; - retval->refcount += 2; /* lock two times */ - } else { - ZEND_EXECUTE_HOOK_ORIGINAL(ZEND_FE_RESET); - } - - /* create the proxy */ - proxy = emalloc(sizeof(spl_foreach_proxy)); - proxy->obj = retval; - proxy->obj_ce = instance_ce; - proxy->index = 0; - proxy->is_a = is_a; - memset(&proxy->funcs, 0, sizeof(spl_foreach_funcs)); - ((char*)proxy)[sizeof(spl_foreach_proxy)-1] = '\0'; - /* And pack it into a zval. Since it is nowhere accessible using a - * zval of type STRING is the fastest approach of storing the proxy. - */ - ALLOC_ZVAL(retval); - ZVAL_STRINGL(retval, (char*)proxy, sizeof(spl_foreach_proxy)-1, 0); - retval->is_ref = 0; - retval->refcount = 2; /* lock two times */ - /* return the created proxy container */ - tmp = &EX_T(EX(opline)->result.u.var); - tmp->var.ptr = retval; - tmp->var.ptr_ptr = &tmp->var.ptr; - - NEXT_OPCODE(); -} -/* }}} */ - -/* {{{ OPTIMIZED_ARRAY_CONSTRUCT macros */ -#ifdef OPTIMIZED_ARRAY_CONSTRUCT -#define CONNECT_TO_BUCKET_DLLIST(element, list_head) \ - (element)->pNext = (list_head); \ - (element)->pLast = NULL; - -#define CONNECT_TO_GLOBAL_DLLIST(element, ht) \ - (element)->pListLast = (ht)->pListTail; \ - (ht)->pListTail = (element); \ - (element)->pListNext = NULL; \ - if ((element)->pListLast != NULL) { \ - (element)->pListLast->pListNext = (element); \ - } \ - if (!(ht)->pListHead) { \ - (ht)->pListHead = (element); \ - } \ - if ((ht)->pInternalPointer == NULL) { \ - (ht)->pInternalPointer = (element); \ - } -#endif -/* }}} */ - -/* {{{ ZEND_EXECUTE_HOOK_FUNCTION(ZEND_FE_FETCH) */ -ZEND_EXECUTE_HOOK_FUNCTION(ZEND_FE_FETCH) -{ - znode *op1 = &EX(opline)->op1; - zval **obj = spl_get_zval_ptr_ptr(op1, EX(Ts) TSRMLS_CC); - zval *more, *value, *key, *result; - spl_foreach_proxy *proxy; - - if (Z_TYPE_PP(obj) == IS_STRING) { - int has_more; - - proxy = (spl_foreach_proxy*)Z_STRVAL_PP(obj); - obj = &proxy->obj; /* will be optimized out */ - - if (proxy->index++) { - spl_call_method_0(obj, proxy->obj_ce, &proxy->funcs.next, "next", sizeof("next")-1, NULL); - } else { - if (proxy->is_a & SPL_IS_A_SEQUENCE) { - spl_call_method_0(obj, proxy->obj_ce, &proxy->funcs.rewind, "rewind", sizeof("rewind")-1, NULL); - } - /* now this is an optimization trick: - ZEND_SWITCH_FREE receives the array copy or the spl object in op1 and has an unused op2 - We have to check for op1 being an object that implements spl_forwar... Or we simply set - op2 and know we can safely free the object as needed, which is waht we do. */ - op_array->opcodes[EX(opline)->op2.u.opline_num].op2 = *op1; - } - - spl_call_method_0(obj, proxy->obj_ce, &proxy->funcs.more, "hasmore", sizeof("hasmore")-1, &more); - has_more = i_zend_is_true(more); - zval_dtor(more); - FREE_ZVAL(more); - if (has_more) { - result = &EX_T(EX(opline)->result.u.var).tmp_var; - - spl_call_method_0(obj, proxy->obj_ce, &proxy->funcs.current, "current", sizeof("current")-1, &value); - - if (proxy->is_a & SPL_IS_A_ASSOC) { - spl_call_method_0(obj, proxy->obj_ce, &proxy->funcs.key, "key", sizeof("key")-1, &key); - } else { - MAKE_STD_ZVAL(key); - key->value.lval = proxy->index; - key->type = IS_LONG; - } -#ifndef OPTIMIZED_ARRAY_CONSTRUCT - array_init(result); - add_next_index_zval(result, value); - add_next_index_zval(result, key); -#else - { - Bucket *p; - HashTable *ht; - - ht = emalloc(sizeof(HashTable)); - result->value.ht = ht; - ht->nTableSize = 1 << 1; - ht->nTableMask = ht->nTableSize - 1; -#if ZEND_DEBUG - ht->inconsistent = 0; /*HT_OK;*/ -#endif - - ht->arBuckets = (Bucket **)emalloc(ht->nTableSize * sizeof(Bucket *)); - - ht->pDestructor = ZVAL_PTR_DTOR; - ht->pListHead = NULL; - ht->pListTail = NULL; - ht->nNumOfElements = 0; - ht->nNextFreeElement = 0; - ht->pInternalPointer = NULL; - ht->persistent = 0; - ht->nApplyCount = 0; - ht->bApplyProtection = 1; - result->type = IS_ARRAY; - - p = (Bucket*)emalloc(sizeof(Bucket)-1); - p->pDataPtr = value; - p->pData = &p->pDataPtr; - p->nKeyLength = 0; - p->h = 0; - result->value.ht->arBuckets[0] = p; - CONNECT_TO_BUCKET_DLLIST(p, ht->arBuckets[0]); - CONNECT_TO_GLOBAL_DLLIST(p, ht); - - p = (Bucket*)emalloc(sizeof(Bucket)-1); - p->pDataPtr = key; - p->pData = &p->pDataPtr; - p->nKeyLength = 0; - p->h = 1; - result->value.ht->arBuckets[1] = p; - CONNECT_TO_BUCKET_DLLIST(p, ht->arBuckets[1]); - CONNECT_TO_GLOBAL_DLLIST(p, ht); - - ht->nNumOfElements = 2; - } -#endif - NEXT_OPCODE(); - } - EX(opline) = op_array->opcodes+EX(opline)->op2.u.opline_num; - return 0; - } - ZEND_EXECUTE_HOOK_ORIGINAL(ZEND_FE_FETCH); -} -/* }}} */ - -/* {{{ ZEND_EXECUTE_HOOK_FUNCTION(ZEND_SWITCH_FREE) */ -ZEND_EXECUTE_HOOK_FUNCTION(ZEND_SWITCH_FREE) -{ - /* See not in ZEND_FE_FETCH on setting op2 */ - znode *op2 = &EX(opline)->op2; - zval *tmp, **obj = spl_get_zval_ptr_ptr(op2, EX(Ts) TSRMLS_CC); - spl_foreach_proxy *proxy; - - if (obj) { - proxy = (spl_foreach_proxy*)Z_STRVAL_PP(obj); - tmp = *obj; - *obj = proxy->obj; /* restore */ - - efree(tmp->value.str.val); - FREE_ZVAL(tmp); - - spl_unlock_zval_ptr_ptr(&EX(opline)->op1, EX(Ts) TSRMLS_CC); - spl_pzval_lock_func(*obj); - - SET_UNUSED(*op2); - } - ZEND_EXECUTE_HOOK_ORIGINAL(ZEND_SWITCH_FREE); -} -/* }}} */ - -/* - * Local variables: - * tab-width: 4 - * c-basic-offset: 4 - * End: - * vim600: fdm=marker - * vim: noet sw=4 ts=4 - */ diff --git a/ext/spl/spl_functions.c b/ext/spl/spl_functions.c index 126a6f15e3..415901d908 100755 --- a/ext/spl/spl_functions.c +++ b/ext/spl/spl_functions.c @@ -24,7 +24,6 @@ #include "php_ini.h" #include "ext/standard/info.h" #include "php_spl.h" -#include "spl_foreach.h" /* {{{ spl_destroy_class */ void spl_destroy_class(zend_class_entry ** ppce) @@ -62,17 +61,24 @@ void spl_register_std_class(zend_class_entry ** ppce, char * class_name, void * } /* }}} */ -/* {{{ spl_register_parent_ce */ -void spl_register_parent_ce(zend_class_entry * class_entry, zend_class_entry * parent_class TSRMLS_DC) +/* {{{ spl_register_sub_class */ +void spl_register_sub_class(zend_class_entry ** ppce, zend_class_entry * parent_ce, char * class_name, void *obj_ctor, function_entry * function_list TSRMLS_DC) { - class_entry->parent = parent_class; + zend_class_entry ce; + + INIT_CLASS_ENTRY(ce, class_name, function_list); + ce.name_length = strlen(class_name); + *ppce = zend_register_internal_class_ex(&ce, parent_ce, NULL TSRMLS_CC); + + /* entries changed by initialize */ + (*ppce)->create_object = obj_ctor; } /* }}} */ -/* {{{ spl_register_implement */ -void spl_register_implement(zend_class_entry * class_entry, zend_class_entry * interface_entry TSRMLS_DC) +/* {{{ spl_register_parent_ce */ +void spl_register_parent_ce(zend_class_entry * class_entry, zend_class_entry * parent_class TSRMLS_DC) { - zend_class_implements(class_entry TSRMLS_CC, 1, interface_entry); + class_entry->parent = parent_class; } /* }}} */ diff --git a/ext/spl/spl_functions.h b/ext/spl/spl_functions.h index 1a2aa15037..99dfd7f1c8 100755 --- a/ext/spl/spl_functions.h +++ b/ext/spl/spl_functions.h @@ -24,19 +24,22 @@ typedef zend_object_value (*create_object_func_t)(zend_class_entry *class_type TSRMLS_DC); #define REGISTER_SPL_STD_CLASS(class_name, obj_ctor) \ - spl_register_std_class(&spl_ce_ ## class_name, "spl_" # class_name, obj_ctor, NULL TSRMLS_CC); + spl_register_std_class(&spl_ce_ ## class_name, # class_name, obj_ctor, NULL TSRMLS_CC); #define REGISTER_SPL_STD_CLASS_EX(class_name, obj_ctor, funcs) \ - spl_register_std_class(&spl_ce_ ## class_name, "spl_" # class_name, obj_ctor, funcs TSRMLS_CC); + spl_register_std_class(&spl_ce_ ## class_name, # class_name, obj_ctor, funcs TSRMLS_CC); + +#define REGISTER_SPL_SUB_CLASS_EX(class_name, parent_class_name, obj_ctor, funcs) \ + spl_register_sub_class(&spl_ce_ ## class_name, spl_ce_ ## parent_class_name, # class_name, obj_ctor, funcs TSRMLS_CC); #define REGISTER_SPL_INTERFACE(class_name) \ - spl_register_interface(&spl_ce_ ## class_name, "spl_" # class_name, spl_funcs_ ## class_name TSRMLS_CC); + spl_register_interface(&spl_ce_ ## class_name, # class_name, spl_funcs_ ## class_name TSRMLS_CC); #define REGISTER_SPL_PARENT_CE(class_name, parent_class) \ spl_register_parent_ce(spl_ce_ ## class_name, spl_ce_ ## parent_class TSRMLS_CC); -#define REGISTER_SPL_IMPLEMENT(class_name, interface_name) \ - spl_register_implement(spl_ce_ ## class_name, spl_ce_ ## interface_name TSRMLS_CC); +#define REGISTER_SPL_IMPLEMENTS(class_name, interface_name) \ + zend_class_implements(spl_ce_ ## class_name TSRMLS_CC, 1, spl_ce_ ## interface_name); #define REGISTER_SPL_FUNCTIONS(class_name, function_list) \ spl_register_functions(spl_ce_ ## class_name, function_list TSRMLS_CC); @@ -47,11 +50,11 @@ typedef zend_object_value (*create_object_func_t)(zend_class_entry *class_type T void spl_destroy_class(zend_class_entry ** ppce); void spl_register_std_class(zend_class_entry ** ppce, char * class_name, create_object_func_t ctor, function_entry * function_list TSRMLS_DC); +void spl_register_sub_class(zend_class_entry ** ppce, zend_class_entry * parent_ce, char * class_name, create_object_func_t ctor, function_entry * function_list TSRMLS_DC); void spl_register_interface(zend_class_entry ** ppce, char * class_name, zend_function_entry *functions TSRMLS_DC); void spl_register_parent_ce(zend_class_entry * class_entry, zend_class_entry * parent_class TSRMLS_DC); -void spl_register_implement(zend_class_entry * class_entry, zend_class_entry * interface_entry TSRMLS_DC); void spl_register_functions(zend_class_entry * class_entry, function_entry * function_list TSRMLS_DC); void spl_register_property( zend_class_entry * class_entry, char *prop_name, zval *prop_val, int prop_flags TSRMLS_DC); @@ -59,10 +62,13 @@ void spl_add_class_name(zval * list, zend_class_entry * pce TSRMLS_DC); void spl_add_interfaces(zval * list, zend_class_entry * pce TSRMLS_DC); int spl_add_classes(zend_class_entry ** ppce, zval *list TSRMLS_DC); -#define SPL_CLASS_FE(class_name, function_name, arg_info, flags) \ +#define SPL_ME(class_name, function_name, arg_info, flags) \ PHP_ME( spl_ ## class_name, function_name, arg_info, flags) + +#define SPL_ABSTRACT_ME(class_name, arg_info, flags) \ + ZEND_ABSTRACT_ME( spl_ ## class_name, arg_info, flags) -#define SPL_CLASS_FUNCTION(class_name, function_name) \ +#define SPL_METHOD(class_name, function_name) \ PHP_METHOD(spl_ ## class_name, function_name) #endif /* PHP_FUNCTIONS_H */ diff --git a/ext/spl/spl_iterators.c b/ext/spl/spl_iterators.c new file mode 100755 index 0000000000..8ee28fc745 --- /dev/null +++ b/ext/spl/spl_iterators.c @@ -0,0 +1,399 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2003 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.0 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_0.txt. | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Marcus Boerger <helly@php.net> | + +----------------------------------------------------------------------+ + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "php.h" +#include "php_ini.h" +#include "ext/standard/info.h" +#include "zend_default_classes.h" +#include "zend_interfaces.h" + +#include "php_spl.h" +#include "spl_functions.h" +#include "spl_engine.h" +#include "spl_iterators.h" + +zend_class_entry *spl_ce_RecursiveIterator; +zend_class_entry *spl_ce_RecursiveIteratorIterator; + +function_entry spl_funcs_RecursiveIterator[] = { + SPL_ABSTRACT_ME(RecursiveIterator, hasChildren, NULL) + SPL_ABSTRACT_ME(RecursiveIterator, getChildren, NULL) + {NULL, NULL, NULL} +}; + +SPL_METHOD(RecursiveIteratorIterator, __construct); +SPL_METHOD(RecursiveIteratorIterator, rewind); +SPL_METHOD(RecursiveIteratorIterator, hasMore); +SPL_METHOD(RecursiveIteratorIterator, key); +SPL_METHOD(RecursiveIteratorIterator, current); +SPL_METHOD(RecursiveIteratorIterator, next); +SPL_METHOD(RecursiveIteratorIterator, getLevel); + +static +ZEND_BEGIN_ARG_INFO(arginfo_recursive_it___construct, 0) + ZEND_ARG_INFO(0, iterator) /* parameter name */ +ZEND_END_ARG_INFO(); + +static zend_function_entry spl_funcs_RecursiveIteratorIterator[] = { + SPL_ME(RecursiveIteratorIterator, __construct, arginfo_recursive_it___construct, ZEND_ACC_PUBLIC) + SPL_ME(RecursiveIteratorIterator, rewind, NULL, ZEND_ACC_PUBLIC) + SPL_ME(RecursiveIteratorIterator, hasMore, NULL, ZEND_ACC_PUBLIC) + SPL_ME(RecursiveIteratorIterator, key, NULL, ZEND_ACC_PUBLIC) + SPL_ME(RecursiveIteratorIterator, current, NULL, ZEND_ACC_PUBLIC) + SPL_ME(RecursiveIteratorIterator, next, NULL, ZEND_ACC_PUBLIC) + SPL_ME(RecursiveIteratorIterator, getLevel, NULL, ZEND_ACC_PUBLIC) + {NULL, NULL, NULL} +}; + +typedef struct _spl_sub_iterator { + zend_object_iterator *iterator; + zval *zobject; + zend_class_entry *ce; +} spl_sub_iterator; + +typedef struct _spl_recursive_it_object { + zend_object std; + spl_sub_iterator *iterators; + int level; +} spl_recursive_it_object; + +typedef struct _spl_recursive_it_iterator { + zend_object_iterator intern; + zval *zobject; +} spl_recursive_it_iterator; + +static zend_object_handlers spl_handlers_RecursiveIteratorIterator; + +static void spl_recursive_it_dtor(zend_object_iterator *_iter TSRMLS_DC) +{ + spl_recursive_it_iterator *iter = (spl_recursive_it_iterator*)_iter; + spl_recursive_it_object *object = (spl_recursive_it_object*)_iter->data; + zend_object_iterator *sub_iter; + + while (object->level) { + sub_iter = object->iterators[object->level].iterator; + sub_iter->funcs->dtor(sub_iter TSRMLS_CC); + zval_ptr_dtor(&object->iterators[object->level--].zobject); + } + erealloc(object->iterators, sizeof(spl_sub_iterator)); + object->level = 0; + + zval_ptr_dtor(&iter->zobject); + efree(iter); +} + +static int spl_recursive_it_has_more_ex(spl_recursive_it_object *object TSRMLS_DC) +{ + zend_object_iterator *sub_iter; + int level = object->level; + + while (level >=0) { + sub_iter = object->iterators[level].iterator; + if (sub_iter->funcs->has_more(sub_iter TSRMLS_CC) == SUCCESS) { + return SUCCESS; + } + level--; + } + return FAILURE; +} + +static int spl_recursive_it_has_more(zend_object_iterator *iter TSRMLS_DC) +{ + spl_recursive_it_object *object = (spl_recursive_it_object*)iter->data; + + return spl_recursive_it_has_more_ex(object TSRMLS_CC); +} + +static void spl_recursive_it_get_current_data(zend_object_iterator *iter, zval ***data TSRMLS_DC) +{ + spl_recursive_it_object *object = (spl_recursive_it_object*)iter->data; + zend_object_iterator *sub_iter = object->iterators[object->level].iterator; + + return sub_iter->funcs->get_current_data(sub_iter, data TSRMLS_CC); +} + +static int spl_recursive_it_get_current_key(zend_object_iterator *iter, char **str_key, uint *str_key_len, ulong *int_key TSRMLS_DC) +{ + spl_recursive_it_object *object = (spl_recursive_it_object*)iter->data; + zend_object_iterator *sub_iter = object->iterators[object->level].iterator; + + if (sub_iter->funcs->get_current_key) { + return sub_iter->funcs->get_current_key(sub_iter, str_key, str_key_len, int_key TSRMLS_CC); + } else { + *int_key = iter->index; + return HASH_KEY_IS_LONG; + } +} + +static void spl_recursive_it_move_forward_ex(spl_recursive_it_object *object TSRMLS_DC) +{ + zend_object_iterator *iterator; + zval *zobject; + zend_class_entry *ce; + zval *retval, *child; + zend_object_iterator *sub_iter; + + while (1) { + iterator = object->iterators[object->level].iterator; + iterator->funcs->move_forward(iterator TSRMLS_CC); + if (iterator->funcs->has_more(iterator TSRMLS_CC) == SUCCESS) { + zobject = object->iterators[object->level].zobject; + ce = object->iterators[object->level].ce; + zend_call_method_with_0_params(&zobject, ce, NULL, "haschildren", &retval); + if (zend_is_true(retval)) { + zend_call_method_with_0_params(&zobject, ce, NULL, "getchildren", &child); + ce = Z_OBJCE_P(child); + if (!ce || !instanceof_function(ce, spl_ce_RecursiveIterator TSRMLS_CC)) { + zend_throw_exception(zend_exception_get_default(), "Objects returned by RecursiveIterator::getChildren() must implement RecursiveIterator", 0 TSRMLS_CC); + zval_ptr_dtor(&retval); + return; + } + object->iterators = erealloc(object->iterators, sizeof(spl_sub_iterator) * (++object->level+1)); + sub_iter = ce->get_iterator(ce, child TSRMLS_CC); + if (sub_iter->funcs->rewind) { + sub_iter->funcs->rewind(sub_iter TSRMLS_CC); + } + object->iterators[object->level].iterator = sub_iter; + object->iterators[object->level].zobject = child; + object->iterators[object->level].ce = ce; + } + zval_ptr_dtor(&retval); + return; /* return the element */ + } + /* no more elements */ + if (object->level > 0) { + iterator->funcs->dtor(iterator TSRMLS_CC); + zval_ptr_dtor(&object->iterators[object->level].zobject); + object->level--; + } else { + return; /* done completeley */ + } + } +} + +static void spl_recursive_it_rewind_ex(spl_recursive_it_object *object TSRMLS_DC) +{ + zend_object_iterator *sub_iter; + + while (object->level) { + sub_iter = object->iterators[object->level].iterator; + sub_iter->funcs->dtor(sub_iter TSRMLS_CC); + zval_ptr_dtor(&object->iterators[object->level--].zobject); + } + erealloc(object->iterators, sizeof(spl_sub_iterator)); + sub_iter = object->iterators[0].iterator; + if (sub_iter->funcs->rewind) { + sub_iter->funcs->rewind(sub_iter TSRMLS_CC); + } +} + +static void spl_recursive_it_move_forward(zend_object_iterator *iter TSRMLS_DC) +{ + spl_recursive_it_move_forward_ex((spl_recursive_it_object*)iter->data TSRMLS_CC); +} + +static void spl_recursive_it_rewind(zend_object_iterator *iter TSRMLS_DC) +{ + spl_recursive_it_rewind_ex((spl_recursive_it_object*)iter->data TSRMLS_CC); +} + +static zend_object_iterator *spl_recursive_it_get_iterator(zend_class_entry *ce, zval *zobject TSRMLS_DC) +{ + spl_recursive_it_iterator *iterator = emalloc(sizeof(spl_recursive_it_iterator)); + spl_recursive_it_object *object = (spl_recursive_it_object*)zend_object_store_get_object(zobject TSRMLS_CC); + + zobject->refcount++; + iterator->intern.data = (void*)object; + iterator->intern.funcs = ce->iterator_funcs.funcs; + iterator->zobject = zobject; + return (zend_object_iterator*)iterator; +} + +zend_object_iterator_funcs spl_recursive_it_iterator_funcs = { + spl_recursive_it_dtor, + spl_recursive_it_has_more, + spl_recursive_it_get_current_data, + spl_recursive_it_get_current_key, + spl_recursive_it_move_forward, + spl_recursive_it_rewind +}; + +SPL_METHOD(RecursiveIteratorIterator, __construct) +{ + zval *object = getThis(); + spl_recursive_it_object *intern; + zval *iterator; + zend_class_entry *ce_iterator; + + php_set_error_handling(EH_THROW, zend_exception_get_default() TSRMLS_CC); + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &iterator, spl_ce_RecursiveIterator) == FAILURE) { + php_set_error_handling(EH_NORMAL, NULL TSRMLS_CC); + return; + } + + intern = (spl_recursive_it_object*)zend_object_store_get_object(object TSRMLS_CC); + intern->iterators = emalloc(sizeof(spl_sub_iterator)); + intern->level = 0; + ce_iterator = Z_OBJCE_P(iterator); /* respect inheritance, don't use spl_ce_RecursiveIterator */ + intern->iterators[0].iterator = ce_iterator->get_iterator(ce_iterator, iterator TSRMLS_CC); + intern->iterators[0].zobject = iterator; + intern->iterators[0].ce = ce_iterator; + + php_set_error_handling(EH_NORMAL, NULL TSRMLS_CC); +} + +SPL_METHOD(RecursiveIteratorIterator, rewind) +{ + spl_recursive_it_object *object = (spl_recursive_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + + spl_recursive_it_rewind_ex(object TSRMLS_CC); +} + +SPL_METHOD(RecursiveIteratorIterator, hasMore) +{ + spl_recursive_it_object *object = (spl_recursive_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + + RETURN_BOOL(spl_recursive_it_has_more_ex(object TSRMLS_CC) == SUCCESS); +} + +SPL_METHOD(RecursiveIteratorIterator, 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; + + if (iterator->funcs->get_current_key) { + char *str_key; + uint str_key_len; + ulong int_key; + if (iterator->funcs->get_current_key(iterator, &str_key, &str_key_len, &int_key TSRMLS_CC) == HASH_KEY_IS_LONG) { + RETURN_LONG(int_key); + } else { + RETURN_STRINGL(str_key, str_key_len, 1); + } + } else { + RETURN_NULL(); + } +} + +SPL_METHOD(RecursiveIteratorIterator, current) +{ + 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 **data; + + iterator->funcs->get_current_data(iterator, &data TSRMLS_CC); + *return_value = **data; + return_value->refcount++; +} + +SPL_METHOD(RecursiveIteratorIterator, next) +{ + spl_recursive_it_object *object = (spl_recursive_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + + spl_recursive_it_move_forward_ex(object TSRMLS_CC); +} + +SPL_METHOD(RecursiveIteratorIterator, getLevel) +{ + spl_recursive_it_object *object = (spl_recursive_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + + RETURN_LONG(object->level); +} + +/* {{{ spl_dtor_RecursiveIteratorIterator */ +static void spl_dtor_RecursiveIteratorIterator(void *_object, zend_object_handle handle TSRMLS_DC) +{ + spl_recursive_it_object *object = (spl_recursive_it_object *)_object; + zend_object_iterator *sub_iter; + + if (object->iterators) { + while (object->level >= 0) { + sub_iter = object->iterators[object->level].iterator; + sub_iter->funcs->dtor(sub_iter TSRMLS_CC); + zval_ptr_dtor(&object->iterators[object->level--].zobject); + } + efree(object->iterators); + } + + zend_hash_destroy(object->std.properties); + FREE_HASHTABLE(object->std.properties); + + efree(object); +} +/* }}} */ + +static int spl_recursive_it_gets_implemented(zend_class_entry *iface, zend_class_entry *class_type TSRMLS_DC) +{ + return SUCCESS; +} + +/* {{{ spl_new_RecursiveIteratorIterator */ +static zend_object_value spl_new_RecursiveIteratorIterator(zend_class_entry *class_type TSRMLS_DC) +{ + zend_object_value retval; + spl_recursive_it_object *intern; + zval *tmp; + + intern = emalloc(sizeof(spl_recursive_it_object)); + memset(intern, 0, sizeof(spl_recursive_it_object)); + intern->std.ce = class_type; + + ALLOC_HASHTABLE(intern->std.properties); + zend_hash_init(intern->std.properties, 0, NULL, ZVAL_PTR_DTOR, 0); + zend_hash_copy(intern->std.properties, &class_type->default_properties, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *)); + + retval.handle = zend_objects_store_put(intern, spl_dtor_RecursiveIteratorIterator, NULL TSRMLS_CC); + retval.handlers = &spl_handlers_RecursiveIteratorIterator; + return retval; +} +/* }}} */ + +/* {{{ PHP_MINIT_FUNCTION(spl_iterators) + */ +PHP_MINIT_FUNCTION(spl_iterators) +{ + REGISTER_SPL_INTERFACE(RecursiveIterator); + zend_class_implements(spl_ce_RecursiveIterator TSRMLS_CC, 1, zend_ce_iterator); + + REGISTER_SPL_STD_CLASS_EX(RecursiveIteratorIterator, spl_new_RecursiveIteratorIterator, spl_funcs_RecursiveIteratorIterator); + zend_class_implements(spl_ce_RecursiveIteratorIterator TSRMLS_CC, 1, zend_ce_iterator); + memcpy(&spl_handlers_RecursiveIteratorIterator, zend_get_std_object_handlers(), sizeof(zend_object_handlers)); + spl_handlers_RecursiveIteratorIterator.clone_obj = NULL; + + spl_ce_RecursiveIterator->interface_gets_implemented = spl_recursive_it_gets_implemented; + + spl_ce_RecursiveIteratorIterator->get_iterator = spl_recursive_it_get_iterator; + spl_ce_RecursiveIteratorIterator->iterator_funcs.funcs = &spl_recursive_it_iterator_funcs; + + return SUCCESS; +} +/* }}} */ + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + * vim600: fdm=marker + * vim: noet sw=4 ts=4 + */ diff --git a/ext/spl/spl_iterators.h b/ext/spl/spl_iterators.h new file mode 100755 index 0000000000..c694d6da67 --- /dev/null +++ b/ext/spl/spl_iterators.h @@ -0,0 +1,39 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2003 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.0 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_0.txt. | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Marcus Boerger <helly@php.net> | + +----------------------------------------------------------------------+ + */ + +#ifndef SPL_ITERATORS_H +#define SPL_ITERATORS_H + +#include "php.h" +#include "php_spl.h" + +extern zend_class_entry *spl_ce_RecursiveIterator; +extern zend_class_entry *spl_ce_RecursiveIteratorIterator; + +PHP_MINIT_FUNCTION(spl_iterators); + +#endif /* SPL_ITERATORS_H */ + +/* + * Local Variables: + * c-basic-offset: 4 + * tab-width: 4 + * End: + * vim600: fdm=marker + * vim: noet sw=4 ts=4 + */ |