]> granicus.if.org Git - php/commitdiff
- Change FileObject's line counting to be zero based
authorMarcus Boerger <helly@php.net>
Tue, 3 May 2005 21:11:26 +0000 (21:11 +0000)
committerMarcus Boerger <helly@php.net>
Tue, 3 May 2005 21:11:26 +0000 (21:11 +0000)
- Make FileObject implement SeekableIterator
- Add tests

ext/spl/spl_directory.c
ext/spl/tests/fileobject_001.phpt [new file with mode: 0755]
ext/spl/tests/fileobject_001a.txt [new file with mode: 0755]
ext/spl/tests/fileobject_001b.txt [new file with mode: 0755]

index 8c68992b2690b0bcc6133b49e2cb96f27525709b..c2fd725c466204c3090e03a596de4ab00074342d 100755 (executable)
@@ -872,14 +872,19 @@ 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) /* {{{ */
@@ -940,31 +945,35 @@ static int spl_file_object_read(spl_file_object *intern, int silent TSRMLS_DC) /
        size_t line_len;
        int len;
 
-       buf = php_stream_get_line(intern->stream, NULL, intern->max_line_len, &line_len);
-
-       if (!buf) {
+       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;
        }
 
+       buf = php_stream_get_line(intern->stream, NULL, intern->max_line_len, &line_len);
+
        spl_file_object_free_line(intern TSRMLS_CC);
        
-       if (intern->flags & SPL_FILE_OBJECT_DROP_NEW_LINE) {
-               line_len = strcspn(buf, "\r\n");
-               buf[line_len] = '\0';
-       }
-
-       if (PG(magic_quotes_runtime)) {
-               buf = php_addslashes(buf, line_len, &len, 1 TSRMLS_CC);
-               line_len = len;
+       if (!buf) {
+               intern->current_line = estrdup("");
+               intern->current_line_len = 0;
+       } else {
+               if (intern->flags & SPL_FILE_OBJECT_DROP_NEW_LINE) {
+                       line_len = strcspn(buf, "\r\n");
+                       buf[line_len] = '\0';
+               }
+       
+               if (PG(magic_quotes_runtime)) {
+                       buf = php_addslashes(buf, line_len, &len, 1 TSRMLS_CC);
+                       line_len = len;
+               }
+       
+               intern->current_line = buf;
+               intern->current_line_len = line_len;
        }
 
-       intern->current_line = buf;
-       intern->current_line_len = line_len;
-       intern->current_line_num++;
-
        return SUCCESS;
 } /* }}} */
 
@@ -976,6 +985,7 @@ static void spl_file_object_read_line(zval * this_ptr, spl_file_object *intern,
        if (intern->func_getCurr->common.scope != spl_ce_FileObject) {
                zend_call_method_with_0_params(&getThis(), Z_OBJCE_P(getThis()), &intern->func_getCurr, "getCurrentLine", &retval);
                if (retval) {
+                       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));
                                intern->current_line_len = Z_STRLEN_P(retval);
@@ -984,13 +994,22 @@ 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);
-                       intern->current_line_num++;
                }
        } else {
                spl_file_object_read(intern, silent TSRMLS_CC);
        }
 } /* }}} */
 
+static void spl_file_object_rewind(spl_file_object *intern TSRMLS_DC) /* {{{ */
+{
+       if (-1 == php_stream_rewind(intern->stream)) {
+               zend_throw_exception_ex(spl_ce_RuntimeException, 0 TSRMLS_CC, "Cannot rewind file %s", intern->file_name);
+       } else {
+               spl_file_object_free_line(intern TSRMLS_CC);
+               intern->current_line_num = 0;
+       }
+} /* }}} */
+
 static int spl_file_object_open(spl_file_object *intern, int use_include_path, int silent TSRMLS_DC) /* {{{ */
 {
        intern->context = php_stream_context_from_zval(intern->zcontext, 0);
@@ -1050,12 +1069,7 @@ SPL_METHOD(FileObject, rewind)
 {
        spl_file_object *intern = (spl_file_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
 
-       if (-1 == php_stream_rewind(intern->stream)) {
-               zend_throw_exception_ex(spl_ce_RuntimeException, 0 TSRMLS_CC, "Cannot rewind file %s", intern->file_name);
-       } else {
-               intern->current_line_num = 0;
-               spl_file_object_free_line(intern TSRMLS_CC);
-       }
+       spl_file_object_rewind(intern TSRMLS_CC);
 } /* }}} */
 
 /* {{{ proto string FileObject::getFilename()
@@ -1264,10 +1278,11 @@ SPL_METHOD(FileObject, fgetcsv)
        MAKE_STD_ZVAL(arg2);
        ZVAL_LONG(arg2, intern->max_line_len);
 
+       spl_file_object_free_line(intern TSRMLS_CC);
+
        FileFunctionCall(fgetcsv, arg2);
 
        zval_ptr_dtor(&arg2);
-       intern->current_line_num++;
 }
 /* }}} */
 
@@ -1344,10 +1359,11 @@ SPL_METHOD(FileObject, fgetss)
        MAKE_STD_ZVAL(arg2);
        ZVAL_LONG(arg2, intern->max_line_len);
 
+       spl_file_object_free_line(intern TSRMLS_CC);
+
        FileFunctionCall(fgetss, arg2);
 
        zval_ptr_dtor(&arg2);
-       intern->current_line_num++;
 } /* }}} */
 
 /* {{{ proto int FileObject::fpassthru()
@@ -1365,9 +1381,9 @@ SPL_METHOD(FileObject, fscanf)
 {
        spl_file_object *intern = (spl_file_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
 
-       FileFunctionCall(fscanf, NULL);
+       spl_file_object_free_line(intern TSRMLS_CC);
 
-       intern->current_line_num++;
+       FileFunctionCall(fscanf, NULL);
 }
 /* }}} */
 
@@ -1427,6 +1443,28 @@ SPL_METHOD(FileObject, ftruncate)
        RETURN_BOOL(0 == php_stream_truncate_set_size(intern->stream, size));
 } /* }}} */
 
+/* {{{ proto void FileObject::seek(int line_pos)
+   Seek to specified line */
+SPL_METHOD(FileObject, seek)
+{
+       spl_file_object *intern = (spl_file_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
+       long line_pos;
+       
+       if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &line_pos) == FAILURE) {
+               return;
+       }
+       if (line_pos < 0) {
+               zend_throw_exception_ex(spl_ce_LogicException, 0 TSRMLS_CC, "Can't seek file %s to negative line %ld", intern->file_name, line_pos);
+               RETURN_FALSE;           
+       }
+       
+       spl_file_object_rewind(intern TSRMLS_CC);
+       
+       while(intern->current_line_num < line_pos) {
+               spl_file_object_read_line(getThis(), intern, 1 TSRMLS_CC);
+       }
+}
+
 static
 ZEND_BEGIN_ARG_INFO_EX(arginfo_file_object___construct, 0, 0, 1)
        ZEND_ARG_INFO(0, file_name)
@@ -1484,6 +1522,11 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_file_object_ftruncate, 0, 0, 1)
        ZEND_ARG_INFO(0, size)
 ZEND_END_ARG_INFO();
 
+static
+ZEND_BEGIN_ARG_INFO_EX(arginfo_file_object_seek, 0, 0, 1) 
+       ZEND_ARG_INFO(0, line_pos)
+ZEND_END_ARG_INFO();
+
 static zend_function_entry spl_file_object_class_functions[] = {
        SPL_ME(FileObject, __construct,    arginfo_file_object___construct,   ZEND_ACC_PUBLIC)
        SPL_ME(FileObject, getFilename,    NULL, ZEND_ACC_PUBLIC)
@@ -1512,6 +1555,8 @@ static zend_function_entry spl_file_object_class_functions[] = {
        SPL_ME(FileObject, getMaxLineLen,  NULL, ZEND_ACC_PUBLIC)
        SPL_ME(FileObject, hasChildren,    NULL, ZEND_ACC_PUBLIC)
        SPL_ME(FileObject, getChildren,    NULL, ZEND_ACC_PUBLIC)
+       SPL_ME(FileObject, seek,           arginfo_file_object_seek,          ZEND_ACC_PUBLIC)
+       // mappings
        SPL_MA(FileObject, getCurrentLine, FileObject, fgets,      NULL, ZEND_ACC_PUBLIC)
        SPL_MA(FileObject, __toString,     FileObject, current,    NULL, ZEND_ACC_PUBLIC)
        {NULL, NULL, NULL}
@@ -1536,6 +1581,7 @@ PHP_MINIT_FUNCTION(spl_directory)
 
        REGISTER_SPL_STD_CLASS_EX(FileObject, spl_file_object_new, spl_file_object_class_functions);
        REGISTER_SPL_IMPLEMENTS(FileObject, RecursiveIterator);
+       REGISTER_SPL_IMPLEMENTS(FileObject, SeekableIterator);
 
        REGISTER_LONG_CONSTANT("FO_DROP_NEW_LINE",  (long)SPL_FILE_OBJECT_DROP_NEW_LINE,  CONST_CS | CONST_PERSISTENT); 
 
diff --git a/ext/spl/tests/fileobject_001.phpt b/ext/spl/tests/fileobject_001.phpt
new file mode 100755 (executable)
index 0000000..056c1e1
--- /dev/null
@@ -0,0 +1,88 @@
+--TEST--
+SPL: FileObject::seek'ing
+--FILE--
+<?php
+
+$o = new FileObject(dirname(__FILE__) . '/fileobject_001a.txt');
+
+var_dump($o->key());
+var_dump($o->current());
+$o->setFlags(FO_DROP_NEW_LINE);
+var_dump($o->key());
+var_dump($o->current());
+var_dump($o->key());
+$o->next();
+var_dump($o->key());
+var_dump($o->current());
+var_dump($o->key());
+$o->rewind();
+var_dump($o->key());
+var_dump($o->current());
+var_dump($o->key());
+$o->seek(4);
+var_dump($o->key());
+var_dump($o->current());
+var_dump($o->key());
+
+echo "===A===\n";
+foreach($o as $n => $l)
+{
+       var_dump($n, $l);
+}
+
+echo "===B===\n";
+$o = new FileObject(dirname(__FILE__) . '/fileobject_001b.txt');
+$o->setFlags(FO_DROP_NEW_LINE);
+foreach($o as $n => $l)
+{
+       var_dump($n, $l);
+}
+
+?>
+===DONE===
+--EXPECT--
+int(0)
+string(2) "0
+"
+int(0)
+string(2) "0
+"
+int(0)
+int(1)
+string(1) "1"
+int(1)
+int(0)
+string(1) "0"
+int(0)
+int(4)
+string(1) "4"
+int(4)
+===A===
+int(0)
+string(1) "0"
+int(1)
+string(1) "1"
+int(2)
+string(1) "2"
+int(3)
+string(1) "3"
+int(4)
+string(1) "4"
+int(5)
+string(1) "5"
+int(6)
+string(0) ""
+===B===
+int(0)
+string(1) "0"
+int(1)
+string(1) "1"
+int(2)
+string(1) "2"
+int(3)
+string(1) "3"
+int(4)
+string(1) "4"
+int(5)
+string(1) "5"
+===DONE===
diff --git a/ext/spl/tests/fileobject_001a.txt b/ext/spl/tests/fileobject_001a.txt
new file mode 100755 (executable)
index 0000000..e8371f0
--- /dev/null
@@ -0,0 +1,6 @@
+0
+1
+2
+3
+4
+5
diff --git a/ext/spl/tests/fileobject_001b.txt b/ext/spl/tests/fileobject_001b.txt
new file mode 100755 (executable)
index 0000000..0c4a8b5
--- /dev/null
@@ -0,0 +1,6 @@
+0
+1
+2
+3
+4
+5
\ No newline at end of file