2 // $Id: fcgio.cpp,v 1.3 2000/07/27 12:21:54 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 /*------------------------------------------------------------------*/
32 // **** fcgio_streambuf
34 // default constructor
35 fcgi_streambuf::fcgi_streambuf(void)
37 // we setup the buffer
38 setb(buffer,buffer + (buffersize * sizeof(char)),0);
39 // but we do not know yet if we are a reader or
44 // good idea to declare buffer status
45 if (buffersize < 1) unbuffered(1);
48 // disarm till initialized
55 fcgi_streambuf::~fcgi_streambuf(void) {}
59 int fcgi_streambuf::doallocate()
66 // this method provides an advanced feature and is
67 // considered experimental, see the header file for docs
68 // it is provided as it may save somebody someday
69 int fcgi_streambuf::drain_strm(char *s, int n)
71 int numinget; // number of chars in get buffer
72 int numtoextract; // number of chars to pull out of the
77 // no meaning if not initialized
78 if (!defined) return (EOF);
79 // is already drained if no buffer
80 if (unbuffered()) return (0);
82 numinget = egptr() - gptr(); // calculate how much stuff is in
85 // bogus requests deserve bogus answers
88 // an empty get area is an already drained get area
89 if (numinget<1) return(0);
91 // the number we extract is the lesser of the number of chars
92 // in the get area and the number of chars the user's array
93 // can hold. Maybe should use a ? operator here.
94 if (numinget<n) numtoextract = numinget;
95 else numtoextract = n;
98 // adjust the get pointer
99 // probably could use memcpy() to speed things up,
100 // however this may not be portable and if you are
101 // using drain(), performance is gonna take a back seat
102 for (i=0;i<numtoextract;i++)
108 return (numtoextract);
112 // little routine so that you can tell if the streambuf
113 // was ever initialized
114 int fcgi_streambuf::isstrmdefined(void)
120 // overflow is called for flush and every time the put buffer
121 // is full. Returns EOF on error
122 // This is the only method that actually writes data to
123 // the FCGI interface.
124 int fcgi_streambuf::overflow(int c)
126 int numinbuf; // number of chars in put buffer
128 // we will not allow a bogus fcgx_strm (because the user
129 // forgot to attach()) to do even more harm.
130 if (!defined) return (EOF);
132 // get the number of chars in the put buffer
133 numinbuf = pptr() - pbase();
135 // send out the entire put buffer
136 if (numinbuf > 0 && !unbuffered())
137 if (FCGX_PutStr(pbase(), numinbuf, fcgx_strm) < 0) return (EOF);
139 // reset the put buffer to empty
140 setp(pbase(),epptr());
142 // if we are given an overflow char, send it out too.
144 if (FCGX_PutChar(c, fcgx_strm) < 0) return (EOF);
151 // we have our own methods to setup buffering
152 // in case somebody calls this, ignore it
153 streambuf * fcgi_streambuf::setbuf(char *s, int n)
155 // tell them what they want to hear to make them
161 // just sets up the pointer and declares things defined.
162 // used by fcgi_iostream attach()
163 void fcgi_streambuf::stream_initialize(FCGX_Stream *str, int dir)
165 // setup the main buffer
166 setb(buffer,buffer + (buffersize * sizeof(char)),0);
170 if (buffersize < 1) unbuffered(1);
171 else // setup the get or put buffers
174 if (dir) // if writer
176 setg(0,0,0); // no get buffer
177 setp(base(),ebuf()); // buffer is all put
181 setg(base(),ebuf(),ebuf()); // buffer is all get
182 setp(0,0); // no put buffer
186 // set the FCGI interface
188 // we are ready for action
193 // flush all the output
194 int fcgi_streambuf::sync()
196 // flush the put area
197 if (overflow(-1) < 0) return (EOF);
200 return FCGX_FFlush(fcgx_strm);
204 // Underflow is called to get characters to fill up the get buffer
205 // so something that uses the stream can get the data. If there
206 // is nothing else to read, this returns EOF. This is the only method
207 // which reads from the FCGI interface.
208 int fcgi_streambuf::underflow()
212 // we will not allow a bogus fcgx_strm (because the user
213 // forgot to attach()) to do even more harm.
214 if (!defined) return (EOF);
216 // if it is unbuffered, then get & return a char
217 if (unbuffered()) return FCGX_GetChar(fcgx_strm);
219 // read as much data as we can, then adjust the get area so it
220 // reflects the data we just read
221 numread=FCGX_GetStr(base(), blen(), fcgx_strm);
222 if (numread<=0) return EOF;
223 setg(base(),base(),base()+numread);
225 // We avoid a common bug. You NEED the unsigned char cast or
226 // else this routine will return a false EOF when reading
227 // control chars outside the normal ascii range!
228 // i.e. "negative" chars map to positive ints and we
229 // reserve negative return values for EOF and error
230 // conditions. Now, even binary data will come through
232 // The reason the get buffer uses chars rather
233 // than unsigned chars is a mystery from AT&T history.
234 // It probably has to due with the old 7bit text limits.
235 return ((unsigned char)(*eback()));
240 // here comes the higher level iostream stuff
244 // parameterless constructor allows us to create first, then
245 // initialize later via attach()
246 fcgi_istream::fcgi_istream() {}
249 // or we can create and initialize in one step
250 // constructor calls ios::init to assign our streambuf to
251 // the istream derived class. Also sets up buffering.
252 fcgi_istream::fcgi_istream(FCGX_Stream *str)
254 // initialize as a reader, use all buffering for the
256 fcgi_strmbuf.stream_initialize(str,0);
257 // init is a protected member of ios
263 fcgi_istream::~fcgi_istream() {}
266 // does everything the constructor with parameter does at the
267 // request of the programmer
268 void fcgi_istream::attach(FCGX_Stream *str)
270 // initialize as a reader, use all buffering for the
272 fcgi_strmbuf.stream_initialize(str,0);
273 // init is a protected member of ios
278 // experimental method to drain the get buffer. Allows you
279 // to sync reads with FCGI library (non-istream reads).
280 // reads upto n chars into the s array from the get buffer, does
281 // not call underflow(). Returned is the number of chars extracted
282 // or EOF on error. If n>0 (normal use) and returns a nonnegative
283 // value less than n, the get buffer is empty and it is safe to
284 // use an FCGI library read.
285 // see the header file for more info
286 int fcgi_istream::drain(char *s, int n)
288 return (fcgi_strmbuf.drain_strm(s,n));
292 // little routine so that you can tell if the streambuf
294 int fcgi_istream::isdefined(void)
296 return (fcgi_strmbuf.isstrmdefined());
303 // parameterless constructor allows us to create first, then
304 // initialize later via attach()
305 fcgi_ostream::fcgi_ostream() {}
308 // or we can create and initialize in one step
309 // constructor calls ios::init to assign our streambuf to
310 // the ostream derived class. Also sets up buffering
311 fcgi_ostream::fcgi_ostream(FCGX_Stream *str)
313 // initialize as a writer, use all buffering for the
315 fcgi_strmbuf.stream_initialize(str,1);
316 // init is a protected member of ios
322 fcgi_ostream::~fcgi_ostream()
324 // don't blowup if the user never defined the
326 if (fcgi_strmbuf.isstrmdefined())
328 // this may protect a few poor souls who forgot to flush
329 // before deleting. Always flush when you are done.
335 // does everything the constructor with parameter does at the
336 // request of the programmer
337 void fcgi_ostream::attach(FCGX_Stream *str)
339 // initialize as a writer, use all buffering for the
341 fcgi_strmbuf.stream_initialize(str,1);
342 // init is a protected member of ios
347 // helper function to find out if this
348 // stream was ever initialized.
349 int fcgi_ostream::isdefined(void)
351 return (fcgi_strmbuf.isstrmdefined());