-// fcgio.h - defines classes fcgio_buf, fcgio_ostream, fcgio_istream
-// and replaces cin, cout and cerr with FastCGI versions
-// you must include this file in any source file which
-// uses cin, cout or cerr. It must also appear at the end
-// of your includes
//
-// $Id: fcgio.h,v 1.1 1999/08/15 03:37:59 roberts Exp $
+// $Id: fcgio.h,v 1.2 2000/07/21 20:56:28 robs Exp $
//
-// This work is based on routines written by George Feinberg. They
-// have been mostly re-written and extensively changed by
+// Allows you communicate with FastCGI streams using C++ iostream
+// objects
+//
+// defines classes fcgi_streambuf, fcgi_ostream, fcgi_istream
+// you can redefine cin, cout, cerr or use your own custom
+// FCGI stream names.
+//
+// ORIGINAL AUTHOR: George Feinberg
+//
+//
+// REWRITTEN BY: Michael Richards 06/20/1999
+// -added cin support
+// -added ability to replace cin/cout so existing code only
+// needs to include the header file and use the normal
+// cin/cout. This has been altered as of 2/2000, see below.
+// -added buffered read support which is required for ungets.
+//
+//
+// REWRITTEN AGAIN BY: Michael Shell 02/23/2000
+//
+// Previous versions of this code had problems.
+// Two hellish bugs have been fixed and there is now full
+// buffering for both input and output streams.
+//
+// - fixed signed char bug in underflow() that would
+// cause a false EOF to be flagged when reading binary
+// data. Uploading short binary files via <input type=file
+// which uses multipart/form-data encoding would reveal
+// this bug. Also could be triggered by hackers
+// sending binary data instead of legitimate form data,
+// in which case the hung network connection, depending on
+// how the FCGI application server handles things, could
+// form the basis for a stupid denial of service attack.
+// - fixed code to properly use the get and put buffers via
+// underflow() and overflow() NOT xsgetn() and xsputn() as
+// was done before. Because of this, the previous
+// version would often drop data, especially if the
+// user did an initial getline() followed by a read().
+// - added the attach() method and a parameterless
+// constructor so that you can declare fcgi_iostream
+// objects and attach() to them later - after accept().
+// - enhanced docs to include examples that actually work.
+// - removed any predefined redefinitions of cin,cout,cerr.
+// The example shows how you can use these names if you
+// want (via properly placed #undefs) or use ones of your
+// choosing (such as fin,fout,ferr). This may be very
+// helpful when testing code. Also, as a result, you
+// no longer have to place fcgio2.h in any special
+// order in your #includes.
+// - added an experimental method drain() to istream which
+// allows the user to drain the get buffer. This is
+// designed to provide users with a way to drain the get
+// buffer prior to using a read function from the FCGI
+// library in applications which mix I/O methods. i.e.
+// it is the input equivalent to flush(). It does not
+// read from the FCGI stream, but gets only characters
+// already in the istream buffer. Mixing I/O methods is
+// not recommended since this iostream implementation
+// is complete and should provide you with everything
+// you need.
+//
+//
+// NOTES: encapsulates the FastCGI protocol in an iostream via a
+// nice custom streambuf. Very nice, very robust, and very powerful.
+//
+// This work is based on routines written by George Feinberg. They
+// have been mostly re-written and extensively changed by
// Michael Richards.
//
-// Copyright (c) 1999 by Apollo Software. All rights reserved.
+// Rewritten again with bug fixes and numerous enhancements by
+// Michael Shell.
+//
+// Special Thanks to Dietmar Kuehl for his help and the numerous custom
+// streambuf examples on his web site.
+//
+// Copyright (c) 2000 Tux the Linux Penguin
//
// You are free to use this software without charge or royalty
-// as long as this notice is not removed or altered, and recognition
+// as long as this notice is not removed or altered, and recognition
// is given to the author(s)
//
-
+// This code is offered as-is without any warranty either expressed or
+// implied; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE.
+// If it breaks, you get to keep both halves.
+
+
+// BEGIN EXAMPLE CODE: test_fcgio2.cpp
+/*
+// This code uses the fcgiapp interface to show a little bit more
+// complexity and to demonstrate the fact that with fcgio2 and just
+// a few more lines of code (like FCGX_Init etc.) you can easily
+// make FastCGI programs without needing wrapper functions.
+// You can use the fcgi_stdio interface if you you want a
+// simpler accept(). However note that the fcgio2 interface
+// removes the need for the fcgi_stdio wrapper functions.
+// i.e. Why override printf when you aren't going to use it anyway?
+// Also, be aware that because of iostream buffering, you must take
+// care when mixing FCGI iostream I/O with the FCGI library I/O
+// commands (such as printf). Be sure to flush() any open
+// fcgi_ostreams prior to using commands such as printf. This is true
+// even on systems which have the C I/O commands synced with C++
+// iostreams, such as Linux, because the FCGI wrapper printf, etc. are
+// not the same as the "normal" printf etc. It is recommended that you
+// not use any FCGI library input (read) commands if you use
+// fcgi_istream (cin) input as there is no easy way to "flush" (drain)
+// an istream get buffer. However, an experimental istream method
+// drain() has been provided to istream for those of you who need to
+// do mixed input. There should be no need to do mixed I/O as the
+// fcgio2 iostream implementation is complete.
+
+#include <stdlib.h>
+#include "fcgio2.h" // fcgio2.h includes fcgiapp.h
+ // however you must include fcgi_stdio.h if
+ // you want to use it as fcgio2.h does not
+ // include it for you
+
+#undef cin // remember you have to undo the stuff predefined
+#undef cout // for cin, cout, cerr if you wish to use these
+#undef cerr // names for your FastCGI streams
+
+int main(void)
+{
+
+ int count = 0;
+
+ // I can create/declare my objects here, but I don't dare use them
+ // until I set them up with attach().
+
+ // note that version 1.0 of fcgio used fcgio_istream & fcgio_ostream
+ // we made a little change to the names in V2.00 for clarity.
+ fcgi_istream cin; // you do not *HAVE* to use these names, you
+ fcgi_ostream cout; // could use other stream names of your choice
+ fcgi_ostream cerr; // don't forget that the input is
+ // fcgi_*I*stream class
+
+ FCGX_Request request; // here is our request structure
+
+ // get everything ready for the customers
+ FCGX_Init();
+
+ FCGX_InitRequest(&request,0,0);
+
+
+ // let the games begin
+ while(FCGX_Accept_r(&request) >= 0)
+ {
+ count++;
+
+ cout.attach(request.out); // now I know my pointer values for
+ cerr.attach(request.err); // this request. attach to them
+ cin.attach(request.in);
+ // attach will initialize everything
+ // alternatively, you could declare the streams here and the
+ // constructor with the (FCGX_Stream *str) parameter would
+ // do the same job as attach
+
+ // If you are using fcgi_stdio.h, the equivalent command would
+ // be cout.attach(FCGI_stdout->fcgx_stream);
+ // and so forth for cin,cerr using FCGI_stdin and FCGI_stderr
+ // respectively.
+
+
+ // now I can fire at will:
+ cout << "Content-type: text/html\r\n\r\n"
+ << "<title> FastCGI cin, cout, cerr tester </title>\r\n"
+ << "<h1><center> FastCGI C++ IOstream test: "
+ << "It works! </center></h1>\r\n";
+ cout << "<h4><center><i> Total served by this task: "
+ << count << "</i></center></h4>\r\n";
+
+// didn't use cin or cerr in this example.
+
+// it is good practice to flush the buffers.
+// use cout.flush() if you don't want the line feed.
+
+ cout << endl;
+
+// there is no cxxx.close() and you do not need it with the fcgio
+// interface. You would need to call cxxx.close() if cxxx was an
+// fstream based object and attached to a file descripter you got
+// from a command like fd=open(blah). (GNU (Linux) based fstreams
+// support this) Then you need to call cxxx.close() before you
+// close the physical file with close(fd). If doing this with
+// fstream objects, you should call cxxx.clear() after
+// attach(fd) as the file descriptor attach is not as complete in
+// initialization as our fcgi_iostream attach()
+// If you don't understand any of this, don't worry about it and
+// forget I even mentioned it.
+
+ // all done with this request
+ FCGX_Finish_r(&request);
+
+ // do the next request
+ }
+ return (1);
+}
+
+*/
+
+// END EXAMPLE CODE
+
+/*------------------------------------------------------------------*/
+
+
#ifndef FCGIO_H
#define FCGIO_H
-
+
#include <iostream.h>
#include <fcgiapp.h>
-
-// FastCGI streambuf replacement. Implements low level io to the
-// FastCGI c functions so our higher level iostreams will talk
-// in the fcgi protocol
-class fcgio_buf : public streambuf {
- // construction
+
+// FastCGI streambuf replacement. Implements low level I/O to the
+// FastCGI C functions so our higher level iostreams will talk
+// in the FastCGI protocol
+class fcgi_streambuf : public streambuf
+{
public:
- fcgio_buf( FCGX_Stream *str) { fcgi_str = str; }
- ~fcgio_buf() {}
-
- // from streambuf
- // tells the stream to go flush itself
- virtual int sync();
- // handles allocation of buffers by failing since buffer support isn't used
- virtual int doallocate() { return 0; }
-
- virtual int xsgetn(char *s, int n);
- virtual int xsputn(const char* s, int n);
+ // constructor
+ fcgi_streambuf(void);
+ ~fcgi_streambuf();
+
+ // handles allocation of buffers by doing nothing since buffer
+ // allocation isn't needed
+ virtual int doallocate();
+
+ // gets data (upto the given maximum) from the get buffer and
+ // copies it to the given char array. Returns the number of chars
+ // written or -1 on error. A returned value less than the given
+ // maximum, assuming the user requested at least one char,
+ // indicates that the get buffer is empty. The underflow() method
+ // is never called to refill the get buffer, so this method can be
+ // used to drain the get buffer. It is used to form an istream
+ // drain() method which is the input equivalent to flush().
+ virtual int drain_strm(char *,int);
+
+ // let's us know if this strembuf has been initialized
+ virtual int isstrmdefined(void);
+
+ // (for writers) empties the put buffer and possibly an
+ // overflow char into the FCGI interface
virtual int overflow(int);
+
+ // bogus routine in case somebody thinks they know
+ // better and calls it. We currently are happy with
+ // our static buffer.
+ virtual streambuf * setbuf(char *, int);
+
+ // initializes the buffering and FCGI interface
+ virtual void stream_initialize(FCGX_Stream *,int);
+
+ // (for writers) flushes the put buffer into the FCGI
+ // interface and then flushes the FCGI interface
+ virtual int sync();
+
+ // (for readers) fills the get buffer with data from the
+ // FCGI interface
virtual int underflow();
- virtual streambuf* setbuf(char* s, int n);
-
+
private:
- FCGX_Stream * fcgi_str;
-};
+ // pointer to our underlying FCGI interface
+ FCGX_Stream * fcgx_strm;
-
-// Here's the ostream class definition. All it has to do is
-// call ios::init() passing an instance of fcgio_buf
-class fcgio_ostream : public ostream {
- public:
- fcgio_ostream(FCGX_Stream *str);
- ~fcgio_ostream() { buf.sync(); }
+ // our buffer
+ // we aren't pulling from the heap, so it is best not
+ // to make it too big
+ static const int buffersize=200;
+ char buffer[buffersize];
- private:
- fcgio_buf buf;
+ // little flag so that we can tell if the
+ // fcgi_str pointer was ever set
+ int defined;
};
-// Here's the istream class definition. All it has to do is
-// call ios::init() passing an instance of fcgio_buf
-class fcgio_istream : public istream {
+
+// Here's the istream class definition.
+class fcgi_istream : public istream
+{
public:
- fcgio_istream(FCGX_Stream *str);
- ~fcgio_istream() {}
+ fcgi_istream();
+ fcgi_istream(FCGX_Stream *str);
+ ~fcgi_istream();
+
+ // connects the fcgi_streambuf of an existing fcgi_istream
+ // object to a given FCGI interface
+ virtual void attach(FCGX_Stream *str);
+
+ // allows you to drain down the streambuf buffer. It will not
+ // read any chars from the FCGI interface. You can repeatedly
+ // call drain() to empty the get buffer prior to using a
+ // FCGI library function to ensure syncronization of the
+ // reads. i.e. it flushes the input stream
+ // This method should be considered both nonstandard and
+ // experimental. It's use is entirely optional to the user,
+ // but could be very helpful for applications which use
+ // both istream and FCGI library based reads on a single
+ // FCGI interface and need a way to sync the reads.
+ // It copies upto the given number of chars into the given
+ // char array. It returns the number of chars written or
+ // -1 on error. If the number of chars written is less than
+ // the number the user requested, the get buffer is empty.
+ // This method does not alter or check any of the input
+ // status flags such as EOF or FAIL since it does not interact
+ // with the underlying FCGI interface at all - it only reads from
+ // the get buffer.
+ virtual int drain(char *,int);
+
+ // lets us know if this object has been initialized
+ virtual int isdefined(void);
private:
- // FastCGI stuff used for the FCGX_ functions
- fcgio_buf buf;
- // buffer for getting data
- const int buffersize=100;
- char buffer[buffersize];
+ // FastCGI streambuf
+ fcgi_streambuf fcgi_strmbuf;
+
};
-// replace cin and cout with our own versions
-#ifndef USE_CIN_COUT_CERR
- #undef cout
- #define cout (*FCGIX_cout)
- extern fcgio_ostream *FCGIX_cout;
- #undef cerr
- #define cerr (*FCGIX_cerr)
- extern fcgio_ostream *FCGIX_cerr;
+// Here's the ostream class definition.
+class fcgi_ostream : public ostream
+{
+ public:
+ fcgi_ostream(void);
+ fcgi_ostream(FCGX_Stream *str);
+ ~fcgi_ostream();
+
+ // connects the fcgi_streambuf of an existing fcgi_ostream
+ // object to a given FCGI interface
+ virtual void attach(FCGX_Stream *str);
+
+ // lets us know if this object has been initialized
+ virtual int isdefined(void);
- #undef cin
- #define cin (*FCGIX_cin)
- extern fcgio_istream *FCGIX_cin;
-#endif
+ private:
+ // FastCGI streambuf
+ fcgi_streambuf fcgi_strmbuf;
+};
-#endif __FCCIO_H__
+#endif FCGIO_H
-// FILE NAME: fcgio.cpp
//
-// $Id: fcgio.cpp,v 1.1 1999/08/15 03:37:59 roberts Exp $
+// $Id: fcgio.cpp,v 1.2 2000/07/21 20:56:28 robs Exp $
//
-// REWRITTEN BY: Michael Richards 06/20/1999
-// -added cin support
-// -added ability to replace cin/cout so existing code only
-// needs to include the header file and use the normal cin/cout
-// -added buffered read support which is required by getline
+// Allows you communicate with FastCGI streams using C++ iostream
+// objects
//
-// ORIGINAL AUTHOR: George Feinberg
+// ORIGINAL AUTHOR: George Feinberg
+// REWRITTEN BY: Michael Richards 06/20/1999
+// REWRITTEN AGAIN BY: Michael Shell 02/23/2000
//
-// NOTES: encapsulates FCGI function in an ostream and replaces cin,
-// cout and cerr
+// Special Thanks to Dietmar Kuehl for his help and the numerous custom
+// streambuf examples on his web site.
//
-// This work is based on routines written by George Feinberg. They
-// have been mostly re-written and extensively changed by
-// Michael Richards.
-//
-// Copyright (c) 1999 by Apollo Software. All rights reserved.
+// see the header file fcgio2.h for lotsa docs and a code example.
+//
+// Copyright (c) 2000 Tux the Linux Penguin
//
// You are free to use this software without charge or royalty
// as long as this notice is not removed or altered, and recognition
-// is given to the author(s)
-//
-
-#include <fcgiapp.h>
-#include "fcgio.h"
-
-
-// the definition that replaces cout and cin
-#ifndef USE_CIN_COUT_CERR
- fcgio_ostream *FCGIX_cout;
- fcgio_ostream *FCGIX_cerr;
- fcgio_istream *FCGIX_cin;
-#endif
-
-/*---------------------------------------------------------------------*/
-
-
-// gets a number of characters at once for a more efficient implementation
-int fcgio_buf::xsgetn(char *s, int n) {
- return FCGX_GetStr(s, n, fcgi_str);
-}
-
-
-// writes a gob of data out, This is called for things like:
-// output << "hello world"
-// output.write(string, n);
-int fcgio_buf::xsputn(const char* s, int n) {
- return FCGX_PutStr(s, n, fcgi_str);
-}
-
-
-// overflow is called for "endl" and every time the put buffer
-// is full. Since we are using a single char put buffer, we just
-// pump the waiting character out and return the number of chars
-// we just got rid of (1). Returns EOF on error
-int fcgio_buf::overflow(int c) {
- if (c)
- return FCGX_PutChar(c, fcgi_str);
- else
- return EOF;
-}
+// is given to the author(s)
+//
+// This code is offered as-is without any warranty either expressed or
+// implied; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE.
+
+/*------------------------------------------------------------------*/
+
+
+#include "fcgio2.h"
+
+
+// **** 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<n) numtoextract = numinget;
+ else numtoextract = n;
+
+ // copy over the data
+ // adjust the get pointer
+ // probably could use memcpy() to speed things up,
+ // however this may not be portable and if you are
+ // using drain(), performance is gonna take a back seat
+ for (i=0;i<numtoextract;i++)
+ {
+ s[i] = *gptr();
+ gbump(1);
+ }
+ // all done
+ return (numtoextract);
+ }
+
+
+// little routine so that you can tell if the streambuf
+// was ever initialized
+int fcgi_streambuf::isstrmdefined(void)
+ {
+ return defined;
+ }
+
+
+// overflow is called for flush and every time the put buffer
+// is full. Returns EOF on error
+// This is the only method that actually writes data to
+// the FCGI interface.
+int fcgi_streambuf::overflow(int c)
+ {
+ int numinbuf; // number of chars in put buffer
+
+ // we will not allow a bogus fcgx_strm (because the user
+ // forgot to attach()) to do even more harm.
+ if (!defined) return (EOF);
+
+ // get the number of chars in the put buffer
+ numinbuf = pptr() - pbase();
+
+ // send out the entire put buffer
+ if (numinbuf > 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
+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
-int fcgio_buf::underflow() {
- // if it is unbuffered, then get & return a char
- if (unbuffered())
- return FCGX_GetChar(fcgi_str);
+// is nothing else to read, this returns EOF. This is the only method
+// which reads from the FCGI interface.
+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
- int numread=FCGX_GetStr(eback(), blen(), fcgi_str);
- if (numread==0) return EOF;
- setg(eback(),eback(),eback()+numread);
+ // 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);
- return *eback();
-}
+ // 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()));
+ }
-// sets up any buffering used for input or output
-streambuf* fcgio_buf::setbuf(char *p, int n) {
- // if setbuf is offered a buffer, then use it, otherwise, set the stream to unbuffered
- setb(p,p+n,0);
- // output is not buffered
- setp(0,0);
- setg(p,p+n,p+n);
- unbuffered(p==NULL);
- return this;
-}
+// here comes the higher level iostream stuff
+// **** Istream
-// flush all the output using FCGX_FFlush
-int fcgio_buf::sync() {
- return FCGX_FFlush(fcgi_str);
-}
+// 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 ostream derived class. Also sets up buffering
-fcgio_ostream::fcgio_ostream(FCGX_Stream *str) : buf(str) {
- // init is a protected member of ios
- init(&buf);
- buf.setbuf(NULL,0);
-}
+// 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
-fcgio_istream::fcgio_istream(FCGX_Stream *str) : buf(str) {
+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(&buf);
- // set up the buffers
- buf.setbuf(buffer,buffersize);
-}
+ 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());
+ }