lbarnaud                Sat Nov 15 12:52:14 2008 UTC

  Added files:                 (Branch: PHP_5_3)
    /php-src/ext/standard/tests/file    userstreams_002.phpt 
                                        userstreams_003.phpt 

  Modified files:              
    /php-src/main/streams       userspace.c 
    /php-src    NEWS 
  Log:
  MFH: Added stream_cast() and stream_set_options() to user-space stream
  wrappers, allowing stream_select(), stream_set_blocking(),
  stream_set_timeout() and stream_set_write_buffer() to work with user-space
  stream wrappers.
  Will document.
  
  
http://cvs.php.net/viewvc.cgi/php-src/main/streams/userspace.c?r1=1.31.2.3.2.7.2.4&r2=1.31.2.3.2.7.2.5&diff_format=u
Index: php-src/main/streams/userspace.c
diff -u php-src/main/streams/userspace.c:1.31.2.3.2.7.2.4 
php-src/main/streams/userspace.c:1.31.2.3.2.7.2.5
--- php-src/main/streams/userspace.c:1.31.2.3.2.7.2.4   Fri Jul 25 08:23:06 2008
+++ php-src/main/streams/userspace.c    Sat Nov 15 12:52:13 2008
@@ -17,7 +17,7 @@
    +----------------------------------------------------------------------+
 */
 
-/* $Id: userspace.c,v 1.31.2.3.2.7.2.4 2008/07/25 08:23:06 dmitry Exp $ */
+/* $Id: userspace.c,v 1.31.2.3.2.7.2.5 2008/11/15 12:52:13 lbarnaud Exp $ */
 
 #include "php.h"
 #include "php_globals.h"
@@ -82,6 +82,19 @@
        REGISTER_LONG_CONSTANT("STREAM_MKDIR_RECURSIVE",        
PHP_STREAM_MKDIR_RECURSIVE,             CONST_CS|CONST_PERSISTENT);
 
        REGISTER_LONG_CONSTANT("STREAM_IS_URL", PHP_STREAM_IS_URL,              
CONST_CS|CONST_PERSISTENT);
+
+       REGISTER_LONG_CONSTANT("STREAM_OPTION_BLOCKING",        
PHP_STREAM_OPTION_BLOCKING,             CONST_CS|CONST_PERSISTENT);
+       REGISTER_LONG_CONSTANT("STREAM_OPTION_READ_TIMEOUT",    
PHP_STREAM_OPTION_READ_TIMEOUT,         CONST_CS|CONST_PERSISTENT);
+       REGISTER_LONG_CONSTANT("STREAM_OPTION_READ_BUFFER",     
PHP_STREAM_OPTION_READ_BUFFER,          CONST_CS|CONST_PERSISTENT);
+       REGISTER_LONG_CONSTANT("STREAM_OPTION_WRITE_BUFFER",    
PHP_STREAM_OPTION_WRITE_BUFFER,         CONST_CS|CONST_PERSISTENT);
+
+       REGISTER_LONG_CONSTANT("STREAM_BUFFER_NONE",            
PHP_STREAM_BUFFER_NONE,                 CONST_CS|CONST_PERSISTENT);
+       REGISTER_LONG_CONSTANT("STREAM_BUFFER_LINE",            
PHP_STREAM_BUFFER_LINE,                 CONST_CS|CONST_PERSISTENT);
+       REGISTER_LONG_CONSTANT("STREAM_BUFFER_FULL",            
PHP_STREAM_BUFFER_FULL,                 CONST_CS|CONST_PERSISTENT);
+
+       REGISTER_LONG_CONSTANT("STREAM_CAST_AS_STREAM",         
PHP_STREAM_AS_STDIO,                    CONST_CS|CONST_PERSISTENT);
+       REGISTER_LONG_CONSTANT("STREAM_CAST_FOR_SELECT",        
PHP_STREAM_AS_FD_FOR_SELECT,            CONST_CS|CONST_PERSISTENT);
+
        return SUCCESS;
 }
 
@@ -111,6 +124,8 @@
 #define USERSTREAM_DIR_REWIND  "dir_rewinddir"
 #define USERSTREAM_DIR_CLOSE   "dir_closedir"
 #define USERSTREAM_LOCK     "stream_lock"
+#define USERSTREAM_CAST                "stream_cast"
+#define USERSTREAM_SET_OPTION  "stream_set_option"
 
 /* {{{ class should have methods like these:
  
@@ -160,6 +175,33 @@
                return array( just like that returned by fstat() );
        }
 
+       function stream_cast($castas)
+       {
+               if ($castas == STREAM_CAST_FOR_SELECT) {
+                       return $this->underlying_stream;
+               }
+               return false;
+       }
+
+       function stream_set_option($option, $arg1, $arg2)
+       {
+               switch($option) {
+               case STREAM_OPTION_BLOCKING:
+                       $blocking = $arg1;
+                       ...
+               case STREAM_OPTION_READ_TIMEOUT:
+                       $sec = $arg1;
+                       $usec = $arg2;
+                       ...
+               case STREAM_OPTION_WRITE_BUFFER:
+                       $mode = $arg1;
+                       $size = $arg2;
+                       ...
+               default:
+                       return false;
+               }
+       }
+
        function url_stat(string $url, int $flags)
        {
                return array( just like that returned by stat() );
@@ -882,7 +924,7 @@
        php_userstream_data_t *us = (php_userstream_data_t *)stream->abstract;
        int ret = -1;
        zval *zvalue = NULL;
-       zval **args[1];
+       zval **args[3];
 
        switch (option) {
        case PHP_STREAM_OPTION_CHECK_LIVENESS:
@@ -925,6 +967,75 @@
                }
 
                break;
+       
+       case PHP_STREAM_OPTION_READ_BUFFER:
+       case PHP_STREAM_OPTION_WRITE_BUFFER:
+       case PHP_STREAM_OPTION_READ_TIMEOUT:
+       case PHP_STREAM_OPTION_BLOCKING: {
+               zval *zoption = NULL;
+               zval *zptrparam = NULL;
+               
+               ZVAL_STRINGL(&func_name, USERSTREAM_SET_OPTION, 
sizeof(USERSTREAM_SET_OPTION)-1, 0);
+
+               ALLOC_INIT_ZVAL(zoption);
+               ZVAL_LONG(zoption, option);
+
+               ALLOC_INIT_ZVAL(zvalue);
+               ALLOC_INIT_ZVAL(zptrparam);
+
+               args[0] = &zoption;
+               args[1] = &zvalue;
+               args[2] = &zptrparam;
+
+               switch(option) {
+               case PHP_STREAM_OPTION_READ_BUFFER:
+               case PHP_STREAM_OPTION_WRITE_BUFFER:
+                       ZVAL_LONG(zvalue, value);
+                       if (ptrparam) {
+                               ZVAL_LONG(zptrparam, *(long *)ptrparam);
+                       } else {
+                               ZVAL_LONG(zptrparam, BUFSIZ);
+                       }
+                       break;
+               case PHP_STREAM_OPTION_READ_TIMEOUT: {
+                       struct timeval tv = *(struct timeval*)ptrparam;
+                       ZVAL_LONG(zvalue, tv.tv_sec);
+                       ZVAL_LONG(zptrparam, tv.tv_usec);
+                       break;
+                       }
+               case PHP_STREAM_OPTION_BLOCKING:
+                       ZVAL_LONG(zvalue, value);
+                       break;
+               default:
+                       break;
+               }
+
+               call_result = call_user_function_ex(NULL,
+                       &us->object,
+                       &func_name,
+                       &retval,
+                       3, args, 0, NULL TSRMLS_CC);
+       
+               do {
+                       if (call_result == FAILURE) {
+                               php_error_docref(NULL TSRMLS_CC, E_WARNING, 
"%s::" USERSTREAM_SET_OPTION " is not implemented!",
+                                               us->wrapper->classname);
+                               break;
+                       }
+                       if (retval && zend_is_true(retval)) {
+                               ret = PHP_STREAM_OPTION_RETURN_OK;
+                       }
+               } while (0);
+
+               if (zoption) {
+                       zval_ptr_dtor(&zoption);
+               }
+               if (zptrparam) {
+                       zval_ptr_dtor(&zptrparam);
+               }
+
+               break;
+               }
        }
 
        /* clean up */
@@ -1331,12 +1442,76 @@
 
 }
 
+static int php_userstreamop_cast(php_stream *stream, int castas, void **retptr 
TSRMLS_DC)
+{
+       php_userstream_data_t *us = (php_userstream_data_t *)stream->abstract;
+       zval func_name;
+       zval *retval = NULL;
+       zval *zcastas = NULL;
+       zval **args[1];
+       php_stream * intstream = NULL;
+       int call_result;
+       int ret = FAILURE;
+
+       ZVAL_STRINGL(&func_name, USERSTREAM_CAST, sizeof(USERSTREAM_CAST)-1, 0);
+
+       ALLOC_INIT_ZVAL(zcastas);
+       switch(castas) {
+       case PHP_STREAM_AS_FD_FOR_SELECT:
+               ZVAL_LONG(zcastas, PHP_STREAM_AS_FD_FOR_SELECT);
+               break;
+       default:
+               ZVAL_LONG(zcastas, PHP_STREAM_AS_STDIO);
+               break;
+       }
+       args[0] = &zcastas;
+
+       call_result = call_user_function_ex(NULL,
+                       &us->object,
+                       &func_name,
+                       &retval,
+                       1, args, 0, NULL TSRMLS_CC);
+
+       do {
+               if (call_result == FAILURE) {
+                       php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s::" 
USERSTREAM_CAST " is not implemented!",
+                                       us->wrapper->classname);
+                       break;
+               }
+               if (retval == NULL || !zend_is_true(retval)) {
+                       break;
+               }
+               php_stream_from_zval_no_verify(intstream, &retval);
+               if (!intstream) {
+                       php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s::" 
USERSTREAM_CAST " must return a stream resource",
+                                       us->wrapper->classname);
+                       break;
+               }
+               if (intstream == stream) {
+                       php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s::" 
USERSTREAM_CAST " must not return itself",
+                                       us->wrapper->classname);
+                       intstream = NULL;
+                       break;
+               }
+               ret = php_stream_cast(intstream, castas, retptr, 1);
+       } while (0);
+
+       if (retval) {
+               zval_ptr_dtor(&retval);
+       }
+       if (zcastas) {
+               zval_ptr_dtor(&zcastas);
+       }
+
+       return ret;
+}
+
 php_stream_ops php_stream_userspace_ops = {
        php_userstreamop_write, php_userstreamop_read,
        php_userstreamop_close, php_userstreamop_flush,
        "user-space",
        php_userstreamop_seek,
-       NULL, /* cast */
+       php_userstreamop_cast,
        php_userstreamop_stat, 
        php_userstreamop_set_option,
 };
http://cvs.php.net/viewvc.cgi/php-src/NEWS?r1=1.2027.2.547.2.965.2.376&r2=1.2027.2.547.2.965.2.377&diff_format=u
Index: php-src/NEWS
diff -u php-src/NEWS:1.2027.2.547.2.965.2.376 
php-src/NEWS:1.2027.2.547.2.965.2.377
--- php-src/NEWS:1.2027.2.547.2.965.2.376       Thu Nov 13 10:14:03 2008
+++ php-src/NEWS        Sat Nov 15 12:52:13 2008
@@ -10,6 +10,9 @@
   parameter validation. (Felipe)
 - Changed openssl info to show the shared library version number. (Scott)
 
+- Added stream_cast() and stream_set_options() to user-space stream wrappers,
+  allowing stream_select(), stream_set_blocking(), stream_set_timeout() and 
+  stream_set_write_buffer() to work with user-space stream wrappers. (Arnaud)
 - Added header_remove() function. (chsc at peytz dot dk, Arnaud)
 - Added stream_context_get_params() function. (Arnaud)
 - Added optional parameter "new" to sybase_connect() (Timm)

http://cvs.php.net/viewvc.cgi/php-src/ext/standard/tests/file/userstreams_002.phpt?view=markup&rev=1.1
Index: php-src/ext/standard/tests/file/userstreams_002.phpt
+++ php-src/ext/standard/tests/file/userstreams_002.phpt
--TEST--
User-space streams: stream_cast()
--FILE--
<?php
class test_wrapper_base {
        public $return_value;
        function stream_open($path, $mode, $openedpath) {
                return true;
        }
        function stream_eof() {
                return false;
        }
}
class test_wrapper extends test_wrapper_base {
        function stream_cast($castas) {
                return $this->return_value;
        }
}
function test($name, $fd, $return_value) {
        echo "\n------ $name: -------\n";
        $data = stream_get_meta_data($fd);
        $data['wrapper_data']->return_value = $return_value;
        $r = array($fd);
        $w = $e = null;
        var_dump(stream_select($r, $w, $e, 0) !== false);
}

var_dump(stream_wrapper_register('test', 'test_wrapper'));
var_dump(stream_wrapper_register('test2', 'test_wrapper_base'));

$fd = fopen("test://foo","r");
$fd2 = fopen("test2://foo","r");

test("valid stream", $fd, STDIN);
test("stream_cast not implemented", $fd2, null);
test("return value is false", $fd, false);
test("return value not a stream resource", $fd, "foo");
test("return value is stream itself", $fd, $fd);
test("return value cannot be casted", $fd, $fd2);

?>
--EXPECTF--
bool(true)
bool(true)

------ valid stream: -------
bool(true)

------ stream_cast not implemented: -------

Warning: stream_select(): test_wrapper_base::stream_cast is not implemented! in 
%s

Warning: stream_select(): cannot represent a stream of type user-space as a 
select()able descriptor in %s

Warning: stream_select(): No stream arrays were passed in %s
bool(false)

------ return value is false: -------

Warning: stream_select(): cannot represent a stream of type user-space as a 
select()able descriptor in %s

Warning: stream_select(): No stream arrays were passed in %s
bool(false)

------ return value not a stream resource: -------

Warning: stream_select(): supplied argument is not a valid stream resource in %s

Warning: stream_select(): test_wrapper::stream_cast must return a stream 
resource in %s

Warning: stream_select(): cannot represent a stream of type user-space as a 
select()able descriptor in %s

Warning: stream_select(): No stream arrays were passed in %s
bool(false)

------ return value is stream itself: -------

Warning: stream_select(): test_wrapper::stream_cast must not return itself in %s

Warning: stream_select(): cannot represent a stream of type user-space as a 
select()able descriptor in %s

Warning: stream_select(): No stream arrays were passed in %s
bool(false)

------ return value cannot be casted: -------

Warning: stream_select(): test_wrapper_base::stream_cast is not implemented! in 
%s

Warning: stream_select(): cannot represent a stream of type user-space as a 
select()able descriptor in %s

Warning: stream_select(): cannot represent a stream of type user-space as a 
select()able descriptor in %s

Warning: stream_select(): No stream arrays were passed in %s
bool(false)

http://cvs.php.net/viewvc.cgi/php-src/ext/standard/tests/file/userstreams_003.phpt?view=markup&rev=1.1
Index: php-src/ext/standard/tests/file/userstreams_003.phpt
+++ php-src/ext/standard/tests/file/userstreams_003.phpt
--TEST--
User-space streams: stream_set_option()
--FILE--
<?php
class test_wrapper_base {
        public $return_value;
        public $expected_option;
        public $expected_value;
        function stream_open($path, $mode, $openedpath) {
                return true;
        }
        function stream_eof() {
                return false;
        }
}
class test_wrapper extends test_wrapper_base {
        function stream_set_option($option, $value, $ptrparam) {
                echo "value:\n";
                var_dump($value);
                echo "ptrparam:\n";
                var_dump($ptrparam);
                echo "\$option === $option === " . $this->expected_option . 
":\n";;
                var_dump($option === $this->expected_option);
                echo "\$value === $value === " . $this->expected_value. ":\n";;
                var_dump($value === $this->expected_value);
                return $this->return_value;
        }
}

function test($name, $fd, $return_value, $func, $args, $expected_option, 
$expected_value) {
        echo "\n------ $name: -------\n";
        $data = stream_get_meta_data($fd);
        $data['wrapper_data']->return_value = $return_value;
        $data['wrapper_data']->expected_option = $expected_option;
        $data['wrapper_data']->expected_value = $expected_value;
        var_dump(call_user_func_array($func, $args));
}

var_dump(stream_wrapper_register('test', 'test_wrapper'));
var_dump(stream_wrapper_register('test2', 'test_wrapper_base'));

$fd = fopen("test://foo","r");
$fd2 = fopen("test2://foo","r");

test("stream_set_blocking - 1", $fd, true, "stream_set_blocking", array($fd,0), 
STREAM_OPTION_BLOCKING, 0);
test("stream_set_blocking - 2", $fd, false, "stream_set_blocking", 
array($fd,1), STREAM_OPTION_BLOCKING, 1);
test("stream_set_blocking - 3", $fd, "foo", "stream_set_blocking", 
array($fd,0), STREAM_OPTION_BLOCKING, 0);
test("stream_set_blocking - 4", $fd2, true, "stream_set_blocking", 
array($fd2,1), STREAM_OPTION_BLOCKING, 1);

test("stream_set_write_buffer - 1", $fd, true, "stream_set_write_buffer", 
array($fd,0), STREAM_OPTION_WRITE_BUFFER, STREAM_BUFFER_NONE);
test("stream_set_write_buffer - 2", $fd, true, "stream_set_write_buffer", 
array($fd,4096), STREAM_OPTION_WRITE_BUFFER, STREAM_BUFFER_FULL);
test("stream_set_write_buffer - 3", $fd, false, "stream_set_write_buffer", 
array($fd,8192), STREAM_OPTION_WRITE_BUFFER, STREAM_BUFFER_FULL);

test("stream_set_timeout - 1", $fd, true, "stream_set_timeout", 
array($fd,10,11), STREAM_OPTION_READ_TIMEOUT, 10);
test("stream_set_timeout - 2", $fd, false, "stream_set_timeout", 
array($fd,11,12), STREAM_OPTION_READ_TIMEOUT, 11);

?>
--EXPECTF--
bool(true)
bool(true)

------ stream_set_blocking - 1: -------
value:
int(0)
ptrparam:
NULL
$option === 1 === 1:
bool(true)
$value === 0 === 0:
bool(true)
bool(true)

------ stream_set_blocking - 2: -------
value:
int(1)
ptrparam:
NULL
$option === 1 === 1:
bool(true)
$value === 1 === 1:
bool(true)
bool(false)

------ stream_set_blocking - 3: -------
value:
int(0)
ptrparam:
NULL
$option === 1 === 1:
bool(true)
$value === 0 === 0:
bool(true)
bool(true)

------ stream_set_blocking - 4: -------

Warning: stream_set_blocking(): test_wrapper_base::stream_set_option is not 
implemented! in %s
bool(false)

------ stream_set_write_buffer - 1: -------
value:
int(0)
ptrparam:
int(8192)
$option === 3 === 3:
bool(true)
$value === 0 === 0:
bool(true)
int(0)

------ stream_set_write_buffer - 2: -------
value:
int(2)
ptrparam:
int(4096)
$option === 3 === 3:
bool(true)
$value === 2 === 2:
bool(true)
int(0)

------ stream_set_write_buffer - 3: -------
value:
int(2)
ptrparam:
int(8192)
$option === 3 === 3:
bool(true)
$value === 2 === 2:
bool(true)
int(-1)

------ stream_set_timeout - 1: -------
value:
int(10)
ptrparam:
int(11)
$option === 4 === 4:
bool(true)
$value === 10 === 10:
bool(true)
bool(true)

------ stream_set_timeout - 2: -------
value:
int(11)
ptrparam:
int(12)
$option === 4 === 4:
bool(true)
$value === 11 === 11:
bool(true)
bool(false)

-- 
PHP CVS Mailing List (http://www.php.net/)
To unsubscribe, visit: http://www.php.net/unsub.php

Reply via email to