3ca1f69a287252c00979648ec7634d6aae1aef1f
[catagits/fcgi2.git] / libfcgi / fcgio.cpp
1 //
2 // $Id: fcgio.cpp,v 1.3 2000/07/27 12:21:54 robs Exp $
3 //
4 // Allows you communicate with FastCGI streams using C++ iostream
5 // objects
6 //
7 // ORIGINAL AUTHOR:     George Feinberg
8 // REWRITTEN BY:        Michael Richards  06/20/1999
9 // REWRITTEN AGAIN BY:  Michael Shell     02/23/2000
10 //
11 // Special Thanks to Dietmar Kuehl for his help and the numerous custom
12 // streambuf examples on his web site.
13 //
14 // see the header file fcgio2.h for lotsa docs and a code example.
15 //
16 // Copyright (c) 2000 Tux the Linux Penguin
17 //
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)
21 //
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.
25
26 /*------------------------------------------------------------------*/
27
28
29 #include "fcgio.h"
30
31
32 // **** fcgio_streambuf
33
34 // default constructor
35 fcgi_streambuf::fcgi_streambuf(void)
36    {
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
40    // a writer
41    setp(0,0);
42    setg(0,0,0);
43
44    // good idea to declare buffer status
45    if (buffersize < 1) unbuffered(1);
46    else unbuffered(0);
47
48    // disarm till initialized
49    fcgx_strm = NULL;
50    defined = 0;
51    }
52
53
54 // destructor
55 fcgi_streambuf::~fcgi_streambuf(void) {}
56
57
58 // do nothing
59 int fcgi_streambuf::doallocate()
60    {
61    return (0);
62    }
63
64
65 // drain the get area
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)
70    {
71    int numinget;     // number of chars in get buffer
72    int numtoextract; // number of chars to pull out of the
73                      // get area
74
75    int i;            // counter
76
77    // no meaning if not initialized
78    if (!defined) return (EOF);
79    // is already drained if no buffer
80    if (unbuffered()) return (0);
81
82    numinget = egptr() - gptr(); // calculate how much stuff is in
83                                 // the get buffer
84
85    // bogus requests deserve bogus answers
86    if (n<1) return (0);
87
88    // an empty get area is an already drained get area
89    if (numinget<1) return(0);
90
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;
96
97    // copy over the data
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++)
103        {
104        s[i] = *gptr();
105        gbump(1);
106        }
107    // all done
108    return (numtoextract);
109    }
110
111
112 // little routine so that you can tell if the streambuf
113 // was ever initialized
114 int fcgi_streambuf::isstrmdefined(void)
115    {
116    return defined;
117    }
118
119
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)
125   {
126   int numinbuf; // number of chars in put buffer
127
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);
131
132   // get the number of chars in the put buffer
133   numinbuf = pptr() - pbase();
134
135   // send out the entire put buffer
136   if (numinbuf > 0 && !unbuffered())
137      if (FCGX_PutStr(pbase(), numinbuf, fcgx_strm) < 0) return (EOF);
138
139   // reset the put buffer to empty
140   setp(pbase(),epptr());
141
142   // if we are given an overflow char, send it out too.
143   if (c >= 0)
144      if (FCGX_PutChar(c, fcgx_strm) < 0) return (EOF);
145
146   // all done
147   return (0);
148   }
149
150
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)
154    {
155    // tell them what they want to hear to make them
156    // go away
157    return this;
158    }
159
160
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)
164    {
165    // setup the main buffer
166    setb(buffer,buffer + (buffersize * sizeof(char)),0);
167    setp(0,0);
168    setg(0,0,0);
169
170    if (buffersize < 1) unbuffered(1);
171    else // setup the get or put buffers
172       {
173       unbuffered(0);
174       if (dir) // if writer
175          {
176          setg(0,0,0); // no get buffer
177          setp(base(),ebuf()); // buffer is all put
178          }
179       else // reader
180          {
181          setg(base(),ebuf(),ebuf()); // buffer is all get
182          setp(0,0); // no put buffer
183          }
184       }
185
186    // set the FCGI interface
187    fcgx_strm = str;
188    // we are ready for action
189    defined = 1;
190    }
191
192
193 // flush all the output
194 int fcgi_streambuf::sync()
195    {
196    // flush the put area
197    if (overflow(-1) < 0) return (EOF);
198
199    // now flush FCGX
200    return FCGX_FFlush(fcgx_strm);
201    }
202
203
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()
209    {
210    int numread;
211
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);
215
216    // if it is unbuffered, then get & return a char
217    if (unbuffered()) return FCGX_GetChar(fcgx_strm);
218
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);
224
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
231    // perfectly.
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()));
236    }
237
238
239
240 // here comes the higher level iostream stuff
241
242 // **** Istream
243
244 // parameterless constructor allows us to create first, then
245 // initialize later via attach()
246 fcgi_istream::fcgi_istream() {}
247
248
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)
253    {
254    // initialize as a reader, use all buffering for the
255    // get area
256    fcgi_strmbuf.stream_initialize(str,0);
257    // init is a protected member of ios
258    init(&fcgi_strmbuf);
259    }
260
261
262 // destructor
263 fcgi_istream::~fcgi_istream() {}
264
265
266 // does everything the constructor with parameter does at the
267 // request of the programmer
268 void fcgi_istream::attach(FCGX_Stream *str)
269    {
270    // initialize as a reader, use all buffering for the
271    // get area
272    fcgi_strmbuf.stream_initialize(str,0);
273    // init is a protected member of ios
274    init(&fcgi_strmbuf);
275    }
276
277
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)
287    {
288    return (fcgi_strmbuf.drain_strm(s,n));
289    }
290
291
292 // little routine so that you can tell if the streambuf
293 // was ever defined
294 int fcgi_istream::isdefined(void)
295    {
296    return (fcgi_strmbuf.isstrmdefined());
297    }
298
299
300
301 // **** Ostream
302
303 // parameterless constructor allows us to create first, then
304 // initialize later via attach()
305 fcgi_ostream::fcgi_ostream() {}
306
307
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)
312   {
313   // initialize as a writer, use all buffering for the
314   // put area
315   fcgi_strmbuf.stream_initialize(str,1);
316   // init is a protected member of ios
317   init(&fcgi_strmbuf);
318   }
319
320
321 // destructor
322 fcgi_ostream::~fcgi_ostream()
323    {
324    // don't blowup if the user never defined the
325    // stream
326    if (fcgi_strmbuf.isstrmdefined())
327       {
328       // this may protect a few poor souls who forgot to flush
329       // before deleting. Always flush when you are done.
330       fcgi_strmbuf.sync();
331       }
332    }
333
334
335 // does everything the constructor with parameter does at the
336 // request of the programmer
337 void fcgi_ostream::attach(FCGX_Stream *str)
338    {
339    // initialize as a writer, use all buffering for the
340    // put area
341    fcgi_strmbuf.stream_initialize(str,1);
342    // init is a protected member of ios
343    init(&fcgi_strmbuf);
344    }
345
346
347 // helper function to find out if this
348 // stream was ever initialized.
349 int fcgi_ostream::isdefined(void)
350    {
351    return (fcgi_strmbuf.isstrmdefined());
352    }
353