diff options
Diffstat (limited to 'ext/spl/spl_directory.c')
| -rwxr-xr-x | ext/spl/spl_directory.c | 577 |
1 files changed, 492 insertions, 85 deletions
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 */ |
