diff options
author | Wez Furlong <wez@php.net> | 2002-09-23 13:22:10 +0000 |
---|---|---|
committer | Wez Furlong <wez@php.net> | 2002-09-23 13:22:10 +0000 |
commit | 9e84b3d5b584e9d98ff8b009bc7220245bee6df1 (patch) | |
tree | 720eb8bd46d6f094c0b475a70232599b4d3e052e /main | |
parent | 2f4ed252de9dd0e0dbfb04e7767d63e12692003c (diff) | |
download | php-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.c | 9 | ||||
-rwxr-xr-x | main/php_streams.h | 4 | ||||
-rwxr-xr-x | main/streams.c | 78 | ||||
-rw-r--r-- | main/user_streams.c | 96 |
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); |