Flush FastCGI buffers at application exit. <eichin@fastengines.com>
[catagits/fcgi2.git] / libfcgi / fcgi_stdio.c
1 /* 
2  * fcgi_stdio.c --
3  *
4  *      FastCGI-stdio compatibility package
5  *
6  *
7  * Copyright (c) 1996 Open Market, Inc.
8  *
9  * See the file "LICENSE.TERMS" for information on usage and redistribution
10  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
11  *
12  */
13
14 #ifndef lint
15 static const char rcsid[] = "$Id: fcgi_stdio.c,v 1.5 1999/06/07 05:03:48 roberts Exp $";
16 #endif /* not lint */
17
18 #ifdef _WIN32
19 #define DLLAPI  __declspec(dllexport)
20 #endif
21
22 #define NO_FCGI_DEFINES
23 #include "fcgi_stdio.h"
24 #undef NO_FCGI_DEFINES
25
26 #ifdef _WIN32
27 #include <windows.h>
28 #endif
29 #include <errno.h>
30     /* for errno */
31 #include <stdarg.h>
32     /* for va_arg */
33 #include <stdlib.h>
34     /* for malloc */
35 #include <string.h>
36     /* for strerror */
37 #ifdef HAVE_UNISTD_H
38 #include <unistd.h>
39 #endif
40
41 #include "fcgiapp.h"
42 #include "fcgios.h"
43
44 #ifndef FALSE
45 #define FALSE (0)
46 #endif
47 #ifndef TRUE
48 #define TRUE  (1)
49 #endif
50
51 #ifdef _WIN32
52 FCGI_FILE _fcgi_sF[3];
53 #else
54 FCGI_FILE _fcgi_sF[3] = {{stdin, NULL}, {stdout, NULL}, {stderr, NULL}};
55 #endif
56
57 #ifdef _WIN32
58 #define popen _popen
59 #endif
60 \f
61 /*
62  *----------------------------------------------------------------------
63  *
64  * FCGI_Accept --
65  *
66  *      Accepts a new request from the HTTP server and creates
67  *      a conventional execution environment for the request.
68  *
69  *      If the application was invoked as a FastCGI server,
70  *      the first call to FCGI_Accept indicates that the application
71  *      has completed its initialization and is ready to accept
72  *      a request.  Subsequent calls to FCGI_Accept indicate that
73  *      the application has completed its processing of the
74  *      current request and is ready to accept a new request.
75  *
76  *      If the application was invoked as a CGI program, the first
77  *      call to FCGI_Accept is essentially a no-op and the second
78  *      call returns EOF (-1).
79  *
80  * Results:
81  *    0 for successful call, -1 for error (application should exit).
82  *
83  * Side effects:
84  *      If the application was invoked as a FastCGI server,
85  *      and this is not the first call to this procedure,
86  *      FCGI_Accept first performs the equivalent of FCGI_Finish.
87  *
88  *      On every call, FCGI_Accept accepts the new request and
89  *      reads the FCGI_PARAMS stream into an environment array,
90  *      i.e. a NULL-terminated array of strings of the form
91  *      ``name=value''.  It assigns a pointer to this array
92  *      to the global variable environ, used by the standard
93  *      library function getenv.  It creates new FCGI_FILE *s
94  *      representing input from the HTTP server, output to the HTTP
95  *      server, and error output to the HTTP server, and assigns these
96  *      new files to stdin, stdout, and stderr respectively.
97  *
98  *      DO NOT mutate or retain pointers to environ or any values
99  *      contained in it (e.g. to the result of calling getenv(3)),
100  *      since these are freed by the next call to FCGI_Finish or
101  *      FCGI_Accept.  In particular do not use setenv(3) or putenv(3)
102  *      in conjunction with FCGI_Accept.
103  *
104  *----------------------------------------------------------------------
105  */
106 static int acceptCalled = FALSE;
107 static int isCGI = FALSE;
108 #ifndef _WIN32
109 extern char **environ;
110 #endif
111
112 int FCGI_Accept(void)
113 {
114     if(!acceptCalled) {
115         /*
116          * First call to FCGI_Accept.  Is application running
117          * as FastCGI or as CGI?
118          */
119         isCGI = FCGX_IsCGI();
120         acceptCalled = TRUE;
121         atexit(&FCGI_Finish);
122     } else if(isCGI) {
123         /*
124          * Not first call to FCGI_Accept and running as CGI means
125          * application is done.
126          */
127         return(EOF);
128     }
129     if(isCGI) {
130         FCGI_stdin->stdio_stream = stdin;
131         FCGI_stdin->fcgx_stream = NULL;
132         FCGI_stdout->stdio_stream = stdout;
133         FCGI_stdout->fcgx_stream = NULL;
134         FCGI_stderr->stdio_stream = stderr;
135         FCGI_stderr->fcgx_stream = NULL;
136     } else {
137         FCGX_Stream *in, *out, *error;
138         FCGX_ParamArray envp;
139         int acceptResult = FCGX_Accept(&in, &out, &error, &envp);
140         if(acceptResult < 0) {
141             return acceptResult;
142         }
143         FCGI_stdin->stdio_stream = NULL;
144         FCGI_stdin->fcgx_stream = in;
145         FCGI_stdout->stdio_stream = NULL;
146         FCGI_stdout->fcgx_stream = out;
147         FCGI_stderr->stdio_stream = NULL;
148         FCGI_stderr->fcgx_stream = error;
149         environ = envp;
150     }
151     return 0;
152 }
153 \f
154 /*
155  *----------------------------------------------------------------------
156  *
157  * FCGI_Finish --
158  *
159  *      Finishes the current request from the HTTP server.
160  *
161  * Side effects:
162  *
163  *      Flushes any buffered output to the HTTP server.  Then frees
164  *      all storage allocated by the previous call, including all
165  *      storage reachable from the value of environ set by the previous
166  *      call to FCGI_Accept.
167  *
168  *      DO NOT use stdin, stdout, stderr, or environ between calling
169  *      FCGI_Finish and calling FCGI_Accept.
170  *
171  *      DO NOT mutate or retain pointers to environ or any values
172  *      contained in it (e.g. to the result of calling getenv(3)),
173  *      since these are freed by the next call to FCGI_Finish or
174  *      FCGI_Accept.  In particular do not use setenv(3) or putenv(3)
175  *      in conjunction with FCGI_Accept.
176  *
177  *----------------------------------------------------------------------
178  */
179 void FCGI_Finish(void)
180 {
181     if(!acceptCalled || isCGI) {
182         return;
183     }
184     FCGX_Finish();
185     FCGI_stdin->fcgx_stream = NULL;
186     FCGI_stdout->fcgx_stream = NULL;
187     FCGI_stderr->fcgx_stream = NULL;
188     environ = NULL;
189 }
190 \f
191 /*
192  *----------------------------------------------------------------------
193  *
194  * FCGI_StartFilterData --
195  *
196  *      
197  *      The current request is for the filter role, and stdin is
198  *      positioned at EOF of FCGI_STDIN.  The call repositions 
199  *      stdin to the start of FCGI_DATA.
200  *      If the preconditions are not met (e.g. FCGI_STDIN has not
201  *      been read to EOF), the call sets the stream error code to
202  *      FCGX_CALL_SEQ_ERROR.
203  *
204  * Results:
205  *      0 for a normal return, < 0 for error 
206  *
207  *----------------------------------------------------------------------
208  */
209
210 int FCGI_StartFilterData(void)
211 {
212     if(FCGI_stdin->stdio_stream) {
213         return -1;
214     } else {
215         return FCGX_StartFilterData(FCGI_stdin->fcgx_stream);
216     }
217 }
218 \f
219 /*
220  *----------------------------------------------------------------------
221  *
222  * FCGI_SetExitStatus --
223  *
224  *      Sets the exit status for the current request. The exit status
225  *      is the status code the request would have exited with, had
226  *      the request been run as a CGI program.  You can call
227  *      FCGI_SetExitStatus several times during a request; the last call
228  *      before the request ends (by calling FCGI_Accept) determines the
229  *      value.
230  *
231  *----------------------------------------------------------------------
232  */
233
234 void FCGI_SetExitStatus(int status)
235 {
236     if(FCGI_stdin->fcgx_stream) {
237         FCGX_SetExitStatus(status, FCGI_stdin->fcgx_stream);
238     }
239 }
240 \f
241 /*
242  *----------------------------------------------------------------------
243  *
244  * FCGI_perror --
245  *
246  *       Wrapper for function defined in H&S Section 11.2
247  *
248  *----------------------------------------------------------------------
249  */
250
251 void FCGI_perror(const char *str)
252 {
253     FCGI_fputs(str, FCGI_stderr);
254     FCGI_fputs(": ", FCGI_stderr);
255     FCGI_fputs(strerror(OS_Errno), FCGI_stderr);
256     return;
257 }
258 \f
259 /*
260  *----------------------------------------------------------------------
261  *
262  * FCGI_OpenFromFILE --
263  *
264  *      Constructs a new FCGI_FILE * from the FILE *stream.
265  *
266  * Results:
267  *      NULL if stream == NULL or storage could not be allocated,
268  *      otherwise the new FCGI_FILE *.
269  *
270  *----------------------------------------------------------------------
271  */ 
272
273 static FCGI_FILE *FCGI_OpenFromFILE(FILE *stream)
274 {
275     FCGI_FILE *fp;
276     if(stream == NULL)
277         return NULL;
278     fp = malloc(sizeof(FCGI_FILE));
279     if(fp == NULL)
280         return NULL;
281     fp->stdio_stream = stream;
282     fp->fcgx_stream = NULL;
283     return fp;
284 }
285 \f
286 /*
287  *----------------------------------------------------------------------
288  *
289  * FCGI_fopen, FCGI_fclose, FCGI_fflush, FCGI_freopen --
290  *
291  *       Wrappers for functions defined in H&S Section 15.2
292  *
293  *----------------------------------------------------------------------
294  */
295
296 FCGI_FILE *FCGI_fopen(const char *path, const char *mode)
297 {
298     return FCGI_OpenFromFILE(fopen(path, mode));
299 }
300
301 int FCGI_fclose(FCGI_FILE *fp)
302 {
303     int n = EOF;
304     if(fp->stdio_stream) {
305         n = fclose(fp->stdio_stream);
306         fp->stdio_stream = NULL;
307     } else if(fp->fcgx_stream) {
308         n = FCGX_FClose(fp->fcgx_stream);
309         fp->fcgx_stream = NULL;
310     }
311     if((fp != FCGI_stdin) && (fp != FCGI_stdout) && (fp != FCGI_stderr)) {
312         free(fp);
313     }
314     return n;
315 }
316
317 int FCGI_fflush(FCGI_FILE *fp)
318 {
319     if(fp == NULL)
320         return fflush(NULL);
321     if(fp->stdio_stream)
322         return fflush(fp->stdio_stream);
323     else if(fp->fcgx_stream)
324         return FCGX_FFlush(fp->fcgx_stream);
325     return EOF;
326 }
327
328 FCGI_FILE *FCGI_freopen(const char *path, const char *mode,
329                         FCGI_FILE *fp)
330 {
331     if(fp->stdio_stream) {
332         if(freopen(path, mode, fp->stdio_stream) == NULL)
333             return NULL;
334         else
335             return fp;
336     } else if(fp->fcgx_stream) {
337         (void) FCGX_FClose(fp->fcgx_stream);
338         fp->stdio_stream = fopen(path, mode);
339         if(fp->stdio_stream == NULL)
340             return NULL;
341         else {
342             fp->fcgx_stream = NULL;
343             return fp;
344         }
345     }
346     return NULL;
347 }
348 \f
349 /*
350  *----------------------------------------------------------------------
351  *
352  * FCGI_setvbuf, FCGI_setbuf --
353  *
354  *       Wrappers for functions defined in H&S Section 15.3
355  *
356  *----------------------------------------------------------------------
357  */
358 int FCGI_setvbuf(FCGI_FILE *fp, char *buf, int bufmode, size_t size)
359 {
360     if(fp->stdio_stream)
361         return setvbuf(fp->stdio_stream, buf, bufmode, size);
362     else {
363         return -1;
364     }
365 }
366
367 void FCGI_setbuf(FCGI_FILE *fp, char *buf)
368 {
369     if(fp->stdio_stream)
370         setbuf(fp->stdio_stream, buf);
371 }
372 \f
373 /*
374  *----------------------------------------------------------------------
375  *
376  * FCGI_fseek, FCGI_ftell, FCGI_rewind, FCGI_fgetpos, FCGI_fsetpos --
377  *
378  *       Wrappers for functions defined in H&S Section 15.5
379  *
380  *----------------------------------------------------------------------
381  */
382
383 int FCGI_fseek(FCGI_FILE *fp, long offset, int whence)
384 {
385     if(fp->stdio_stream)
386         return fseek(fp->stdio_stream, offset, whence);
387     else {
388         OS_SetErrno(ESPIPE);
389         return -1;
390     }
391 }
392
393 int FCGI_ftell(FCGI_FILE *fp)
394 {
395     if(fp->stdio_stream)
396         return ftell(fp->stdio_stream);
397     else {
398         OS_SetErrno(ESPIPE);
399         return -1;
400     } 
401 }
402
403 void FCGI_rewind(FCGI_FILE *fp)
404 {
405     if(fp->stdio_stream)
406         rewind(fp->stdio_stream);
407     else
408         OS_SetErrno(ESPIPE);
409 }
410
411 #ifdef HAVE_FPOS
412 int FCGI_fgetpos(FCGI_FILE *fp, fpos_t *pos)
413 {
414     if(fp->stdio_stream)
415         return fgetpos(fp->stdio_stream, pos);
416     else {
417         OS_SetErrno(ESPIPE);
418         return -1;
419     } 
420 }
421
422 int FCGI_fsetpos(FCGI_FILE *fp, const fpos_t *pos)
423 {
424     if(fp->stdio_stream)
425         return fsetpos(fp->stdio_stream, pos);
426     else {
427         OS_SetErrno(ESPIPE);
428         return -1;
429     } 
430 }
431 #endif
432 \f
433 /*
434  *----------------------------------------------------------------------
435  *
436  * FCGI_fgetc, FCGI_getchar, FCGI_ungetc --
437  *
438  *       Wrappers for functions defined in H&S Section 15.6
439  *
440  *       XXX: getc and getchar are generally defined as macros
441  *            for performance reasons
442  *
443  *----------------------------------------------------------------------
444  */
445
446 int FCGI_fgetc(FCGI_FILE *fp)
447 {
448     if(fp->stdio_stream)
449         return fgetc(fp->stdio_stream);
450     else if(fp->fcgx_stream)
451         return FCGX_GetChar(fp->fcgx_stream);
452     return EOF;
453 }
454
455 int FCGI_getchar(void)
456 {
457     return FCGI_fgetc(FCGI_stdin);
458 }
459
460 int FCGI_ungetc(int c, FCGI_FILE *fp)
461 {
462     if(fp->stdio_stream)
463         return ungetc(c, fp->stdio_stream);
464     else if(fp->fcgx_stream)
465         return FCGX_UnGetChar(c, fp->fcgx_stream);
466     return EOF;
467 }
468 \f
469 /*
470  *----------------------------------------------------------------------
471  *
472  * FCGI_fgets, FCGI_gets --
473  *
474  *       Wrappers for functions defined in H&S Section 15.7
475  *
476  *----------------------------------------------------------------------
477  */
478
479 char *FCGI_fgets(char *str, int size, FCGI_FILE *fp)
480 {
481     if(fp->stdio_stream)
482         return fgets(str, size, fp->stdio_stream);
483     else if(fp->fcgx_stream)
484         return FCGX_GetLine(str, size, fp->fcgx_stream);
485     return NULL;
486 }
487
488 /*
489  * There is no standard equivalent of gets that takes an explicit
490  * FILE * argument, so the following "wrapper" implements
491  * gets for both FILE * and FCGX_Stream * in terms of FCGI_getchar.
492  */
493
494 char *FCGI_gets(char *str)
495 {
496     char *s;
497     int c;
498     for (s = str; ((c = FCGI_getchar()) != '\n');) {
499         if(c == EOF) {
500             if(s == str) 
501                 return NULL;
502             else
503                 break;
504         } else
505             *s++ = c;
506     }
507     *s = 0;
508     return str;
509 }
510 \f
511 /*
512  *----------------------------------------------------------------------
513  *
514  * --
515  *
516  *       Wrappers for functions defined in H&S Section 15.8
517  *
518  *       XXX: missing: fscanf, scanf
519  *
520  *----------------------------------------------------------------------
521  */
522
523 \f
524 /*
525  *----------------------------------------------------------------------
526  *
527  * FCGI_fputc, FCGI_putchar --
528  *
529  *       Wrappers for functions defined in H&S Section 15.9
530  *
531  *       XXX: putc and putchar are generally defined as macros
532  *            for performance reasons
533  *
534  *----------------------------------------------------------------------
535  */
536
537 int FCGI_fputc(int c, FCGI_FILE *fp)
538 {
539     if(fp->stdio_stream) 
540         return fputc(c, fp->stdio_stream);
541     else if(fp->fcgx_stream)
542         return FCGX_PutChar(c, fp->fcgx_stream);
543     else return EOF;
544 }
545
546 int FCGI_putchar(int c)
547 {
548     return FCGI_fputc(c, FCGI_stdout);
549 }
550 \f
551 /*
552  *----------------------------------------------------------------------
553  *
554  * FCGI_fputs, FCGI_puts
555  *
556  *       Wrappers for functions defined in H&S Section 15.10
557  *
558  *----------------------------------------------------------------------
559  */
560
561 int FCGI_fputs(const char *str, FCGI_FILE *fp)
562 {
563     if(fp->stdio_stream)
564         return fputs(str, fp->stdio_stream);
565     else if(fp->fcgx_stream)
566         return FCGX_PutS(str, fp->fcgx_stream);
567     return EOF;
568 }
569
570 int FCGI_puts(const char *str)
571 {
572     int n;
573     if(FCGI_stdout->stdio_stream) {
574         n = fputs(str, FCGI_stdout->stdio_stream);
575         if(n < 0)
576             return n;
577         else
578             return fputc('\n', FCGI_stdout->stdio_stream);
579     } else if(FCGI_stdout->fcgx_stream) {
580         n = FCGX_PutS(str, FCGI_stdout->fcgx_stream);
581         if(n < 0)
582             return n;
583         else
584             return FCGX_PutChar('\n', FCGI_stdout->fcgx_stream);
585     }
586     return EOF;
587 }
588 \f
589 /*
590  *----------------------------------------------------------------------
591  *
592  * FCGI_fprintf, FCGI_printf --
593  *
594  *       Wrappers for functions defined in H&S Section 15.11
595  *
596  *----------------------------------------------------------------------
597  */
598
599 int FCGI_fprintf(FCGI_FILE *fp, const char *format, ...)
600 {
601     va_list ap;
602     int n = 0;
603     va_start(ap, format);
604     if(fp->stdio_stream)
605         n = vfprintf(fp->stdio_stream, format, ap);
606     else if(fp->fcgx_stream)
607         n = FCGX_VFPrintF(fp->fcgx_stream, format, ap);
608     va_end(ap);
609     return n;
610 }
611
612 int FCGI_printf(const char *format, ...)
613 {
614     va_list ap;
615     int n;
616     va_start(ap, format);
617     n = FCGI_vfprintf(FCGI_stdout, format, ap);
618     va_end(ap);
619     return n;
620 }
621 \f
622 /*
623  *----------------------------------------------------------------------
624  *
625  * FCGI_vfprintf, FCGI_vprintf --
626  *
627  *       Wrappers for functions defined in H&S Section 15.12
628  *
629  *----------------------------------------------------------------------
630  */
631
632 int FCGI_vfprintf(FCGI_FILE *fp, const char *format, va_list ap)
633 {
634     if(fp->stdio_stream)
635         return vfprintf(fp->stdio_stream, format, ap);
636     else if(fp->fcgx_stream) 
637         return FCGX_VFPrintF(fp->fcgx_stream, format, ap);
638     return EOF;
639 }
640
641 int FCGI_vprintf(const char *format, va_list ap)
642 {
643     if(FCGI_stdout->stdio_stream)
644         return vfprintf(FCGI_stdout->stdio_stream, format, ap);
645     else if(FCGI_stdout->fcgx_stream) 
646         return FCGX_VFPrintF(FCGI_stdout->fcgx_stream, format, ap);
647     return EOF;
648 }
649 \f
650 /*
651  *----------------------------------------------------------------------
652  *
653  * FCGI_fread, FCGI_fwrite --
654  *
655  *       Wrappers for functions defined in H&S Section 15.13
656  *
657  *----------------------------------------------------------------------
658  */
659
660 size_t FCGI_fread(void *ptr, size_t size, size_t nmemb, FCGI_FILE *fp)
661 {
662     int n;
663     if(fp->stdio_stream)
664         return fread(ptr, size, nmemb, fp->stdio_stream);
665     else if(fp->fcgx_stream) {
666         if((size * nmemb) == 0) {
667             return 0;
668         }
669         n = FCGX_GetStr((char *) ptr, size * nmemb, fp->fcgx_stream);
670         return (n/size);
671     }
672     return (size_t)EOF;
673 }
674
675 size_t FCGI_fwrite(void *ptr, size_t size, size_t nmemb, FCGI_FILE *fp)
676 {
677     int n;
678     if(fp->stdio_stream)
679         return fwrite(ptr, size, nmemb, fp->stdio_stream);
680     else if(fp->fcgx_stream) {
681         if((size * nmemb) == 0) {
682             return 0;
683         }
684         n = FCGX_PutStr((char *) ptr, size * nmemb, fp->fcgx_stream);
685         return (n/size);
686     }
687     return (size_t)EOF;
688 }
689 \f
690 /*
691  *----------------------------------------------------------------------
692  *
693  * FCGI_feof, FCGI_ferror, FCGI_clearerr --
694  *
695  *       Wrappers for functions defined in H&S Section 15.14
696  *
697  *----------------------------------------------------------------------
698  */
699 int FCGI_feof(FCGI_FILE *fp)
700 {
701     if(fp->stdio_stream) {
702         return feof(fp->stdio_stream);
703     } else if (fp->fcgx_stream){
704         return FCGX_HasSeenEOF(fp->fcgx_stream);
705     }
706     return -1;
707
708 }
709
710 int FCGI_ferror(FCGI_FILE *fp)
711 {
712     if(fp->stdio_stream) {
713         return ferror(fp->stdio_stream);
714     } else if(fp->fcgx_stream) {
715         return FCGX_GetError(fp->fcgx_stream);
716     }
717     return -1;
718 }
719
720 void FCGI_clearerr(FCGI_FILE *fp)
721 {
722     if(fp->stdio_stream) {
723         clearerr(fp->stdio_stream);
724     } else if(fp->fcgx_stream) {
725         FCGX_ClearError(fp->fcgx_stream);
726     }
727     return;
728 }
729 \f
730 /*
731  *----------------------------------------------------------------------
732  *
733  * FCGI_tmpfile --
734  *
735  *       Wrappers for function defined in H&S Section 15.16
736  *
737  *----------------------------------------------------------------------
738  */
739 FCGI_FILE *FCGI_tmpfile(void)
740 {
741         return FCGI_OpenFromFILE(tmpfile());
742 }
743
744 \f
745 /*
746  *----------------------------------------------------------------------
747  *
748  * FCGI_fileno, FCGI_fdopen, FCGI_popen, FCGI_pclose --
749  *
750  *       Wrappers for POSIX, X/OPEN functions not in ISO C
751  *
752  *----------------------------------------------------------------------
753  */
754
755 /*
756  * These definitions should be supplied by stdio.h but for some
757  * reason they get lost on certain platforms.
758  */
759 /*
760  * XXX: Need to find the right way to handle this for NT
761  */
762 #ifndef _WIN32
763 #ifndef fileno
764 extern int fileno(FILE *stream);
765 #endif
766 extern FILE *fdopen(int fildes, const char *type);
767 extern FILE *popen(const char *command, const char *type);
768 extern int pclose(FILE *stream);
769 #endif
770
771 int FCGI_fileno(FCGI_FILE *fp)
772 {
773     if(fp->stdio_stream)
774         return fileno(fp->stdio_stream);
775     else
776         return -1;
777 }
778
779 FCGI_FILE *FCGI_fdopen(int fd, const char *mode)
780 {
781 #ifndef _WIN32
782     return FCGI_OpenFromFILE(fdopen(fd, mode));
783 #else
784     return NULL;
785 #endif
786 }
787
788 FCGI_FILE *FCGI_popen(const char *cmd, const char *type)
789 {
790     return FCGI_OpenFromFILE(popen(cmd, type));
791 }
792
793 int FCGI_pclose(FCGI_FILE *fp)
794 {
795     int n = EOF;
796     if(fp->stdio_stream) {
797 #ifndef _WIN32
798         n = pclose(fp->stdio_stream);
799 #endif
800         fp->stdio_stream = NULL;
801     } else if(fp->fcgx_stream) {
802         /*
803          * The caller is deeply confused; don't free the storage.
804          */
805         return EOF;
806     }
807     if((fp != FCGI_stdin) && (fp != FCGI_stdout) && (fp != FCGI_stderr)) {
808         free(fp);
809     }
810     return n;
811 }
812
813 /*
814  *----------------------------------------------------------------------
815  */