X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=libfcgi%2Ffcgio.cpp;h=5a54c1153c9dce8ad07412e23dc8c6729ecc44ca;hb=89856cf418427fa82845a7c164253d4faacbf614;hp=3ca1f69a287252c00979648ec7634d6aae1aef1f;hpb=e52a748723a17122b8bd00b47be39de1bfeb25cd;p=catagits%2Ffcgi2.git diff --git a/libfcgi/fcgio.cpp b/libfcgi/fcgio.cpp index 3ca1f69..5a54c11 100644 --- a/libfcgi/fcgio.cpp +++ b/libfcgi/fcgio.cpp @@ -1,17 +1,12 @@ // -// $Id: fcgio.cpp,v 1.3 2000/07/27 12:21:54 robs Exp $ +// $Id: fcgio.cpp,v 1.14 2003/06/22 00:51:27 robs Exp $ // -// Allows you communicate with FastCGI streams using C++ iostream -// objects +// Allows you communicate with FastCGI streams using C++ iostreams // // ORIGINAL AUTHOR: George Feinberg // REWRITTEN BY: Michael Richards 06/20/1999 // REWRITTEN AGAIN BY: Michael Shell 02/23/2000 -// -// Special Thanks to Dietmar Kuehl for his help and the numerous custom -// streambuf examples on his web site. -// -// see the header file fcgio2.h for lotsa docs and a code example. +// REWRITTEN AGAIN BY: Rob Saccoccio 11 Nov 2001 // // Copyright (c) 2000 Tux the Linux Penguin // @@ -23,331 +18,184 @@ // implied; without even the implied warranty of MERCHANTABILITY or // FITNESS FOR A PARTICULAR PURPOSE. -/*------------------------------------------------------------------*/ - +#ifdef _WIN32 +#define DLLAPI __declspec(dllexport) +#endif +#include #include "fcgio.h" +using std::streambuf; +using std::istream; +using std::ostream; +using std::streamsize; + +fcgi_streambuf::fcgi_streambuf(FCGX_Stream * fs, char * b, int bs) +{ + init(fs, b, bs); +} + +fcgi_streambuf::fcgi_streambuf(char_type * b, streamsize bs) +{ + init(0, b, bs); +} + +fcgi_streambuf::fcgi_streambuf(FCGX_Stream * fs) +{ + init(fs, 0, 0); +} + +fcgi_streambuf::~fcgi_streambuf(void) +{ + overflow(EOF); + // FCGX_Finish()/FCGX_Accept() will flush and close +} + +void fcgi_streambuf::init(FCGX_Stream * fs, char_type * b, streamsize bs) +{ + this->fcgx = fs; + this->buf = 0; + this->bufsize = 0; + setbuf(b, bs); +} -// **** fcgio_streambuf - -// default constructor -fcgi_streambuf::fcgi_streambuf(void) - { - // we setup the buffer - setb(buffer,buffer + (buffersize * sizeof(char)),0); - // but we do not know yet if we are a reader or - // a writer - setp(0,0); - setg(0,0,0); - - // good idea to declare buffer status - if (buffersize < 1) unbuffered(1); - else unbuffered(0); - - // disarm till initialized - fcgx_strm = NULL; - defined = 0; - } - - -// destructor -fcgi_streambuf::~fcgi_streambuf(void) {} - - -// do nothing -int fcgi_streambuf::doallocate() - { - return (0); - } - - -// drain the get area -// this method provides an advanced feature and is -// considered experimental, see the header file for docs -// it is provided as it may save somebody someday -int fcgi_streambuf::drain_strm(char *s, int n) - { - int numinget; // number of chars in get buffer - int numtoextract; // number of chars to pull out of the - // get area - - int i; // counter - - // no meaning if not initialized - if (!defined) return (EOF); - // is already drained if no buffer - if (unbuffered()) return (0); - - numinget = egptr() - gptr(); // calculate how much stuff is in - // the get buffer - - // bogus requests deserve bogus answers - if (n<1) return (0); - - // an empty get area is an already drained get area - if (numinget<1) return(0); - - // the number we extract is the lesser of the number of chars - // in the get area and the number of chars the user's array - // can hold. Maybe should use a ? operator here. - if (numinget 0 && !unbuffered()) - if (FCGX_PutStr(pbase(), numinbuf, fcgx_strm) < 0) return (EOF); - - // reset the put buffer to empty - setp(pbase(),epptr()); - - // if we are given an overflow char, send it out too. - if (c >= 0) - if (FCGX_PutChar(c, fcgx_strm) < 0) return (EOF); - - // all done - return (0); - } - - -// we have our own methods to setup buffering -// in case somebody calls this, ignore it -streambuf * fcgi_streambuf::setbuf(char *s, int n) - { - // tell them what they want to hear to make them - // go away - return this; - } - - -// just sets up the pointer and declares things defined. -// used by fcgi_iostream attach() -void fcgi_streambuf::stream_initialize(FCGX_Stream *str, int dir) - { - // setup the main buffer - setb(buffer,buffer + (buffersize * sizeof(char)),0); - setp(0,0); - setg(0,0,0); - - if (buffersize < 1) unbuffered(1); - else // setup the get or put buffers - { - unbuffered(0); - if (dir) // if writer - { - setg(0,0,0); // no get buffer - setp(base(),ebuf()); // buffer is all put - } - else // reader - { - setg(base(),ebuf(),ebuf()); // buffer is all get - setp(0,0); // no put buffer - } - } - - // set the FCGI interface - fcgx_strm = str; - // we are ready for action - defined = 1; - } - - -// flush all the output +{ + if (this->bufsize) + { + int plen = pptr() - pbase(); + + if (plen) + { + if (FCGX_PutStr(pbase(), plen, this->fcgx) != plen) return EOF; + pbump(-plen); + } + } + + if (c != EOF) + { + if (FCGX_PutChar(c, this->fcgx) != c) return EOF; + } + + return 0; +} + +// default base class behaviour seems to be inconsistent int fcgi_streambuf::sync() - { - // flush the put area - if (overflow(-1) < 0) return (EOF); - - // now flush FCGX - return FCGX_FFlush(fcgx_strm); - } - - -// Underflow is called to get characters to fill up the get buffer -// so something that uses the stream can get the data. If there -// is nothing else to read, this returns EOF. This is the only method -// which reads from the FCGI interface. +{ + if (overflow(EOF)) return EOF; + if (FCGX_FFlush(this->fcgx)) return EOF; + return 0; +} + +// uflow() removes the char, underflow() doesn't +int fcgi_streambuf::uflow() +{ + if (this->bufsize) + { + int c = underflow(); + gbump(1); + return c; + } + else + { + return FCGX_GetChar(this->fcgx); + } +} + int fcgi_streambuf::underflow() - { - int numread; - - // we will not allow a bogus fcgx_strm (because the user - // forgot to attach()) to do even more harm. - if (!defined) return (EOF); - - // if it is unbuffered, then get & return a char - if (unbuffered()) return FCGX_GetChar(fcgx_strm); - - // read as much data as we can, then adjust the get area so it - // reflects the data we just read - numread=FCGX_GetStr(base(), blen(), fcgx_strm); - if (numread<=0) return EOF; - setg(base(),base(),base()+numread); - - // We avoid a common bug. You NEED the unsigned char cast or - // else this routine will return a false EOF when reading - // control chars outside the normal ascii range! - // i.e. "negative" chars map to positive ints and we - // reserve negative return values for EOF and error - // conditions. Now, even binary data will come through - // perfectly. - // The reason the get buffer uses chars rather - // than unsigned chars is a mystery from AT&T history. - // It probably has to due with the old 7bit text limits. - return ((unsigned char)(*eback())); - } - - - -// here comes the higher level iostream stuff - -// **** Istream - -// parameterless constructor allows us to create first, then -// initialize later via attach() -fcgi_istream::fcgi_istream() {} - - -// or we can create and initialize in one step -// constructor calls ios::init to assign our streambuf to -// the istream derived class. Also sets up buffering. -fcgi_istream::fcgi_istream(FCGX_Stream *str) - { - // initialize as a reader, use all buffering for the - // get area - fcgi_strmbuf.stream_initialize(str,0); - // init is a protected member of ios - init(&fcgi_strmbuf); - } - - -// destructor -fcgi_istream::~fcgi_istream() {} - - -// does everything the constructor with parameter does at the -// request of the programmer -void fcgi_istream::attach(FCGX_Stream *str) - { - // initialize as a reader, use all buffering for the - // get area - fcgi_strmbuf.stream_initialize(str,0); - // init is a protected member of ios - init(&fcgi_strmbuf); - } - - -// experimental method to drain the get buffer. Allows you -// to sync reads with FCGI library (non-istream reads). -// reads upto n chars into the s array from the get buffer, does -// not call underflow(). Returned is the number of chars extracted -// or EOF on error. If n>0 (normal use) and returns a nonnegative -// value less than n, the get buffer is empty and it is safe to -// use an FCGI library read. -// see the header file for more info -int fcgi_istream::drain(char *s, int n) - { - return (fcgi_strmbuf.drain_strm(s,n)); - } - - -// little routine so that you can tell if the streambuf -// was ever defined -int fcgi_istream::isdefined(void) - { - return (fcgi_strmbuf.isstrmdefined()); - } - - - -// **** Ostream - -// parameterless constructor allows us to create first, then -// initialize later via attach() -fcgi_ostream::fcgi_ostream() {} - - -// or we can create and initialize in one step -// constructor calls ios::init to assign our streambuf to -// the ostream derived class. Also sets up buffering -fcgi_ostream::fcgi_ostream(FCGX_Stream *str) - { - // initialize as a writer, use all buffering for the - // put area - fcgi_strmbuf.stream_initialize(str,1); - // init is a protected member of ios - init(&fcgi_strmbuf); - } - - -// destructor -fcgi_ostream::~fcgi_ostream() - { - // don't blowup if the user never defined the - // stream - if (fcgi_strmbuf.isstrmdefined()) - { - // this may protect a few poor souls who forgot to flush - // before deleting. Always flush when you are done. - fcgi_strmbuf.sync(); - } - } - - -// does everything the constructor with parameter does at the -// request of the programmer -void fcgi_ostream::attach(FCGX_Stream *str) - { - // initialize as a writer, use all buffering for the - // put area - fcgi_strmbuf.stream_initialize(str,1); - // init is a protected member of ios - init(&fcgi_strmbuf); - } - - -// helper function to find out if this -// stream was ever initialized. -int fcgi_ostream::isdefined(void) - { - return (fcgi_strmbuf.isstrmdefined()); - } - +{ + if (this->bufsize) + { + if (in_avail() == 0) + { + int glen = FCGX_GetStr(eback(), this->bufsize, this->fcgx); + if (glen <= 0) return EOF; + + setg(eback(), eback(), eback() + glen); + } + + return (unsigned char) *gptr(); + } + else + { + return FCGX_UnGetChar(FCGX_GetChar(this->fcgx), this->fcgx); + } +} + +void fcgi_streambuf::reset(void) +{ + // it should be ok to set up both the get and put areas + setg(this->buf, this->buf, this->buf); + setp(this->buf, this->buf + this->bufsize); +} + +std::streambuf * fcgi_streambuf::setbuf(char_type * b, streamsize bs) +{ + // XXX support moving data from an old buffer + if (this->bufsize) return 0; + + this->buf = b; + this->bufsize = bs; + + // the base setbuf() *has* to be called + streambuf::setbuf(b, bs); + + reset(); + + return this; +} + +int fcgi_streambuf::attach(FCGX_Stream * fs) +{ + this->fcgx = fs; + + if (this->bufsize) + { + reset(); + } + + return 0; +} + +streamsize fcgi_streambuf::xsgetn(char_type * s, streamsize n) +{ + if (n > INT_MAX) return 0; + return (this->bufsize) + ? streambuf::xsgetn(s, n) + : (streamsize) FCGX_GetStr((char *) s, (int) n, this->fcgx); +} + +streamsize fcgi_streambuf::xsputn(const char_type * s, streamsize n) +{ + if (n > INT_MAX) return 0; + return (this->bufsize) + ? streambuf::xsputn(s, n) + : (streamsize) FCGX_PutStr((char *) s, (int) n, this->fcgx); +} + +// deprecated +fcgi_istream::fcgi_istream(FCGX_Stream * fs) : + istream(&fcgi_strmbuf) +{ + fcgi_strmbuf.attach(fs); +} + +// deprecated +void fcgi_istream::attach(FCGX_Stream * fs) +{ + fcgi_strmbuf.attach(fs); +} + +// deprecated +fcgi_ostream::fcgi_ostream(FCGX_Stream * fs) : + ostream(&fcgi_strmbuf) +{ + fcgi_strmbuf.attach(fs); +} + +// deprecated +void fcgi_ostream::attach(FCGX_Stream * fs) +{ + fcgi_strmbuf.attach(fs); +}