move PRINTF into correct package
[catagits/fcgi2.git] / perl / FCGI.PL
1 use Config;
2
3 open OUT, ">FCGI.xs";
4
5 print "Generating FCGI.xs for Perl version $]\n";
6 #unless (exists $Config{apiversion} && $Config{apiversion} >= 5.005) 
7 unless ($] >= 5.005) {
8     for (qw(sv_undef diehook warnhook in_eval)) {
9         print OUT "#define PL_$_ $_\n" 
10     }
11 }
12 print OUT while <DATA>;
13 close OUT;
14 __END__
15 /* $Id: FCGI.PL,v 1.9 1999/07/31 21:54:46 skimo Exp $ */
16
17 #include "EXTERN.h"
18 #include "perl.h"
19 #include "XSUB.h"
20
21 #include "fcgiapp.h"
22
23 #ifndef FALSE
24 #define FALSE (0)
25 #endif
26
27 #ifndef TRUE
28 #define TRUE  (1)
29 #endif
30
31 #ifdef USE_SFIO
32 typedef struct
33 {
34     Sfdisc_t    disc;
35     FCGX_Stream *stream;
36 } FCGI_Disc;
37
38 static ssize_t
39 sffcgiread(f, buf, n, disc)
40 Sfio_t*         f;      /* stream involved */
41 Void_t*         buf;    /* buffer to read into */
42 size_t          n;      /* number of bytes to read */
43 Sfdisc_t*       disc;   /* discipline */
44 {
45     return FCGX_GetStr(buf, n, ((FCGI_Disc *)disc)->stream);
46 }
47
48 static ssize_t
49 sffcgiwrite(f, buf, n, disc)
50 Sfio_t*         f;      /* stream involved */
51 const Void_t*   buf;    /* buffer to read into */
52 size_t          n;      /* number of bytes to read */
53 Sfdisc_t*       disc;   /* discipline */
54 {
55     n = FCGX_PutStr(buf, n, ((FCGI_Disc *)disc)->stream);
56     FCGX_FFlush(((FCGI_Disc *)disc)->stream);
57     return n;
58 }
59
60 Sfdisc_t *
61 sfdcnewfcgi(stream)
62         FCGX_Stream *stream;
63 {
64     FCGI_Disc*  disc;
65
66     New(1000,disc,1,FCGI_Disc);
67     if (!disc) return (Sfdisc_t *)disc;
68
69     disc->disc.exceptf = (Sfexcept_f)NULL;
70     disc->disc.seekf = (Sfseek_f)NULL;
71     disc->disc.readf = sffcgiread;
72     disc->disc.writef = sffcgiwrite;
73     disc->stream = stream;
74     return (Sfdisc_t *)disc;
75 }
76
77 Sfdisc_t *
78 sfdcdelfcgi(disc)
79     Sfdisc_t*   disc;
80 {
81     Safefree(disc);
82     return 0;
83 }
84 #endif
85
86 static int isCGI = -1; /* -1: not checked; 0: FCGI; 1: FCGI */
87
88 typedef struct FCGP_Request {
89     int             acceptCalled;
90     int             finishCalled;
91     SV*             svin;
92     SV*             svout;
93     SV*             sverr;
94     GV*             gv[3];
95     GV*             gvNew[3];
96     HV*             hvEnv;
97     FCGX_Stream*    in;
98     FCGX_Request*   requestPtr;
99 #ifdef USE_SFIO
100     int             sfcreated[3];
101 #endif
102 } FCGP_Request;
103
104 static int 
105 FCGI_Flush(FCGP_Request* request)
106 {
107     if(!request->acceptCalled || isCGI) {
108         return;
109     }
110 #ifdef USE_SFIO
111     sfsync(IoOFP(GvIOp(request->gv[1])));
112     sfsync(IoOFP(GvIOp(request->gv[2])));
113 #else
114     FCGX_FFlush((FCGX_Stream *) SvIV((SV*) SvRV(request->svout)));
115     FCGX_FFlush((FCGX_Stream *) SvIV((SV*) SvRV(request->sverr)));
116 #endif
117 }
118
119 static void
120 FCGI_UndoBinding(FCGP_Request* request)
121 {
122 #ifdef USE_SFIO
123     IO *io[3];
124     int i;
125 #endif
126
127 #ifdef USE_SFIO
128     sfdcdelfcgi(sfdisc(IoIFP(io[0] = GvIOp(request->gv[0])), SF_POPDISC));
129     sfdcdelfcgi(sfdisc(IoOFP(io[1] = GvIOp(request->gv[1])), SF_POPDISC));
130     sfdcdelfcgi(sfdisc(IoOFP(io[2] = GvIOp(request->gv[2])), SF_POPDISC));
131     for (i = 0; i < 3; ++i) {
132         if (request->sfcreated[i]) {
133             sfclose(IoIFP(io[i]));
134             IoIFP(io[i]) = IoOFP(io[i]) = Nullfp;
135             request->sfcreated[i] = FALSE;
136         }
137     }
138 #else
139     FCGI_Flush(request);
140     sv_unmagic((SV *)request->gv[0], 'q');
141     sv_unmagic((SV *)request->gv[1], 'q');
142     sv_unmagic((SV *)request->gv[2], 'q');
143 #endif
144 }
145
146 static int 
147 FCGI_Accept(FCGP_Request* request)
148 {
149     if(isCGI == -1) {
150         /*
151          * First call to FCGI_Accept.  Is application running
152          * as FastCGI or as CGI?
153          */
154         isCGI = FCGX_IsCGI();
155     } else if(isCGI) {
156         /*
157          * Not first call to FCGI_Accept and running as CGI means
158          * application is done.
159          */
160         return(EOF);
161     } 
162     if(request->acceptCalled && !request->finishCalled) {
163         FCGI_UndoBinding(request);
164     }
165     if(!isCGI) {
166 #ifdef USE_SFIO
167         IO *io[3];
168         int i;
169 #endif
170         FCGX_Stream *out, *error;
171         FCGX_ParamArray envp;
172         int acceptResult = FCGX_Accept_r(&request->in, &out, &error, 
173                                          &envp, request->requestPtr);
174         if(acceptResult < 0) {
175             return acceptResult;
176         }
177
178         populate_env(envp, request->hvEnv);
179
180 #ifdef USE_SFIO
181         for (i = 0; i < 3; ++i) {
182             io[i] = GvIOn(request->gv[i] = request->gvNew[i]);
183             if (!(i == 0 ? IoIFP(io[i]) : IoOFP(io[i]))) {
184                 IoIFP(io[i]) = sftmp(0);
185                 /*IoIFP(io[i]) = sfnew(NULL, NULL, SF_UNBOUND, 0, 
186                                      SF_STRING | (i ? SF_WRITE : SF_READ));*/
187                 if (i != 0) IoOFP(io[i]) = IoIFP(io[i]);
188                 request->sfcreated[i] = TRUE;
189             }
190         }
191         sfdisc(IoIFP(io[0]), sfdcnewfcgi(request->in));
192         sfdisc(IoOFP(io[1]), sfdcnewfcgi(out));
193         sfdisc(IoOFP(io[2]), sfdcnewfcgi(error));
194 #else
195         if (!request->svout) {
196             newSVrv(request->svout = newSV(0), "FCGI::Stream");
197             newSVrv(request->sverr = newSV(0), "FCGI::Stream");
198             newSVrv(request->svin = newSV(0), "FCGI::Stream");
199         }
200         sv_magic((SV *)request->gv[1] = request->gvNew[1], 
201                 request->svout, 'q', Nullch, 0);
202         sv_magic((SV *)request->gv[2] = request->gvNew[2], 
203                 request->sverr, 'q', Nullch, 0);
204         sv_magic((SV *)request->gv[0] = request->gvNew[0], 
205                 request->svin, 'q', Nullch, 0);
206         sv_setiv(SvRV(request->svout), (IV) out);
207         sv_setiv(SvRV(request->sverr), (IV) error);
208         sv_setiv(SvRV(request->svin), (IV) request->in);
209 #endif
210         request->finishCalled = FALSE;
211     }
212     request->acceptCalled = TRUE;
213     return 0;
214 }
215
216 static void 
217 FCGI_Finish(FCGP_Request* request)
218 {
219     if(!request->acceptCalled || isCGI) {
220         return;
221     }
222     FCGI_UndoBinding(request);
223     request->in = NULL;
224     FCGX_Finish_r(request->requestPtr);
225     request->finishCalled = TRUE;
226 }
227
228 static int 
229 FCGI_StartFilterData(FCGP_Request* request)
230 {
231     return request->in ? FCGX_StartFilterData(request->in) : -1;
232 }
233
234 static void
235 FCGI_SetExitStatus(FCGP_Request* request, int status)
236 {
237     if (request->in) FCGX_SetExitStatus(status, request->in);
238 }
239
240 static FCGP_Request *
241 FCGI_Request()
242 {
243     FCGX_Request* fcgx_req;
244     FCGP_Request* req;
245
246     Newz(551, fcgx_req, 1, FCGX_Request);
247     Newz(551, req, 1, FCGP_Request);
248     req->requestPtr = fcgx_req;
249
250     return req;
251 }
252
253 static void
254 FCGI_Release_Request(FCGP_Request *req)
255 {
256     Safefree(req->requestPtr);
257     Safefree(req);
258 }
259
260 static void
261 populate_env(envp, hv)
262 char **envp;
263 HV *hv;
264 {
265     int i;
266     char *p, *p1;
267     SV   *sv;
268
269     for(i = 0; ; i++) {
270         if((p = envp[i]) == NULL) {
271             break;
272         }
273         p1 = strchr(p, '=');
274         assert(p1 != NULL);
275         sv = newSVpv(p1 + 1, 0);
276         /* call magic for this value ourselves */
277         hv_store(hv, p, p1 - p, sv, 0);
278         SvSETMAGIC(sv);
279     }
280 }
281
282 typedef FCGX_Stream *   FCGI__Stream;
283 typedef FCGP_Request *  FCGI;
284 typedef GV*             GLOBREF;
285 typedef HV*             HASHREF;
286
287 MODULE = FCGI           PACKAGE = FCGI
288
289
290 SV *
291 Request()
292
293     PROTOTYPE:
294     CODE:
295     RETVAL = Perl_sv_setref_pv(Perl_newSV(0), "FCGI", FCGI_Request());
296
297     OUTPUT:
298     RETVAL
299
300
301 int
302 Accept(request, in, out, err, env)
303
304     FCGI    request;
305     GLOBREF in;
306     GLOBREF out;
307     GLOBREF err;
308     HASHREF env;
309
310     PROTOTYPE: $***$
311
312     CODE:
313     request->gvNew[0] = in;
314     request->gvNew[1] = out;
315     request->gvNew[2] = err;
316     request->hvEnv = env;
317
318     RETVAL = FCGI_Accept(request);
319
320     OUTPUT:
321     RETVAL
322
323
324 void
325 Finish(request)
326
327     FCGI    request;
328
329     PROTOTYPE: $
330
331     CODE:
332     {
333         /*
334          * Finish the request.
335          */
336         FCGI_Finish(request);
337     }
338
339
340 void
341 Flush(request)
342
343     FCGI    request;
344
345     PROTOTYPE: $
346
347     CODE:
348     FCGI_Flush(request);
349
350
351 int
352 StartFilterData(request)
353
354     FCGI    request;
355
356     PROTOTYPE: $
357
358     CODE:
359     RETVAL = FCGI_StartFilterData(request);
360
361     OUTPUT:
362     RETVAL
363
364 void
365 DESTROY(request)
366     FCGI    request;
367
368     CODE:
369     FCGI_Release_Request(request);
370
371
372
373 MODULE = FCGI           PACKAGE = FCGI::Stream
374
375 #ifndef USE_SFIO
376
377 void
378 PRINT(stream, ...)
379         FCGI::Stream    stream;
380
381         PREINIT:
382         int     n;
383
384         CODE:
385         for (n = 1; n < items; ++n) {
386             STRLEN len;
387             register char *tmps = (char *)SvPV(ST(n),len);
388             FCGX_PutStr(tmps, len, stream);
389         }
390         if (SvTRUEx(perl_get_sv("|", FALSE))) 
391             FCGX_FFlush(stream);
392
393 int
394 WRITE(stream, bufsv, len, ...)
395         FCGI::Stream    stream;
396         SV *    bufsv;
397         int     len;
398
399         PREINIT:
400         int     offset;
401         char *  buf;
402         STRLEN  blen;
403         int     n;
404
405         CODE:
406         offset = (items == 4) ? (int)SvIV(ST(3)) : 0;
407         buf = SvPV(bufsv, blen);
408         if (offset < 0) offset += blen;
409         if (len > blen - offset)
410             len = blen - offset;
411         if (offset < 0 || offset >= blen ||
412                 (n = FCGX_PutStr(buf+offset, len, stream)) < 0) 
413             ST(0) = &PL_sv_undef;
414         else {
415             ST(0) = sv_newmortal();
416             sv_setpvf(ST(0), "%c", n);
417         }
418
419 int
420 READ(stream, bufsv, len, ...)
421         FCGI::Stream    stream;
422         SV *    bufsv;
423         int     len;
424
425         PREINIT:
426         int     offset;
427         char *  buf;
428
429         CODE:
430         offset = (items == 4) ? (int)SvIV(ST(3)) : 0;
431         if (! SvOK(bufsv))
432             sv_setpvn(bufsv, "", 0);
433         buf = SvGROW(bufsv, len+offset+1);
434         len = FCGX_GetStr(buf+offset, len, stream);
435         SvCUR_set(bufsv, len+offset);
436         *SvEND(bufsv) = '\0';
437         (void)SvPOK_only(bufsv);
438         SvSETMAGIC(bufsv);
439         RETVAL = len;
440
441         OUTPUT:
442         RETVAL
443
444 SV *
445 GETC(stream)
446         FCGI::Stream    stream;
447
448         PREINIT:
449         int     retval;
450
451         CODE:
452         if ((retval = FCGX_GetChar(stream)) != -1) {
453             ST(0) = sv_newmortal();
454             sv_setpvf(ST(0), "%c", retval);
455         } else ST(0) = &PL_sv_undef;
456
457 bool
458 CLOSE(stream)
459         FCGI::Stream    stream;
460
461         ALIAS:
462         DESTROY = 1
463
464         CODE:
465         RETVAL = FCGX_FClose(stream) != -1;
466
467         OUTPUT:
468         RETVAL
469
470 #endif