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