]> granicus.if.org Git - php/commitdiff
- Make line counting work with FileObject::fgetc()
authorMarcus Boerger <helly@php.net>
Tue, 3 May 2005 22:18:19 +0000 (22:18 +0000)
committerMarcus Boerger <helly@php.net>
Tue, 3 May 2005 22:18:19 +0000 (22:18 +0000)
- Add a test for FileObject::fgetc()
- Update docs

ext/spl/internal/fileobject.inc
ext/spl/spl_directory.c
ext/spl/tests/fileobject_002.phpt [new file with mode: 0755]

index 152b6e4ece470f76bed4fc24aadf1fd7536a7f16..6cabf97cddee98e847897fdf5814bb0f7f7f04e3 100755 (executable)
@@ -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();
+               }
+       }
 }
 
 ?>
index c2fd725c466204c3090e03a596de4ab00074342d..4a942687fc7da94073663cedede63bec553b1a93 100755 (executable)
@@ -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 (executable)
index 0000000..f85b020
--- /dev/null
@@ -0,0 +1,122 @@
+--TEST--
+SPL: FileObject::fgetc
+--FILE--
+<?php
+
+function test($name)
+{
+       echo "===$name===\n";
+
+       $o = new FileObject(dirname(__FILE__) . '/' . $name);
+
+       var_dump($o->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===
+<?php exit(0); ?>
+--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===