lbarnaud Sat Nov 15 12:50:17 2008 UTC Added files: /php-src/ext/standard/tests/file userstreams_002.phpt userstreams_003.phpt
Modified files: /php-src/main/streams userspace.c Log: 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.48&r2=1.49&diff_format=u Index: php-src/main/streams/userspace.c diff -u php-src/main/streams/userspace.c:1.48 php-src/main/streams/userspace.c:1.49 --- php-src/main/streams/userspace.c:1.48 Fri Jul 25 08:53:11 2008 +++ php-src/main/streams/userspace.c Sat Nov 15 12:50:17 2008 @@ -17,7 +17,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: userspace.c,v 1.48 2008/07/25 08:53:11 dmitry Exp $ */ +/* $Id: userspace.c,v 1.49 2008/11/15 12:50:17 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/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