Touch args to avoid compiler warnings.
[catagits/fcgi2.git] / libfcgi / fcgio.cpp
CommitLineData
c124bb9b 1//
494c52ac 2// $Id: fcgio.cpp,v 1.4 2001/06/20 16:08:51 robs Exp $
c124bb9b 3//
98e2ddaa 4// Allows you communicate with FastCGI streams using C++ iostream
5// objects
c124bb9b 6//
98e2ddaa 7// ORIGINAL AUTHOR: George Feinberg
8// REWRITTEN BY: Michael Richards 06/20/1999
9// REWRITTEN AGAIN BY: Michael Shell 02/23/2000
c124bb9b 10//
98e2ddaa 11// Special Thanks to Dietmar Kuehl for his help and the numerous custom
12// streambuf examples on his web site.
c124bb9b 13//
98e2ddaa 14// see the header file fcgio2.h for lotsa docs and a code example.
15//
16// Copyright (c) 2000 Tux the Linux Penguin
c124bb9b 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
98e2ddaa 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
e52a7487 29#include "fcgio.h"
98e2ddaa 30
31
32// **** fcgio_streambuf
33
34// default constructor
35fcgi_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
55fcgi_streambuf::~fcgi_streambuf(void) {}
56
57
58// do nothing
59int 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
69int 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
114int 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.
124int 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
153streambuf * fcgi_streambuf::setbuf(char *s, int n)
154 {
494c52ac 155 // Touch the args to avoid compiler warnings
156 s = NULL; n = 0;
98e2ddaa 157 return this;
158 }
159
160
161// just sets up the pointer and declares things defined.
162// used by fcgi_iostream attach()
163void 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
194int 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 }
c124bb9b 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
98e2ddaa 206// is nothing else to read, this returns EOF. This is the only method
207// which reads from the FCGI interface.
208int 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);
c124bb9b 218
98e2ddaa 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);
c124bb9b 224
98e2ddaa 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 }
c124bb9b 237
238
c124bb9b 239
98e2ddaa 240// here comes the higher level iostream stuff
c124bb9b 241
98e2ddaa 242// **** Istream
c124bb9b 243
98e2ddaa 244// parameterless constructor allows us to create first, then
245// initialize later via attach()
246fcgi_istream::fcgi_istream() {}
c124bb9b 247
248
98e2ddaa 249// or we can create and initialize in one step
c124bb9b 250// constructor calls ios::init to assign our streambuf to
98e2ddaa 251// the istream derived class. Also sets up buffering.
252fcgi_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
263fcgi_istream::~fcgi_istream() {}
c124bb9b 264
265
98e2ddaa 266// does everything the constructor with parameter does at the
267// request of the programmer
268void 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
286int 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
294int 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()
305fcgi_ostream::fcgi_ostream() {}
306
307
308// or we can create and initialize in one step
c124bb9b 309// constructor calls ios::init to assign our streambuf to
310// the ostream derived class. Also sets up buffering
98e2ddaa 311fcgi_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);
c124bb9b 316 // init is a protected member of ios
98e2ddaa 317 init(&fcgi_strmbuf);
318 }
319
320
321// destructor
322fcgi_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
337void 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
c124bb9b 346
98e2ddaa 347// helper function to find out if this
348// stream was ever initialized.
349int fcgi_ostream::isdefined(void)
350 {
351 return (fcgi_strmbuf.isstrmdefined());
352 }
c124bb9b 353