summaryrefslogtreecommitdiff
path: root/main
diff options
context:
space:
mode:
authorWez Furlong <wez@php.net>2002-09-23 13:22:10 +0000
committerWez Furlong <wez@php.net>2002-09-23 13:22:10 +0000
commit9e84b3d5b584e9d98ff8b009bc7220245bee6df1 (patch)
tree720eb8bd46d6f094c0b475a70232599b4d3e052e /main
parent2f4ed252de9dd0e0dbfb04e7767d63e12692003c (diff)
downloadphp-git-9e84b3d5b584e9d98ff8b009bc7220245bee6df1.tar.gz
Revise buffer/seek code a little.
Tidy up user streams even more. Make test case quite aggressive.
Diffstat (limited to 'main')
-rw-r--r--main/memory_streams.c9
-rwxr-xr-xmain/php_streams.h4
-rwxr-xr-xmain/streams.c78
-rw-r--r--main/user_streams.c96
4 files changed, 148 insertions, 39 deletions
diff --git a/main/memory_streams.c b/main/memory_streams.c
index e48d5faa21..520225c87c 100644
--- a/main/memory_streams.c
+++ b/main/memory_streams.c
@@ -216,6 +216,7 @@ php_stream_ops php_stream_memory_ops = {
PHPAPI php_stream *_php_stream_memory_create(int mode STREAMS_DC TSRMLS_DC)
{
php_stream_memory_data *self;
+ php_stream *stream;
self = emalloc(sizeof(*self));
assert(self != NULL);
@@ -224,7 +225,10 @@ PHPAPI php_stream *_php_stream_memory_create(int mode STREAMS_DC TSRMLS_DC)
self->fsize = 0;
self->smax = -1;
self->mode = mode;
- return php_stream_alloc(&php_stream_memory_ops, self, 0, "rwb");
+
+ stream = php_stream_alloc(&php_stream_memory_ops, self, 0, "rwb");
+ stream->flags |= PHP_STREAM_FLAG_NO_BUFFER;
+ return stream;
}
/* }}} */
@@ -435,8 +439,9 @@ PHPAPI php_stream *_php_stream_temp_create(int mode, size_t max_memory_usage STR
self->smax = max_memory_usage;
self->mode = mode;
stream = php_stream_alloc(&php_stream_temp_ops, self, 0, "rwb");
+ stream->flags |= PHP_STREAM_FLAG_NO_BUFFER;
self->innerstream = php_stream_memory_create(mode);
-/* php_stream_temp_write(stream, NULL, 0 TSRMLS_CC); */
+
return stream;
}
/* }}} */
diff --git a/main/php_streams.h b/main/php_streams.h
index 5cd12839f0..8044f05026 100755
--- a/main/php_streams.h
+++ b/main/php_streams.h
@@ -377,6 +377,10 @@ PHPAPI int _php_stream_set_option(php_stream *stream, int option, int value, voi
#define PHP_STREAM_BUFFER_LINE 1 /* line buffered */
#define PHP_STREAM_BUFFER_FULL 2 /* fully buffered */
+#define PHP_STREAM_OPTION_RETURN_OK 0 /* option set OK */
+#define PHP_STREAM_OPTION_RETURN_ERR -1 /* problem setting option */
+#define PHP_STREAM_OPTION_RETURN_NOTIMPL -2 /* underlying stream does not implement; streams can handle it instead */
+
/* copy up to maxlen bytes from src to dest. If maxlen is PHP_STREAM_COPY_ALL, copy until eof(src).
* Uses mmap if the src is a plain file and at offset 0 */
#define PHP_STREAM_COPY_ALL -1
diff --git a/main/streams.c b/main/streams.c
index e81d1bd305..7225921705 100755
--- a/main/streams.c
+++ b/main/streams.c
@@ -357,8 +357,36 @@ static void php_stream_fill_read_buffer(php_stream *stream, size_t size TSRMLS_D
PHPAPI size_t _php_stream_read(php_stream *stream, char *buf, size_t size TSRMLS_DC)
{
+ size_t avail, toread, didread = 0;
+
+ /* take from the read buffer first.
+ * It is possible that a buffered stream was switched to non-buffered, so we
+ * drain the remainder of the buffer before using the "raw" read mode for
+ * the excess */
+ avail = stream->writepos - stream->readpos;
+ if (avail) {
+ toread = avail;
+ if (toread > size)
+ toread = size;
+
+ memcpy(buf, stream->readbuf + stream->readpos, toread);
+ stream->readpos += toread;
+ size -= toread;
+ buf += toread;
+ didread += size;
+ }
+
+ if (size == 0)
+ return didread;
+
if (stream->flags & PHP_STREAM_FLAG_NO_BUFFER || stream->chunk_size == 1) {
- return stream->ops->read(stream, buf, size TSRMLS_CC);
+ if (stream->filterhead) {
+ didread += stream->filterhead->fops->read(stream, stream->filterhead,
+ buf, size
+ TSRMLS_CC);
+ } else {
+ didread += stream->ops->read(stream, buf, size TSRMLS_CC);
+ }
} else {
php_stream_fill_read_buffer(stream, size TSRMLS_CC);
@@ -367,9 +395,10 @@ PHPAPI size_t _php_stream_read(php_stream *stream, char *buf, size_t size TSRMLS
memcpy(buf, stream->readbuf + stream->readpos, size);
stream->readpos += size;
- stream->position += size;
- return size;
+ didread += size;
}
+ stream->position += size;
+ return didread;
}
PHPAPI int _php_stream_eof(php_stream *stream TSRMLS_DC)
@@ -550,7 +579,7 @@ PHPAPI off_t _php_stream_tell(php_stream *stream TSRMLS_DC)
PHPAPI int _php_stream_seek(php_stream *stream, off_t offset, int whence TSRMLS_DC)
{
/* not moving anywhere */
- if (offset == 0 && whence == SEEK_CUR)
+ if ((offset == 0 && whence == SEEK_CUR) || (offset == stream->position && whence == SEEK_SET))
return 0;
/* handle the case where we are in the buffer */
@@ -576,6 +605,8 @@ PHPAPI int _php_stream_seek(php_stream *stream, off_t offset, int whence TSRMLS_
stream->readpos = stream->writepos = 0;
if (stream->ops->seek && (stream->flags & PHP_STREAM_FLAG_NO_SEEK) == 0) {
+ int ret;
+
if (stream->filterhead)
stream->filterhead->fops->flush(stream, stream->filterhead, 0 TSRMLS_CC);
@@ -585,7 +616,12 @@ PHPAPI int _php_stream_seek(php_stream *stream, off_t offset, int whence TSRMLS_
whence = SEEK_SET;
break;
}
- return stream->ops->seek(stream, offset, whence, &stream->position TSRMLS_CC);
+ ret = stream->ops->seek(stream, offset, whence, &stream->position TSRMLS_CC);
+
+ if (((stream->flags & PHP_STREAM_FLAG_NO_SEEK) == 0) || ret == 0)
+ return ret;
+ /* else the stream has decided that it can't support seeking after all;
+ * fall through to attempt emulation */
}
/* emulate forward moving seeks with reads */
@@ -603,16 +639,37 @@ PHPAPI int _php_stream_seek(php_stream *stream, off_t offset, int whence TSRMLS_
return 0;
}
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "streams of type %s do not support seeking", stream->ops->label);
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "stream does not support seeking");
return -1;
}
PHPAPI int _php_stream_set_option(php_stream *stream, int option, int value, void *ptrparam TSRMLS_DC)
{
- if (stream->ops->set_option)
- return stream->ops->set_option(stream, option, value, ptrparam TSRMLS_CC);
- return -1;
+ int ret = PHP_STREAM_OPTION_RETURN_NOTIMPL;
+
+ if (stream->ops->set_option) {
+ ret = stream->ops->set_option(stream, option, value, ptrparam TSRMLS_CC);
+ }
+
+ if (ret == PHP_STREAM_OPTION_RETURN_NOTIMPL) {
+ switch(option) {
+ case PHP_STREAM_OPTION_BUFFER:
+ /* try to match the buffer mode as best we can */
+ if (value == PHP_STREAM_BUFFER_NONE) {
+ stream->flags |= PHP_STREAM_FLAG_NO_BUFFER;
+ } else {
+ stream->flags ^= PHP_STREAM_FLAG_NO_BUFFER;
+ }
+ ret = PHP_STREAM_OPTION_RETURN_OK;
+ break;
+
+ default:
+ ret = PHP_STREAM_OPTION_RETURN_ERR;
+ }
+ }
+
+ return ret;
}
PHPAPI size_t _php_stream_passthru(php_stream * stream STREAMS_DC TSRMLS_DC)
@@ -1097,12 +1154,15 @@ static int php_stdiop_set_option(php_stream *stream, int option, int value, void
switch(value) {
case PHP_STREAM_BUFFER_NONE:
+ stream->flags |= PHP_STREAM_FLAG_NO_BUFFER;
return setvbuf(data->file, NULL, _IONBF, 0);
case PHP_STREAM_BUFFER_LINE:
+ stream->flags ^= PHP_STREAM_FLAG_NO_BUFFER;
return setvbuf(data->file, NULL, _IOLBF, size);
case PHP_STREAM_BUFFER_FULL:
+ stream->flags ^= PHP_STREAM_FLAG_NO_BUFFER;
return setvbuf(data->file, NULL, _IOFBF, size);
default:
diff --git a/main/user_streams.c b/main/user_streams.c
index 248e0a3548..cce999da58 100644
--- a/main/user_streams.c
+++ b/main/user_streams.c
@@ -85,29 +85,46 @@ typedef struct _php_userstream_data php_userstream_data_t;
/* class should have methods like these:
-function stream_open($path, $mode, $options, &$opened_path)
- {
- return true/false;
- }
- function stream_read($count)
- {
- return false on error;
- else return string;
- }
- function stream_write($data)
- {
- return false on error;
- else return count written;
- }
- function stream_close()
- {
- }
- function stream_flush()
- {
- }
- function stream_seek($offset, $whence)
- {
- }
+ function stream_open($path, $mode, $options, &$opened_path)
+ {
+ return true/false;
+ }
+
+ function stream_read($count)
+ {
+ return false on error;
+ else return string;
+ }
+
+ function stream_write($data)
+ {
+ return false on error;
+ else return count written;
+ }
+
+ function stream_close()
+ {
+ }
+
+ function stream_flush()
+ {
+ return true/false;
+ }
+
+ function stream_seek($offset, $whence)
+ {
+ return true/false;
+ }
+
+ function stream_tell()
+ {
+ return (int)$position;
+ }
+
+ function stream_eof()
+ {
+ return true/false;
+ }
**/
@@ -267,6 +284,9 @@ static size_t php_userstreamop_write(php_stream *stream, const char *buf, size_t
if (call_result == SUCCESS && retval != NULL) {
convert_to_long_ex(&retval);
didwrite = Z_LVAL_P(retval);
+ } else if (call_result == FAILURE) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s::" USERSTREAM_WRITE " - is not implemented!",
+ us->wrapper->classname);
}
/* don't allow strange buffer overruns due to bogus return */
@@ -305,8 +325,14 @@ static size_t php_userstreamop_read(php_stream *stream, char *buf, size_t count
if (call_result == SUCCESS && retval != NULL && zval_is_true(retval))
didread = 0;
- else
+ else {
+ if (call_result == FAILURE) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s::" USERSTREAM_EOF " - is not implemented! Assuming EOF",
+ us->wrapper->classname);
+ }
+
didread = EOF;
+ }
} else {
zval *zcount;
@@ -334,8 +360,10 @@ static size_t php_userstreamop_read(php_stream *stream, char *buf, size_t count
}
if (didread > 0)
memcpy(buf, Z_STRVAL_P(retval), didread);
+ } else if (call_result == FAILURE) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s::" USERSTREAM_READ " - is not implemented!",
+ us->wrapper->classname);
}
-
zval_ptr_dtor(&zcount);
}
@@ -430,10 +458,19 @@ static int php_userstreamop_seek(php_stream *stream, off_t offset, int whence, o
zval_ptr_dtor(&zoffs);
zval_ptr_dtor(&zwhence);
- if (call_result == SUCCESS && retval != NULL && Z_TYPE_P(retval) == IS_LONG)
- ret = Z_LVAL_P(retval);
- else
+ if (call_result == FAILURE) {
+ /* stream_seek is not implemented, so disable seeks for this stream */
+ stream->flags |= PHP_STREAM_FLAG_NO_SEEK;
+ /* there should be no retval to clean up */
+ return -1;
+ } else if (call_result == SUCCESS && retval != NULL && zval_is_true(retval)) {
+ ret = 0;
+ } else {
ret = -1;
+ }
+
+ if (retval)
+ zval_ptr_dtor(&retval);
/* now determine where we are */
ZVAL_STRINGL(&func_name, USERSTREAM_TELL, sizeof(USERSTREAM_TELL)-1, 0);
@@ -446,6 +483,9 @@ static int php_userstreamop_seek(php_stream *stream, off_t offset, int whence, o
if (call_result == SUCCESS && retval != NULL && Z_TYPE_P(retval) == IS_LONG)
*newoffs = Z_LVAL_P(retval);
+ else
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s::" USERSTREAM_TELL " - is not implemented!",
+ us->wrapper->classname);
if (retval)
zval_ptr_dtor(&retval);