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