2 // $Id: fcgio.cpp,v 1.5 2001/06/22 14:27:06 robs Exp $
4 // Allows you communicate with FastCGI streams using C++ iostream
7 // ORIGINAL AUTHOR: George Feinberg
8 // REWRITTEN BY: Michael Richards 06/20/1999
9 // REWRITTEN AGAIN BY: Michael Shell 02/23/2000
11 // Special Thanks to Dietmar Kuehl for his help and the numerous custom
12 // streambuf examples on his web site.
14 // see the header file fcgio2.h for lotsa docs and a code example.
16 // Copyright (c) 2000 Tux the Linux Penguin
18 // You are free to use this software without charge or royalty
19 // as long as this notice is not removed or altered, and recognition
20 // is given to the author(s)
22 // This code is offered as-is without any warranty either expressed or
23 // implied; without even the implied warranty of MERCHANTABILITY or
24 // FITNESS FOR A PARTICULAR PURPOSE.
26 /*------------------------------------------------------------------*/
29 #define DLLAPI __declspec(dllexport)
35 // **** fcgio_streambuf
37 // default constructor
38 fcgi_streambuf::fcgi_streambuf(void)
40 // we setup the buffer
41 setb(buffer,buffer + (buffersize * sizeof(char)),0);
42 // but we do not know yet if we are a reader or
47 // good idea to declare buffer status
48 if (buffersize < 1) unbuffered(1);
51 // disarm till initialized
58 fcgi_streambuf::~fcgi_streambuf(void) {}
62 int fcgi_streambuf::doallocate()
69 // this method provides an advanced feature and is
70 // considered experimental, see the header file for docs
71 // it is provided as it may save somebody someday
72 int fcgi_streambuf::drain_strm(char *s, int n)
74 int numinget; // number of chars in get buffer
75 int numtoextract; // number of chars to pull out of the
80 // no meaning if not initialized
81 if (!defined) return (EOF);
82 // is already drained if no buffer
83 if (unbuffered()) return (0);
85 numinget = egptr() - gptr(); // calculate how much stuff is in
88 // bogus requests deserve bogus answers
91 // an empty get area is an already drained get area
92 if (numinget<1) return(0);
94 // the number we extract is the lesser of the number of chars
95 // in the get area and the number of chars the user's array
96 // can hold. Maybe should use a ? operator here.
97 if (numinget<n) numtoextract = numinget;
98 else numtoextract = n;
100 // copy over the data
101 // adjust the get pointer
102 // probably could use memcpy() to speed things up,
103 // however this may not be portable and if you are
104 // using drain(), performance is gonna take a back seat
105 for (i=0;i<numtoextract;i++)
111 return (numtoextract);
115 // little routine so that you can tell if the streambuf
116 // was ever initialized
117 int fcgi_streambuf::isstrmdefined(void)
123 // overflow is called for flush and every time the put buffer
124 // is full. Returns EOF on error
125 // This is the only method that actually writes data to
126 // the FCGI interface.
127 int fcgi_streambuf::overflow(int c)
129 int numinbuf; // number of chars in put buffer
131 // we will not allow a bogus fcgx_strm (because the user
132 // forgot to attach()) to do even more harm.
133 if (!defined) return (EOF);
135 // get the number of chars in the put buffer
136 numinbuf = pptr() - pbase();
138 // send out the entire put buffer
139 if (numinbuf > 0 && !unbuffered())
140 if (FCGX_PutStr(pbase(), numinbuf, fcgx_strm) < 0) return (EOF);
142 // reset the put buffer to empty
143 setp(pbase(),epptr());
145 // if we are given an overflow char, send it out too.
147 if (FCGX_PutChar(c, fcgx_strm) < 0) return (EOF);
154 // we have our own methods to setup buffering
155 // in case somebody calls this, ignore it
156 streambuf * fcgi_streambuf::setbuf(char *s, int n)
158 // Touch the args to avoid compiler warnings
164 // just sets up the pointer and declares things defined.
165 // used by fcgi_iostream attach()
166 void fcgi_streambuf::stream_initialize(FCGX_Stream *str, int dir)
168 // setup the main buffer
169 setb(buffer,buffer + (buffersize * sizeof(char)),0);
173 if (buffersize < 1) unbuffered(1);
174 else // setup the get or put buffers
177 if (dir) // if writer
179 setg(0,0,0); // no get buffer
180 setp(base(),ebuf()); // buffer is all put
184 setg(base(),ebuf(),ebuf()); // buffer is all get
185 setp(0,0); // no put buffer
189 // set the FCGI interface
191 // we are ready for action
196 // flush all the output
197 int fcgi_streambuf::sync()
199 // flush the put area
200 if (overflow(-1) < 0) return (EOF);
203 return FCGX_FFlush(fcgx_strm);
207 // Underflow is called to get characters to fill up the get buffer
208 // so something that uses the stream can get the data. If there
209 // is nothing else to read, this returns EOF. This is the only method
210 // which reads from the FCGI interface.
211 int fcgi_streambuf::underflow()
215 // we will not allow a bogus fcgx_strm (because the user
216 // forgot to attach()) to do even more harm.
217 if (!defined) return (EOF);
219 // if it is unbuffered, then get & return a char
220 if (unbuffered()) return FCGX_GetChar(fcgx_strm);
222 // read as much data as we can, then adjust the get area so it
223 // reflects the data we just read
224 numread=FCGX_GetStr(base(), blen(), fcgx_strm);
225 if (numread<=0) return EOF;
226 setg(base(),base(),base()+numread);
228 // We avoid a common bug. You NEED the unsigned char cast or
229 // else this routine will return a false EOF when reading
230 // control chars outside the normal ascii range!
231 // i.e. "negative" chars map to positive ints and we
232 // reserve negative return values for EOF and error
233 // conditions. Now, even binary data will come through
235 // The reason the get buffer uses chars rather
236 // than unsigned chars is a mystery from AT&T history.
237 // It probably has to due with the old 7bit text limits.
238 return ((unsigned char)(*eback()));
243 // here comes the higher level iostream stuff
247 // parameterless constructor allows us to create first, then
248 // initialize later via attach()
249 fcgi_istream::fcgi_istream() {}
252 // or we can create and initialize in one step
253 // constructor calls ios::init to assign our streambuf to
254 // the istream derived class. Also sets up buffering.
255 fcgi_istream::fcgi_istream(FCGX_Stream *str)
257 // initialize as a reader, use all buffering for the
259 fcgi_strmbuf.stream_initialize(str,0);
260 // init is a protected member of ios
266 fcgi_istream::~fcgi_istream() {}
269 // does everything the constructor with parameter does at the
270 // request of the programmer
271 void fcgi_istream::attach(FCGX_Stream *str)
273 // initialize as a reader, use all buffering for the
275 fcgi_strmbuf.stream_initialize(str,0);
276 // init is a protected member of ios
281 // experimental method to drain the get buffer. Allows you
282 // to sync reads with FCGI library (non-istream reads).
283 // reads upto n chars into the s array from the get buffer, does
284 // not call underflow(). Returned is the number of chars extracted
285 // or EOF on error. If n>0 (normal use) and returns a nonnegative
286 // value less than n, the get buffer is empty and it is safe to
287 // use an FCGI library read.
288 // see the header file for more info
289 int fcgi_istream::drain(char *s, int n)
291 return (fcgi_strmbuf.drain_strm(s,n));
295 // little routine so that you can tell if the streambuf
297 int fcgi_istream::isdefined(void)
299 return (fcgi_strmbuf.isstrmdefined());
306 // parameterless constructor allows us to create first, then
307 // initialize later via attach()
308 fcgi_ostream::fcgi_ostream() {}
311 // or we can create and initialize in one step
312 // constructor calls ios::init to assign our streambuf to
313 // the ostream derived class. Also sets up buffering
314 fcgi_ostream::fcgi_ostream(FCGX_Stream *str)
316 // initialize as a writer, use all buffering for the
318 fcgi_strmbuf.stream_initialize(str,1);
319 // init is a protected member of ios
325 fcgi_ostream::~fcgi_ostream()
327 // don't blowup if the user never defined the
329 if (fcgi_strmbuf.isstrmdefined())
331 // this may protect a few poor souls who forgot to flush
332 // before deleting. Always flush when you are done.
338 // does everything the constructor with parameter does at the
339 // request of the programmer
340 void fcgi_ostream::attach(FCGX_Stream *str)
342 // initialize as a writer, use all buffering for the
344 fcgi_strmbuf.stream_initialize(str,1);
345 // init is a protected member of ios
350 // helper function to find out if this
351 // stream was ever initialized.
352 int fcgi_ostream::isdefined(void)
354 return (fcgi_strmbuf.isstrmdefined());