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

Reply via email to