mirror of
https://github.com/php/php-src.git
synced 2024-09-24 03:17:26 +00:00
- Add read ahead ability
- Add skipping empty lines - Add ability to read lines as csv
This commit is contained in:
parent
8cabf9175e
commit
b7f6e116f7
@ -1368,19 +1368,89 @@ static int spl_filesystem_file_read(spl_filesystem_object *intern, int silent TS
|
||||
return SUCCESS;
|
||||
} /* }}} */
|
||||
|
||||
static int spl_filesystem_file_read_line(zval * this_ptr, spl_filesystem_object *intern, int silent TSRMLS_DC) /* {{{ */
|
||||
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) /* {{{ */
|
||||
{
|
||||
zend_fcall_info fci;
|
||||
zend_fcall_info_cache fcic;
|
||||
zval z_fname;
|
||||
zval * zresource_ptr = &intern->u.file.zresource, *retval;
|
||||
int result;
|
||||
int num_args = pass_num_args + (arg2 ? 2 : 1);
|
||||
|
||||
zval ***params = (zval***)safe_emalloc(num_args, sizeof(zval**), 0);
|
||||
|
||||
params[0] = &zresource_ptr;
|
||||
|
||||
if (arg2) {
|
||||
params[1] = &arg2;
|
||||
}
|
||||
|
||||
zend_get_parameters_array_ex(pass_num_args, params+(arg2 ? 2 : 1));
|
||||
|
||||
ZVAL_STRING(&z_fname, func_ptr->common.function_name.s, 0);
|
||||
|
||||
fci.size = sizeof(fci);
|
||||
fci.function_table = EG(function_table);
|
||||
fci.object_pp = NULL;
|
||||
fci.function_name = &z_fname;
|
||||
fci.retval_ptr_ptr = &retval;
|
||||
fci.param_count = num_args;
|
||||
fci.params = params;
|
||||
fci.no_separation = 1;
|
||||
fci.symbol_table = NULL;
|
||||
|
||||
fcic.initialized = 1;
|
||||
fcic.function_handler = func_ptr;
|
||||
fcic.calling_scope = NULL;
|
||||
fcic.object_pp = NULL;
|
||||
|
||||
result = zend_call_function(&fci, &fcic TSRMLS_CC);
|
||||
|
||||
ZVAL_ZVAL(return_value, retval, 1, 1);
|
||||
|
||||
efree(params);
|
||||
return result;
|
||||
} /* }}} */
|
||||
|
||||
#define FileFunctionCall(func_name, pass_num_args, arg2) \
|
||||
{ \
|
||||
zend_function *func_ptr; \
|
||||
zend_hash_find(EG(function_table), #func_name, sizeof(#func_name), (void **) &func_ptr); \
|
||||
spl_filesystem_file_call(intern, func_ptr, pass_num_args, return_value, arg2 TSRMLS_CC); \
|
||||
}
|
||||
|
||||
static void spl_filesystem_file_read_csv(zval * this_ptr, spl_filesystem_object *intern, int pass_num_args, zval *return_value TSRMLS_DC) /* {{{ */
|
||||
{
|
||||
zval *arg2 = NULL;
|
||||
MAKE_STD_ZVAL(arg2);
|
||||
ZVAL_LONG(arg2, intern->u.file.max_line_len);
|
||||
|
||||
spl_filesystem_file_free_line(intern TSRMLS_CC);
|
||||
|
||||
FileFunctionCall(fgetcsv, pass_num_args, arg2);
|
||||
|
||||
zval_ptr_dtor(&arg2);
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
static int spl_filesystem_file_read_line_ex(zval * this_ptr, spl_filesystem_object *intern, int silent TSRMLS_DC) /* {{{ */
|
||||
{
|
||||
zval *retval;
|
||||
|
||||
/* if overloaded call the function, otherwise do it directly */
|
||||
if (intern->u.file.func_getCurr->common.scope != spl_ce_SplFileObject) {
|
||||
/* 1) use fgetcsv? 2) overloaded call the function, 3) do it directly */
|
||||
if (intern->flags & SPL_FILE_OBJECT_READ_CSV || intern->u.file.func_getCurr->common.scope != spl_ce_SplFileObject) {
|
||||
if (php_stream_eof(intern->u.file.stream)) {
|
||||
if (!silent) {
|
||||
zend_throw_exception_ex(spl_ce_RuntimeException, 0 TSRMLS_CC, "Cannot read from file %s", intern->file_name);
|
||||
}
|
||||
return FAILURE;
|
||||
}
|
||||
zend_call_method_with_0_params(&getThis(), Z_OBJCE_P(getThis()), &intern->u.file.func_getCurr, "getCurrentLine", &retval);
|
||||
if (intern->flags & SPL_FILE_OBJECT_READ_CSV) {
|
||||
MAKE_STD_ZVAL(retval);
|
||||
spl_filesystem_file_read_csv(this_ptr, intern, 0, retval TSRMLS_CC);
|
||||
} else {
|
||||
zend_call_method_with_0_params(&this_ptr, Z_OBJCE_P(getThis()), &intern->u.file.func_getCurr, "getCurrentLine", &retval);
|
||||
}
|
||||
if (retval) {
|
||||
if (intern->u.file.current_line || intern->u.file.current_zval) {
|
||||
intern->u.file.current_line_num++;
|
||||
@ -1403,7 +1473,49 @@ static int spl_filesystem_file_read_line(zval * this_ptr, spl_filesystem_object
|
||||
}
|
||||
} /* }}} */
|
||||
|
||||
static void spl_filesystem_file_rewind(spl_filesystem_object *intern TSRMLS_DC) /* {{{ */
|
||||
static int spl_filesystem_file_is_empty_line(spl_filesystem_object *intern TSRMLS_DC) /* {{{ */
|
||||
{
|
||||
if (intern->u.file.current_line) {
|
||||
return intern->u.file.current_line_len == 0;
|
||||
} else if (intern->u.file.current_zval) {
|
||||
switch(Z_TYPE_P(intern->u.file.current_zval)) {
|
||||
case IS_STRING:
|
||||
case IS_UNICODE:
|
||||
return Z_STRLEN_P(intern->u.file.current_zval) == 0;
|
||||
case IS_ARRAY:
|
||||
if ((intern->flags & SPL_FILE_OBJECT_READ_CSV)
|
||||
&& zend_hash_num_elements(Z_ARRVAL_P(intern->u.file.current_zval)) == 1) {
|
||||
zval ** first = Z_ARRVAL_P(intern->u.file.current_zval)->pListHead->pData;
|
||||
|
||||
return (Z_TYPE_PP(first) == IS_STRING || Z_TYPE_PP(first) == IS_UNICODE)
|
||||
&& Z_STRLEN_PP(first) == 0;
|
||||
}
|
||||
return zend_hash_num_elements(Z_ARRVAL_P(intern->u.file.current_zval)) == 0;
|
||||
case IS_NULL:
|
||||
return 1;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
static int spl_filesystem_file_read_line(zval * this_ptr, spl_filesystem_object *intern, int silent TSRMLS_DC) /* {{{ */
|
||||
{
|
||||
int ret = spl_filesystem_file_read_line_ex(this_ptr, intern, silent TSRMLS_CC);
|
||||
|
||||
while ((intern->flags & SPL_FILE_OBJECT_SKIP_EMPTY) && ret == SUCCESS && spl_filesystem_file_is_empty_line(intern TSRMLS_CC)) {
|
||||
spl_filesystem_file_free_line(intern TSRMLS_CC);
|
||||
ret = spl_filesystem_file_read_line_ex(this_ptr, intern, silent TSRMLS_CC);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
static void spl_filesystem_file_rewind(zval * this_ptr, spl_filesystem_object *intern TSRMLS_DC) /* {{{ */
|
||||
{
|
||||
if (-1 == php_stream_rewind(intern->u.file.stream)) {
|
||||
zend_throw_exception_ex(spl_ce_RuntimeException, 0 TSRMLS_CC, "Cannot rewind file %s", intern->file_name);
|
||||
@ -1411,6 +1523,9 @@ static void spl_filesystem_file_rewind(spl_filesystem_object *intern TSRMLS_DC)
|
||||
spl_filesystem_file_free_line(intern TSRMLS_CC);
|
||||
intern->u.file.current_line_num = 0;
|
||||
}
|
||||
if (intern->flags & SPL_FILE_OBJECT_READ_AHEAD) {
|
||||
spl_filesystem_file_read_line(this_ptr, intern, 1 TSRMLS_CC);
|
||||
}
|
||||
} /* }}} */
|
||||
|
||||
/* {{{ proto void SplFileObject::__construct(string filename [, string mode = 'r' [, bool use_include_path [, resource context]]]])
|
||||
@ -1495,7 +1610,7 @@ SPL_METHOD(SplFileObject, rewind)
|
||||
{
|
||||
spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
|
||||
|
||||
spl_filesystem_file_rewind(intern TSRMLS_CC);
|
||||
spl_filesystem_file_rewind(getThis(), intern TSRMLS_CC);
|
||||
} /* }}} */
|
||||
|
||||
/* {{{ proto string SplFileObject::getFilename()
|
||||
@ -1522,7 +1637,11 @@ SPL_METHOD(SplFileObject, valid)
|
||||
{
|
||||
spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
|
||||
|
||||
RETVAL_BOOL(!php_stream_eof(intern->u.file.stream));
|
||||
if (intern->flags & SPL_FILE_OBJECT_READ_AHEAD) {
|
||||
RETURN_BOOL(intern->u.file.current_line || intern->u.file.current_zval);
|
||||
} else {
|
||||
RETVAL_BOOL(!php_stream_eof(intern->u.file.stream));
|
||||
}
|
||||
} /* }}} */
|
||||
|
||||
/* {{{ proto string SplFileObject::fgets()
|
||||
@ -1543,7 +1662,7 @@ SPL_METHOD(SplFileObject, current)
|
||||
{
|
||||
spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
|
||||
|
||||
if (!intern->u.file.current_line) {
|
||||
if (!intern->u.file.current_line && !intern->u.file.current_zval) {
|
||||
spl_filesystem_file_read_line(getThis(), intern, 1 TSRMLS_CC);
|
||||
}
|
||||
if (intern->u.file.current_line) {
|
||||
@ -1574,6 +1693,9 @@ SPL_METHOD(SplFileObject, next)
|
||||
spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
|
||||
|
||||
spl_filesystem_file_free_line(intern TSRMLS_CC);
|
||||
if (intern->flags & SPL_FILE_OBJECT_READ_AHEAD) {
|
||||
spl_filesystem_file_read_line(getThis(), intern, 1 TSRMLS_CC);
|
||||
}
|
||||
intern->u.file.current_line_num++;
|
||||
} /* }}} */
|
||||
|
||||
@ -1638,62 +1760,12 @@ SPL_METHOD(SplFileObject, getChildren)
|
||||
/* return NULL */
|
||||
} /* }}} */
|
||||
|
||||
static int spl_filesystem_file_call(INTERNAL_FUNCTION_PARAMETERS, spl_filesystem_object *intern, zend_function *func_ptr, zval *arg2) /* {{{ */
|
||||
{
|
||||
zend_fcall_info fci;
|
||||
zend_fcall_info_cache fcic;
|
||||
zval z_fname;
|
||||
zval * zresource_ptr = &intern->u.file.zresource, *retval;
|
||||
int result;
|
||||
|
||||
zval ***params = (zval***)safe_emalloc(ZEND_NUM_ARGS(), sizeof(zval**), (arg2 ? 2 : 1) * sizeof(zval**));
|
||||
|
||||
params[0] = &zresource_ptr;
|
||||
|
||||
if (arg2) {
|
||||
params[1] = &arg2;
|
||||
}
|
||||
|
||||
zend_get_parameters_array_ex(ZEND_NUM_ARGS(), params+(arg2 ? 2 : 1));
|
||||
|
||||
ZVAL_STRING(&z_fname, func_ptr->common.function_name.s, 0);
|
||||
|
||||
fci.size = sizeof(fci);
|
||||
fci.function_table = EG(function_table);
|
||||
fci.object_pp = NULL;
|
||||
fci.function_name = &z_fname;
|
||||
fci.retval_ptr_ptr = &retval;
|
||||
fci.param_count = ZEND_NUM_ARGS() + (arg2 ? 2 : 1);
|
||||
fci.params = params;
|
||||
fci.no_separation = 1;
|
||||
fci.symbol_table = NULL;
|
||||
|
||||
fcic.initialized = 1;
|
||||
fcic.function_handler = func_ptr;
|
||||
fcic.calling_scope = NULL;
|
||||
fcic.object_pp = NULL;
|
||||
|
||||
result = zend_call_function(&fci, &fcic TSRMLS_CC);
|
||||
|
||||
ZVAL_ZVAL(return_value, retval, 1, 1);
|
||||
|
||||
efree(params);
|
||||
return result;
|
||||
} /* }}} */
|
||||
|
||||
#define FileFunctionCall(func_name, arg2) \
|
||||
{ \
|
||||
zend_function *func_ptr; \
|
||||
zend_hash_find(EG(function_table), #func_name, sizeof(#func_name), (void **) &func_ptr); \
|
||||
spl_filesystem_file_call(INTERNAL_FUNCTION_PARAM_PASSTHRU, intern, func_ptr, arg2); \
|
||||
}
|
||||
|
||||
/* {{{ FileFunction */
|
||||
#define FileFunction(func_name) \
|
||||
SPL_METHOD(SplFileObject, func_name) \
|
||||
{ \
|
||||
spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC); \
|
||||
FileFunctionCall(func_name, NULL); \
|
||||
FileFunctionCall(func_name, ZEND_NUM_ARGS(), NULL); \
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
@ -1702,16 +1774,9 @@ SPL_METHOD(SplFileObject, func_name) \
|
||||
SPL_METHOD(SplFileObject, fgetcsv)
|
||||
{
|
||||
spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
|
||||
zval *arg2 = NULL;
|
||||
MAKE_STD_ZVAL(arg2);
|
||||
ZVAL_LONG(arg2, intern->u.file.max_line_len);
|
||||
|
||||
spl_filesystem_file_free_line(intern TSRMLS_CC);
|
||||
|
||||
spl_filesystem_file_read_csv(getThis(), intern, ZEND_NUM_ARGS(), return_value TSRMLS_CC);
|
||||
intern->u.file.current_line_num++;
|
||||
|
||||
FileFunctionCall(fgetcsv, arg2);
|
||||
|
||||
zval_ptr_dtor(&arg2);
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
@ -1796,7 +1861,7 @@ SPL_METHOD(SplFileObject, fgetss)
|
||||
spl_filesystem_file_free_line(intern TSRMLS_CC);
|
||||
intern->u.file.current_line_num++;
|
||||
|
||||
FileFunctionCall(fgetss, arg2);
|
||||
FileFunctionCall(fgetss, ZEND_NUM_ARGS(), arg2);
|
||||
|
||||
zval_ptr_dtor(&arg2);
|
||||
} /* }}} */
|
||||
@ -1819,7 +1884,7 @@ SPL_METHOD(SplFileObject, fscanf)
|
||||
spl_filesystem_file_free_line(intern TSRMLS_CC);
|
||||
intern->u.file.current_line_num++;
|
||||
|
||||
FileFunctionCall(fscanf, NULL);
|
||||
FileFunctionCall(fscanf, ZEND_NUM_ARGS(), NULL);
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
@ -1885,7 +1950,7 @@ SPL_METHOD(SplFileObject, seek)
|
||||
RETURN_FALSE;
|
||||
}
|
||||
|
||||
spl_filesystem_file_rewind(intern TSRMLS_CC);
|
||||
spl_filesystem_file_rewind(getThis(), intern TSRMLS_CC);
|
||||
|
||||
while(intern->u.file.current_line_num < line_pos) {
|
||||
spl_filesystem_file_read_line(getThis(), intern, 1 TSRMLS_CC);
|
||||
@ -2036,7 +2101,9 @@ PHP_MINIT_FUNCTION(spl_directory)
|
||||
REGISTER_SPL_SUB_CLASS_EX(SplTempFileObject, SplFileObject, spl_filesystem_object_new, spl_SplTempFileObject_functions);
|
||||
|
||||
REGISTER_SPL_CLASS_CONST_LONG(SplFileObject, "DROP_NEW_LINE", SPL_FILE_OBJECT_DROP_NEW_LINE);
|
||||
|
||||
REGISTER_SPL_CLASS_CONST_LONG(SplFileObject, "READ_AHEAD", SPL_FILE_OBJECT_READ_AHEAD);
|
||||
REGISTER_SPL_CLASS_CONST_LONG(SplFileObject, "SKIP_EMPTY", SPL_FILE_OBJECT_SKIP_EMPTY);
|
||||
REGISTER_SPL_CLASS_CONST_LONG(SplFileObject, "READ_CSV", SPL_FILE_OBJECT_READ_CSV);
|
||||
return SUCCESS;
|
||||
}
|
||||
/* }}} */
|
||||
|
@ -82,11 +82,15 @@ struct _spl_filesystem_object {
|
||||
long current_line_num;
|
||||
zval zresource;
|
||||
zend_function *func_getCurr;
|
||||
zend_function *func_fgetcsv;
|
||||
} file;
|
||||
} u;
|
||||
};
|
||||
|
||||
#define SPL_FILE_OBJECT_DROP_NEW_LINE 0x00000001 /* drop new lines */
|
||||
#define SPL_FILE_OBJECT_READ_AHEAD 0x00000002 /* read on rewind/next */
|
||||
#define SPL_FILE_OBJECT_SKIP_EMPTY 0x00000006 /* skip empty lines */
|
||||
#define SPL_FILE_OBJECT_READ_CSV 0x00000008 /* read via fgetcsv */
|
||||
|
||||
#define SPL_FILE_DIR_CURRENT_AS_FILEINFO 0x00000010 /* make RecursiveDirectoryTree::current() return SplFileInfo */
|
||||
#define SPL_FILE_DIR_CURRENT_AS_PATHNAME 0x00000020 /* make RecursiveDirectoryTree::current() return getPathname() */
|
||||
|
Loading…
Reference in New Issue
Block a user