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