diff options
author | Wez Furlong <wez@php.net> | 2002-03-16 13:48:57 +0000 |
---|---|---|
committer | Wez Furlong <wez@php.net> | 2002-03-16 13:48:57 +0000 |
commit | 30647934a477f876992c3390ce483bb55a3eee51 (patch) | |
tree | f6b85a5d08e90028538485c8a0addadd0f0a62c2 | |
parent | d4e63bc5bf1dacce00f317bc2b3b759f6f6138d7 (diff) | |
download | php-git-30647934a477f876992c3390ce483bb55a3eee51.tar.gz |
Tweak the API to be more consistent.
Update docs.
-rw-r--r-- | README.STREAMS | 179 | ||||
-rw-r--r-- | TODO | 4 | ||||
-rw-r--r-- | ext/gd/gd.c | 2 | ||||
-rw-r--r-- | ext/hyperwave/hw.c | 2 | ||||
-rwxr-xr-x | main/php_streams.h | 2 | ||||
-rwxr-xr-x | main/streams.c | 26 |
6 files changed, 146 insertions, 69 deletions
diff --git a/README.STREAMS b/README.STREAMS index 2ae89b7a51..e5a3cca35a 100644 --- a/README.STREAMS +++ b/README.STREAMS @@ -4,9 +4,6 @@ $Id$ Please send comments to: Wez Furlong <wez@thebrainroom.com> -Note: this doc is preliminary and is intended to give the reader an idea of -how streams work and should be used. - Why Streams? ============ You may have noticed a shed-load of issock parameters flying around the PHP @@ -26,7 +23,7 @@ The main functions are: PHPAPI size_t php_stream_read(php_stream * stream, char * buf, size_t count); PHPAPI size_t php_stream_write(php_stream * stream, const char * buf, size_t - count); + count); PHPAPI int php_stream_eof(php_stream * stream); PHPAPI int php_stream_getc(php_stream * stream); PHPAPI char *php_stream_gets(php_stream * stream, char *buf, size_t maxlen); @@ -40,16 +37,77 @@ names: fread, fwrite, feof, fgetc, fgets, fclose, fflush, fseek, ftell. Opening Streams =============== -Ultimately, I aim to implement an fopen_wrapper-like call to do this with -minimum fuss. -Currently, mostly for testing purposes, you can use php_stream_fopen to open a -stream on a regular file. +In most cases, you should use this API: + +PHPAPI php_stream *php_stream_open_wrapper(char *path, char *mode, + int options, char **opened_path TSRMLS_DC); + +Where: + path is the file or resource to open. + mode is the stdio compatible mode eg: "wb", "rb" etc. + options is a combination of the following values: + IGNORE_PATH (default) - don't use include path to search for the file + USE_PATH - use include path to search for the file + IGNORE_URL - do not use plugin wrappers + REPORT_ERRORS - show errors in a standard format if something + goes wrong. + opened_path is used to return the path of the actual file opened. + +If you need to open a specific stream, or convert standard resources into +streams there are a range of functions to do this defined in php_streams.h. +A brief list of the most commonly used functions: + +PHPAPI php_stream *php_stream_fopen_from_file(FILE *file, const char *mode); + Convert a FILE * into a stream. -PHPAPI php_stream * php_stream_fopen(const char * filename, const char * - mode); +PHPAPI php_stream *php_stream_fopen_tmpfile(void); + Open a FILE * with tmpfile() and convert into a stream. -This call behaves just like fopen(), except it returns a stream instead of a -FILE * +PHPAPI php_stream *php_stream_fopen_temporary_file(const char *dir, + const char *pfx, char **opened_path TSRMLS_DC); + Generate a temporary file name and open it. + +There are some network enabled relatives in php_network.h: + +PHPAPI php_stream *php_stream_sock_open_from_socket(int socket, int persistent); + Convert a socket into a stream. + +PHPAPI php_stream *php_stream_sock_open_host(const char *host, unsigned short port, + int socktype, int timeout, int persistent); + Open a connection to a host and return a stream. + +PHPAPI php_stream *php_stream_sock_open_unix(const char *path, int persistent, + struct timeval *timeout); + Open a UNIX domain socket. + + +Stream Utilities +================ + +If you need to copy some data from one stream to another, you will be please +to know that the streams API provides a standard way to do this: + +PHPAPI size_t php_stream_copy_to_stream(php_stream *src, + php_stream *dest, size_t maxlen); + +If you want to copy all remaining data from the src stream, pass +PHP_STREAM_COPY_ALL as the maxlen parameter, otherwise maxlen indicates the +number of bytes to copy. +This function will try to use mmap where available to make the copying more +efficient. + +If you want to read the contents of a stream into an allocated memory buffer, +you should use: + +PHPAPI size_t php_stream_copy_to_mem(php_stream *src, char **buf, + size_t maxlen, int persistent); + +This function will set buf to the address of the buffer that it allocated, +which will be maxlen bytes in length, or will be the entire length of the +data remaining on the stream if you set maxlen to PHP_STREAM_COPY_ALL. +The buffer is allocated using pemalloc(); you need to call pefree() to +release the memory when you are done. +As with copy_to_stream, this function will try use mmap where it can. Casting Streams =============== @@ -59,14 +117,14 @@ You need to "cast" the stream into a FILE*, and this is how you do it: FILE * fp; php_stream * stream; /* already opened */ -if (php_stream_cast(stream, PHP_STREAM_AS_STDIO, &fp, 1) == FAILURE) { - RETURN_FALSE; +if (php_stream_cast(stream, PHP_STREAM_AS_STDIO, (void*)&fp, REPORT_ERRORS) == FAILURE) { + RETURN_FALSE; } The prototype is: PHPAPI int php_stream_cast(php_stream * stream, int castas, void ** ret, int - show_err); + show_err); The show_err parameter, if non-zero, will cause the function to display an appropriate error message of type E_WARNING if the cast fails. @@ -83,8 +141,14 @@ if you mix ANSI stdio calls on the FILE* with php stream calls on the stream. If your system has the fopencookie function, php streams can synthesize a FILE* on top of any stream, which is useful for SSL sockets, memory based streams, data base streams etc. etc. -NOTE: There might be situations where this is not desireable, and we need to -provide a flag to inform the casting routine of this. + +In situations where this is not desireable, you should query the stream +to see if it naturally supports FILE *. You can use this code snippet +for this purpose: + + if (php_stream_is(stream, PHP_STREAM_IS_STDIO)) { + /* can safely cast to FILE* with no adverse side effects */ + } You can use: @@ -93,10 +157,15 @@ PHPAPI int php_stream_can_cast(php_stream * stream, int castas) to find out if a stream can be cast, without actually performing the cast, so to check if a stream is a socket you might use: -if (php_stream_can_cast(stream, PHP_STREAM_AS_SOCKETD) == SUCCESS) { - /* it's a socket */ +if (php_stream_can_cast(stream, PHP_STREAM_AS_SOCKETD) == SUCCESS) { + /* it can be a socket */ } +Please note the difference between php_stream_is and php_stream_can_cast; +stream_is tells you if the stream is a particular type of stream, whereas +can_cast tells you if the stream can be forced into the form you request. +The format doesn't change anything, while the later *might* change some +state in the stream. Stream Internals ================ @@ -121,17 +190,17 @@ As an example, the php_stream_fopen() function looks like this: PHPAPI php_stream * php_stream_fopen(const char * filename, const char * mode) { - FILE * fp = fopen(filename, mode); - php_stream * ret; - - if (fp) { - ret = php_stream_alloc(&php_stream_stdio_ops, fp, 0, 0, mode); - if (ret) - return ret; - - fclose(fp); - } - return NULL; + FILE * fp = fopen(filename, mode); + php_stream * ret; + + if (fp) { + ret = php_stream_alloc(&php_stream_stdio_ops, fp, 0, 0, mode); + if (ret) + return ret; + + fclose(fp); + } + return NULL; } php_stream_stdio_ops is a php_stream_ops structure that can be used to handle @@ -143,7 +212,7 @@ to be passed back to fopen_wrapper (or it's yet to be implemented successor). The prototype for php_stream_alloc is this: PHPAPI php_stream * php_stream_alloc(php_stream_ops * ops, void * abstract, - size_t bufsize, int persistent, const char * mode) + size_t bufsize, int persistent, const char * mode) ops is a pointer to the implementation, abstract holds implementation specific data that is relevant to this instance @@ -176,9 +245,9 @@ appropriately), and use the abstract pointer to refer to it. For structured state you might have this: -struct my_state { - MYSQL conn; - MYSQL_RES * result; +struct my_state { + MYSQL conn; + MYSQL_RES * result; }; struct my_state * state = pemalloc(sizeof(struct my_state), persistent); @@ -201,32 +270,32 @@ For example, for reading from this wierd mysql stream: static size_t php_mysqlop_read(php_stream * stream, char * buf, size_t count) { - struct my_state * state = (struct my_state*)stream->abstract; - - if (buf == NULL && count == 0) { - /* in this special case, php_streams is asking if we have reached the - * end of file */ - if (... at end of file ...) - return EOF; - else - return 0; - } - - /* pull out some data from the stream and put it in buf */ - ... mysql_fetch_row(state->result) ... - /* we could do something strange, like format the data as XML here, - and place that in the buf, but that brings in some complexities, - such as coping with a buffer size too small to hold the data, - so I won't even go in to how to do that here */ + struct my_state * state = (struct my_state*)stream->abstract; + + if (buf == NULL && count == 0) { + /* in this special case, php_streams is asking if we have reached the + * end of file */ + if (... at end of file ...) + return EOF; + else + return 0; + } + + /* pull out some data from the stream and put it in buf */ + ... mysql_fetch_row(state->result) ... + /* we could do something strange, like format the data as XML here, + and place that in the buf, but that brings in some complexities, + such as coping with a buffer size too small to hold the data, + so I won't even go in to how to do that here */ } Implement the other operations - remember that write, read, close and flush are all mandatory. The rest are optional. Declare your stream ops struct: php_stream_ops my_ops = { - php_mysqlop_write, php_mysqlop_read, php_mysqlop_close, - php_mysqlop_flush, NULL, NULL, NULL, - "Strange mySQL example" + php_mysqlop_write, php_mysqlop_read, php_mysqlop_close, + php_mysqlop_flush, NULL, NULL, NULL, + "Strange mySQL example" } Thats it! @@ -240,4 +309,4 @@ connection and then use pefree to dispose of the struct you allocated. You may read the stream->persistent field to determine if your struct was allocated in persistent mode or not. -vim:tw=78 +vim:tw=78:et @@ -43,10 +43,6 @@ global * on some platforms unimplemented function will just do nothing (e.g. symlink) they should print a warning or not even be defined! (DONE ?) - * Finish PHP streams abstraction, nuke all that issock stuff, implement SSL - socket support. (wez) - - ext/ftp/ -> all FILEs to streams - - ext/bz2/ -> convert to stream impl. * Use arg_separator.input to implode args in the CGI sapi extension and arg_separator.input to explode in php_build_argv(). (DONE?) * Change the odbc_fetch_into() function to require ALWAYS the first two diff --git a/ext/gd/gd.c b/ext/gd/gd.c index c839bfe267..30ed567792 100644 --- a/ext/gd/gd.c +++ b/ext/gd/gd.c @@ -1171,7 +1171,7 @@ static void _php_image_create_from(INTERNAL_FUNCTION_PARAMETERS, int image_type, char *buff; /* needs to be malloc (persistent) - GD will free() it later */ - buff_size = php_stream_read_all(stream, &buff, 1); + buff_size = php_stream_copy_to_mem(stream, &buff, PHP_STREAM_COPY_ALL, 1); if(!buff_size) { php_error(E_WARNING,"%s: Cannot read image data", get_active_function_name(TSRMLS_C)); diff --git a/ext/hyperwave/hw.c b/ext/hyperwave/hw.c index 006a8f2209..978a1915c0 100644 --- a/ext/hyperwave/hw.c +++ b/ext/hyperwave/hw.c @@ -2892,7 +2892,7 @@ PHP_FUNCTION(hw_new_document_from_file) if(NULL == doc) RETURN_FALSE; - doc->size = php_stream_read_all(stream, &doc->data, 1); + doc->size = php_stream_copy_to_mem(stream, &doc->data, PHP_STREAM_COPY_ALL, 1); php_stream_close(stream); diff --git a/main/php_streams.h b/main/php_streams.h index 289ae46b63..7ec7f6f6f7 100755 --- a/main/php_streams.h +++ b/main/php_streams.h @@ -107,7 +107,7 @@ PHPAPI int php_stream_puts(php_stream *stream, char *buf); PHPAPI size_t php_stream_copy_to_stream(php_stream *src, php_stream *dest, size_t maxlen); /* read all data from stream and put into a buffer. Caller must free buffer when done. * The copy will use mmap if available. */ -PHPAPI size_t php_stream_read_all(php_stream *src, char **buf, int persistent); +PHPAPI size_t php_stream_copy_to_mem(php_stream *src, char **buf, size_t maxlen, int persistent); /* maybe implement someday */ #define php_stream_error(stream) (0) diff --git a/main/streams.c b/main/streams.c index 5a7ff97c50..eb0c942f27 100755 --- a/main/streams.c +++ b/main/streams.c @@ -227,7 +227,7 @@ PHPAPI int php_stream_seek(php_stream *stream, off_t offset, int whence) return -1; } -PHPAPI size_t php_stream_read_all(php_stream *src, char **buf, int persistent) +PHPAPI size_t php_stream_copy_to_mem(php_stream *src, char **buf, size_t maxlen, int persistent) { size_t ret = 0; char *ptr; @@ -238,6 +238,15 @@ PHPAPI size_t php_stream_read_all(php_stream *src, char **buf, int persistent) int srcfd; #endif + if (buf) + *buf = NULL; + + if (maxlen == 0) + return 0; + + if (maxlen == PHP_STREAM_COPY_ALL) + maxlen = 0; + #if HAVE_MMAP /* try and optimize the case where we are copying from the start of a plain file. * We could probably make this work in more situations, but I don't trust the stdio @@ -251,18 +260,21 @@ PHPAPI size_t php_stream_read_all(php_stream *src, char **buf, int persistent) if (fstat(srcfd, &sbuf) == 0) { void *srcfile; - - srcfile = mmap(NULL, sbuf.st_size, PROT_READ, MAP_SHARED, srcfd, 0); + + if (maxlen > sbuf.st_size || maxlen == 0) + maxlen = sbuf.st_size; + + srcfile = mmap(NULL, maxlen, PROT_READ, MAP_SHARED, srcfd, 0); if (srcfile != (void*)MAP_FAILED) { - *buf = pemalloc(persistent, sbuf.st_size); + *buf = pemalloc(persistent, maxlen); if (*buf) { - memcpy(*buf, srcfile, sbuf.st_size); - ret = sbuf.st_size; + memcpy(*buf, srcfile, maxlen); + ret = maxlen; } - munmap(srcfile, sbuf.st_size); + munmap(srcfile, maxlen); return ret; } } |