initial commit
[fcgi] / libfcgi / fcgio.cpp
1 //
2 // $Id: fcgio.cpp,v 1.14 2003/06/22 00:51:27 robs Exp $
3 //
4 // Allows you communicate with FastCGI streams using C++ iostreams
5 //
6 // ORIGINAL AUTHOR:     George Feinberg
7 // REWRITTEN BY:        Michael Richards  06/20/1999
8 // REWRITTEN AGAIN BY:  Michael Shell     02/23/2000
9 // REWRITTEN AGAIN BY:  Rob Saccoccio     11 Nov 2001
10 //
11 // Copyright (c) 2000 Tux the Linux Penguin
12 //
13 // You are free to use this software without charge or royalty
14 // as long as this notice is not removed or altered, and recognition
15 // is given to the author(s)
16 //
17 // This code is offered as-is without any warranty either expressed or
18 // implied; without even the implied warranty of MERCHANTABILITY or
19 // FITNESS FOR A PARTICULAR PURPOSE.
20
21 #ifdef _WIN32
22 #define DLLAPI  __declspec(dllexport)
23 #endif
24
25 #include <limits.h>
26 #include "fcgio.h"
27
28 using std::streambuf;
29 using std::istream;
30 using std::ostream;
31 using std::streamsize;
32
33 fcgi_streambuf::fcgi_streambuf(FCGX_Stream * fs, char * b, int bs)
34 {
35     init(fs, b, bs);
36 }
37     
38 fcgi_streambuf::fcgi_streambuf(char_type * b, streamsize bs)
39 {
40     init(0, b, bs);
41 }
42     
43 fcgi_streambuf::fcgi_streambuf(FCGX_Stream * fs) 
44
45     init(fs, 0, 0);
46 }
47
48 fcgi_streambuf::~fcgi_streambuf(void)
49 {
50     overflow(EOF);
51     // FCGX_Finish()/FCGX_Accept() will flush and close
52 }
53
54 void fcgi_streambuf::init(FCGX_Stream * fs, char_type * b, streamsize bs)
55 {
56     this->fcgx = fs;
57     this->buf = 0;
58     this->bufsize = 0;
59     setbuf(b, bs);    
60 }
61
62 int fcgi_streambuf::overflow(int c)
63 {
64     if (this->bufsize)
65     {
66         int plen = pptr() - pbase();
67
68         if (plen) 
69         {
70             if (FCGX_PutStr(pbase(), plen, this->fcgx) != plen) return EOF;
71             pbump(-plen);
72         }
73     }
74
75     if (c != EOF) 
76     {
77         if (FCGX_PutChar(c, this->fcgx) != c) return EOF;
78     }
79
80     return 0;
81 }
82
83 // default base class behaviour seems to be inconsistent
84 int fcgi_streambuf::sync()
85 {
86     if (overflow(EOF)) return EOF;
87     if (FCGX_FFlush(this->fcgx)) return EOF;
88     return 0;
89 }
90
91 // uflow() removes the char, underflow() doesn't
92 int fcgi_streambuf::uflow() 
93 {
94     if (this->bufsize)
95     {
96         int c = underflow();        
97         gbump(1);
98         return c;
99     }
100     else
101     {
102         return FCGX_GetChar(this->fcgx);
103     }
104 }
105                                 
106 int fcgi_streambuf::underflow()
107 {
108     if (this->bufsize)
109     {
110         if (in_avail() == 0)
111         {
112             int glen = FCGX_GetStr(eback(), this->bufsize, this->fcgx);
113             if (glen <= 0) return EOF;
114
115             setg(eback(), eback(), eback() + glen);
116         }
117
118         return (unsigned char) *gptr();       
119     }
120     else
121     {
122         return FCGX_UnGetChar(FCGX_GetChar(this->fcgx), this->fcgx);
123     } 
124 }
125
126 void fcgi_streambuf::reset(void)
127 {
128     // it should be ok to set up both the get and put areas
129     setg(this->buf, this->buf, this->buf);
130     setp(this->buf, this->buf + this->bufsize);
131 }
132
133 std::streambuf * fcgi_streambuf::setbuf(char_type * b, streamsize bs)
134 {
135     // XXX support moving data from an old buffer
136     if (this->bufsize) return 0;
137
138     this->buf = b;
139     this->bufsize = bs;
140
141     // the base setbuf() *has* to be called
142     streambuf::setbuf(b, bs);
143
144     reset();
145
146     return this;
147 }
148
149 int fcgi_streambuf::attach(FCGX_Stream * fs)
150
151     this->fcgx = fs;
152
153     if (this->bufsize)
154     {
155         reset();
156     }
157
158     return 0;
159 }
160
161 streamsize fcgi_streambuf::xsgetn(char_type * s, streamsize n) 
162 {
163     if (n > INT_MAX) return 0;
164     return (this->bufsize) 
165         ? streambuf::xsgetn(s, n) 
166         : (streamsize) FCGX_GetStr((char *) s, (int) n, this->fcgx);
167 }
168    
169 streamsize fcgi_streambuf::xsputn(const char_type * s, streamsize n) 
170 {
171     if (n > INT_MAX) return 0;
172     return (this->bufsize) 
173         ? streambuf::xsputn(s, n) 
174         : (streamsize) FCGX_PutStr((char *) s, (int) n, this->fcgx);
175 }
176
177 // deprecated
178 fcgi_istream::fcgi_istream(FCGX_Stream * fs) :
179     istream(&fcgi_strmbuf)
180 {
181     fcgi_strmbuf.attach(fs);
182 }
183
184 // deprecated
185 void fcgi_istream::attach(FCGX_Stream * fs)
186 {
187     fcgi_strmbuf.attach(fs);
188 }
189
190 // deprecated
191 fcgi_ostream::fcgi_ostream(FCGX_Stream * fs) :
192     ostream(&fcgi_strmbuf)
193 {
194     fcgi_strmbuf.attach(fs);
195 }
196
197 // deprecated
198 void fcgi_ostream::attach(FCGX_Stream * fs)
199 {
200     fcgi_strmbuf.attach(fs);
201 }