Back to index

php5  5.3.10
spl_directory.c
Go to the documentation of this file.
00001 /*
00002    +----------------------------------------------------------------------+
00003    | PHP Version 5                                                        |
00004    +----------------------------------------------------------------------+
00005    | Copyright (c) 1997-2012 The PHP Group                                |
00006    +----------------------------------------------------------------------+
00007    | This source file is subject to version 3.01 of the PHP license,      |
00008    | that is bundled with this package in the file LICENSE, and is        |
00009    | available through the world-wide-web at the following url:           |
00010    | http://www.php.net/license/3_01.txt                                  |
00011    | If you did not receive a copy of the PHP license and are unable to   |
00012    | obtain it through the world-wide-web, please send a note to          |
00013    | license@php.net so we can mail you a copy immediately.               |
00014    +----------------------------------------------------------------------+
00015    | Author: Marcus Boerger <helly@php.net>                               |
00016    +----------------------------------------------------------------------+
00017  */
00018 
00019 /* $Id: spl_directory.c 321634 2012-01-01 13:15:04Z felipe $ */
00020 
00021 #ifdef HAVE_CONFIG_H
00022 # include "config.h"
00023 #endif
00024 
00025 #include "php.h"
00026 #include "php_ini.h"
00027 #include "ext/standard/info.h"
00028 #include "ext/standard/file.h"
00029 #include "ext/standard/php_string.h"
00030 #include "zend_compile.h"
00031 #include "zend_exceptions.h"
00032 #include "zend_interfaces.h"
00033 
00034 #include "php_spl.h"
00035 #include "spl_functions.h"
00036 #include "spl_engine.h"
00037 #include "spl_iterators.h"
00038 #include "spl_directory.h"
00039 #include "spl_exceptions.h"
00040 
00041 #include "php.h"
00042 #include "fopen_wrappers.h"
00043 
00044 #include "ext/standard/basic_functions.h"
00045 #include "ext/standard/php_filestat.h"
00046 
00047 #define SPL_HAS_FLAG(flags, test_flag) ((flags & test_flag) ? 1 : 0)
00048 
00049 /* declare the class handlers */
00050 static zend_object_handlers spl_filesystem_object_handlers;
00051 /* includes handler to validate object state when retrieving methods */
00052 static zend_object_handlers spl_filesystem_object_check_handlers;
00053 
00054 /* decalre the class entry */
00055 PHPAPI zend_class_entry *spl_ce_SplFileInfo;
00056 PHPAPI zend_class_entry *spl_ce_DirectoryIterator;
00057 PHPAPI zend_class_entry *spl_ce_FilesystemIterator;
00058 PHPAPI zend_class_entry *spl_ce_RecursiveDirectoryIterator;
00059 PHPAPI zend_class_entry *spl_ce_GlobIterator;
00060 PHPAPI zend_class_entry *spl_ce_SplFileObject;
00061 PHPAPI zend_class_entry *spl_ce_SplTempFileObject;
00062 
00063 static void spl_filesystem_file_free_line(spl_filesystem_object *intern TSRMLS_DC) /* {{{ */
00064 {
00065        if (intern->u.file.current_line) {
00066               efree(intern->u.file.current_line);
00067               intern->u.file.current_line = NULL;
00068        }
00069        if (intern->u.file.current_zval) {
00070               zval_ptr_dtor(&intern->u.file.current_zval);
00071               intern->u.file.current_zval = NULL;
00072        }
00073 } /* }}} */
00074 
00075 static void spl_filesystem_object_free_storage(void *object TSRMLS_DC) /* {{{ */
00076 {
00077        spl_filesystem_object *intern = (spl_filesystem_object*)object;
00078 
00079        if (intern->oth_handler && intern->oth_handler->dtor) {
00080               intern->oth_handler->dtor(intern TSRMLS_CC);
00081        }
00082        
00083        zend_object_std_dtor(&intern->std TSRMLS_CC);
00084        
00085        if (intern->_path) {
00086               efree(intern->_path);
00087        }
00088        if (intern->file_name) {
00089               efree(intern->file_name);
00090        }
00091        switch(intern->type) {
00092        case SPL_FS_INFO:
00093               break;
00094        case SPL_FS_DIR:
00095               if (intern->u.dir.dirp) {
00096                      php_stream_close(intern->u.dir.dirp);
00097                      intern->u.dir.dirp = NULL;
00098               }
00099               if (intern->u.dir.sub_path) {
00100                      efree(intern->u.dir.sub_path);
00101               }             
00102               break;
00103        case SPL_FS_FILE:
00104               if (intern->u.file.stream) {
00105                      if (intern->u.file.zcontext) {
00106 /*                          zend_list_delref(Z_RESVAL_P(intern->zcontext));*/
00107                      }
00108                      if (!intern->u.file.stream->is_persistent) {
00109                             php_stream_free(intern->u.file.stream, PHP_STREAM_FREE_CLOSE);
00110                      } else {
00111                             php_stream_free(intern->u.file.stream, PHP_STREAM_FREE_CLOSE_PERSISTENT);
00112                      }
00113                      if (intern->u.file.open_mode) {
00114                             efree(intern->u.file.open_mode);
00115                      }
00116                      if (intern->orig_path) {
00117                             efree(intern->orig_path);
00118                      }
00119               }
00120               spl_filesystem_file_free_line(intern TSRMLS_CC);
00121               break;
00122        }
00123        efree(object);
00124 } /* }}} */
00125 
00126 /* {{{ spl_ce_dir_object_new */
00127 /* creates the object by 
00128    - allocating memory 
00129    - initializing the object members
00130    - storing the object
00131    - setting it's handlers
00132 
00133    called from 
00134    - clone
00135    - new
00136  */
00137 static zend_object_value spl_filesystem_object_new_ex(zend_class_entry *class_type, spl_filesystem_object **obj TSRMLS_DC)
00138 {
00139        zend_object_value retval;
00140        spl_filesystem_object *intern;
00141        zval *tmp;
00142 
00143        intern = emalloc(sizeof(spl_filesystem_object));
00144        memset(intern, 0, sizeof(spl_filesystem_object));
00145        /* intern->type = SPL_FS_INFO; done by set 0 */
00146        intern->file_class = spl_ce_SplFileObject;
00147        intern->info_class = spl_ce_SplFileInfo;
00148        if (obj) *obj = intern;
00149 
00150        zend_object_std_init(&intern->std, class_type TSRMLS_CC);
00151        zend_hash_copy(intern->std.properties, &class_type->default_properties, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *));
00152 
00153        retval.handle = zend_objects_store_put(intern, (zend_objects_store_dtor_t) zend_objects_destroy_object, (zend_objects_free_object_storage_t) spl_filesystem_object_free_storage, NULL TSRMLS_CC);
00154        retval.handlers = &spl_filesystem_object_handlers;
00155        return retval;
00156 }
00157 /* }}} */
00158 
00159 /* {{{ spl_filesystem_object_new */
00160 /* See spl_filesystem_object_new_ex */
00161 static zend_object_value spl_filesystem_object_new(zend_class_entry *class_type TSRMLS_DC)
00162 {
00163        return spl_filesystem_object_new_ex(class_type, NULL TSRMLS_CC);
00164 }
00165 /* }}} */
00166 
00167 /* {{{ spl_filesystem_object_new_ex */
00168 static zend_object_value spl_filesystem_object_new_check(zend_class_entry *class_type TSRMLS_DC)
00169 {
00170        zend_object_value ret = spl_filesystem_object_new_ex(class_type, NULL TSRMLS_CC);
00171        ret.handlers = &spl_filesystem_object_check_handlers;
00172        return ret;
00173 }
00174 /* }}} */
00175 
00176 
00177 PHPAPI char* spl_filesystem_object_get_path(spl_filesystem_object *intern, int *len TSRMLS_DC) /* {{{ */
00178 {
00179 #ifdef HAVE_GLOB
00180        if (intern->type == SPL_FS_DIR) {
00181               if (php_stream_is(intern->u.dir.dirp ,&php_glob_stream_ops)) {
00182                      return php_glob_stream_get_path(intern->u.dir.dirp, 0, len);
00183               }
00184        }
00185 #endif
00186        if (len) {
00187               *len = intern->_path_len;
00188        }
00189        return intern->_path;
00190 } /* }}} */
00191 
00192 static inline void spl_filesystem_object_get_file_name(spl_filesystem_object *intern TSRMLS_DC) /* {{{ */
00193 {
00194        char slash = SPL_HAS_FLAG(intern->flags, SPL_FILE_DIR_UNIXPATHS) ? '/' : DEFAULT_SLASH;
00195 
00196        if (!intern->file_name) {
00197               switch (intern->type) {
00198               case SPL_FS_INFO:
00199               case SPL_FS_FILE:
00200                      php_error_docref(NULL TSRMLS_CC, E_ERROR, "Object not initialized");
00201                      break;
00202               case SPL_FS_DIR:
00203                      intern->file_name_len = spprintf(&intern->file_name, 0, "%s%c%s",
00204                                                       spl_filesystem_object_get_path(intern, NULL TSRMLS_CC),
00205                                                       slash, intern->u.dir.entry.d_name);
00206                      break;
00207               }
00208        }
00209 } /* }}} */
00210 
00211 static int spl_filesystem_dir_read(spl_filesystem_object *intern TSRMLS_DC) /* {{{ */
00212 {
00213        if (!intern->u.dir.dirp || !php_stream_readdir(intern->u.dir.dirp, &intern->u.dir.entry)) {
00214               intern->u.dir.entry.d_name[0] = '\0';
00215               return 0;
00216        } else {
00217               return 1;
00218        }
00219 }
00220 /* }}} */
00221 
00222 #define IS_SLASH_AT(zs, pos) (IS_SLASH(zs[pos]))
00223 
00224 static inline int spl_filesystem_is_dot(const char * d_name) /* {{{ */
00225 {
00226        return !strcmp(d_name, ".") || !strcmp(d_name, "..");
00227 }
00228 /* }}} */
00229 
00230 /* {{{ spl_filesystem_dir_open */
00231 /* open a directory resource */
00232 static void spl_filesystem_dir_open(spl_filesystem_object* intern, char *path TSRMLS_DC)
00233 {
00234        int skip_dots = SPL_HAS_FLAG(intern->flags, SPL_FILE_DIR_SKIPDOTS);
00235 
00236        intern->type = SPL_FS_DIR;
00237        intern->_path_len = strlen(path);
00238        intern->u.dir.dirp = php_stream_opendir(path, ENFORCE_SAFE_MODE|REPORT_ERRORS, NULL);
00239 
00240        if (intern->_path_len > 1 && IS_SLASH_AT(path, intern->_path_len-1)) {
00241               intern->_path = estrndup(path, --intern->_path_len);
00242        } else {
00243               intern->_path = estrndup(path, intern->_path_len);
00244        }
00245        intern->u.dir.index = 0;
00246 
00247        if (EG(exception) || intern->u.dir.dirp == NULL) {
00248               intern->u.dir.entry.d_name[0] = '\0';
00249               if (!EG(exception)) {
00250                      /* open failed w/out notice (turned to exception due to EH_THROW) */
00251                      zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0
00252                             TSRMLS_CC, "Failed to open directory \"%s\"", path);
00253               }
00254        } else {
00255               do {
00256                      spl_filesystem_dir_read(intern TSRMLS_CC);
00257               } while (skip_dots && spl_filesystem_is_dot(intern->u.dir.entry.d_name));
00258        }
00259 }
00260 /* }}} */
00261 
00262 static int spl_filesystem_file_open(spl_filesystem_object *intern, int use_include_path, int silent TSRMLS_DC) /* {{{ */
00263 {
00264        intern->type = SPL_FS_FILE;
00265        intern->u.file.context = php_stream_context_from_zval(intern->u.file.zcontext, 0);
00266        intern->u.file.stream = php_stream_open_wrapper_ex(intern->file_name, intern->u.file.open_mode, (use_include_path ? USE_PATH : 0) | ENFORCE_SAFE_MODE | REPORT_ERRORS, NULL, intern->u.file.context);
00267 
00268        if (!intern->file_name_len || !intern->u.file.stream) {
00269               if (!EG(exception)) {
00270                      zend_throw_exception_ex(spl_ce_RuntimeException, 0 TSRMLS_CC, "Cannot open file '%s'", intern->file_name_len ? intern->file_name : "");
00271               }
00272               intern->file_name = NULL; /* until here it is not a copy */
00273               intern->u.file.open_mode = NULL;
00274               return FAILURE;
00275        }
00276 
00277        if (intern->u.file.zcontext) {
00278               zend_list_addref(Z_RESVAL_P(intern->u.file.zcontext));
00279        }
00280 
00281        if (intern->file_name_len > 1 && IS_SLASH_AT(intern->file_name, intern->file_name_len-1)) {
00282               intern->file_name_len--;
00283        }
00284 
00285        intern->orig_path = estrndup(intern->u.file.stream->orig_path, strlen(intern->u.file.stream->orig_path));
00286 
00287        intern->file_name = estrndup(intern->file_name, intern->file_name_len);
00288        intern->u.file.open_mode = estrndup(intern->u.file.open_mode, intern->u.file.open_mode_len);
00289 
00290        /* avoid reference counting in debug mode, thus do it manually */
00291        ZVAL_RESOURCE(&intern->u.file.zresource, php_stream_get_resource_id(intern->u.file.stream));
00292        Z_SET_REFCOUNT(intern->u.file.zresource, 1);
00293        
00294        intern->u.file.delimiter = ',';
00295        intern->u.file.enclosure = '"';
00296        intern->u.file.escape = '\\';
00297 
00298        zend_hash_find(&intern->std.ce->function_table, "getcurrentline", sizeof("getcurrentline"), (void **) &intern->u.file.func_getCurr);
00299 
00300        return SUCCESS;
00301 } /* }}} */
00302 
00303 /* {{{ spl_filesystem_object_clone */
00304 /* Local zend_object_value creation (on stack)
00305    Load the 'other' object 
00306    Create a new empty object (See spl_filesystem_object_new_ex)
00307    Open the directory
00308    Clone other members (properties)
00309  */
00310 static zend_object_value spl_filesystem_object_clone(zval *zobject TSRMLS_DC)
00311 {
00312        zend_object_value new_obj_val;
00313        zend_object *old_object;
00314        zend_object *new_object;
00315        zend_object_handle handle = Z_OBJ_HANDLE_P(zobject);
00316        spl_filesystem_object *intern;
00317        spl_filesystem_object *source;
00318        int index, skip_dots;
00319 
00320        old_object = zend_objects_get_address(zobject TSRMLS_CC);
00321        source = (spl_filesystem_object*)old_object;
00322 
00323        new_obj_val = spl_filesystem_object_new_ex(old_object->ce, &intern TSRMLS_CC);
00324        new_object = &intern->std;
00325 
00326        intern->flags = source->flags;
00327 
00328        switch (source->type) {
00329        case SPL_FS_INFO:
00330               intern->_path_len = source->_path_len;
00331               intern->_path = estrndup(source->_path, source->_path_len);
00332               intern->file_name_len = source->file_name_len;
00333               intern->file_name = estrndup(source->file_name, intern->file_name_len);
00334               break;
00335        case SPL_FS_DIR:
00336               spl_filesystem_dir_open(intern, source->_path TSRMLS_CC);
00337               /* read until we hit the position in which we were before */
00338               skip_dots = SPL_HAS_FLAG(source->flags, SPL_FILE_DIR_SKIPDOTS);
00339               for(index = 0; index < source->u.dir.index; ++index) {
00340                      do {
00341                             spl_filesystem_dir_read(intern TSRMLS_CC);
00342                      } while (skip_dots && spl_filesystem_is_dot(intern->u.dir.entry.d_name));
00343               }
00344               intern->u.dir.index = index;
00345               break;
00346        case SPL_FS_FILE:
00347               php_error_docref(NULL TSRMLS_CC, E_ERROR, "An object of class %s cannot be cloned", old_object->ce->name);
00348               break;
00349        }
00350        
00351        intern->file_class = source->file_class;
00352        intern->info_class = source->info_class;
00353        intern->oth = source->oth;
00354        intern->oth_handler = source->oth_handler;
00355 
00356        zend_objects_clone_members(new_object, new_obj_val, old_object, handle TSRMLS_CC);
00357 
00358        if (intern->oth_handler && intern->oth_handler->clone) {
00359               intern->oth_handler->clone(source, intern TSRMLS_CC);
00360        }
00361 
00362        return new_obj_val;
00363 }
00364 /* }}} */
00365 
00366 void spl_filesystem_info_set_filename(spl_filesystem_object *intern, char *path, int len, int use_copy TSRMLS_DC) /* {{{ */
00367 {
00368        char *p1, *p2;
00369 
00370        intern->file_name = use_copy ? estrndup(path, len) : path;
00371        intern->file_name_len = len;
00372 
00373        while(IS_SLASH_AT(intern->file_name, intern->file_name_len-1) && intern->file_name_len > 1) {
00374               intern->file_name[intern->file_name_len-1] = 0;
00375               intern->file_name_len--;
00376        }
00377 
00378        p1 = strrchr(intern->file_name, '/');
00379 #if defined(PHP_WIN32) || defined(NETWARE)
00380        p2 = strrchr(intern->file_name, '\\');
00381 #else
00382        p2 = 0;
00383 #endif
00384        if (p1 || p2) {
00385               intern->_path_len = (p1 > p2 ? p1 : p2) - intern->file_name;
00386        } else {
00387               intern->_path_len = 0;
00388        }
00389 
00390        intern->_path = estrndup(path, intern->_path_len);
00391 } /* }}} */
00392 
00393 static spl_filesystem_object * spl_filesystem_object_create_info(spl_filesystem_object *source, char *file_path, int file_path_len, int use_copy, zend_class_entry *ce, zval *return_value TSRMLS_DC) /* {{{ */
00394 {
00395        spl_filesystem_object *intern;
00396        zval *arg1;
00397        zend_error_handling error_handling;
00398 
00399        if (!file_path || !file_path_len) {
00400 #if defined(PHP_WIN32)
00401               zend_throw_exception_ex(spl_ce_RuntimeException, 0 TSRMLS_CC, "Cannot create SplFileInfo for empty path");
00402               if (file_path && !use_copy) {
00403                      efree(file_path);
00404               }
00405 #else
00406               if (file_path && !use_copy) {
00407                      efree(file_path);
00408               }
00409               use_copy = 1;
00410               file_path_len = 1;
00411               file_path = "/";
00412 #endif
00413               return NULL;
00414        }
00415 
00416        zend_replace_error_handling(EH_THROW, spl_ce_RuntimeException, &error_handling TSRMLS_CC);
00417 
00418        ce = ce ? ce : source->info_class;
00419 
00420        zend_update_class_constants(ce TSRMLS_CC);
00421 
00422        return_value->value.obj = spl_filesystem_object_new_ex(ce, &intern TSRMLS_CC);
00423        Z_TYPE_P(return_value) = IS_OBJECT;
00424 
00425        if (ce->constructor->common.scope != spl_ce_SplFileInfo) {
00426               MAKE_STD_ZVAL(arg1);
00427               ZVAL_STRINGL(arg1, file_path, file_path_len, use_copy);
00428               zend_call_method_with_1_params(&return_value, ce, &ce->constructor, "__construct", NULL, arg1);
00429               zval_ptr_dtor(&arg1);
00430        } else {
00431               spl_filesystem_info_set_filename(intern, file_path, file_path_len, use_copy TSRMLS_CC);
00432        }
00433        
00434        zend_restore_error_handling(&error_handling TSRMLS_CC);
00435        return intern;
00436 } /* }}} */
00437 
00438 static spl_filesystem_object * spl_filesystem_object_create_type(int ht, spl_filesystem_object *source, int type, zend_class_entry *ce, zval *return_value TSRMLS_DC) /* {{{ */
00439 {
00440        spl_filesystem_object *intern;
00441        zend_bool use_include_path = 0;
00442        zval *arg1, *arg2;
00443        zend_error_handling error_handling;
00444 
00445        zend_replace_error_handling(EH_THROW, spl_ce_RuntimeException, &error_handling TSRMLS_CC);
00446 
00447        switch (source->type) {
00448        case SPL_FS_INFO:
00449        case SPL_FS_FILE:
00450               break;
00451        case SPL_FS_DIR:
00452               if (!source->u.dir.entry.d_name[0]) {
00453                      zend_throw_exception_ex(spl_ce_RuntimeException, 0 TSRMLS_CC, "Could not open file");
00454                      zend_restore_error_handling(&error_handling TSRMLS_CC);
00455                      return NULL;
00456               }
00457        }
00458 
00459        switch (type) {
00460        case SPL_FS_INFO:
00461               ce = ce ? ce : source->info_class;
00462 
00463               zend_update_class_constants(ce TSRMLS_CC);
00464 
00465               return_value->value.obj = spl_filesystem_object_new_ex(ce, &intern TSRMLS_CC);
00466               Z_TYPE_P(return_value) = IS_OBJECT;
00467 
00468               spl_filesystem_object_get_file_name(source TSRMLS_CC);
00469               if (ce->constructor->common.scope != spl_ce_SplFileInfo) {
00470                      MAKE_STD_ZVAL(arg1);
00471                      ZVAL_STRINGL(arg1, source->file_name, source->file_name_len, 1);
00472                      zend_call_method_with_1_params(&return_value, ce, &ce->constructor, "__construct", NULL, arg1);
00473                      zval_ptr_dtor(&arg1);
00474               } else {
00475                      intern->file_name = estrndup(source->file_name, source->file_name_len);
00476                      intern->file_name_len = source->file_name_len;
00477                      intern->_path = spl_filesystem_object_get_path(source, &intern->_path_len TSRMLS_CC);
00478                      intern->_path = estrndup(intern->_path, intern->_path_len);
00479               }
00480               break;
00481        case SPL_FS_FILE:
00482               ce = ce ? ce : source->file_class;
00483 
00484               zend_update_class_constants(ce TSRMLS_CC);
00485 
00486               return_value->value.obj = spl_filesystem_object_new_ex(ce, &intern TSRMLS_CC);
00487               Z_TYPE_P(return_value) = IS_OBJECT;
00488        
00489               spl_filesystem_object_get_file_name(source TSRMLS_CC);
00490 
00491               if (ce->constructor->common.scope != spl_ce_SplFileObject) {
00492                      MAKE_STD_ZVAL(arg1);
00493                      MAKE_STD_ZVAL(arg2);
00494                      ZVAL_STRINGL(arg1, source->file_name, source->file_name_len, 1);
00495                      ZVAL_STRINGL(arg2, "r", 1, 1);
00496                      zend_call_method_with_2_params(&return_value, ce, &ce->constructor, "__construct", NULL, arg1, arg2);
00497                      zval_ptr_dtor(&arg1);
00498                      zval_ptr_dtor(&arg2);
00499               } else {
00500                      intern->file_name = source->file_name;
00501                      intern->file_name_len = source->file_name_len;
00502                      intern->_path = spl_filesystem_object_get_path(source, &intern->_path_len TSRMLS_CC);
00503                      intern->_path = estrndup(intern->_path, intern->_path_len);
00504               
00505                      intern->u.file.open_mode = "r";
00506                      intern->u.file.open_mode_len = 1;
00507               
00508                      if (ht && zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|sbr", 
00509                                    &intern->u.file.open_mode, &intern->u.file.open_mode_len, 
00510                                    &use_include_path, &intern->u.file.zcontext) == FAILURE) {
00511                             zend_restore_error_handling(&error_handling TSRMLS_CC);
00512                             intern->u.file.open_mode = NULL;
00513                             intern->file_name = NULL;
00514                             zval_dtor(return_value);
00515                             Z_TYPE_P(return_value) = IS_NULL;
00516                             return NULL;
00517                      }
00518               
00519                      if (spl_filesystem_file_open(intern, use_include_path, 0 TSRMLS_CC) == FAILURE) {
00520                             zend_restore_error_handling(&error_handling TSRMLS_CC);
00521                             zval_dtor(return_value);
00522                             Z_TYPE_P(return_value) = IS_NULL;
00523                             return NULL;
00524                      }
00525               }
00526               break;
00527        case SPL_FS_DIR:     
00528               zend_restore_error_handling(&error_handling TSRMLS_CC);
00529               zend_throw_exception_ex(spl_ce_RuntimeException, 0 TSRMLS_CC, "Operation not supported");
00530               return NULL;
00531        }
00532        zend_restore_error_handling(&error_handling TSRMLS_CC);
00533        return NULL;
00534 } /* }}} */
00535 
00536 static int spl_filesystem_is_invalid_or_dot(const char * d_name) /* {{{ */
00537 {
00538        return d_name[0] == '\0' || spl_filesystem_is_dot(d_name);
00539 }
00540 /* }}} */
00541 
00542 static char *spl_filesystem_object_get_pathname(spl_filesystem_object *intern, int *len TSRMLS_DC) { /* {{{ */
00543        switch (intern->type) {
00544        case SPL_FS_INFO:
00545        case SPL_FS_FILE:
00546               *len = intern->file_name_len;
00547               return intern->file_name;
00548        case SPL_FS_DIR:
00549               if (intern->u.dir.entry.d_name[0]) {
00550                      spl_filesystem_object_get_file_name(intern TSRMLS_CC);
00551                      *len = intern->file_name_len;
00552                      return intern->file_name;
00553               }
00554        }
00555        *len = 0;
00556        return NULL;
00557 }
00558 /* }}} */
00559 
00560 static HashTable* spl_filesystem_object_get_debug_info(zval *obj, int *is_temp TSRMLS_DC) /* {{{ */
00561 {
00562        spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(obj TSRMLS_CC);
00563        HashTable *rv;
00564        zval *tmp, zrv;
00565        char *pnstr, *path;
00566        int  pnlen, path_len;
00567        char stmp[2];
00568 
00569        *is_temp = 1;
00570 
00571        ALLOC_HASHTABLE(rv);
00572        ZEND_INIT_SYMTABLE_EX(rv, zend_hash_num_elements(intern->std.properties) + 3, 0);
00573 
00574        INIT_PZVAL(&zrv);
00575        Z_ARRVAL(zrv) = rv;
00576 
00577        zend_hash_copy(rv, intern->std.properties, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *));
00578 
00579        pnstr = spl_gen_private_prop_name(spl_ce_SplFileInfo, "pathName", sizeof("pathName")-1, &pnlen TSRMLS_CC);
00580        path = spl_filesystem_object_get_pathname(intern, &path_len TSRMLS_CC);
00581        add_assoc_stringl_ex(&zrv, pnstr, pnlen+1, path, path_len, 1);
00582        efree(pnstr);
00583 
00584        if (intern->file_name) {
00585               pnstr = spl_gen_private_prop_name(spl_ce_SplFileInfo, "fileName", sizeof("fileName")-1, &pnlen TSRMLS_CC);
00586               spl_filesystem_object_get_path(intern, &path_len TSRMLS_CC);
00587               
00588               if (path_len && path_len < intern->file_name_len) {
00589                      add_assoc_stringl_ex(&zrv, pnstr, pnlen+1, intern->file_name + path_len + 1, intern->file_name_len - (path_len + 1), 1);
00590               } else {
00591                      add_assoc_stringl_ex(&zrv, pnstr, pnlen+1, intern->file_name, intern->file_name_len, 1);
00592               }
00593               efree(pnstr);
00594        }
00595        if (intern->type == SPL_FS_DIR) {
00596 #ifdef HAVE_GLOB
00597               pnstr = spl_gen_private_prop_name(spl_ce_DirectoryIterator, "glob", sizeof("glob")-1, &pnlen TSRMLS_CC);
00598               if (php_stream_is(intern->u.dir.dirp ,&php_glob_stream_ops)) {
00599                      add_assoc_stringl_ex(&zrv, pnstr, pnlen+1, intern->_path, intern->_path_len, 1);
00600               } else {
00601                      add_assoc_bool_ex(&zrv, pnstr, pnlen+1, 0);
00602               }
00603               efree(pnstr);
00604 #endif
00605               pnstr = spl_gen_private_prop_name(spl_ce_RecursiveDirectoryIterator, "subPathName", sizeof("subPathName")-1, &pnlen TSRMLS_CC);
00606               if (intern->u.dir.sub_path) {
00607                      add_assoc_stringl_ex(&zrv, pnstr, pnlen+1, intern->u.dir.sub_path, intern->u.dir.sub_path_len, 1);
00608               } else {
00609                      add_assoc_stringl_ex(&zrv, pnstr, pnlen+1, "", 0, 1);
00610               }
00611               efree(pnstr);
00612        }
00613        if (intern->type == SPL_FS_FILE) {
00614               pnstr = spl_gen_private_prop_name(spl_ce_SplFileObject, "openMode", sizeof("openMode")-1, &pnlen TSRMLS_CC);
00615               add_assoc_stringl_ex(&zrv, pnstr, pnlen+1, intern->u.file.open_mode, intern->u.file.open_mode_len, 1);
00616               efree(pnstr);
00617               stmp[1] = '\0';
00618               stmp[0] = intern->u.file.delimiter;
00619               pnstr = spl_gen_private_prop_name(spl_ce_SplFileObject, "delimiter", sizeof("delimiter")-1, &pnlen TSRMLS_CC);
00620               add_assoc_stringl_ex(&zrv, pnstr, pnlen+1, stmp, 1, 1);
00621               efree(pnstr);
00622               stmp[0] = intern->u.file.enclosure;
00623               pnstr = spl_gen_private_prop_name(spl_ce_SplFileObject, "enclosure", sizeof("enclosure")-1, &pnlen TSRMLS_CC);
00624               add_assoc_stringl_ex(&zrv, pnstr, pnlen+1, stmp, 1, 1);
00625               efree(pnstr);
00626        }
00627 
00628        return rv;
00629 }
00630 /* }}} */
00631 
00632 zend_function *spl_filesystem_object_get_method_check(zval **object_ptr, char *method, int method_len TSRMLS_DC) /* {{{ */
00633 {
00634        spl_filesystem_object *fsobj = zend_object_store_get_object(*object_ptr TSRMLS_CC);
00635        
00636        if (fsobj->u.dir.entry.d_name[0] == '\0' && fsobj->orig_path == NULL) {
00637               method = "_bad_state_ex";
00638               method_len = sizeof("_bad_state_ex") - 1;
00639        }
00640        
00641        return zend_get_std_object_handlers()->get_method(object_ptr, method, method_len TSRMLS_CC);
00642 }
00643 /* }}} */
00644 
00645 #define DIT_CTOR_FLAGS  0x00000001
00646 #define DIT_CTOR_GLOB   0x00000002
00647 
00648 void spl_filesystem_object_construct(INTERNAL_FUNCTION_PARAMETERS, long ctor_flags) /* {{{ */
00649 {
00650        spl_filesystem_object *intern;
00651        char *path;
00652        int parsed, len;
00653        long flags;
00654        zend_error_handling error_handling;
00655 
00656        zend_replace_error_handling(EH_THROW, spl_ce_UnexpectedValueException, &error_handling TSRMLS_CC);
00657 
00658        if (SPL_HAS_FLAG(ctor_flags, DIT_CTOR_FLAGS)) {
00659               flags = SPL_FILE_DIR_KEY_AS_PATHNAME|SPL_FILE_DIR_CURRENT_AS_FILEINFO;
00660               parsed = zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|l", &path, &len, &flags);
00661        } else {
00662               flags = SPL_FILE_DIR_KEY_AS_PATHNAME|SPL_FILE_DIR_CURRENT_AS_SELF;
00663               parsed = zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &path, &len);
00664        }
00665        if (SPL_HAS_FLAG(ctor_flags, SPL_FILE_DIR_SKIPDOTS)) {
00666               flags |= SPL_FILE_DIR_SKIPDOTS;
00667        }
00668        if (SPL_HAS_FLAG(ctor_flags, SPL_FILE_DIR_UNIXPATHS)) {
00669               flags |= SPL_FILE_DIR_UNIXPATHS;
00670        }
00671        if (parsed == FAILURE) {
00672               zend_restore_error_handling(&error_handling TSRMLS_CC);
00673               return;
00674        }
00675        if (!len) {
00676               zend_throw_exception_ex(spl_ce_RuntimeException, 0 TSRMLS_CC, "Directory name must not be empty.");
00677               zend_restore_error_handling(&error_handling TSRMLS_CC);
00678               return;
00679        }
00680 
00681        intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
00682        intern->flags = flags;
00683 #ifdef HAVE_GLOB
00684        if (SPL_HAS_FLAG(ctor_flags, DIT_CTOR_GLOB) && strstr(path, "glob://") != path) {
00685               spprintf(&path, 0, "glob://%s", path);
00686               spl_filesystem_dir_open(intern, path TSRMLS_CC);
00687               efree(path);
00688        } else
00689 #endif
00690        {
00691               spl_filesystem_dir_open(intern, path TSRMLS_CC);
00692 
00693        }
00694 
00695        intern->u.dir.is_recursive = instanceof_function(intern->std.ce, spl_ce_RecursiveDirectoryIterator TSRMLS_CC) ? 1 : 0;
00696 
00697        zend_restore_error_handling(&error_handling TSRMLS_CC);
00698 }
00699 /* }}} */
00700 
00701 /* {{{ proto void DirectoryIterator::__construct(string path)
00702  Cronstructs a new dir iterator from a path. */
00703 SPL_METHOD(DirectoryIterator, __construct)
00704 {
00705        spl_filesystem_object_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
00706 }
00707 /* }}} */
00708 
00709 /* {{{ proto void DirectoryIterator::rewind()
00710    Rewind dir back to the start */
00711 SPL_METHOD(DirectoryIterator, rewind)
00712 {
00713        spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
00714        
00715        if (zend_parse_parameters_none() == FAILURE) {
00716               return;
00717        }
00718 
00719        intern->u.dir.index = 0;
00720        if (intern->u.dir.dirp) {
00721               php_stream_rewinddir(intern->u.dir.dirp);
00722        }
00723        spl_filesystem_dir_read(intern TSRMLS_CC);
00724 }
00725 /* }}} */
00726 
00727 /* {{{ proto string DirectoryIterator::key()
00728    Return current dir entry */
00729 SPL_METHOD(DirectoryIterator, key)
00730 {
00731        spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
00732        
00733        if (zend_parse_parameters_none() == FAILURE) {
00734               return;
00735        }
00736 
00737        if (intern->u.dir.dirp) {
00738               RETURN_LONG(intern->u.dir.index);
00739        } else {
00740               RETURN_FALSE;
00741        }
00742 }
00743 /* }}} */
00744 
00745 /* {{{ proto DirectoryIterator DirectoryIterator::current()
00746    Return this (needed for Iterator interface) */
00747 SPL_METHOD(DirectoryIterator, current)
00748 {
00749        if (zend_parse_parameters_none() == FAILURE) {
00750               return;
00751        }
00752        RETURN_ZVAL(getThis(), 1, 0);
00753 }
00754 /* }}} */
00755 
00756 /* {{{ proto void DirectoryIterator::next()
00757    Move to next entry */
00758 SPL_METHOD(DirectoryIterator, next)
00759 {
00760        spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
00761        int skip_dots = SPL_HAS_FLAG(intern->flags, SPL_FILE_DIR_SKIPDOTS);
00762        
00763        if (zend_parse_parameters_none() == FAILURE) {
00764               return;
00765        }
00766 
00767        intern->u.dir.index++;
00768        do {
00769               spl_filesystem_dir_read(intern TSRMLS_CC);
00770        } while (skip_dots && spl_filesystem_is_dot(intern->u.dir.entry.d_name));
00771        if (intern->file_name) {
00772               efree(intern->file_name);
00773               intern->file_name = NULL;
00774        }
00775 }
00776 /* }}} */
00777 
00778 /* {{{ proto void DirectoryIterator::seek(int position)
00779    Seek to the given position */
00780 SPL_METHOD(DirectoryIterator, seek)
00781 {
00782        spl_filesystem_object *intern    = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
00783        zval                  *retval    = NULL;
00784        long                   pos;
00785 
00786        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &pos) == FAILURE) {
00787               return;
00788        }
00789 
00790        if (intern->u.dir.index > pos) {
00791               /* we first rewind */
00792               zend_call_method_with_0_params(&this_ptr, Z_OBJCE_P(getThis()), &intern->u.dir.func_rewind, "rewind", &retval);
00793               if (retval) {
00794                      zval_ptr_dtor(&retval);
00795               }
00796        }
00797 
00798        while (intern->u.dir.index < pos) {
00799               int valid = 0;
00800               zend_call_method_with_0_params(&this_ptr, Z_OBJCE_P(getThis()), &intern->u.dir.func_valid, "valid", &retval);
00801               if (retval) {
00802                      valid = zend_is_true(retval);
00803                      zval_ptr_dtor(&retval);
00804               }
00805               if (!valid) {
00806                      break;
00807               }
00808               zend_call_method_with_0_params(&this_ptr, Z_OBJCE_P(getThis()), &intern->u.dir.func_next, "next", &retval);
00809               if (retval) {
00810                      zval_ptr_dtor(&retval);
00811               }
00812        }
00813 } /* }}} */
00814 
00815 /* {{{ proto string DirectoryIterator::valid()
00816    Check whether dir contains more entries */
00817 SPL_METHOD(DirectoryIterator, valid)
00818 {
00819        spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
00820        
00821        if (zend_parse_parameters_none() == FAILURE) {
00822               return;
00823        }
00824 
00825        RETURN_BOOL(intern->u.dir.entry.d_name[0] != '\0');
00826 }
00827 /* }}} */
00828 
00829 /* {{{ proto string SplFileInfo::getPath()
00830    Return the path */
00831 SPL_METHOD(SplFileInfo, getPath)
00832 {
00833        spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
00834        char *path;
00835        int path_len;
00836        
00837        if (zend_parse_parameters_none() == FAILURE) {
00838               return;
00839        }
00840 
00841        path = spl_filesystem_object_get_path(intern, &path_len TSRMLS_CC);
00842        RETURN_STRINGL(path, path_len, 1);
00843 }
00844 /* }}} */
00845 
00846 /* {{{ proto string SplFileInfo::getFilename()
00847    Return filename only */
00848 SPL_METHOD(SplFileInfo, getFilename)
00849 {
00850        spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
00851        int path_len;
00852        
00853        if (zend_parse_parameters_none() == FAILURE) {
00854               return;
00855        }
00856 
00857        spl_filesystem_object_get_path(intern, &path_len TSRMLS_CC);
00858        
00859        if (path_len && path_len < intern->file_name_len) {
00860               RETURN_STRINGL(intern->file_name + path_len + 1, intern->file_name_len - (path_len + 1), 1);
00861        } else {
00862               RETURN_STRINGL(intern->file_name, intern->file_name_len, 1);
00863        }
00864 }
00865 /* }}} */
00866 
00867 /* {{{ proto string DirectoryIterator::getFilename()
00868    Return filename of current dir entry */
00869 SPL_METHOD(DirectoryIterator, getFilename)
00870 {
00871        spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
00872        
00873        if (zend_parse_parameters_none() == FAILURE) {
00874               return;
00875        }
00876 
00877        RETURN_STRING(intern->u.dir.entry.d_name, 1);
00878 }
00879 /* }}} */
00880 
00881 /* {{{ proto string SplFileInfo::getExtension()
00882    Returns file extension component of path */
00883 SPL_METHOD(SplFileInfo, getExtension)
00884 {
00885        spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
00886        char *fname = NULL;
00887        const char *p;
00888        size_t flen;
00889        int path_len, idx;
00890 
00891        if (zend_parse_parameters_none() == FAILURE) {
00892               return;
00893        }
00894 
00895        spl_filesystem_object_get_path(intern, &path_len TSRMLS_CC);
00896 
00897        if (path_len && path_len < intern->file_name_len) {
00898               fname = intern->file_name + path_len + 1;
00899               flen = intern->file_name_len - (path_len + 1);
00900        } else {
00901               fname = intern->file_name;
00902               flen = intern->file_name_len;
00903        }
00904 
00905        php_basename(fname, flen, NULL, 0, &fname, &flen TSRMLS_CC);
00906 
00907        p = zend_memrchr(fname, '.', flen);
00908        if (p) {
00909               idx = p - fname;
00910               RETVAL_STRINGL(fname + idx + 1, flen - idx - 1, 1);
00911               efree(fname);
00912               return;
00913        } else {
00914               if (fname) {
00915                      efree(fname);
00916               }
00917               RETURN_EMPTY_STRING();
00918        }
00919 }
00920 /* }}}*/
00921 
00922 /* {{{ proto string DirectoryIterator::getExtension()
00923    Returns the file extension component of path */
00924 SPL_METHOD(DirectoryIterator, getExtension)
00925 {
00926        spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
00927        char *fname = NULL;
00928        const char *p;
00929        size_t flen;
00930        int idx;
00931 
00932        if (zend_parse_parameters_none() == FAILURE) {
00933               return;
00934        }
00935 
00936        php_basename(intern->u.dir.entry.d_name, strlen(intern->u.dir.entry.d_name), NULL, 0, &fname, &flen TSRMLS_CC);
00937 
00938        p = zend_memrchr(fname, '.', flen);
00939        if (p) {
00940               idx = p - fname;
00941               RETVAL_STRINGL(fname + idx + 1, flen - idx - 1, 1);
00942               efree(fname);
00943               return;
00944        } else {
00945               if (fname) {
00946                      efree(fname);
00947               }
00948               RETURN_EMPTY_STRING();
00949        }
00950 }
00951 /* }}} */
00952 
00953 /* {{{ proto string SplFileInfo::getBasename([string $suffix]) U
00954    Returns filename component of path */
00955 SPL_METHOD(SplFileInfo, getBasename)
00956 {
00957        spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
00958        char *fname, *suffix = 0;
00959        size_t flen;
00960        int slen = 0, path_len;
00961 
00962        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &suffix, &slen) == FAILURE) {
00963               return;
00964        }
00965 
00966        spl_filesystem_object_get_path(intern, &path_len TSRMLS_CC);
00967 
00968        if (path_len && path_len < intern->file_name_len) {
00969               fname = intern->file_name + path_len + 1;
00970               flen = intern->file_name_len - (path_len + 1);
00971        } else {
00972               fname = intern->file_name;
00973               flen = intern->file_name_len;
00974        }
00975 
00976        php_basename(fname, flen, suffix, slen, &fname, &flen TSRMLS_CC);
00977 
00978        RETURN_STRINGL(fname, flen, 0);
00979 }
00980 /* }}}*/   
00981 
00982 /* {{{ proto string DirectoryIterator::getBasename([string $suffix]) U
00983    Returns filename component of current dir entry */
00984 SPL_METHOD(DirectoryIterator, getBasename)
00985 {
00986        spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
00987        char *suffix = 0, *fname;
00988        int slen = 0;
00989        size_t flen;
00990        
00991        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &suffix, &slen) == FAILURE) {
00992               return;
00993        }
00994 
00995        php_basename(intern->u.dir.entry.d_name, strlen(intern->u.dir.entry.d_name), suffix, slen, &fname, &flen TSRMLS_CC);
00996 
00997        RETURN_STRINGL(fname, flen, 0);
00998 }
00999 /* }}} */
01000 
01001 /* {{{ proto string SplFileInfo::getPathname()
01002    Return path and filename */
01003 SPL_METHOD(SplFileInfo, getPathname)
01004 {
01005        spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
01006        char *path;
01007        int path_len;
01008 
01009        if (zend_parse_parameters_none() == FAILURE) {
01010               return;
01011        }
01012        path = spl_filesystem_object_get_pathname(intern, &path_len TSRMLS_CC);
01013        if (path != NULL) {
01014               RETURN_STRINGL(path, path_len, 1);
01015        } else {
01016               RETURN_FALSE;
01017        }
01018 }
01019 /* }}} */
01020 
01021 /* {{{ proto string FilesystemIterator::key()
01022    Return getPathname() or getFilename() depending on flags */
01023 SPL_METHOD(FilesystemIterator, key)
01024 {
01025        spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
01026        
01027        if (zend_parse_parameters_none() == FAILURE) {
01028               return;
01029        }
01030 
01031        if (SPL_FILE_DIR_KEY(intern, SPL_FILE_DIR_KEY_AS_FILENAME)) {
01032               RETURN_STRING(intern->u.dir.entry.d_name, 1);
01033        } else {
01034               spl_filesystem_object_get_file_name(intern TSRMLS_CC);
01035               RETURN_STRINGL(intern->file_name, intern->file_name_len, 1);
01036        }
01037 }
01038 /* }}} */
01039 
01040 /* {{{ proto string FilesystemIterator::current()
01041    Return getFilename(), getFileInfo() or $this depending on flags */
01042 SPL_METHOD(FilesystemIterator, current)
01043 {
01044        spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
01045        
01046        if (zend_parse_parameters_none() == FAILURE) {
01047               return;
01048        }
01049 
01050        if (SPL_FILE_DIR_CURRENT(intern, SPL_FILE_DIR_CURRENT_AS_PATHNAME)) {
01051               spl_filesystem_object_get_file_name(intern TSRMLS_CC);
01052               RETURN_STRINGL(intern->file_name, intern->file_name_len, 1);
01053        } else if (SPL_FILE_DIR_CURRENT(intern, SPL_FILE_DIR_CURRENT_AS_FILEINFO)) {
01054               spl_filesystem_object_get_file_name(intern TSRMLS_CC);
01055               spl_filesystem_object_create_type(0, intern, SPL_FS_INFO, NULL, return_value TSRMLS_CC);
01056        } else {
01057               RETURN_ZVAL(getThis(), 1, 0);
01058               /*RETURN_STRING(intern->u.dir.entry.d_name, 1);*/
01059        }
01060 }
01061 /* }}} */
01062 
01063 /* {{{ proto bool DirectoryIterator::isDot()
01064    Returns true if current entry is '.' or  '..' */
01065 SPL_METHOD(DirectoryIterator, isDot)
01066 {
01067        spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
01068        
01069        if (zend_parse_parameters_none() == FAILURE) {
01070               return;
01071        }
01072 
01073        RETURN_BOOL(spl_filesystem_is_dot(intern->u.dir.entry.d_name));
01074 }
01075 /* }}} */
01076 
01077 /* {{{ proto void SplFileInfo::__construct(string file_name)
01078  Cronstructs a new SplFileInfo from a path. */
01079 /* zend_replace_error_handling() is used to throw exceptions in case
01080    the constructor fails. Here we use this to ensure the object
01081    has a valid directory resource.
01082    
01083    When the constructor gets called the object is already created 
01084    by the engine, so we must only call 'additional' initializations.
01085  */
01086 SPL_METHOD(SplFileInfo, __construct)
01087 {
01088        spl_filesystem_object *intern;
01089        char *path;
01090        int len;
01091        zend_error_handling error_handling;
01092 
01093        zend_replace_error_handling(EH_THROW, spl_ce_RuntimeException, &error_handling TSRMLS_CC);
01094 
01095        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &path, &len) == FAILURE) {
01096               zend_restore_error_handling(&error_handling TSRMLS_CC);
01097               return;
01098        }
01099 
01100        intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
01101        
01102        spl_filesystem_info_set_filename(intern, path, len, 1 TSRMLS_CC);
01103 
01104        zend_restore_error_handling(&error_handling TSRMLS_CC);
01105        
01106        /* intern->type = SPL_FS_INFO; already set */
01107 }
01108 /* }}} */
01109 
01110 /* {{{ FileInfoFunction */
01111 #define FileInfoFunction(func_name, func_num) \
01112 SPL_METHOD(SplFileInfo, func_name) \
01113 { \
01114        spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC); \
01115        zend_error_handling error_handling; \
01116        if (zend_parse_parameters_none() == FAILURE) { \
01117               return; \
01118        } \
01119  \
01120        zend_replace_error_handling(EH_THROW, spl_ce_RuntimeException, &error_handling TSRMLS_CC);\
01121        spl_filesystem_object_get_file_name(intern TSRMLS_CC); \
01122        php_stat(intern->file_name, intern->file_name_len, func_num, return_value TSRMLS_CC); \
01123        zend_restore_error_handling(&error_handling TSRMLS_CC); \
01124 }
01125 /* }}} */
01126 
01127 /* {{{ proto int SplFileInfo::getPerms()
01128    Get file permissions */
01129 FileInfoFunction(getPerms, FS_PERMS)
01130 /* }}} */
01131 
01132 /* {{{ proto int SplFileInfo::getInode()
01133    Get file inode */
01134 FileInfoFunction(getInode, FS_INODE)
01135 /* }}} */
01136 
01137 /* {{{ proto int SplFileInfo::getSize()
01138    Get file size */
01139 FileInfoFunction(getSize, FS_SIZE)
01140 /* }}} */
01141 
01142 /* {{{ proto int SplFileInfo::getOwner()
01143    Get file owner */
01144 FileInfoFunction(getOwner, FS_OWNER)
01145 /* }}} */
01146 
01147 /* {{{ proto int SplFileInfo::getGroup()
01148    Get file group */
01149 FileInfoFunction(getGroup, FS_GROUP)
01150 /* }}} */
01151 
01152 /* {{{ proto int SplFileInfo::getATime()
01153    Get last access time of file */
01154 FileInfoFunction(getATime, FS_ATIME)
01155 /* }}} */
01156 
01157 /* {{{ proto int SplFileInfo::getMTime()
01158    Get last modification time of file */
01159 FileInfoFunction(getMTime, FS_MTIME)
01160 /* }}} */
01161 
01162 /* {{{ proto int SplFileInfo::getCTime()
01163    Get inode modification time of file */
01164 FileInfoFunction(getCTime, FS_CTIME)
01165 /* }}} */
01166 
01167 /* {{{ proto string SplFileInfo::getType()
01168    Get file type */
01169 FileInfoFunction(getType, FS_TYPE)
01170 /* }}} */
01171 
01172 /* {{{ proto bool SplFileInfo::isWritable()
01173    Returns true if file can be written */
01174 FileInfoFunction(isWritable, FS_IS_W)
01175 /* }}} */
01176 
01177 /* {{{ proto bool SplFileInfo::isReadable()
01178    Returns true if file can be read */
01179 FileInfoFunction(isReadable, FS_IS_R)
01180 /* }}} */
01181 
01182 /* {{{ proto bool SplFileInfo::isExecutable()
01183    Returns true if file is executable */
01184 FileInfoFunction(isExecutable, FS_IS_X)
01185 /* }}} */
01186 
01187 /* {{{ proto bool SplFileInfo::isFile()
01188    Returns true if file is a regular file */
01189 FileInfoFunction(isFile, FS_IS_FILE)
01190 /* }}} */
01191 
01192 /* {{{ proto bool SplFileInfo::isDir()
01193    Returns true if file is directory */
01194 FileInfoFunction(isDir, FS_IS_DIR)
01195 /* }}} */
01196 
01197 /* {{{ proto bool SplFileInfo::isLink()
01198    Returns true if file is symbolic link */
01199 FileInfoFunction(isLink, FS_IS_LINK)
01200 /* }}} */
01201 
01202 /* {{{ proto string SplFileInfo::getLinkTarget() U
01203    Return the target of a symbolic link */
01204 SPL_METHOD(SplFileInfo, getLinkTarget)
01205 {
01206        spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
01207        int ret;
01208        char buff[MAXPATHLEN];
01209        zend_error_handling error_handling;
01210        
01211        if (zend_parse_parameters_none() == FAILURE) {
01212               return;
01213        }
01214 
01215        zend_replace_error_handling(EH_THROW, spl_ce_RuntimeException, &error_handling TSRMLS_CC);
01216 
01217 #if defined(PHP_WIN32) || HAVE_SYMLINK
01218        if (intern->file_name == NULL) {
01219               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Empty filename");
01220               RETURN_FALSE;
01221        } else if (!IS_ABSOLUTE_PATH(intern->file_name, intern->file_name_len)) {
01222               char expanded_path[MAXPATHLEN];
01223 
01224               /* TODO: Fix expand_filepath to do not resolve links but only expand the path
01225                  avoiding double two resolution attempts
01226                  (Pierre) */
01227               if (!expand_filepath(intern->file_name, expanded_path TSRMLS_CC)) {
01228                      php_error_docref(NULL TSRMLS_CC, E_WARNING, "No such file or directory");
01229                      RETURN_FALSE;
01230               }
01231               ret = php_sys_readlink(expanded_path, buff, MAXPATHLEN - 1);
01232        } else {
01233               ret = php_sys_readlink(intern->file_name, buff,  MAXPATHLEN-1);
01234        }
01235 #else
01236        ret = -1; /* always fail if not implemented */
01237 #endif
01238 
01239        if (ret == -1) {
01240               zend_throw_exception_ex(spl_ce_RuntimeException, 0 TSRMLS_CC, "Unable to read link %s, error: %s", intern->file_name, strerror(errno));
01241               RETVAL_FALSE;
01242        } else {
01243               /* Append NULL to the end of the string */
01244               buff[ret] = '\0';
01245 
01246               RETVAL_STRINGL(buff, ret, 1);
01247        }
01248 
01249        zend_restore_error_handling(&error_handling TSRMLS_CC);
01250 }
01251 /* }}} */
01252 
01253 #if (!defined(__BEOS__) && !defined(NETWARE) && HAVE_REALPATH) || defined(ZTS)
01254 /* {{{ proto string SplFileInfo::getRealPath()
01255    Return the resolved path */
01256 SPL_METHOD(SplFileInfo, getRealPath)
01257 {
01258        spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
01259        char buff[MAXPATHLEN];
01260        char *filename;
01261        zend_error_handling error_handling;
01262        
01263        if (zend_parse_parameters_none() == FAILURE) {
01264               return;
01265        }
01266 
01267        zend_replace_error_handling(EH_THROW, spl_ce_RuntimeException, &error_handling TSRMLS_CC);
01268 
01269        if (intern->type == SPL_FS_DIR && !intern->file_name && intern->u.dir.entry.d_name[0]) {
01270               spl_filesystem_object_get_file_name(intern TSRMLS_CC);
01271        }
01272        
01273        if (intern->orig_path) {
01274               filename = intern->orig_path;
01275        } else { 
01276               filename = intern->file_name;
01277        }
01278 
01279 
01280        if (filename && VCWD_REALPATH(filename, buff)) {
01281 #ifdef ZTS
01282               if (VCWD_ACCESS(buff, F_OK)) {
01283                      RETVAL_FALSE;
01284               } else
01285 #endif
01286               RETVAL_STRING(buff, 1);
01287        } else {
01288               RETVAL_FALSE;
01289        }
01290 
01291        zend_restore_error_handling(&error_handling TSRMLS_CC);
01292 }
01293 /* }}} */
01294 #endif
01295 
01296 /* {{{ proto SplFileObject SplFileInfo::openFile([string mode = 'r' [, bool use_include_path  [, resource context]]])
01297    Open the current file */
01298 SPL_METHOD(SplFileInfo, openFile)
01299 {
01300        spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
01301 
01302        spl_filesystem_object_create_type(ht, intern, SPL_FS_FILE, NULL, return_value TSRMLS_CC);
01303 }
01304 /* }}} */
01305 
01306 /* {{{ proto void SplFileInfo::setFileClass([string class_name])
01307    Class to use in openFile() */
01308 SPL_METHOD(SplFileInfo, setFileClass)
01309 {
01310        spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
01311        zend_class_entry *ce = spl_ce_SplFileObject;
01312        zend_error_handling error_handling;
01313        
01314        zend_replace_error_handling(EH_THROW, spl_ce_UnexpectedValueException, &error_handling TSRMLS_CC);
01315 
01316        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|C", &ce) == SUCCESS) {
01317               intern->file_class = ce;
01318        }
01319 
01320        zend_restore_error_handling(&error_handling TSRMLS_CC);
01321 }
01322 /* }}} */
01323 
01324 /* {{{ proto void SplFileInfo::setInfoClass([string class_name])
01325    Class to use in getFileInfo(), getPathInfo() */
01326 SPL_METHOD(SplFileInfo, setInfoClass)
01327 {
01328        spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
01329        zend_class_entry *ce = spl_ce_SplFileInfo;
01330        zend_error_handling error_handling;
01331        
01332        zend_replace_error_handling(EH_THROW, spl_ce_UnexpectedValueException, &error_handling  TSRMLS_CC);
01333 
01334        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|C", &ce) == SUCCESS) {
01335               intern->info_class = ce;
01336        }
01337 
01338        zend_restore_error_handling(&error_handling TSRMLS_CC);
01339 }
01340 /* }}} */
01341 
01342 /* {{{ proto SplFileInfo SplFileInfo::getFileInfo([string $class_name])
01343    Get/copy file info */
01344 SPL_METHOD(SplFileInfo, getFileInfo)
01345 {
01346        spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
01347        zend_class_entry *ce = intern->info_class;
01348        zend_error_handling error_handling;
01349        
01350        zend_replace_error_handling(EH_THROW, spl_ce_UnexpectedValueException, &error_handling TSRMLS_CC);
01351 
01352        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|C", &ce) == SUCCESS) {
01353               spl_filesystem_object_create_type(ht, intern, SPL_FS_INFO, ce, return_value TSRMLS_CC);
01354        }
01355 
01356        zend_restore_error_handling(&error_handling TSRMLS_CC);
01357 }
01358 /* }}} */
01359 
01360 /* {{{ proto SplFileInfo SplFileInfo::getPathInfo([string $class_name])
01361    Get/copy file info */
01362 SPL_METHOD(SplFileInfo, getPathInfo)
01363 {
01364        spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
01365        zend_class_entry *ce = intern->info_class;
01366        zend_error_handling error_handling;
01367        
01368        zend_replace_error_handling(EH_THROW, spl_ce_UnexpectedValueException, &error_handling TSRMLS_CC);
01369 
01370        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|C", &ce) == SUCCESS) {
01371               int path_len;
01372               char *path = spl_filesystem_object_get_pathname(intern, &path_len TSRMLS_CC);
01373               if (path) {
01374                      char *dpath = estrndup(path, path_len);
01375                      path_len = php_dirname(dpath, path_len);
01376                      spl_filesystem_object_create_info(intern, dpath, path_len, 1, ce, return_value TSRMLS_CC);
01377                      efree(dpath);
01378               }
01379        }
01380 
01381        zend_restore_error_handling(&error_handling TSRMLS_CC);
01382 }
01383 /* }}} */
01384 
01385 /* {{{ */
01386 SPL_METHOD(SplFileInfo, _bad_state_ex)
01387 {
01388        zend_throw_exception_ex(spl_ce_LogicException, 0 TSRMLS_CC,
01389               "The parent constructor was not called: the object is in an "
01390               "invalid state ");
01391 }
01392 /* }}} */
01393 
01394 /* {{{ proto void FilesystemIterator::__construct(string path [, int flags])
01395  Cronstructs a new dir iterator from a path. */
01396 SPL_METHOD(FilesystemIterator, __construct)
01397 {
01398        spl_filesystem_object_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, DIT_CTOR_FLAGS | SPL_FILE_DIR_SKIPDOTS);
01399 }
01400 /* }}} */
01401 
01402 /* {{{ proto void FilesystemIterator::rewind()
01403    Rewind dir back to the start */
01404 SPL_METHOD(FilesystemIterator, rewind)
01405 {
01406        spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
01407 
01408        if (zend_parse_parameters_none() == FAILURE) {
01409               return;
01410        }
01411 
01412        intern->u.dir.index = 0;
01413        if (intern->u.dir.dirp) {
01414               php_stream_rewinddir(intern->u.dir.dirp);
01415        }
01416        do {
01417               spl_filesystem_dir_read(intern TSRMLS_CC);
01418        } while (spl_filesystem_is_dot(intern->u.dir.entry.d_name));
01419 }
01420 /* }}} */
01421 
01422 /* {{{ proto int FilesystemIterator::getFlags()
01423    Get handling flags */
01424 SPL_METHOD(FilesystemIterator, getFlags)
01425 {
01426        spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
01427        
01428        if (zend_parse_parameters_none() == FAILURE) {
01429               return;
01430        }
01431 
01432        RETURN_LONG(intern->flags & (SPL_FILE_DIR_KEY_MODE_MASK | SPL_FILE_DIR_CURRENT_MODE_MASK | SPL_FILE_DIR_OTHERS_MASK));
01433 } /* }}} */
01434 
01435 /* {{{ proto void FilesystemIterator::setFlags(long $flags)
01436    Set handling flags */
01437 SPL_METHOD(FilesystemIterator, setFlags)
01438 {
01439        spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
01440        long flags;
01441 
01442        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &flags) == FAILURE) {
01443               return;
01444        }
01445 
01446        intern->flags &= ~(SPL_FILE_DIR_KEY_MODE_MASK|SPL_FILE_DIR_CURRENT_MODE_MASK|SPL_FILE_DIR_OTHERS_MASK);
01447        intern->flags |= ((SPL_FILE_DIR_KEY_MODE_MASK|SPL_FILE_DIR_CURRENT_MODE_MASK|SPL_FILE_DIR_OTHERS_MASK) & flags);
01448 } /* }}} */
01449 
01450 /* {{{ proto bool RecursiveDirectoryIterator::hasChildren([bool $allow_links = false])
01451    Returns whether current entry is a directory and not '.' or '..' */
01452 SPL_METHOD(RecursiveDirectoryIterator, hasChildren)
01453 {
01454        zend_bool allow_links = 0;
01455        spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
01456 
01457        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b", &allow_links) == FAILURE) {
01458               return;
01459        }
01460        if (spl_filesystem_is_invalid_or_dot(intern->u.dir.entry.d_name)) {
01461               RETURN_FALSE;
01462        } else {
01463               spl_filesystem_object_get_file_name(intern TSRMLS_CC);
01464               if (!allow_links && !(intern->flags & SPL_FILE_DIR_FOLLOW_SYMLINKS)) {
01465                      php_stat(intern->file_name, intern->file_name_len, FS_IS_LINK, return_value TSRMLS_CC);
01466                      if (zend_is_true(return_value)) {
01467                             RETURN_FALSE;
01468                      }
01469               }
01470               php_stat(intern->file_name, intern->file_name_len, FS_IS_DIR, return_value TSRMLS_CC);
01471     }
01472 }
01473 /* }}} */
01474 
01475 /* {{{ proto RecursiveDirectoryIterator DirectoryIterator::getChildren()
01476    Returns an iterator for the current entry if it is a directory */
01477 SPL_METHOD(RecursiveDirectoryIterator, getChildren)
01478 {
01479        zval zpath, zflags;
01480        spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
01481        spl_filesystem_object *subdir;
01482        char slash = SPL_HAS_FLAG(intern->flags, SPL_FILE_DIR_UNIXPATHS) ? '/' : DEFAULT_SLASH;
01483        
01484        if (zend_parse_parameters_none() == FAILURE) {
01485               return;
01486        }
01487        
01488        spl_filesystem_object_get_file_name(intern TSRMLS_CC);
01489 
01490        if (SPL_HAS_FLAG(intern->flags, SPL_FILE_DIR_CURRENT_AS_PATHNAME)) {
01491               RETURN_STRINGL(intern->file_name, intern->file_name_len, 1);
01492        } else {
01493               INIT_PZVAL(&zflags);
01494               INIT_PZVAL(&zpath);
01495               ZVAL_LONG(&zflags, intern->flags);
01496               ZVAL_STRINGL(&zpath, intern->file_name, intern->file_name_len, 0);
01497               spl_instantiate_arg_ex2(Z_OBJCE_P(getThis()), &return_value, 0, &zpath, &zflags TSRMLS_CC);
01498               
01499               subdir = (spl_filesystem_object*)zend_object_store_get_object(return_value TSRMLS_CC);
01500               if (subdir) {
01501                      if (intern->u.dir.sub_path && intern->u.dir.sub_path[0]) {
01502                             subdir->u.dir.sub_path_len = spprintf(&subdir->u.dir.sub_path, 0, "%s%c%s", intern->u.dir.sub_path, slash, intern->u.dir.entry.d_name);
01503                      } else {
01504                             subdir->u.dir.sub_path_len = strlen(intern->u.dir.entry.d_name);
01505                             subdir->u.dir.sub_path = estrndup(intern->u.dir.entry.d_name, subdir->u.dir.sub_path_len);
01506                      }
01507                      subdir->info_class = intern->info_class;
01508                      subdir->file_class = intern->file_class;
01509                      subdir->oth = intern->oth;
01510               }
01511        }
01512 }
01513 /* }}} */
01514 
01515 /* {{{ proto void RecursiveDirectoryIterator::getSubPath()
01516    Get sub path */
01517 SPL_METHOD(RecursiveDirectoryIterator, getSubPath)
01518 {
01519        spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
01520        
01521        if (zend_parse_parameters_none() == FAILURE) {
01522               return;
01523        }
01524 
01525        if (intern->u.dir.sub_path) {
01526               RETURN_STRINGL(intern->u.dir.sub_path, intern->u.dir.sub_path_len, 1);
01527        } else {
01528               RETURN_STRINGL("", 0, 1);
01529        }
01530 }
01531 /* }}} */
01532 
01533 /* {{{ proto void RecursiveDirectoryIterator::getSubPathname()
01534    Get sub path and file name */
01535 SPL_METHOD(RecursiveDirectoryIterator, getSubPathname)
01536 {
01537        spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
01538        char *sub_name;
01539        int len;
01540        char slash = SPL_HAS_FLAG(intern->flags, SPL_FILE_DIR_UNIXPATHS) ? '/' : DEFAULT_SLASH;
01541        
01542        if (zend_parse_parameters_none() == FAILURE) {
01543               return;
01544        }
01545 
01546        if (intern->u.dir.sub_path) {
01547               len = spprintf(&sub_name, 0, "%s%c%s", intern->u.dir.sub_path, slash, intern->u.dir.entry.d_name);
01548               RETURN_STRINGL(sub_name, len, 0);
01549        } else {
01550               RETURN_STRING(intern->u.dir.entry.d_name, 1);
01551        }
01552 }
01553 /* }}} */
01554 
01555 /* {{{ proto int RecursiveDirectoryIterator::__construct(string path [, int flags])
01556  Cronstructs a new dir iterator from a path. */
01557 SPL_METHOD(RecursiveDirectoryIterator, __construct)
01558 {
01559        spl_filesystem_object_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, DIT_CTOR_FLAGS);
01560 }
01561 /* }}} */
01562 
01563 #ifdef HAVE_GLOB
01564 /* {{{ proto int GlobIterator::__construct(string path [, int flags])
01565  Cronstructs a new dir iterator from a glob expression (no glob:// needed). */
01566 SPL_METHOD(GlobIterator, __construct)
01567 {
01568        spl_filesystem_object_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, DIT_CTOR_FLAGS|DIT_CTOR_GLOB);
01569 }
01570 /* }}} */
01571 
01572 /* {{{ proto int GlobIterator::cont()
01573    Return the number of directories and files found by globbing */
01574 SPL_METHOD(GlobIterator, count)
01575 {
01576        spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
01577        
01578        if (zend_parse_parameters_none() == FAILURE) {
01579               return;
01580        }
01581 
01582        if (php_stream_is(intern->u.dir.dirp ,&php_glob_stream_ops)) {
01583               RETURN_LONG(php_glob_stream_get_count(intern->u.dir.dirp, NULL));
01584        } else {
01585               /* should not happen */
01586               php_error_docref(NULL TSRMLS_CC, E_ERROR, "GlobIterator lost glob state");
01587        }
01588 }
01589 /* }}} */
01590 #endif /* HAVE_GLOB */
01591 
01592 /* {{{ forward declarations to the iterator handlers */
01593 static void spl_filesystem_dir_it_dtor(zend_object_iterator *iter TSRMLS_DC);
01594 static int spl_filesystem_dir_it_valid(zend_object_iterator *iter TSRMLS_DC);
01595 static void spl_filesystem_dir_it_current_data(zend_object_iterator *iter, zval ***data TSRMLS_DC);
01596 static int spl_filesystem_dir_it_current_key(zend_object_iterator *iter, char **str_key, uint *str_key_len, ulong *int_key TSRMLS_DC);
01597 static void spl_filesystem_dir_it_move_forward(zend_object_iterator *iter TSRMLS_DC);
01598 static void spl_filesystem_dir_it_rewind(zend_object_iterator *iter TSRMLS_DC);
01599 
01600 /* iterator handler table */
01601 zend_object_iterator_funcs spl_filesystem_dir_it_funcs = {
01602        spl_filesystem_dir_it_dtor,
01603        spl_filesystem_dir_it_valid,
01604        spl_filesystem_dir_it_current_data,
01605        spl_filesystem_dir_it_current_key,
01606        spl_filesystem_dir_it_move_forward,
01607        spl_filesystem_dir_it_rewind
01608 };
01609 /* }}} */
01610 
01611 /* {{{ spl_ce_dir_get_iterator */
01612 zend_object_iterator *spl_filesystem_dir_get_iterator(zend_class_entry *ce, zval *object, int by_ref TSRMLS_DC)
01613 {
01614        spl_filesystem_iterator *iterator;
01615        spl_filesystem_object   *dir_object;
01616 
01617        if (by_ref) {
01618               zend_error(E_ERROR, "An iterator cannot be used with foreach by reference");
01619        }
01620        dir_object = (spl_filesystem_object*)zend_object_store_get_object(object TSRMLS_CC);
01621        iterator   = spl_filesystem_object_to_iterator(dir_object);
01622 
01623        Z_SET_REFCOUNT_P(object, Z_REFCOUNT_P(object) + 2);
01624        iterator->intern.data = (void*)object;
01625        iterator->intern.funcs = &spl_filesystem_dir_it_funcs;
01626        iterator->current = object;
01627        
01628        return (zend_object_iterator*)iterator;
01629 }
01630 /* }}} */
01631 
01632 /* {{{ spl_filesystem_dir_it_dtor */
01633 static void spl_filesystem_dir_it_dtor(zend_object_iterator *iter TSRMLS_DC)
01634 {
01635        spl_filesystem_iterator *iterator = (spl_filesystem_iterator *)iter;
01636        zval *zfree = (zval*)iterator->intern.data;
01637 
01638        iterator->intern.data = NULL; /* mark as unused */
01639        zval_ptr_dtor(&iterator->current);
01640        if (zfree) {
01641               zval_ptr_dtor(&zfree);
01642        }
01643 }
01644 /* }}} */
01645 
01646 /* {{{ spl_filesystem_dir_it_valid */
01647 static int spl_filesystem_dir_it_valid(zend_object_iterator *iter TSRMLS_DC)
01648 {
01649        spl_filesystem_object *object = spl_filesystem_iterator_to_object((spl_filesystem_iterator *)iter);
01650 
01651        return object->u.dir.entry.d_name[0] != '\0' ? SUCCESS : FAILURE;
01652 }
01653 /* }}} */
01654 
01655 /* {{{ spl_filesystem_dir_it_current_data */
01656 static void spl_filesystem_dir_it_current_data(zend_object_iterator *iter, zval ***data TSRMLS_DC)
01657 {
01658        spl_filesystem_iterator *iterator = (spl_filesystem_iterator *)iter;
01659        
01660        *data = &iterator->current;
01661 }
01662 /* }}} */
01663 
01664 /* {{{ spl_filesystem_dir_it_current_key */
01665 static int spl_filesystem_dir_it_current_key(zend_object_iterator *iter, char **str_key, uint *str_key_len, ulong *int_key TSRMLS_DC)
01666 {
01667        spl_filesystem_object *object = spl_filesystem_iterator_to_object((spl_filesystem_iterator *)iter);
01668        
01669        *int_key = object->u.dir.index;
01670        return HASH_KEY_IS_LONG;
01671 }
01672 /* }}} */
01673 
01674 /* {{{ spl_filesystem_dir_it_move_forward */
01675 static void spl_filesystem_dir_it_move_forward(zend_object_iterator *iter TSRMLS_DC)
01676 {
01677        spl_filesystem_object *object = spl_filesystem_iterator_to_object((spl_filesystem_iterator *)iter);
01678        
01679        object->u.dir.index++;
01680        spl_filesystem_dir_read(object TSRMLS_CC);
01681        if (object->file_name) {
01682               efree(object->file_name);
01683               object->file_name = NULL;
01684        }
01685 }
01686 /* }}} */
01687 
01688 /* {{{ spl_filesystem_dir_it_rewind */
01689 static void spl_filesystem_dir_it_rewind(zend_object_iterator *iter TSRMLS_DC)
01690 {
01691        spl_filesystem_object *object = spl_filesystem_iterator_to_object((spl_filesystem_iterator *)iter);
01692        
01693        object->u.dir.index = 0;
01694        if (object->u.dir.dirp) {
01695               php_stream_rewinddir(object->u.dir.dirp);
01696        }
01697        spl_filesystem_dir_read(object TSRMLS_CC);
01698 }
01699 /* }}} */
01700 
01701 /* {{{ spl_filesystem_tree_it_dtor */
01702 static void spl_filesystem_tree_it_dtor(zend_object_iterator *iter TSRMLS_DC)
01703 {
01704        spl_filesystem_iterator *iterator = (spl_filesystem_iterator *)iter;
01705        zval *zfree = (zval*)iterator->intern.data;
01706 
01707        if (iterator->current) {
01708               zval_ptr_dtor(&iterator->current);
01709        }
01710        iterator->intern.data = NULL; /* mark as unused */
01711        /* free twice as we add ref twice */
01712        zval_ptr_dtor(&zfree);
01713        zval_ptr_dtor(&zfree);
01714 }
01715 /* }}} */
01716 
01717 /* {{{ spl_filesystem_tree_it_current_data */
01718 static void spl_filesystem_tree_it_current_data(zend_object_iterator *iter, zval ***data TSRMLS_DC)
01719 {
01720        spl_filesystem_iterator *iterator = (spl_filesystem_iterator *)iter;
01721        spl_filesystem_object   *object   = spl_filesystem_iterator_to_object(iterator);
01722 
01723        if (SPL_FILE_DIR_CURRENT(object, SPL_FILE_DIR_CURRENT_AS_PATHNAME)) {
01724               if (!iterator->current) {
01725                      ALLOC_INIT_ZVAL(iterator->current);
01726                      spl_filesystem_object_get_file_name(object TSRMLS_CC);
01727                      ZVAL_STRINGL(iterator->current, object->file_name, object->file_name_len, 1);
01728               }
01729               *data = &iterator->current;
01730        } else if (SPL_FILE_DIR_CURRENT(object, SPL_FILE_DIR_CURRENT_AS_FILEINFO)) {
01731               if (!iterator->current) {
01732                      ALLOC_INIT_ZVAL(iterator->current);
01733                      spl_filesystem_object_get_file_name(object TSRMLS_CC);
01734                      spl_filesystem_object_create_type(0, object, SPL_FS_INFO, NULL, iterator->current TSRMLS_CC);
01735               }
01736               *data = &iterator->current;
01737        } else {
01738               *data = (zval**)&iterator->intern.data;
01739        }
01740 }
01741 /* }}} */
01742 
01743 /* {{{ spl_filesystem_tree_it_current_key */
01744 static int spl_filesystem_tree_it_current_key(zend_object_iterator *iter, char **str_key, uint *str_key_len, ulong *int_key TSRMLS_DC)
01745 {
01746        spl_filesystem_object *object = spl_filesystem_iterator_to_object((spl_filesystem_iterator *)iter);
01747        
01748        if (SPL_FILE_DIR_KEY(object, SPL_FILE_DIR_KEY_AS_FILENAME)) {
01749               *str_key_len = strlen(object->u.dir.entry.d_name) + 1;
01750               *str_key = estrndup(object->u.dir.entry.d_name, *str_key_len - 1);
01751        } else {
01752               spl_filesystem_object_get_file_name(object TSRMLS_CC);
01753               *str_key_len = object->file_name_len + 1;
01754               *str_key = estrndup(object->file_name, object->file_name_len);
01755        }
01756        return HASH_KEY_IS_STRING;
01757 }
01758 /* }}} */
01759 
01760 /* {{{ spl_filesystem_tree_it_move_forward */
01761 static void spl_filesystem_tree_it_move_forward(zend_object_iterator *iter TSRMLS_DC)
01762 {
01763        spl_filesystem_iterator *iterator = (spl_filesystem_iterator *)iter;
01764        spl_filesystem_object   *object   = spl_filesystem_iterator_to_object(iterator);
01765        
01766        object->u.dir.index++;
01767        do {
01768               spl_filesystem_dir_read(object TSRMLS_CC);
01769        } while (spl_filesystem_is_dot(object->u.dir.entry.d_name));
01770        if (object->file_name) {
01771               efree(object->file_name);
01772               object->file_name = NULL;
01773        }
01774        if (iterator->current) {
01775               zval_ptr_dtor(&iterator->current);
01776               iterator->current = NULL;
01777        }
01778 }
01779 /* }}} */
01780 
01781 /* {{{ spl_filesystem_tree_it_rewind */
01782 static void spl_filesystem_tree_it_rewind(zend_object_iterator *iter TSRMLS_DC)
01783 {
01784        spl_filesystem_iterator *iterator = (spl_filesystem_iterator *)iter;
01785        spl_filesystem_object   *object   = spl_filesystem_iterator_to_object(iterator);
01786        
01787        object->u.dir.index = 0;
01788        if (object->u.dir.dirp) {
01789               php_stream_rewinddir(object->u.dir.dirp);
01790        }
01791        do {
01792               spl_filesystem_dir_read(object TSRMLS_CC);
01793        } while (spl_filesystem_is_dot(object->u.dir.entry.d_name));
01794        if (iterator->current) {
01795               zval_ptr_dtor(&iterator->current);
01796               iterator->current = NULL;
01797        }
01798 }
01799 /* }}} */
01800 
01801 /* {{{ iterator handler table */
01802 zend_object_iterator_funcs spl_filesystem_tree_it_funcs = {
01803        spl_filesystem_tree_it_dtor,
01804        spl_filesystem_dir_it_valid,
01805        spl_filesystem_tree_it_current_data,
01806        spl_filesystem_tree_it_current_key,
01807        spl_filesystem_tree_it_move_forward,
01808        spl_filesystem_tree_it_rewind
01809 };
01810 /* }}} */
01811 
01812 /* {{{ spl_ce_dir_get_iterator */
01813 zend_object_iterator *spl_filesystem_tree_get_iterator(zend_class_entry *ce, zval *object, int by_ref TSRMLS_DC)
01814 {
01815        spl_filesystem_iterator *iterator;
01816        spl_filesystem_object *dir_object;
01817 
01818        if (by_ref) {
01819               zend_error(E_ERROR, "An iterator cannot be used with foreach by reference");
01820        }
01821        dir_object = (spl_filesystem_object*)zend_object_store_get_object(object TSRMLS_CC);
01822        iterator   = spl_filesystem_object_to_iterator(dir_object);
01823 
01824        Z_SET_REFCOUNT_P(object, Z_REFCOUNT_P(object) + 2);
01825        iterator->intern.data = (void*)object;
01826        iterator->intern.funcs = &spl_filesystem_tree_it_funcs;
01827        iterator->current = NULL;
01828        
01829        return (zend_object_iterator*)iterator;
01830 }
01831 /* }}} */
01832 
01833 /* {{{ spl_filesystem_object_cast */
01834 static int spl_filesystem_object_cast(zval *readobj, zval *writeobj, int type TSRMLS_DC)
01835 {
01836        spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(readobj TSRMLS_CC);
01837 
01838        if (type == IS_STRING) {
01839               switch (intern->type) {
01840               case SPL_FS_INFO:
01841               case SPL_FS_FILE:
01842                      if (readobj == writeobj) {
01843                             zval retval;
01844                             zval *retval_ptr = &retval;
01845 
01846                             ZVAL_STRINGL(retval_ptr, intern->file_name, intern->file_name_len, 1);
01847                             zval_dtor(readobj);
01848                             ZVAL_ZVAL(writeobj, retval_ptr, 0, 0);
01849                      } else {
01850                             ZVAL_STRINGL(writeobj, intern->file_name, intern->file_name_len, 1);
01851                      }
01852                      return SUCCESS;
01853               case SPL_FS_DIR:
01854                      if (readobj == writeobj) {
01855                             zval retval;
01856                             zval *retval_ptr = &retval;
01857 
01858                             ZVAL_STRING(retval_ptr, intern->u.dir.entry.d_name, 1);
01859                             zval_dtor(readobj);
01860                             ZVAL_ZVAL(writeobj, retval_ptr, 0, 0);
01861                      } else {
01862                             ZVAL_STRING(writeobj, intern->u.dir.entry.d_name, 1);
01863                      }
01864                      return SUCCESS;
01865               }
01866        }
01867        if (readobj == writeobj) {
01868               zval_dtor(readobj);
01869        }
01870        ZVAL_NULL(writeobj);
01871        return FAILURE;
01872 }
01873 /* }}} */
01874 
01875 /* {{{ declare method parameters */
01876 /* supply a name and default to call by parameter */
01877 ZEND_BEGIN_ARG_INFO(arginfo_info___construct, 0) 
01878        ZEND_ARG_INFO(0, file_name)
01879 ZEND_END_ARG_INFO()
01880 
01881 ZEND_BEGIN_ARG_INFO_EX(arginfo_info_openFile, 0, 0, 0)
01882        ZEND_ARG_INFO(0, open_mode)
01883        ZEND_ARG_INFO(0, use_include_path)
01884        ZEND_ARG_INFO(0, context)
01885 ZEND_END_ARG_INFO()
01886 
01887 ZEND_BEGIN_ARG_INFO_EX(arginfo_info_optinalFileClass, 0, 0, 0)
01888        ZEND_ARG_INFO(0, class_name)
01889 ZEND_END_ARG_INFO()
01890 
01891 ZEND_BEGIN_ARG_INFO_EX(arginfo_optinalSuffix, 0, 0, 0)
01892        ZEND_ARG_INFO(0, suffix)
01893 ZEND_END_ARG_INFO()
01894 
01895 ZEND_BEGIN_ARG_INFO(arginfo_splfileinfo_void, 0)
01896 ZEND_END_ARG_INFO()
01897 
01898 /* the method table */
01899 /* each method can have its own parameters and visibility */
01900 static const zend_function_entry spl_SplFileInfo_functions[] = {
01901        SPL_ME(SplFileInfo,       __construct,   arginfo_info___construct, ZEND_ACC_PUBLIC)
01902        SPL_ME(SplFileInfo,       getPath,       arginfo_splfileinfo_void, ZEND_ACC_PUBLIC)
01903        SPL_ME(SplFileInfo,       getFilename,   arginfo_splfileinfo_void, ZEND_ACC_PUBLIC)
01904        SPL_ME(SplFileInfo,       getExtension,  arginfo_splfileinfo_void, ZEND_ACC_PUBLIC)
01905        SPL_ME(SplFileInfo,       getBasename,   arginfo_optinalSuffix, ZEND_ACC_PUBLIC)
01906        SPL_ME(SplFileInfo,       getPathname,   arginfo_splfileinfo_void, ZEND_ACC_PUBLIC)
01907        SPL_ME(SplFileInfo,       getPerms,      arginfo_splfileinfo_void, ZEND_ACC_PUBLIC)
01908        SPL_ME(SplFileInfo,       getInode,      arginfo_splfileinfo_void, ZEND_ACC_PUBLIC)
01909        SPL_ME(SplFileInfo,       getSize,       arginfo_splfileinfo_void, ZEND_ACC_PUBLIC)
01910        SPL_ME(SplFileInfo,       getOwner,      arginfo_splfileinfo_void, ZEND_ACC_PUBLIC)
01911        SPL_ME(SplFileInfo,       getGroup,      arginfo_splfileinfo_void, ZEND_ACC_PUBLIC)
01912        SPL_ME(SplFileInfo,       getATime,      arginfo_splfileinfo_void, ZEND_ACC_PUBLIC)
01913        SPL_ME(SplFileInfo,       getMTime,      arginfo_splfileinfo_void, ZEND_ACC_PUBLIC)
01914        SPL_ME(SplFileInfo,       getCTime,      arginfo_splfileinfo_void, ZEND_ACC_PUBLIC)
01915        SPL_ME(SplFileInfo,       getType,       arginfo_splfileinfo_void, ZEND_ACC_PUBLIC)
01916        SPL_ME(SplFileInfo,       isWritable,    arginfo_splfileinfo_void, ZEND_ACC_PUBLIC)
01917        SPL_ME(SplFileInfo,       isReadable,    arginfo_splfileinfo_void, ZEND_ACC_PUBLIC)
01918        SPL_ME(SplFileInfo,       isExecutable,  arginfo_splfileinfo_void, ZEND_ACC_PUBLIC)
01919        SPL_ME(SplFileInfo,       isFile,        arginfo_splfileinfo_void, ZEND_ACC_PUBLIC)
01920        SPL_ME(SplFileInfo,       isDir,         arginfo_splfileinfo_void, ZEND_ACC_PUBLIC)
01921        SPL_ME(SplFileInfo,       isLink,        arginfo_splfileinfo_void, ZEND_ACC_PUBLIC)
01922        SPL_ME(SplFileInfo,       getLinkTarget, arginfo_splfileinfo_void, ZEND_ACC_PUBLIC)
01923 #if (!defined(__BEOS__) && !defined(NETWARE) && HAVE_REALPATH) || defined(ZTS)
01924        SPL_ME(SplFileInfo,       getRealPath,   arginfo_splfileinfo_void, ZEND_ACC_PUBLIC)
01925 #endif
01926        SPL_ME(SplFileInfo,       getFileInfo,   arginfo_info_optinalFileClass, ZEND_ACC_PUBLIC)
01927        SPL_ME(SplFileInfo,       getPathInfo,   arginfo_info_optinalFileClass, ZEND_ACC_PUBLIC)
01928        SPL_ME(SplFileInfo,       openFile,      arginfo_info_openFile,         ZEND_ACC_PUBLIC)
01929        SPL_ME(SplFileInfo,       setFileClass,  arginfo_info_optinalFileClass, ZEND_ACC_PUBLIC)
01930        SPL_ME(SplFileInfo,       setInfoClass,  arginfo_info_optinalFileClass, ZEND_ACC_PUBLIC)
01931        SPL_ME(SplFileInfo,       _bad_state_ex, NULL,                                             ZEND_ACC_PUBLIC|ZEND_ACC_FINAL)
01932        SPL_MA(SplFileInfo,       __toString, SplFileInfo, getPathname, arginfo_splfileinfo_void, ZEND_ACC_PUBLIC)
01933        PHP_FE_END
01934 };
01935 
01936 ZEND_BEGIN_ARG_INFO(arginfo_dir___construct, 0) 
01937        ZEND_ARG_INFO(0, path)
01938 ZEND_END_ARG_INFO()
01939 
01940 ZEND_BEGIN_ARG_INFO(arginfo_dir_it_seek, 0) 
01941        ZEND_ARG_INFO(0, position)
01942 ZEND_END_ARG_INFO();
01943 
01944 /* the method table */
01945 /* each method can have its own parameters and visibility */
01946 static const zend_function_entry spl_DirectoryIterator_functions[] = {
01947        SPL_ME(DirectoryIterator, __construct,   arginfo_dir___construct, ZEND_ACC_PUBLIC)
01948        SPL_ME(DirectoryIterator, getFilename,   arginfo_splfileinfo_void, ZEND_ACC_PUBLIC)
01949        SPL_ME(DirectoryIterator, getExtension,  arginfo_splfileinfo_void, ZEND_ACC_PUBLIC)
01950        SPL_ME(DirectoryIterator, getBasename,   arginfo_optinalSuffix, ZEND_ACC_PUBLIC)
01951        SPL_ME(DirectoryIterator, isDot,         arginfo_splfileinfo_void, ZEND_ACC_PUBLIC)
01952        SPL_ME(DirectoryIterator, rewind,        arginfo_splfileinfo_void, ZEND_ACC_PUBLIC)
01953        SPL_ME(DirectoryIterator, valid,         arginfo_splfileinfo_void, ZEND_ACC_PUBLIC)
01954        SPL_ME(DirectoryIterator, key,           arginfo_splfileinfo_void, ZEND_ACC_PUBLIC)
01955        SPL_ME(DirectoryIterator, current,       arginfo_splfileinfo_void, ZEND_ACC_PUBLIC)
01956        SPL_ME(DirectoryIterator, next,          arginfo_splfileinfo_void, ZEND_ACC_PUBLIC)
01957        SPL_ME(DirectoryIterator, seek,          arginfo_dir_it_seek, ZEND_ACC_PUBLIC)
01958        SPL_MA(DirectoryIterator, __toString, DirectoryIterator, getFilename, arginfo_splfileinfo_void, ZEND_ACC_PUBLIC)
01959        PHP_FE_END
01960 };
01961 
01962 ZEND_BEGIN_ARG_INFO_EX(arginfo_r_dir___construct, 0, 0, 1) 
01963        ZEND_ARG_INFO(0, path)
01964        ZEND_ARG_INFO(0, flags)
01965 ZEND_END_ARG_INFO()
01966 
01967 ZEND_BEGIN_ARG_INFO_EX(arginfo_r_dir_hasChildren, 0, 0, 0)
01968        ZEND_ARG_INFO(0, allow_links)
01969 ZEND_END_ARG_INFO()
01970 
01971 ZEND_BEGIN_ARG_INFO_EX(arginfo_r_dir_setFlags, 0, 0, 0)
01972        ZEND_ARG_INFO(0, flags)
01973 ZEND_END_ARG_INFO()
01974 
01975 static const zend_function_entry spl_FilesystemIterator_functions[] = {
01976        SPL_ME(FilesystemIterator, __construct,   arginfo_r_dir___construct, ZEND_ACC_PUBLIC)
01977        SPL_ME(FilesystemIterator, rewind,        arginfo_splfileinfo_void, ZEND_ACC_PUBLIC)
01978        SPL_ME(DirectoryIterator,  next,          arginfo_splfileinfo_void, ZEND_ACC_PUBLIC)
01979        SPL_ME(FilesystemIterator, key,           arginfo_splfileinfo_void, ZEND_ACC_PUBLIC)
01980        SPL_ME(FilesystemIterator, current,       arginfo_splfileinfo_void, ZEND_ACC_PUBLIC)
01981        SPL_ME(FilesystemIterator, getFlags,      arginfo_splfileinfo_void, ZEND_ACC_PUBLIC)
01982        SPL_ME(FilesystemIterator, setFlags,      arginfo_r_dir_setFlags, ZEND_ACC_PUBLIC)
01983        PHP_FE_END
01984 };
01985 
01986 static const zend_function_entry spl_RecursiveDirectoryIterator_functions[] = {
01987        SPL_ME(RecursiveDirectoryIterator, __construct,   arginfo_r_dir___construct, ZEND_ACC_PUBLIC)
01988        SPL_ME(RecursiveDirectoryIterator, hasChildren,   arginfo_r_dir_hasChildren, ZEND_ACC_PUBLIC)
01989        SPL_ME(RecursiveDirectoryIterator, getChildren,   arginfo_splfileinfo_void, ZEND_ACC_PUBLIC)
01990        SPL_ME(RecursiveDirectoryIterator, getSubPath,    arginfo_splfileinfo_void, ZEND_ACC_PUBLIC)
01991        SPL_ME(RecursiveDirectoryIterator, getSubPathname,arginfo_splfileinfo_void, ZEND_ACC_PUBLIC)
01992        PHP_FE_END
01993 };
01994 
01995 #ifdef HAVE_GLOB
01996 static const zend_function_entry spl_GlobIterator_functions[] = {
01997        SPL_ME(GlobIterator, __construct,   arginfo_r_dir___construct, ZEND_ACC_PUBLIC)
01998        SPL_ME(GlobIterator, count,         arginfo_splfileinfo_void,  ZEND_ACC_PUBLIC)
01999        PHP_FE_END
02000 };
02001 #endif
02002 /* }}} */
02003 
02004 static int spl_filesystem_file_read(spl_filesystem_object *intern, int silent TSRMLS_DC) /* {{{ */
02005 {
02006        char *buf;
02007        size_t line_len = 0;
02008        int len;
02009        long line_add = (intern->u.file.current_line || intern->u.file.current_zval) ? 1 : 0;
02010 
02011        spl_filesystem_file_free_line(intern TSRMLS_CC);
02012        
02013        if (php_stream_eof(intern->u.file.stream)) {
02014               if (!silent) {
02015                      zend_throw_exception_ex(spl_ce_RuntimeException, 0 TSRMLS_CC, "Cannot read from file %s", intern->file_name);
02016               }
02017               return FAILURE;
02018        }
02019 
02020        if (intern->u.file.max_line_len > 0) {
02021               buf = safe_emalloc((intern->u.file.max_line_len + 1), sizeof(char), 0);
02022               if (php_stream_get_line(intern->u.file.stream, buf, intern->u.file.max_line_len, &line_len) == NULL) {
02023                      efree(buf);
02024                      buf = NULL;
02025               } else {
02026                      buf[line_len] = '\0';
02027               }
02028        } else {
02029               buf = php_stream_get_line(intern->u.file.stream, NULL, 0, &line_len);
02030        }
02031 
02032        if (!buf) {
02033               intern->u.file.current_line = estrdup("");
02034               intern->u.file.current_line_len = 0;
02035        } else {
02036               if (SPL_HAS_FLAG(intern->flags, SPL_FILE_OBJECT_DROP_NEW_LINE)) {
02037                      line_len = strcspn(buf, "\r\n");
02038                      buf[line_len] = '\0';
02039               }
02040        
02041               if (PG(magic_quotes_runtime)) {
02042                      buf = php_addslashes(buf, line_len, &len, 1 TSRMLS_CC);
02043                      line_len = len;
02044               }
02045        
02046               intern->u.file.current_line = buf;
02047               intern->u.file.current_line_len = line_len;
02048        }
02049        intern->u.file.current_line_num += line_add;
02050 
02051        return SUCCESS;
02052 } /* }}} */
02053 
02054 static int spl_filesystem_file_call(spl_filesystem_object *intern, zend_function *func_ptr, int pass_num_args, zval *return_value, zval *arg2 TSRMLS_DC) /* {{{ */
02055 {
02056        zend_fcall_info fci;
02057        zend_fcall_info_cache fcic;
02058        zval z_fname;
02059        zval * zresource_ptr = &intern->u.file.zresource, *retval;
02060        int result;
02061        int num_args = pass_num_args + (arg2 ? 2 : 1);
02062 
02063        zval ***params = (zval***)safe_emalloc(num_args, sizeof(zval**), 0);
02064 
02065        params[0] = &zresource_ptr;
02066        
02067        if (arg2) {
02068               params[1] = &arg2;
02069        }
02070 
02071        zend_get_parameters_array_ex(pass_num_args, params+(arg2 ? 2 : 1));
02072 
02073        ZVAL_STRING(&z_fname, func_ptr->common.function_name, 0);
02074 
02075        fci.size = sizeof(fci);
02076        fci.function_table = EG(function_table);
02077        fci.object_ptr = NULL;
02078        fci.function_name = &z_fname;
02079        fci.retval_ptr_ptr = &retval;
02080        fci.param_count = num_args;
02081        fci.params = params;
02082        fci.no_separation = 1;
02083        fci.symbol_table = NULL;
02084 
02085        fcic.initialized = 1;
02086        fcic.function_handler = func_ptr;
02087        fcic.calling_scope = NULL;
02088        fcic.called_scope = NULL;
02089        fcic.object_ptr = NULL;
02090 
02091        result = zend_call_function(&fci, &fcic TSRMLS_CC);
02092        
02093        if (result == FAILURE) {
02094               RETVAL_FALSE;
02095        } else {
02096               ZVAL_ZVAL(return_value, retval, 1, 1);
02097        }
02098 
02099        efree(params);
02100        return result;
02101 } /* }}} */
02102 
02103 #define FileFunctionCall(func_name, pass_num_args, arg2) /* {{{ */ \
02104 { \
02105        zend_function *func_ptr; \
02106        int ret; \
02107        ret = zend_hash_find(EG(function_table), #func_name, sizeof(#func_name), (void **) &func_ptr); \
02108        if (ret != SUCCESS) { \
02109               zend_throw_exception_ex(spl_ce_RuntimeException, 0 TSRMLS_CC, "Internal error, function '%s' not found. Please report", #func_name); \
02110               return; \
02111        } \
02112        spl_filesystem_file_call(intern, func_ptr, pass_num_args, return_value, arg2 TSRMLS_CC); \
02113 } /* }}} */
02114 
02115 static int spl_filesystem_file_read_csv(spl_filesystem_object *intern, char delimiter, char enclosure, char escape, zval *return_value TSRMLS_DC) /* {{{ */
02116 {
02117        int ret = SUCCESS;
02118        
02119        do {
02120               ret = spl_filesystem_file_read(intern, 1 TSRMLS_CC);
02121        } while (ret == SUCCESS && !intern->u.file.current_line_len && SPL_HAS_FLAG(intern->flags, SPL_FILE_OBJECT_SKIP_EMPTY));
02122        
02123        if (ret == SUCCESS) {
02124               size_t buf_len = intern->u.file.current_line_len;
02125               char *buf = estrndup(intern->u.file.current_line, buf_len);
02126 
02127               if (intern->u.file.current_zval) {
02128                      zval_ptr_dtor(&intern->u.file.current_zval);
02129               }
02130               ALLOC_INIT_ZVAL(intern->u.file.current_zval);
02131 
02132               php_fgetcsv(intern->u.file.stream, delimiter, enclosure, escape, buf_len, buf, intern->u.file.current_zval TSRMLS_CC);
02133               if (return_value) {
02134                      if (Z_TYPE_P(return_value) != IS_NULL) {
02135                             zval_dtor(return_value);
02136                             ZVAL_NULL(return_value);
02137                      }
02138                      ZVAL_ZVAL(return_value, intern->u.file.current_zval, 1, 0);
02139               }
02140        }
02141        return ret;
02142 }
02143 /* }}} */
02144 
02145 static int spl_filesystem_file_read_line_ex(zval * this_ptr, spl_filesystem_object *intern, int silent TSRMLS_DC) /* {{{ */
02146 {
02147        zval *retval = NULL;
02148 
02149        /* 1) use fgetcsv? 2) overloaded call the function, 3) do it directly */
02150        if (SPL_HAS_FLAG(intern->flags, SPL_FILE_OBJECT_READ_CSV) || intern->u.file.func_getCurr->common.scope != spl_ce_SplFileObject) {
02151               if (php_stream_eof(intern->u.file.stream)) {
02152                      if (!silent) {
02153                             zend_throw_exception_ex(spl_ce_RuntimeException, 0 TSRMLS_CC, "Cannot read from file %s", intern->file_name);
02154                      }
02155                      return FAILURE;
02156               }
02157               if (SPL_HAS_FLAG(intern->flags, SPL_FILE_OBJECT_READ_CSV)) {
02158                      return spl_filesystem_file_read_csv(intern, intern->u.file.delimiter, intern->u.file.enclosure, intern->u.file.escape, NULL TSRMLS_CC);
02159               } else {
02160                      zend_call_method_with_0_params(&this_ptr, Z_OBJCE_P(getThis()), &intern->u.file.func_getCurr, "getCurrentLine", &retval);
02161               }
02162               if (retval) {
02163                      if (intern->u.file.current_line || intern->u.file.current_zval) {
02164                             intern->u.file.current_line_num++;
02165                      }
02166                      spl_filesystem_file_free_line(intern TSRMLS_CC);
02167                      if (Z_TYPE_P(retval) == IS_STRING) {
02168                             intern->u.file.current_line = estrndup(Z_STRVAL_P(retval), Z_STRLEN_P(retval));
02169                             intern->u.file.current_line_len = Z_STRLEN_P(retval);
02170                      } else {
02171                             MAKE_STD_ZVAL(intern->u.file.current_zval);
02172                             ZVAL_ZVAL(intern->u.file.current_zval, retval, 1, 0);
02173                      }
02174                      zval_ptr_dtor(&retval);
02175                      return SUCCESS;
02176               } else {
02177                      return FAILURE;
02178               }
02179        } else {
02180               return spl_filesystem_file_read(intern, silent TSRMLS_CC);
02181        }
02182 } /* }}} */
02183 
02184 static int spl_filesystem_file_is_empty_line(spl_filesystem_object *intern TSRMLS_DC) /* {{{ */
02185 {
02186        if (intern->u.file.current_line) {
02187               return intern->u.file.current_line_len == 0;
02188        } else if (intern->u.file.current_zval) {
02189               switch(Z_TYPE_P(intern->u.file.current_zval)) {
02190               case IS_STRING:
02191                      return Z_STRLEN_P(intern->u.file.current_zval) == 0;
02192               case IS_ARRAY:
02193                      if (SPL_HAS_FLAG(intern->flags, SPL_FILE_OBJECT_READ_CSV)
02194                      && zend_hash_num_elements(Z_ARRVAL_P(intern->u.file.current_zval)) == 1) {
02195                             zval ** first = Z_ARRVAL_P(intern->u.file.current_zval)->pListHead->pData;
02196                                    
02197                             return Z_TYPE_PP(first) == IS_STRING && Z_STRLEN_PP(first) == 0;
02198                      }
02199                      return zend_hash_num_elements(Z_ARRVAL_P(intern->u.file.current_zval)) == 0;
02200               case IS_NULL:
02201                      return 1;
02202               default:
02203                      return 0;
02204               }
02205        } else {
02206               return 1;
02207        }
02208 }
02209 /* }}} */
02210 
02211 static int spl_filesystem_file_read_line(zval * this_ptr, spl_filesystem_object *intern, int silent TSRMLS_DC) /* {{{ */
02212 {
02213        int ret = spl_filesystem_file_read_line_ex(this_ptr, intern, silent TSRMLS_CC);
02214 
02215        while (SPL_HAS_FLAG(intern->flags, SPL_FILE_OBJECT_SKIP_EMPTY) && ret == SUCCESS && spl_filesystem_file_is_empty_line(intern TSRMLS_CC)) {
02216               spl_filesystem_file_free_line(intern TSRMLS_CC);
02217               ret = spl_filesystem_file_read_line_ex(this_ptr, intern, silent TSRMLS_CC);
02218        }
02219        
02220        return ret;
02221 }
02222 /* }}} */
02223 
02224 static void spl_filesystem_file_rewind(zval * this_ptr, spl_filesystem_object *intern TSRMLS_DC) /* {{{ */
02225 {
02226        if (-1 == php_stream_rewind(intern->u.file.stream)) {
02227               zend_throw_exception_ex(spl_ce_RuntimeException, 0 TSRMLS_CC, "Cannot rewind file %s", intern->file_name);
02228        } else {
02229               spl_filesystem_file_free_line(intern TSRMLS_CC);
02230               intern->u.file.current_line_num = 0;
02231        }
02232        if (SPL_HAS_FLAG(intern->flags, SPL_FILE_OBJECT_READ_AHEAD)) {
02233               spl_filesystem_file_read_line(this_ptr, intern, 1 TSRMLS_CC);
02234        }
02235 } /* }}} */
02236 
02237 /* {{{ proto void SplFileObject::__construct(string filename [, string mode = 'r' [, bool use_include_path  [, resource context]]]])
02238    Construct a new file object */
02239 SPL_METHOD(SplFileObject, __construct)
02240 {
02241        spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
02242        zend_bool use_include_path = 0;
02243        char *p1, *p2;
02244        char *tmp_path;
02245        int   tmp_path_len;
02246        zend_error_handling error_handling;
02247 
02248        zend_replace_error_handling(EH_THROW, spl_ce_RuntimeException, &error_handling TSRMLS_CC);
02249 
02250        intern->u.file.open_mode = NULL;
02251        intern->u.file.open_mode_len = 0;
02252 
02253        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|sbr", 
02254                      &intern->file_name, &intern->file_name_len,
02255                      &intern->u.file.open_mode, &intern->u.file.open_mode_len, 
02256                      &use_include_path, &intern->u.file.zcontext) == FAILURE) {            
02257               intern->u.file.open_mode = NULL;
02258               intern->file_name = NULL;
02259               zend_restore_error_handling(&error_handling TSRMLS_CC);
02260               return;
02261        }
02262        
02263        if (intern->u.file.open_mode == NULL) {
02264               intern->u.file.open_mode = "r";
02265               intern->u.file.open_mode_len = 1;
02266        }
02267        
02268        if (spl_filesystem_file_open(intern, use_include_path, 0 TSRMLS_CC) == SUCCESS) {
02269               tmp_path_len = strlen(intern->u.file.stream->orig_path);
02270 
02271               if (tmp_path_len > 1 && IS_SLASH_AT(intern->u.file.stream->orig_path, tmp_path_len-1)) {
02272                      tmp_path_len--;
02273               }
02274 
02275               tmp_path = estrndup(intern->u.file.stream->orig_path, tmp_path_len);
02276 
02277               p1 = strrchr(tmp_path, '/');
02278 #if defined(PHP_WIN32) || defined(NETWARE)
02279               p2 = strrchr(tmp_path, '\\');
02280 #else
02281               p2 = 0;
02282 #endif
02283               if (p1 || p2) {
02284                      intern->_path_len = (p1 > p2 ? p1 : p2) - tmp_path;
02285               } else {
02286                      intern->_path_len = 0;
02287               }
02288 
02289               efree(tmp_path);
02290 
02291               intern->_path = estrndup(intern->u.file.stream->orig_path, intern->_path_len);
02292        }
02293 
02294        zend_restore_error_handling(&error_handling TSRMLS_CC);
02295 
02296 } /* }}} */
02297 
02298 /* {{{ proto void SplTempFileObject::__construct([int max_memory])
02299    Construct a new temp file object */
02300 SPL_METHOD(SplTempFileObject, __construct)
02301 {
02302        long max_memory = PHP_STREAM_MAX_MEM;
02303        char tmp_fname[48];
02304        spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
02305        zend_error_handling error_handling;
02306 
02307        zend_replace_error_handling(EH_THROW, spl_ce_RuntimeException, &error_handling TSRMLS_CC);
02308 
02309        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &max_memory) == FAILURE) {
02310               zend_restore_error_handling(&error_handling TSRMLS_CC);
02311               return;
02312        }
02313 
02314        if (max_memory < 0) {
02315               intern->file_name = "php://memory";
02316               intern->file_name_len = 12;
02317        } else if (ZEND_NUM_ARGS()) {
02318               intern->file_name_len = slprintf(tmp_fname, sizeof(tmp_fname), "php://temp/maxmemory:%ld", max_memory);
02319               intern->file_name = tmp_fname;
02320        } else {
02321               intern->file_name = "php://temp";
02322               intern->file_name_len = 10;
02323        }
02324        intern->u.file.open_mode = "wb";
02325        intern->u.file.open_mode_len = 1;
02326        intern->u.file.zcontext = NULL;
02327        
02328        if (spl_filesystem_file_open(intern, 0, 0 TSRMLS_CC) == SUCCESS) {
02329               intern->_path_len = 0;
02330               intern->_path = estrndup("", 0);
02331        }
02332        zend_restore_error_handling(&error_handling TSRMLS_CC);
02333 } /* }}} */
02334 
02335 /* {{{ proto void SplFileObject::rewind()
02336    Rewind the file and read the first line */
02337 SPL_METHOD(SplFileObject, rewind)
02338 {
02339        spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
02340        
02341        if (zend_parse_parameters_none() == FAILURE) {
02342               return;
02343        }
02344 
02345        spl_filesystem_file_rewind(getThis(), intern TSRMLS_CC);
02346 } /* }}} */
02347 
02348 /* {{{ proto void SplFileObject::eof()
02349    Return whether end of file is reached */
02350 SPL_METHOD(SplFileObject, eof)
02351 {
02352        spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
02353        
02354        if (zend_parse_parameters_none() == FAILURE) {
02355               return;
02356        }
02357 
02358        RETURN_BOOL(php_stream_eof(intern->u.file.stream));
02359 } /* }}} */
02360 
02361 /* {{{ proto void SplFileObject::valid()
02362    Return !eof() */
02363 SPL_METHOD(SplFileObject, valid)
02364 {
02365        spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
02366        
02367        if (zend_parse_parameters_none() == FAILURE) {
02368               return;
02369        }
02370 
02371        if (SPL_HAS_FLAG(intern->flags, SPL_FILE_OBJECT_READ_AHEAD)) {
02372               RETURN_BOOL(intern->u.file.current_line || intern->u.file.current_zval);
02373        } else {
02374               RETVAL_BOOL(!php_stream_eof(intern->u.file.stream));
02375        }
02376 } /* }}} */
02377 
02378 /* {{{ proto string SplFileObject::fgets()
02379    Rturn next line from file */
02380 SPL_METHOD(SplFileObject, fgets)
02381 {
02382        spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
02383        
02384        if (zend_parse_parameters_none() == FAILURE) {
02385               return;
02386        }
02387 
02388        if (spl_filesystem_file_read(intern, 0 TSRMLS_CC) == FAILURE) {
02389               RETURN_FALSE;
02390        }
02391        RETURN_STRINGL(intern->u.file.current_line, intern->u.file.current_line_len, 1);
02392 } /* }}} */
02393 
02394 /* {{{ proto string SplFileObject::current()
02395    Return current line from file */
02396 SPL_METHOD(SplFileObject, current)
02397 {
02398        spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
02399        
02400        if (zend_parse_parameters_none() == FAILURE) {
02401               return;
02402        }
02403 
02404        if (!intern->u.file.current_line && !intern->u.file.current_zval) {
02405               spl_filesystem_file_read_line(getThis(), intern, 1 TSRMLS_CC);
02406        }
02407        if (intern->u.file.current_line && (!SPL_HAS_FLAG(intern->flags, SPL_FILE_OBJECT_READ_CSV) || !intern->u.file.current_zval)) {
02408               RETURN_STRINGL(intern->u.file.current_line, intern->u.file.current_line_len, 1);
02409        } else if (intern->u.file.current_zval) {
02410               RETURN_ZVAL(intern->u.file.current_zval, 1, 0);
02411        }
02412        RETURN_FALSE;
02413 } /* }}} */
02414 
02415 /* {{{ proto int SplFileObject::key()
02416    Return line number */
02417 SPL_METHOD(SplFileObject, key)
02418 {
02419        spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
02420        
02421        if (zend_parse_parameters_none() == FAILURE) {
02422               return;
02423        }
02424 
02425 /*     Do not read the next line to support correct counting with fgetc()
02426        if (!intern->current_line) {
02427               spl_filesystem_file_read_line(getThis(), intern, 1 TSRMLS_CC);
02428        } */
02429        RETURN_LONG(intern->u.file.current_line_num);
02430 } /* }}} */
02431 
02432 /* {{{ proto void SplFileObject::next()
02433    Read next line */
02434 SPL_METHOD(SplFileObject, next)
02435 {
02436        spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
02437        
02438        if (zend_parse_parameters_none() == FAILURE) {
02439               return;
02440        }
02441 
02442        spl_filesystem_file_free_line(intern TSRMLS_CC);
02443        if (SPL_HAS_FLAG(intern->flags, SPL_FILE_OBJECT_READ_AHEAD)) {
02444               spl_filesystem_file_read_line(getThis(), intern, 1 TSRMLS_CC);
02445        }
02446        intern->u.file.current_line_num++;
02447 } /* }}} */
02448 
02449 /* {{{ proto void SplFileObject::setFlags(int flags)
02450    Set file handling flags */
02451 SPL_METHOD(SplFileObject, setFlags)
02452 {
02453        spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
02454 
02455        zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &intern->flags);
02456 } /* }}} */
02457 
02458 /* {{{ proto int SplFileObject::getFlags()
02459    Get file handling flags */
02460 SPL_METHOD(SplFileObject, getFlags)
02461 {
02462        spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
02463 
02464        if (zend_parse_parameters_none() == FAILURE) {
02465               return;
02466        }
02467 
02468        RETURN_LONG(intern->flags & SPL_FILE_OBJECT_MASK);
02469 } /* }}} */
02470 
02471 /* {{{ proto void SplFileObject::setMaxLineLen(int max_len)
02472    Set maximum line length */
02473 SPL_METHOD(SplFileObject, setMaxLineLen)
02474 {
02475        long max_len;
02476 
02477        spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
02478 
02479        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &max_len) == FAILURE) {
02480               return;
02481        }
02482 
02483        if (max_len < 0) {
02484               zend_throw_exception_ex(spl_ce_DomainException, 0 TSRMLS_CC, "Maximum line length must be greater than or equal zero");
02485               return;
02486        }
02487        
02488        intern->u.file.max_line_len = max_len;
02489 } /* }}} */
02490 
02491 /* {{{ proto int SplFileObject::getMaxLineLen()
02492    Get maximum line length */
02493 SPL_METHOD(SplFileObject, getMaxLineLen)
02494 {
02495        spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
02496        
02497        if (zend_parse_parameters_none() == FAILURE) {
02498               return;
02499        }
02500 
02501        RETURN_LONG((long)intern->u.file.max_line_len);
02502 } /* }}} */
02503 
02504 /* {{{ proto bool SplFileObject::hasChildren()
02505    Return false */
02506 SPL_METHOD(SplFileObject, hasChildren)
02507 {
02508        if (zend_parse_parameters_none() == FAILURE) {
02509               return;
02510        }
02511        
02512        RETURN_FALSE;
02513 } /* }}} */
02514 
02515 /* {{{ proto bool SplFileObject::getChildren()
02516    Read NULL */
02517 SPL_METHOD(SplFileObject, getChildren)
02518 {
02519        if (zend_parse_parameters_none() == FAILURE) {
02520               return;
02521        }
02522        /* return NULL */
02523 } /* }}} */
02524 
02525 /* {{{ FileFunction */
02526 #define FileFunction(func_name) \
02527 SPL_METHOD(SplFileObject, func_name) \
02528 { \
02529        spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC); \
02530        FileFunctionCall(func_name, ZEND_NUM_ARGS(), NULL); \
02531 }
02532 /* }}} */
02533 
02534 /* {{{ proto array SplFileObject::fgetcsv([string delimiter [, string enclosure [, escape = '\\']]])
02535    Return current line as csv */
02536 SPL_METHOD(SplFileObject, fgetcsv)
02537 {
02538        spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
02539        char delimiter = intern->u.file.delimiter, enclosure = intern->u.file.enclosure, escape = intern->u.file.escape;
02540        char *delim = NULL, *enclo = NULL, *esc = NULL;
02541        int d_len = 0, e_len = 0, esc_len = 0;
02542        
02543        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|sss", &delim, &d_len, &enclo, &e_len, &esc, &esc_len) == SUCCESS) {
02544               switch(ZEND_NUM_ARGS())
02545               {
02546               case 3:
02547                      if (esc_len != 1) {
02548                             php_error_docref(NULL TSRMLS_CC, E_WARNING, "escape must be a character");
02549                             RETURN_FALSE;
02550                      }
02551                      escape = esc[0];
02552                      /* no break */
02553               case 2:
02554                      if (e_len != 1) {
02555                             php_error_docref(NULL TSRMLS_CC, E_WARNING, "enclosure must be a character");
02556                             RETURN_FALSE;
02557                      }
02558                      enclosure = enclo[0];
02559                      /* no break */
02560               case 1:
02561                      if (d_len != 1) {
02562                             php_error_docref(NULL TSRMLS_CC, E_WARNING, "delimiter must be a character");
02563                             RETURN_FALSE;
02564                      }
02565                      delimiter = delim[0];
02566                      /* no break */
02567               case 0:
02568                      break;
02569               }
02570               spl_filesystem_file_read_csv(intern, delimiter, enclosure, escape, return_value TSRMLS_CC);
02571        }
02572 }
02573 /* }}} */
02574 
02575 /* {{{ proto void SplFileObject::setCsvControl([string delimiter = ',' [, string enclosure = '"' [, string escape = '\\']]])
02576    Set the delimiter and enclosure character used in fgetcsv */
02577 SPL_METHOD(SplFileObject, setCsvControl)
02578 {
02579        spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
02580        char delimiter = ',', enclosure = '"', escape='\\';
02581        char *delim = NULL, *enclo = NULL, *esc = NULL;
02582        int d_len = 0, e_len = 0, esc_len = 0;
02583        
02584        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|sss", &delim, &d_len, &enclo, &e_len, &esc, &esc_len) == SUCCESS) {
02585               switch(ZEND_NUM_ARGS())
02586               {
02587               case 3:
02588                      if (esc_len != 1) {
02589                             php_error_docref(NULL TSRMLS_CC, E_WARNING, "escape must be a character");
02590                             RETURN_FALSE;
02591                      }
02592                      escape = esc[0];
02593                      /* no break */
02594               case 2:
02595                      if (e_len != 1) {
02596                             php_error_docref(NULL TSRMLS_CC, E_WARNING, "enclosure must be a character");
02597                             RETURN_FALSE;
02598                      }
02599                      enclosure = enclo[0];
02600                      /* no break */
02601               case 1:
02602                      if (d_len != 1) {
02603                             php_error_docref(NULL TSRMLS_CC, E_WARNING, "delimiter must be a character");
02604                             RETURN_FALSE;
02605                      }
02606                      delimiter = delim[0];
02607                      /* no break */
02608               case 0:
02609                      break;
02610               }
02611               intern->u.file.delimiter = delimiter;
02612               intern->u.file.enclosure = enclosure;
02613               intern->u.file.escape    = escape;
02614        }
02615 }
02616 /* }}} */
02617 
02618 /* {{{ proto array SplFileObject::getCsvControl()
02619    Get the delimiter and enclosure character used in fgetcsv */
02620 SPL_METHOD(SplFileObject, getCsvControl)
02621 {
02622        spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
02623        char delimiter[2], enclosure[2];
02624 
02625        array_init(return_value);
02626        
02627        delimiter[0] = intern->u.file.delimiter;
02628        delimiter[1] = '\0';
02629        enclosure[0] = intern->u.file.enclosure;
02630        enclosure[1] = '\0';
02631 
02632        add_next_index_string(return_value, delimiter, 1);
02633        add_next_index_string(return_value, enclosure, 1);
02634 }
02635 /* }}} */
02636 
02637 /* {{{ proto bool SplFileObject::flock(int operation [, int &wouldblock])
02638    Portable file locking */
02639 FileFunction(flock)
02640 /* }}} */
02641 
02642 /* {{{ proto bool SplFileObject::fflush()
02643    Flush the file */
02644 SPL_METHOD(SplFileObject, fflush)
02645 {
02646        spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
02647 
02648        RETURN_BOOL(!php_stream_flush(intern->u.file.stream));
02649 } /* }}} */
02650 
02651 /* {{{ proto int SplFileObject::ftell()
02652    Return current file position */
02653 SPL_METHOD(SplFileObject, ftell)
02654 {
02655        spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC);      
02656        long ret = php_stream_tell(intern->u.file.stream);
02657 
02658        if (ret == -1) {
02659               RETURN_FALSE;
02660        } else {
02661               RETURN_LONG(ret);
02662        }
02663 } /* }}} */
02664 
02665 /* {{{ proto int SplFileObject::fseek(int pos [, int whence = SEEK_SET])
02666    Return current file position */
02667 SPL_METHOD(SplFileObject, fseek)
02668 {
02669        spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
02670        long pos, whence = SEEK_SET;
02671 
02672        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l|l", &pos, &whence) == FAILURE) {
02673               return;
02674        }
02675 
02676        spl_filesystem_file_free_line(intern TSRMLS_CC);
02677        RETURN_LONG(php_stream_seek(intern->u.file.stream, pos, whence));
02678 } /* }}} */
02679 
02680 /* {{{ proto int SplFileObject::fgetc()
02681    Get a character form the file */
02682 SPL_METHOD(SplFileObject, fgetc)
02683 {
02684        spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
02685        char buf[2];
02686        int result;
02687 
02688        spl_filesystem_file_free_line(intern TSRMLS_CC);
02689 
02690        result = php_stream_getc(intern->u.file.stream);
02691 
02692        if (result == EOF) {
02693               RETVAL_FALSE;
02694        } else {
02695               if (result == '\n') {
02696                      intern->u.file.current_line_num++;
02697               }
02698               buf[0] = result;
02699               buf[1] = '\0';
02700 
02701               RETURN_STRINGL(buf, 1, 1);
02702        }
02703 } /* }}} */
02704 
02705 /* {{{ proto string SplFileObject::fgetss([string allowable_tags])
02706    Get a line from file pointer and strip HTML tags */
02707 SPL_METHOD(SplFileObject, fgetss)
02708 {
02709        spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
02710        zval *arg2 = NULL;
02711        MAKE_STD_ZVAL(arg2);
02712 
02713        if (intern->u.file.max_line_len > 0) {
02714               ZVAL_LONG(arg2, intern->u.file.max_line_len);
02715        } else {
02716               ZVAL_LONG(arg2, 1024);
02717        }
02718 
02719        spl_filesystem_file_free_line(intern TSRMLS_CC);
02720        intern->u.file.current_line_num++;
02721 
02722        FileFunctionCall(fgetss, ZEND_NUM_ARGS(), arg2);
02723 
02724        zval_ptr_dtor(&arg2);
02725 } /* }}} */
02726 
02727 /* {{{ proto int SplFileObject::fpassthru()
02728    Output all remaining data from a file pointer */
02729 SPL_METHOD(SplFileObject, fpassthru)
02730 {
02731        spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
02732 
02733        RETURN_LONG(php_stream_passthru(intern->u.file.stream));
02734 } /* }}} */
02735 
02736 /* {{{ proto bool SplFileObject::fscanf(string format [, string ...])
02737    Implements a mostly ANSI compatible fscanf() */
02738 SPL_METHOD(SplFileObject, fscanf)
02739 {
02740        spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
02741 
02742        spl_filesystem_file_free_line(intern TSRMLS_CC);
02743        intern->u.file.current_line_num++;
02744 
02745        FileFunctionCall(fscanf, ZEND_NUM_ARGS(), NULL);
02746 }
02747 /* }}} */
02748 
02749 /* {{{ proto mixed SplFileObject::fwrite(string str [, int length])
02750    Binary-safe file write */
02751 SPL_METHOD(SplFileObject, fwrite)
02752 {
02753        spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
02754        char *str;
02755        int str_len;
02756        int ret;
02757        long length = 0;
02758 
02759        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|l", &str, &str_len, &length) == FAILURE) {
02760               return;
02761        }
02762 
02763        if (ZEND_NUM_ARGS() > 1) {
02764               str_len = MAX(0, MIN(length, str_len));
02765        }
02766        if (!str_len) {
02767               RETURN_LONG(0);
02768        }
02769 
02770        if (PG(magic_quotes_runtime)) {
02771               str = estrndup(str, str_len);
02772               php_stripslashes(str, &str_len TSRMLS_CC);
02773               ret = php_stream_write(intern->u.file.stream, str, str_len);
02774               efree(str);
02775               RETURN_LONG(ret);
02776        }
02777 
02778        RETURN_LONG(php_stream_write(intern->u.file.stream, str, str_len));
02779 } /* }}} */
02780 
02781 /* {{{ proto bool SplFileObject::fstat()
02782    Stat() on a filehandle */
02783 FileFunction(fstat)
02784 /* }}} */
02785 
02786 /* {{{ proto bool SplFileObject::ftruncate(int size)
02787    Truncate file to 'size' length */
02788 SPL_METHOD(SplFileObject, ftruncate)
02789 {
02790        spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
02791        long size;
02792        
02793        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &size) == FAILURE) {
02794               return;
02795        }
02796 
02797        if (!php_stream_truncate_supported(intern->u.file.stream)) {
02798               zend_throw_exception_ex(spl_ce_LogicException, 0 TSRMLS_CC, "Can't truncate file %s", intern->file_name);
02799               RETURN_FALSE;
02800        }
02801        
02802        RETURN_BOOL(0 == php_stream_truncate_set_size(intern->u.file.stream, size));
02803 } /* }}} */
02804 
02805 /* {{{ proto void SplFileObject::seek(int line_pos)
02806    Seek to specified line */
02807 SPL_METHOD(SplFileObject, seek)
02808 {
02809        spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
02810        long line_pos;
02811        
02812        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &line_pos) == FAILURE) {
02813               return;
02814        }
02815        if (line_pos < 0) {
02816               zend_throw_exception_ex(spl_ce_LogicException, 0 TSRMLS_CC, "Can't seek file %s to negative line %ld", intern->file_name, line_pos);
02817               RETURN_FALSE;        
02818        }
02819        
02820        spl_filesystem_file_rewind(getThis(), intern TSRMLS_CC);
02821        
02822        while(intern->u.file.current_line_num < line_pos) {
02823               if (spl_filesystem_file_read_line(getThis(), intern, 1 TSRMLS_CC) == FAILURE) {
02824                      break;
02825               }
02826        }
02827 } /* }}} */
02828 
02829 /* {{{ Function/Class/Method definitions */
02830 ZEND_BEGIN_ARG_INFO_EX(arginfo_file_object___construct, 0, 0, 1)
02831        ZEND_ARG_INFO(0, file_name)
02832        ZEND_ARG_INFO(0, open_mode)
02833        ZEND_ARG_INFO(0, use_include_path)
02834        ZEND_ARG_INFO(0, context)
02835 ZEND_END_ARG_INFO()
02836 
02837 ZEND_BEGIN_ARG_INFO(arginfo_file_object_setFlags, 0)
02838        ZEND_ARG_INFO(0, flags)
02839 ZEND_END_ARG_INFO()
02840 
02841 ZEND_BEGIN_ARG_INFO(arginfo_file_object_setMaxLineLen, 0)
02842        ZEND_ARG_INFO(0, max_len)
02843 ZEND_END_ARG_INFO()
02844 
02845 ZEND_BEGIN_ARG_INFO_EX(arginfo_file_object_fgetcsv, 0, 0, 0)
02846        ZEND_ARG_INFO(0, delimiter)
02847        ZEND_ARG_INFO(0, enclosure)
02848 ZEND_END_ARG_INFO()
02849 
02850 ZEND_BEGIN_ARG_INFO_EX(arginfo_file_object_flock, 0, 0, 1) 
02851        ZEND_ARG_INFO(0, operation)
02852        ZEND_ARG_INFO(1, wouldblock)
02853 ZEND_END_ARG_INFO()
02854 
02855 ZEND_BEGIN_ARG_INFO_EX(arginfo_file_object_fseek, 0, 0, 1) 
02856        ZEND_ARG_INFO(0, pos)
02857        ZEND_ARG_INFO(0, whence)
02858 ZEND_END_ARG_INFO()
02859 
02860 ZEND_BEGIN_ARG_INFO_EX(arginfo_file_object_fgetss, 0, 0, 0) 
02861        ZEND_ARG_INFO(0, allowable_tags)
02862 ZEND_END_ARG_INFO()
02863 
02864 ZEND_BEGIN_ARG_INFO_EX(arginfo_file_object_fscanf, 1, 0, 1)
02865        ZEND_ARG_INFO(0, format)
02866 ZEND_END_ARG_INFO()
02867 
02868 ZEND_BEGIN_ARG_INFO_EX(arginfo_file_object_fwrite, 0, 0, 1) 
02869        ZEND_ARG_INFO(0, str)
02870        ZEND_ARG_INFO(0, length)
02871 ZEND_END_ARG_INFO()
02872 
02873 ZEND_BEGIN_ARG_INFO_EX(arginfo_file_object_ftruncate, 0, 0, 1) 
02874        ZEND_ARG_INFO(0, size)
02875 ZEND_END_ARG_INFO()
02876 
02877 ZEND_BEGIN_ARG_INFO_EX(arginfo_file_object_seek, 0, 0, 1) 
02878        ZEND_ARG_INFO(0, line_pos)
02879 ZEND_END_ARG_INFO()
02880 
02881 static const zend_function_entry spl_SplFileObject_functions[] = {
02882        SPL_ME(SplFileObject, __construct,    arginfo_file_object___construct,   ZEND_ACC_PUBLIC)
02883        SPL_ME(SplFileObject, rewind,         arginfo_splfileinfo_void,          ZEND_ACC_PUBLIC)
02884        SPL_ME(SplFileObject, eof,            arginfo_splfileinfo_void,          ZEND_ACC_PUBLIC)
02885        SPL_ME(SplFileObject, valid,          arginfo_splfileinfo_void,          ZEND_ACC_PUBLIC)
02886        SPL_ME(SplFileObject, fgets,          arginfo_splfileinfo_void,          ZEND_ACC_PUBLIC)
02887        SPL_ME(SplFileObject, fgetcsv,        arginfo_file_object_fgetcsv,       ZEND_ACC_PUBLIC)
02888        SPL_ME(SplFileObject, setCsvControl,  arginfo_file_object_fgetcsv,       ZEND_ACC_PUBLIC)
02889        SPL_ME(SplFileObject, getCsvControl,  arginfo_splfileinfo_void,          ZEND_ACC_PUBLIC)
02890        SPL_ME(SplFileObject, flock,          arginfo_file_object_flock,         ZEND_ACC_PUBLIC)
02891        SPL_ME(SplFileObject, fflush,         arginfo_splfileinfo_void,          ZEND_ACC_PUBLIC)
02892        SPL_ME(SplFileObject, ftell,          arginfo_splfileinfo_void,          ZEND_ACC_PUBLIC)
02893        SPL_ME(SplFileObject, fseek,          arginfo_file_object_fseek,         ZEND_ACC_PUBLIC)
02894        SPL_ME(SplFileObject, fgetc,          arginfo_splfileinfo_void,          ZEND_ACC_PUBLIC)
02895        SPL_ME(SplFileObject, fpassthru,      arginfo_splfileinfo_void,          ZEND_ACC_PUBLIC)
02896        SPL_ME(SplFileObject, fgetss,         arginfo_file_object_fgetss,        ZEND_ACC_PUBLIC)
02897        SPL_ME(SplFileObject, fscanf,         arginfo_file_object_fscanf,        ZEND_ACC_PUBLIC)
02898        SPL_ME(SplFileObject, fwrite,         arginfo_file_object_fwrite,        ZEND_ACC_PUBLIC)
02899        SPL_ME(SplFileObject, fstat,          arginfo_splfileinfo_void,          ZEND_ACC_PUBLIC)
02900        SPL_ME(SplFileObject, ftruncate,      arginfo_file_object_ftruncate,     ZEND_ACC_PUBLIC)
02901        SPL_ME(SplFileObject, current,        arginfo_splfileinfo_void,          ZEND_ACC_PUBLIC)
02902        SPL_ME(SplFileObject, key,            arginfo_splfileinfo_void,          ZEND_ACC_PUBLIC)
02903        SPL_ME(SplFileObject, next,           arginfo_splfileinfo_void,          ZEND_ACC_PUBLIC)
02904        SPL_ME(SplFileObject, setFlags,       arginfo_file_object_setFlags,      ZEND_ACC_PUBLIC)
02905        SPL_ME(SplFileObject, getFlags,       arginfo_splfileinfo_void,          ZEND_ACC_PUBLIC)
02906        SPL_ME(SplFileObject, setMaxLineLen,  arginfo_file_object_setMaxLineLen, ZEND_ACC_PUBLIC)
02907        SPL_ME(SplFileObject, getMaxLineLen,  arginfo_splfileinfo_void,          ZEND_ACC_PUBLIC)
02908        SPL_ME(SplFileObject, hasChildren,    arginfo_splfileinfo_void,          ZEND_ACC_PUBLIC)
02909        SPL_ME(SplFileObject, getChildren,    arginfo_splfileinfo_void,          ZEND_ACC_PUBLIC)
02910        SPL_ME(SplFileObject, seek,           arginfo_file_object_seek,          ZEND_ACC_PUBLIC)
02911        /* mappings */
02912        SPL_MA(SplFileObject, getCurrentLine, SplFileObject, fgets,      arginfo_splfileinfo_void, ZEND_ACC_PUBLIC)
02913        SPL_MA(SplFileObject, __toString,     SplFileObject, current,    arginfo_splfileinfo_void, ZEND_ACC_PUBLIC)
02914        PHP_FE_END
02915 };
02916 
02917 ZEND_BEGIN_ARG_INFO_EX(arginfo_temp_file_object___construct, 0, 0, 0)
02918        ZEND_ARG_INFO(0, max_memory)
02919 ZEND_END_ARG_INFO()
02920 
02921 static const zend_function_entry spl_SplTempFileObject_functions[] = {
02922        SPL_ME(SplTempFileObject, __construct, arginfo_temp_file_object___construct,  ZEND_ACC_PUBLIC)
02923        PHP_FE_END
02924 };
02925 /* }}} */
02926 
02927 /* {{{ PHP_MINIT_FUNCTION(spl_directory)
02928  */
02929 PHP_MINIT_FUNCTION(spl_directory)
02930 {
02931        REGISTER_SPL_STD_CLASS_EX(SplFileInfo, spl_filesystem_object_new, spl_SplFileInfo_functions);
02932        memcpy(&spl_filesystem_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
02933        spl_filesystem_object_handlers.clone_obj       = spl_filesystem_object_clone;
02934        spl_filesystem_object_handlers.cast_object     = spl_filesystem_object_cast;
02935        spl_filesystem_object_handlers.get_debug_info  = spl_filesystem_object_get_debug_info;
02936        spl_ce_SplFileInfo->serialize = zend_class_serialize_deny;
02937        spl_ce_SplFileInfo->unserialize = zend_class_unserialize_deny;
02938 
02939        REGISTER_SPL_SUB_CLASS_EX(DirectoryIterator, SplFileInfo, spl_filesystem_object_new, spl_DirectoryIterator_functions);
02940        zend_class_implements(spl_ce_DirectoryIterator TSRMLS_CC, 1, zend_ce_iterator);
02941        REGISTER_SPL_IMPLEMENTS(DirectoryIterator, SeekableIterator);
02942 
02943        spl_ce_DirectoryIterator->get_iterator = spl_filesystem_dir_get_iterator;
02944 
02945        REGISTER_SPL_SUB_CLASS_EX(FilesystemIterator, DirectoryIterator, spl_filesystem_object_new, spl_FilesystemIterator_functions);
02946 
02947        REGISTER_SPL_CLASS_CONST_LONG(FilesystemIterator, "CURRENT_MODE_MASK",   SPL_FILE_DIR_CURRENT_MODE_MASK);
02948        REGISTER_SPL_CLASS_CONST_LONG(FilesystemIterator, "CURRENT_AS_PATHNAME", SPL_FILE_DIR_CURRENT_AS_PATHNAME);
02949        REGISTER_SPL_CLASS_CONST_LONG(FilesystemIterator, "CURRENT_AS_FILEINFO", SPL_FILE_DIR_CURRENT_AS_FILEINFO);
02950        REGISTER_SPL_CLASS_CONST_LONG(FilesystemIterator, "CURRENT_AS_SELF",     SPL_FILE_DIR_CURRENT_AS_SELF);
02951        REGISTER_SPL_CLASS_CONST_LONG(FilesystemIterator, "KEY_MODE_MASK",       SPL_FILE_DIR_KEY_MODE_MASK);
02952        REGISTER_SPL_CLASS_CONST_LONG(FilesystemIterator, "KEY_AS_PATHNAME",     SPL_FILE_DIR_KEY_AS_PATHNAME);
02953        REGISTER_SPL_CLASS_CONST_LONG(FilesystemIterator, "FOLLOW_SYMLINKS",     SPL_FILE_DIR_FOLLOW_SYMLINKS);
02954        REGISTER_SPL_CLASS_CONST_LONG(FilesystemIterator, "KEY_AS_FILENAME",     SPL_FILE_DIR_KEY_AS_FILENAME);
02955        REGISTER_SPL_CLASS_CONST_LONG(FilesystemIterator, "NEW_CURRENT_AND_KEY", SPL_FILE_DIR_KEY_AS_FILENAME|SPL_FILE_DIR_CURRENT_AS_FILEINFO);
02956        REGISTER_SPL_CLASS_CONST_LONG(FilesystemIterator, "SKIP_DOTS",           SPL_FILE_DIR_SKIPDOTS);
02957        REGISTER_SPL_CLASS_CONST_LONG(FilesystemIterator, "UNIX_PATHS",          SPL_FILE_DIR_UNIXPATHS);
02958 
02959        spl_ce_FilesystemIterator->get_iterator = spl_filesystem_tree_get_iterator;
02960 
02961        REGISTER_SPL_SUB_CLASS_EX(RecursiveDirectoryIterator, FilesystemIterator, spl_filesystem_object_new, spl_RecursiveDirectoryIterator_functions);
02962        REGISTER_SPL_IMPLEMENTS(RecursiveDirectoryIterator, RecursiveIterator);
02963        
02964        memcpy(&spl_filesystem_object_check_handlers, &spl_filesystem_object_handlers, sizeof(zend_object_handlers));
02965        spl_filesystem_object_check_handlers.get_method = spl_filesystem_object_get_method_check;
02966 
02967 #ifdef HAVE_GLOB
02968        REGISTER_SPL_SUB_CLASS_EX(GlobIterator, FilesystemIterator, spl_filesystem_object_new_check, spl_GlobIterator_functions);
02969        REGISTER_SPL_IMPLEMENTS(GlobIterator, Countable);
02970 #endif
02971 
02972        REGISTER_SPL_SUB_CLASS_EX(SplFileObject, SplFileInfo, spl_filesystem_object_new_check, spl_SplFileObject_functions);
02973        REGISTER_SPL_IMPLEMENTS(SplFileObject, RecursiveIterator);
02974        REGISTER_SPL_IMPLEMENTS(SplFileObject, SeekableIterator);
02975 
02976        REGISTER_SPL_CLASS_CONST_LONG(SplFileObject, "DROP_NEW_LINE", SPL_FILE_OBJECT_DROP_NEW_LINE);
02977        REGISTER_SPL_CLASS_CONST_LONG(SplFileObject, "READ_AHEAD",    SPL_FILE_OBJECT_READ_AHEAD);
02978        REGISTER_SPL_CLASS_CONST_LONG(SplFileObject, "SKIP_EMPTY",    SPL_FILE_OBJECT_SKIP_EMPTY);
02979        REGISTER_SPL_CLASS_CONST_LONG(SplFileObject, "READ_CSV",      SPL_FILE_OBJECT_READ_CSV);
02980        
02981        REGISTER_SPL_SUB_CLASS_EX(SplTempFileObject, SplFileObject, spl_filesystem_object_new_check, spl_SplTempFileObject_functions);
02982        return SUCCESS;
02983 }
02984 /* }}} */
02985 
02986 /*
02987  * Local variables:
02988  * tab-width: 4
02989  * c-basic-offset: 4
02990  * End:
02991  * vim600: noet sw=4 ts=4 fdm=marker
02992  * vim<600: noet sw=4 ts=4
02993  */