From 177ea26dc1d6942b292072110e7199ba19656a95 Mon Sep 17 00:00:00 2001 From: Marcus Boerger Date: Tue, 3 May 2005 22:18:19 +0000 Subject: [PATCH] - Make line counting work with FileObject::fgetc() - Add a test for FileObject::fgetc() - Update docs --- ext/spl/internal/fileobject.inc | 68 +++++++++++++---- ext/spl/spl_directory.c | 39 +++++++--- ext/spl/tests/fileobject_002.phpt | 122 ++++++++++++++++++++++++++++++ 3 files changed, 206 insertions(+), 23 deletions(-) create mode 100755 ext/spl/tests/fileobject_002.phpt diff --git a/ext/spl/internal/fileobject.inc b/ext/spl/internal/fileobject.inc index 152b6e4ece..6cabf97cdd 100755 --- a/ext/spl/internal/fileobject.inc +++ b/ext/spl/internal/fileobject.inc @@ -15,7 +15,7 @@ * @version 1.0 * @since PHP 5.1 */ -class FileObject implements RecursiveIterator +class FileObject implements RecursiveIterator, SeekableIterator { private $fp; private $fname; @@ -65,6 +65,7 @@ class FileObject implements RecursiveIterator */ function fgets() { + $this->freeLine(); $this->lnum++; $buf = fgets($this->fp, $this->max_len); @@ -77,6 +78,7 @@ class FileObject implements RecursiveIterator */ function fgetcsv($delimiter = ';', $enclosure = '') { + $this->freeLine(); $this->lnum++; return fgetcsv($this->fp, $this->max_len, $delimiter, $enclosure); } @@ -122,7 +124,11 @@ class FileObject implements RecursiveIterator */ function fgetc() { - return fgetc($this->fp); + $this->freeLine(); + $c = fgetc($this->fp); + if ($c == '\n') { + $this->lnum++; + } } /** Read and return remaining part of stream @@ -146,6 +152,7 @@ class FileObject implements RecursiveIterator */ function fscanf($format /* , ... */) { + $this->freeLine(); $this->lnum++; return fscanf($this->fp, $format /* , ... */); } @@ -228,7 +235,7 @@ class FileObject implements RecursiveIterator */ function rewind() { - $this->line = NULL; + $this->freeLine(); $this->lnum = 0; } @@ -254,15 +261,13 @@ class FileObject implements RecursiveIterator } /** - * @note Fill current line buffer if not done yet. * @return line number + * @note fgetc() will increase the line number when reaing a new line char. + * This has the effect key() called on a read a new line will already + * return the increased line number. */ function key() { - if (is_null($this->line)) - { - $line = getCurrentLine(); - } return $this->lnum; } @@ -270,7 +275,7 @@ class FileObject implements RecursiveIterator */ function next() { - $this->line = NULL; + $this->freeLine(); } /** @@ -278,16 +283,41 @@ class FileObject implements RecursiveIterator */ private function readLine() { - $this->lnum++; - return fgets($this->fp, $this->max_len); + if ($this->eof()) + { + $this->freeLine(); + throw new RuntimeException("Cannot read from file " . $this->fname); + } + if ($this->line) { + $this->lnum++; + } + $this->freeLine(); + $this->line = fgets($this->fp, $this->max_len); + return $this->line; + } + + /** + * Free the current line buffer and increment the line counter + */ + private function freeLine() + { + if ($this->line) { + $this->line = NULL; + } } /* - * @note if you overload this function key() and current() will increment - * $this->lnum. + * @note If you DO overload this function key() and current() will increment + * $this->lnum automatically. If not then function reaLine() will do + * that for you. */ function getCurrentLine() { + $this->freeLine(); + if ($this->eof()) + { + throw new RuntimeException("Cannot read from file " . $this->fname); + } $this->readLine(); } @@ -298,6 +328,18 @@ class FileObject implements RecursiveIterator { return current(); } + + /** + * @param $line_pos Seek to this line + */ + function seek($line_pos) + { + $this->rewind(); + while($this->lnum < $line_pos && !$this->eof()) + { + $this->getCurrentLine(); + } + } } ?> diff --git a/ext/spl/spl_directory.c b/ext/spl/spl_directory.c index c2fd725c46..4a942687fc 100755 --- a/ext/spl/spl_directory.c +++ b/ext/spl/spl_directory.c @@ -872,19 +872,14 @@ static zend_function_entry spl_ce_dir_tree_class_functions[] = { static void spl_file_object_free_line(spl_file_object *intern TSRMLS_DC) /* {{{ */ { - long line_add = 0; - if (intern->current_line) { efree(intern->current_line); intern->current_line = NULL; - line_add = 1; } if (intern->current_zval) { zval_ptr_dtor(&intern->current_zval); intern->current_zval = NULL; - line_add = 1; } - intern->current_line_num += line_add; } /* }}} */ static void spl_file_object_free_storage(void *object TSRMLS_DC) /* {{{ */ @@ -944,7 +939,10 @@ static int spl_file_object_read(spl_file_object *intern, int silent TSRMLS_DC) / char *buf; size_t line_len; int len; + long line_add = (intern->current_line || intern->current_zval) ? 1 : 0; + spl_file_object_free_line(intern TSRMLS_CC); + if (php_stream_eof(intern->stream)) { if (!silent) { zend_throw_exception_ex(spl_ce_RuntimeException, 0 TSRMLS_CC, "Cannot read from file %s", intern->file_name); @@ -954,8 +952,6 @@ static int spl_file_object_read(spl_file_object *intern, int silent TSRMLS_DC) / buf = php_stream_get_line(intern->stream, NULL, intern->max_line_len, &line_len); - spl_file_object_free_line(intern TSRMLS_CC); - if (!buf) { intern->current_line = estrdup(""); intern->current_line_len = 0; @@ -973,18 +969,28 @@ static int spl_file_object_read(spl_file_object *intern, int silent TSRMLS_DC) / intern->current_line = buf; intern->current_line_len = line_len; } + intern->current_line_num += line_add; return SUCCESS; } /* }}} */ -static void spl_file_object_read_line(zval * this_ptr, spl_file_object *intern, int silent TSRMLS_DC) /* {{{ */ +static int spl_file_object_read_line(zval * this_ptr, spl_file_object *intern, int silent TSRMLS_DC) /* {{{ */ { zval *retval; /* if overloaded call the function, otherwise do it directly */ if (intern->func_getCurr->common.scope != spl_ce_FileObject) { + if (php_stream_eof(intern->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->func_getCurr, "getCurrentLine", &retval); if (retval) { + if (intern->current_line || intern->current_zval) { + intern->current_line_num++; + } spl_file_object_free_line(intern TSRMLS_CC); if (Z_TYPE_P(retval) == IS_STRING) { intern->current_line = estrndup(Z_STRVAL_P(retval), Z_STRLEN_P(retval)); @@ -994,9 +1000,12 @@ static void spl_file_object_read_line(zval * this_ptr, spl_file_object *intern, ZVAL_ZVAL(intern->current_zval, retval, 1, 0); } zval_ptr_dtor(&retval); + return SUCCESS; + } else { + return FAILURE; } } else { - spl_file_object_read(intern, silent TSRMLS_CC); + return spl_file_object_read(intern, silent TSRMLS_CC); } } /* }}} */ @@ -1134,9 +1143,10 @@ SPL_METHOD(FileObject, key) { spl_file_object *intern = (spl_file_object*)zend_object_store_get_object(getThis() TSRMLS_CC); +/* Do not read the next line to support correct counting with fgetc() if (!intern->current_line) { spl_file_object_read_line(getThis(), intern, 1 TSRMLS_CC); - } + } */ RETURN_LONG(intern->current_line_num); } /* }}} */ @@ -1147,6 +1157,7 @@ SPL_METHOD(FileObject, next) spl_file_object *intern = (spl_file_object*)zend_object_store_get_object(getThis() TSRMLS_CC); spl_file_object_free_line(intern TSRMLS_CC); + intern->current_line_num++; } /* }}} */ /* {{{ proto void FileObject::setFlags(int flags) @@ -1279,6 +1290,7 @@ SPL_METHOD(FileObject, fgetcsv) ZVAL_LONG(arg2, intern->max_line_len); spl_file_object_free_line(intern TSRMLS_CC); + intern->current_line_num++; FileFunctionCall(fgetcsv, arg2); @@ -1338,11 +1350,16 @@ SPL_METHOD(FileObject, fgetc) char buf[2]; int result; + spl_file_object_free_line(intern TSRMLS_CC); + result = php_stream_getc(intern->stream); if (result == EOF) { RETVAL_FALSE; } else { + if (result == '\n') { + intern->current_line_num++; + } buf[0] = result; buf[1] = '\0'; @@ -1360,6 +1377,7 @@ SPL_METHOD(FileObject, fgetss) ZVAL_LONG(arg2, intern->max_line_len); spl_file_object_free_line(intern TSRMLS_CC); + intern->current_line_num++; FileFunctionCall(fgetss, arg2); @@ -1382,6 +1400,7 @@ SPL_METHOD(FileObject, fscanf) spl_file_object *intern = (spl_file_object*)zend_object_store_get_object(getThis() TSRMLS_CC); spl_file_object_free_line(intern TSRMLS_CC); + intern->current_line_num++; FileFunctionCall(fscanf, NULL); } diff --git a/ext/spl/tests/fileobject_002.phpt b/ext/spl/tests/fileobject_002.phpt new file mode 100755 index 0000000000..f85b020503 --- /dev/null +++ b/ext/spl/tests/fileobject_002.phpt @@ -0,0 +1,122 @@ +--TEST-- +SPL: FileObject::fgetc +--FILE-- +key()); + while(($c = $o->fgetc()) !== false) + { + var_dump($o->key(), $c, $o->eof()); + } + echo "===EOF?===\n"; + var_dump($o->eof()); + var_dump($o->key()); + var_dump($o->eof()); +} + +test('fileobject_001a.txt'); +test('fileobject_001b.txt'); + +?> +===DONE=== + +--EXPECT-- +===fileobject_001a.txt=== +int(0) +int(0) +string(1) "0" +bool(false) +int(1) +string(1) " +" +bool(false) +int(1) +string(1) "1" +bool(false) +int(2) +string(1) " +" +bool(false) +int(2) +string(1) "2" +bool(false) +int(3) +string(1) " +" +bool(false) +int(3) +string(1) "3" +bool(false) +int(4) +string(1) " +" +bool(false) +int(4) +string(1) "4" +bool(false) +int(5) +string(1) " +" +bool(false) +int(5) +string(1) "5" +bool(false) +int(6) +string(1) " +" +bool(false) +===EOF?=== +bool(true) +int(6) +bool(true) +===fileobject_001b.txt=== +int(0) +int(0) +string(1) "0" +bool(false) +int(1) +string(1) " +" +bool(false) +int(1) +string(1) "1" +bool(false) +int(2) +string(1) " +" +bool(false) +int(2) +string(1) "2" +bool(false) +int(3) +string(1) " +" +bool(false) +int(3) +string(1) "3" +bool(false) +int(4) +string(1) " +" +bool(false) +int(4) +string(1) "4" +bool(false) +int(5) +string(1) " +" +bool(false) +int(5) +string(1) "5" +bool(false) +===EOF?=== +bool(true) +int(5) +bool(true) +===DONE=== -- 2.50.1