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