Streams' gets function does not work with stdio, because it uses fread(3) instead of fgets(3). Like fill_read_buffer earlier, fread(3) does not return, unless an error occurs or the amount of data has been read completely. It is basically impossible to implement an _efficient_ fgets-like function using fread(3).
Additionally, stdio does its own buffering -- there is no reason to add another buffer layer above it. The streams buffer needs to be disabled, because fgets/fread would otherwise interact wrongly. The attached patch does this: - Disables buffering for stdio using PHP_STREAM_FLAG_NO_BUFFER - Adds a gets hook to stream ops - Adds a gets implementation to stdio ops - Makes stream_gets use that hook, if available - Inverts the semantic of fill_read_buffer regarding blocking "make test" and entering data using stdin works. Comments, please. - Sascha
Index: main/network.c =================================================================== RCS file: /repository/php4/main/network.c,v retrieving revision 1.73 diff -u -r1.73 network.c --- main/network.c 4 Oct 2002 19:08:43 -0000 1.73 +++ main/network.c 4 Oct 2002 20:29:10 -0000 @@ -542,7 +542,6 @@ sock->socket = socket; stream = php_stream_alloc_rel(&php_stream_socket_ops, sock, persistent_id, "r+"); - stream->flags |= PHP_STREAM_FLAG_AVOID_BLOCKING; if (stream == NULL) pefree(sock, persistent_id ? 1 : 0); Index: main/php_streams.h =================================================================== RCS file: /repository/php4/main/php_streams.h,v retrieving revision 1.53 diff -u -r1.53 php_streams.h --- main/php_streams.h 4 Oct 2002 18:59:34 -0000 1.53 +++ main/php_streams.h 4 Oct 2002 20:29:10 -0000 @@ -153,6 +153,7 @@ int (*cast)(php_stream *stream, int castas, void **ret TSRMLS_DC); int (*stat)(php_stream *stream, php_stream_statbuf *ssb TSRMLS_DC); int (*set_option)(php_stream *stream, int option, int value, void *ptrparam TSRMLS_DC); + size_t (*gets)(php_stream *stream, char *buf, size_t count TSRMLS_DC); } php_stream_ops; typedef struct _php_stream_wrapper_ops { @@ -225,11 +226,13 @@ #define PHP_STREAM_FLAG_DETECT_EOL 4 #define PHP_STREAM_FLAG_EOL_MAC 8 -/* set this when the stream might represent "interactive" data. - * When set, the read buffer will avoid certain operations that - * might otherwise cause the read to block for much longer than - * is strictly required. */ -#define PHP_STREAM_FLAG_AVOID_BLOCKING 16 +/* + * By default, your read operation will be called once to + * retrieve a chunk of data. If you do not immediately return + * all available data during one read operation and you want + * us to call it multiple times, use this flag. + */ +#define PHP_STREAM_FLAG_DO_BLOCKING 16 struct _php_stream { php_stream_ops *ops; Index: main/streams.c =================================================================== RCS file: /repository/php4/main/streams.c,v retrieving revision 1.95 diff -u -r1.95 streams.c --- main/streams.c 4 Oct 2002 19:48:59 -0000 1.95 +++ main/streams.c 4 Oct 2002 20:29:12 -0000 @@ -497,7 +497,7 @@ stream->writepos += justread; - if (stream->flags & PHP_STREAM_FLAG_AVOID_BLOCKING) + if (!(stream->flags & PHP_STREAM_FLAG_DO_BLOCKING)) break; } } @@ -657,10 +657,21 @@ { size_t avail = 0; int did_copy = 0; - + if (maxlen == 0) return NULL; + if (stream->ops->gets) { + size_t n; + + n = stream->ops->gets(stream, buf, maxlen TSRMLS_CC); + + if (n == 0) + return NULL; + + return buf + n; + } + /* * If the underlying stream operations block when no new data is readable, * we need to take extra precautions. @@ -1149,6 +1160,8 @@ PHPAPI php_stream *_php_stream_fopen_from_file(FILE *file, const char *mode STREAMS_DC TSRMLS_DC) { php_stdio_stream_data *self; + php_stream *stream; + #ifdef S_ISFIFO int fd; #endif @@ -1167,18 +1180,25 @@ } #endif - return php_stream_alloc_rel(&php_stream_stdio_ops, self, 0, mode); + stream = php_stream_alloc_rel(&php_stream_stdio_ops, self, 0, mode); + stream->flags |= PHP_STREAM_FLAG_NO_BUFFER; + return stream; } PHPAPI php_stream *_php_stream_fopen_from_pipe(FILE *file, const char *mode STREAMS_DC TSRMLS_DC) { php_stdio_stream_data *self; + php_stream *stream; self = emalloc_rel_orig(sizeof(*self)); self->file = file; self->is_pipe = 1; self->is_process_pipe = 1; - return php_stream_alloc_rel(&php_stream_stdio_ops, self, 0, mode); + + stream = php_stream_alloc_rel(&php_stream_stdio_ops, self, 0, mode); + stream->flags |= PHP_STREAM_FLAG_NO_BUFFER; + + return stream; } static size_t php_stdiop_write(php_stream *stream, const char *buf, size_t count TSRMLS_DC) @@ -1197,6 +1217,35 @@ return fwrite(buf, 1, count, data->file); } +static size_t php_stdiop_gets(php_stream *stream, char *buf, size_t count TSRMLS_DC) +{ + php_stdio_stream_data *data = (php_stdio_stream_data*)stream->abstract; + char *r; + + assert(data != NULL); + + if (buf == NULL && count == 0) { + /* check for EOF condition */ + if (feof(data->file)) { + return EOF; + } + return 0; + } + +#if HAVE_FLUSHIO + if (!data->is_pipe && data->last_op == 'w') + fseek(data->file, 0, SEEK_CUR); + data->last_op = 'r'; +#endif + + r = fgets(buf, count, data->file); + + if (r == NULL) + return 0; + + return strlen(buf); +} + static size_t php_stdiop_read(php_stream *stream, char *buf, size_t count TSRMLS_DC) { php_stdio_stream_data *data = (php_stdio_stream_data*)stream->abstract; @@ -1377,7 +1426,8 @@ php_stdiop_seek, php_stdiop_cast, php_stdiop_stat, - php_stdiop_set_option + php_stdiop_set_option, + php_stdiop_gets }; /* }}} */
-- PHP Development Mailing List <http://www.php.net/> To unsubscribe, visit: http://www.php.net/unsub.php