respect CFLAGS
[catagits/fcgi2.git] / libfcgi / fcgio.cpp
1 //
2 // $Id: fcgio.cpp,v 1.5 2001/06/22 14:27:06 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 #ifdef _WIN32
29 #define DLLAPI  __declspec(dllexport)
30 #endif
31
32 #include "fcgio.h"
33
34
35 // **** fcgio_streambuf
36
37 // default constructor
38 fcgi_streambuf::fcgi_streambuf(void)
39    {
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
43    // a writer
44    setp(0,0);
45    setg(0,0,0);
46
47    // good idea to declare buffer status
48    if (buffersize < 1) unbuffered(1);
49    else unbuffered(0);
50
51    // disarm till initialized
52    fcgx_strm = NULL;
53    defined = 0;
54    }
55
56
57 // destructor
58 fcgi_streambuf::~fcgi_streambuf(void) {}
59
60
61 // do nothing
62 int fcgi_streambuf::doallocate()
63    {
64    return (0);
65    }
66
67
68 // drain the get area
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)
73    {
74    int numinget;     // number of chars in get buffer
75    int numtoextract; // number of chars to pull out of the
76                      // get area
77
78    int i;            // counter
79
80    // no meaning if not initialized
81    if (!defined) return (EOF);
82    // is already drained if no buffer
83    if (unbuffered()) return (0);
84
85    numinget = egptr() - gptr(); // calculate how much stuff is in
86                                 // the get buffer
87
88    // bogus requests deserve bogus answers
89    if (n<1) return (0);
90
91    // an empty get area is an already drained get area
92    if (numinget<1) return(0);
93
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;
99
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++)
106        {
107        s[i] = *gptr();
108        gbump(1);
109        }
110    // all done
111    return (numtoextract);
112    }
113
114
115 // little routine so that you can tell if the streambuf
116 // was ever initialized
117 int fcgi_streambuf::isstrmdefined(void)
118    {
119    return defined;
120    }
121
122
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)
128   {
129   int numinbuf; // number of chars in put buffer
130
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);
134
135   // get the number of chars in the put buffer
136   numinbuf = pptr() - pbase();
137
138   // send out the entire put buffer
139   if (numinbuf > 0 && !unbuffered())
140      if (FCGX_PutStr(pbase(), numinbuf, fcgx_strm) < 0) return (EOF);
141
142   // reset the put buffer to empty
143   setp(pbase(),epptr());
144
145   // if we are given an overflow char, send it out too.
146   if (c >= 0)
147      if (FCGX_PutChar(c, fcgx_strm) < 0) return (EOF);
148
149   // all done
150   return (0);
151   }
152
153
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)
157    {
158    // Touch the args to avoid compiler warnings
159    s = NULL; n = 0;
160    return this;
161    }
162
163
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)
167    {
168    // setup the main buffer
169    setb(buffer,buffer + (buffersize * sizeof(char)),0);
170    setp(0,0);
171    setg(0,0,0);
172
173    if (buffersize < 1) unbuffered(1);
174    else // setup the get or put buffers
175       {
176       unbuffered(0);
177       if (dir) // if writer
178          {
179          setg(0,0,0); // no get buffer
180          setp(base(),ebuf()); // buffer is all put
181          }
182       else // reader
183          {
184          setg(base(),ebuf(),ebuf()); // buffer is all get
185          setp(0,0); // no put buffer
186          }
187       }
188
189    // set the FCGI interface
190    fcgx_strm = str;
191    // we are ready for action
192    defined = 1;
193    }
194
195
196 // flush all the output
197 int fcgi_streambuf::sync()
198    {
199    // flush the put area
200    if (overflow(-1) < 0) return (EOF);
201
202    // now flush FCGX
203    return FCGX_FFlush(fcgx_strm);
204    }
205
206
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()
212    {
213    int numread;
214
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);
218
219    // if it is unbuffered, then get & return a char
220    if (unbuffered()) return FCGX_GetChar(fcgx_strm);
221
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);
227
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
234    // perfectly.
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()));
239    }
240
241
242
243 // here comes the higher level iostream stuff
244
245 // **** Istream
246
247 // parameterless constructor allows us to create first, then
248 // initialize later via attach()
249 fcgi_istream::fcgi_istream() {}
250
251
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)
256    {
257    // initialize as a reader, use all buffering for the
258    // get area
259    fcgi_strmbuf.stream_initialize(str,0);
260    // init is a protected member of ios
261    init(&fcgi_strmbuf);
262    }
263
264
265 // destructor
266 fcgi_istream::~fcgi_istream() {}
267
268
269 // does everything the constructor with parameter does at the
270 // request of the programmer
271 void fcgi_istream::attach(FCGX_Stream *str)
272    {
273    // initialize as a reader, use all buffering for the
274    // get area
275    fcgi_strmbuf.stream_initialize(str,0);
276    // init is a protected member of ios
277    init(&fcgi_strmbuf);
278    }
279
280
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)
290    {
291    return (fcgi_strmbuf.drain_strm(s,n));
292    }
293
294
295 // little routine so that you can tell if the streambuf
296 // was ever defined
297 int fcgi_istream::isdefined(void)
298    {
299    return (fcgi_strmbuf.isstrmdefined());
300    }
301
302
303
304 // **** Ostream
305
306 // parameterless constructor allows us to create first, then
307 // initialize later via attach()
308 fcgi_ostream::fcgi_ostream() {}
309
310
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)
315   {
316   // initialize as a writer, use all buffering for the
317   // put area
318   fcgi_strmbuf.stream_initialize(str,1);
319   // init is a protected member of ios
320   init(&fcgi_strmbuf);
321   }
322
323
324 // destructor
325 fcgi_ostream::~fcgi_ostream()
326    {
327    // don't blowup if the user never defined the
328    // stream
329    if (fcgi_strmbuf.isstrmdefined())
330       {
331       // this may protect a few poor souls who forgot to flush
332       // before deleting. Always flush when you are done.
333       fcgi_strmbuf.sync();
334       }
335    }
336
337
338 // does everything the constructor with parameter does at the
339 // request of the programmer
340 void fcgi_ostream::attach(FCGX_Stream *str)
341    {
342    // initialize as a writer, use all buffering for the
343    // put area
344    fcgi_strmbuf.stream_initialize(str,1);
345    // init is a protected member of ios
346    init(&fcgi_strmbuf);
347    }
348
349
350 // helper function to find out if this
351 // stream was ever initialized.
352 int fcgi_ostream::isdefined(void)
353    {
354    return (fcgi_strmbuf.isstrmdefined());
355    }
356