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