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