Add WIN32_LEAN_AND_MEAN to WIN defines
[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.10 2001/06/18 14:44:37 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 \f
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 \f
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 \f
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
220 int FCGI_StartFilterData(void)
221 {
222     if(FCGI_stdin->stdio_stream) {
223         return -1;
224     } else {
225         return FCGX_StartFilterData(FCGI_stdin->fcgx_stream);
226     }
227 }
228 \f
229 /*
230  *----------------------------------------------------------------------
231  *
232  * FCGI_SetExitStatus --
233  *
234  *      Sets the exit status for the current request. The exit status
235  *      is the status code the request would have exited with, had
236  *      the request been run as a CGI program.  You can call
237  *      FCGI_SetExitStatus several times during a request; the last call
238  *      before the request ends (by calling FCGI_Accept) determines the
239  *      value.
240  *
241  *----------------------------------------------------------------------
242  */
243
244 void FCGI_SetExitStatus(int status)
245 {
246     if(FCGI_stdin->fcgx_stream) {
247         FCGX_SetExitStatus(status, FCGI_stdin->fcgx_stream);
248     }
249 }
250 \f
251 /*
252  *----------------------------------------------------------------------
253  *
254  * FCGI_perror --
255  *
256  *       Wrapper for function defined in H&S Section 11.2
257  *
258  *----------------------------------------------------------------------
259  */
260
261 void FCGI_perror(const char *str)
262 {
263     FCGI_fputs(str, FCGI_stderr);
264     FCGI_fputs(": ", FCGI_stderr);
265     FCGI_fputs(strerror(OS_Errno), FCGI_stderr);
266     return;
267 }
268 \f
269 /*
270  *----------------------------------------------------------------------
271  *
272  * FCGI_OpenFromFILE --
273  *
274  *      Constructs a new FCGI_FILE * from the FILE *stream.
275  *
276  * Results:
277  *      NULL if stream == NULL or storage could not be allocated,
278  *      otherwise the new FCGI_FILE *.
279  *
280  *----------------------------------------------------------------------
281  */
282
283 static FCGI_FILE *FCGI_OpenFromFILE(FILE *stream)
284 {
285     FCGI_FILE *fp;
286
287     if (stream == NULL)
288         return NULL;
289
290     fp = (FCGI_FILE *) malloc(sizeof(FCGI_FILE));
291     if (fp != NULL)
292     {
293         fp->stdio_stream = stream;
294         fp->fcgx_stream = NULL;
295     }
296
297     return fp;
298 }
299 \f
300 /*
301  *----------------------------------------------------------------------
302  *
303  * FCGI_fopen, FCGI_fclose, FCGI_fflush, FCGI_freopen --
304  *
305  *       Wrappers for functions defined in H&S Section 15.2
306  *
307  *----------------------------------------------------------------------
308  */
309
310 FCGI_FILE *FCGI_fopen(const char *path, const char *mode)
311 {
312     FILE * file = fopen(path, mode);
313     FCGI_FILE * fcgi_file = FCGI_OpenFromFILE(file);
314
315     if (file && !fcgi_file)
316         fclose(file);
317
318     return fcgi_file;
319 }
320
321 int FCGI_fclose(FCGI_FILE *fp)
322 {
323     int n = EOF;
324     if(fp->stdio_stream) {
325         n = fclose(fp->stdio_stream);
326         fp->stdio_stream = NULL;
327     } else if(fp->fcgx_stream) {
328         n = FCGX_FClose(fp->fcgx_stream);
329         fp->fcgx_stream = NULL;
330     }
331     if((fp != FCGI_stdin) && (fp != FCGI_stdout) && (fp != FCGI_stderr)) {
332         free(fp);
333     }
334     return n;
335 }
336
337 int FCGI_fflush(FCGI_FILE *fp)
338 {
339     if(fp == NULL)
340         return fflush(NULL);
341     if(fp->stdio_stream)
342         return fflush(fp->stdio_stream);
343     else if(fp->fcgx_stream)
344         return FCGX_FFlush(fp->fcgx_stream);
345     return EOF;
346 }
347
348 FCGI_FILE *FCGI_freopen(const char *path, const char *mode,
349                         FCGI_FILE *fp)
350 {
351     if(fp->stdio_stream) {
352         if(freopen(path, mode, fp->stdio_stream) == NULL)
353             return NULL;
354         else
355             return fp;
356     } else if(fp->fcgx_stream) {
357         (void) FCGX_FClose(fp->fcgx_stream);
358         fp->stdio_stream = fopen(path, mode);
359         if(fp->stdio_stream == NULL)
360             return NULL;
361         else {
362             fp->fcgx_stream = NULL;
363             return fp;
364         }
365     }
366     return NULL;
367 }
368 \f
369 /*
370  *----------------------------------------------------------------------
371  *
372  * FCGI_setvbuf, FCGI_setbuf --
373  *
374  *       Wrappers for functions defined in H&S Section 15.3
375  *
376  *----------------------------------------------------------------------
377  */
378 int FCGI_setvbuf(FCGI_FILE *fp, char *buf, int bufmode, size_t size)
379 {
380     if(fp->stdio_stream)
381         return setvbuf(fp->stdio_stream, buf, bufmode, size);
382     else {
383         return -1;
384     }
385 }
386
387 void FCGI_setbuf(FCGI_FILE *fp, char *buf)
388 {
389     if(fp->stdio_stream)
390         setbuf(fp->stdio_stream, buf);
391 }
392 \f
393 /*
394  *----------------------------------------------------------------------
395  *
396  * FCGI_fseek, FCGI_ftell, FCGI_rewind, FCGI_fgetpos, FCGI_fsetpos --
397  *
398  *       Wrappers for functions defined in H&S Section 15.5
399  *
400  *----------------------------------------------------------------------
401  */
402
403 int FCGI_fseek(FCGI_FILE *fp, long offset, int whence)
404 {
405     if(fp->stdio_stream)
406         return fseek(fp->stdio_stream, offset, whence);
407     else {
408         OS_SetErrno(ESPIPE);
409         return -1;
410     }
411 }
412
413 int FCGI_ftell(FCGI_FILE *fp)
414 {
415     if(fp->stdio_stream)
416         return ftell(fp->stdio_stream);
417     else {
418         OS_SetErrno(ESPIPE);
419         return -1;
420     }
421 }
422
423 void FCGI_rewind(FCGI_FILE *fp)
424 {
425     if(fp->stdio_stream)
426         rewind(fp->stdio_stream);
427     else
428         OS_SetErrno(ESPIPE);
429 }
430
431 #ifdef HAVE_FPOS
432 int FCGI_fgetpos(FCGI_FILE *fp, fpos_t *pos)
433 {
434     if(fp->stdio_stream)
435         return fgetpos(fp->stdio_stream, pos);
436     else {
437         OS_SetErrno(ESPIPE);
438         return -1;
439     }
440 }
441
442 int FCGI_fsetpos(FCGI_FILE *fp, const fpos_t *pos)
443 {
444     if(fp->stdio_stream)
445         return fsetpos(fp->stdio_stream, pos);
446     else {
447         OS_SetErrno(ESPIPE);
448         return -1;
449     }
450 }
451 #endif
452 \f
453 /*
454  *----------------------------------------------------------------------
455  *
456  * FCGI_fgetc, FCGI_getchar, FCGI_ungetc --
457  *
458  *       Wrappers for functions defined in H&S Section 15.6
459  *
460  *       XXX: getc and getchar are generally defined as macros
461  *            for performance reasons
462  *
463  *----------------------------------------------------------------------
464  */
465
466 int FCGI_fgetc(FCGI_FILE *fp)
467 {
468     if(fp->stdio_stream)
469         return fgetc(fp->stdio_stream);
470     else if(fp->fcgx_stream)
471         return FCGX_GetChar(fp->fcgx_stream);
472     return EOF;
473 }
474
475 int FCGI_getchar(void)
476 {
477     return FCGI_fgetc(FCGI_stdin);
478 }
479
480 int FCGI_ungetc(int c, FCGI_FILE *fp)
481 {
482     if(fp->stdio_stream)
483         return ungetc(c, fp->stdio_stream);
484     else if(fp->fcgx_stream)
485         return FCGX_UnGetChar(c, fp->fcgx_stream);
486     return EOF;
487 }
488 \f
489 /*
490  *----------------------------------------------------------------------
491  *
492  * FCGI_fgets, FCGI_gets --
493  *
494  *       Wrappers for functions defined in H&S Section 15.7
495  *
496  *----------------------------------------------------------------------
497  */
498
499 char *FCGI_fgets(char *str, int size, FCGI_FILE *fp)
500 {
501     if(fp->stdio_stream)
502         return fgets(str, size, fp->stdio_stream);
503     else if(fp->fcgx_stream)
504         return FCGX_GetLine(str, size, fp->fcgx_stream);
505     return NULL;
506 }
507
508 /*
509  * There is no standard equivalent of gets that takes an explicit
510  * FILE * argument, so the following "wrapper" implements
511  * gets for both FILE * and FCGX_Stream * in terms of FCGI_getchar.
512  */
513
514 char *FCGI_gets(char *str)
515 {
516     char *s;
517     int c;
518     for (s = str; ((c = FCGI_getchar()) != '\n');) {
519         if(c == EOF) {
520             if(s == str)
521                 return NULL;
522             else
523                 break;
524         } else
525             *s++ = c;
526     }
527     *s = 0;
528     return str;
529 }
530 \f
531 /*
532  *----------------------------------------------------------------------
533  *
534  * --
535  *
536  *       Wrappers for functions defined in H&S Section 15.8
537  *
538  *       XXX: missing: fscanf, scanf
539  *
540  *----------------------------------------------------------------------
541  */
542
543 \f
544 /*
545  *----------------------------------------------------------------------
546  *
547  * FCGI_fputc, FCGI_putchar --
548  *
549  *       Wrappers for functions defined in H&S Section 15.9
550  *
551  *       XXX: putc and putchar are generally defined as macros
552  *            for performance reasons
553  *
554  *----------------------------------------------------------------------
555  */
556
557 int FCGI_fputc(int c, FCGI_FILE *fp)
558 {
559     if(fp->stdio_stream)
560         return fputc(c, fp->stdio_stream);
561     else if(fp->fcgx_stream)
562         return FCGX_PutChar(c, fp->fcgx_stream);
563     else return EOF;
564 }
565
566 int FCGI_putchar(int c)
567 {
568     return FCGI_fputc(c, FCGI_stdout);
569 }
570 \f
571 /*
572  *----------------------------------------------------------------------
573  *
574  * FCGI_fputs, FCGI_puts
575  *
576  *       Wrappers for functions defined in H&S Section 15.10
577  *
578  *----------------------------------------------------------------------
579  */
580
581 int FCGI_fputs(const char *str, FCGI_FILE *fp)
582 {
583     if(fp->stdio_stream)
584         return fputs(str, fp->stdio_stream);
585     else if(fp->fcgx_stream)
586         return FCGX_PutS(str, fp->fcgx_stream);
587     return EOF;
588 }
589
590 int FCGI_puts(const char *str)
591 {
592     int n;
593     if(FCGI_stdout->stdio_stream) {
594         n = fputs(str, FCGI_stdout->stdio_stream);
595         if(n < 0)
596             return n;
597         else
598             return fputc('\n', FCGI_stdout->stdio_stream);
599     } else if(FCGI_stdout->fcgx_stream) {
600         n = FCGX_PutS(str, FCGI_stdout->fcgx_stream);
601         if(n < 0)
602             return n;
603         else
604             return FCGX_PutChar('\n', FCGI_stdout->fcgx_stream);
605     }
606     return EOF;
607 }
608 \f
609 /*
610  *----------------------------------------------------------------------
611  *
612  * FCGI_fprintf, FCGI_printf --
613  *
614  *       Wrappers for functions defined in H&S Section 15.11
615  *
616  *----------------------------------------------------------------------
617  */
618
619 int FCGI_fprintf(FCGI_FILE *fp, const char *format, ...)
620 {
621     va_list ap;
622     int n = 0;
623     va_start(ap, format);
624     if(fp->stdio_stream)
625         n = vfprintf(fp->stdio_stream, format, ap);
626     else if(fp->fcgx_stream)
627         n = FCGX_VFPrintF(fp->fcgx_stream, format, ap);
628     va_end(ap);
629     return n;
630 }
631
632 int FCGI_printf(const char *format, ...)
633 {
634     va_list ap;
635     int n;
636     va_start(ap, format);
637     n = FCGI_vfprintf(FCGI_stdout, format, ap);
638     va_end(ap);
639     return n;
640 }
641 \f
642 /*
643  *----------------------------------------------------------------------
644  *
645  * FCGI_vfprintf, FCGI_vprintf --
646  *
647  *       Wrappers for functions defined in H&S Section 15.12
648  *
649  *----------------------------------------------------------------------
650  */
651
652 int FCGI_vfprintf(FCGI_FILE *fp, const char *format, va_list ap)
653 {
654     if(fp->stdio_stream)
655         return vfprintf(fp->stdio_stream, format, ap);
656     else if(fp->fcgx_stream)
657         return FCGX_VFPrintF(fp->fcgx_stream, format, ap);
658     return EOF;
659 }
660
661 int FCGI_vprintf(const char *format, va_list ap)
662 {
663     if(FCGI_stdout->stdio_stream)
664         return vfprintf(FCGI_stdout->stdio_stream, format, ap);
665     else if(FCGI_stdout->fcgx_stream)
666         return FCGX_VFPrintF(FCGI_stdout->fcgx_stream, format, ap);
667     return EOF;
668 }
669 \f
670 /*
671  *----------------------------------------------------------------------
672  *
673  * FCGI_fread, FCGI_fwrite --
674  *
675  *       Wrappers for functions defined in H&S Section 15.13
676  *
677  *----------------------------------------------------------------------
678  */
679
680 size_t FCGI_fread(void *ptr, size_t size, size_t nmemb, FCGI_FILE *fp)
681 {
682     int n;
683     if(fp->stdio_stream)
684         return fread(ptr, size, nmemb, fp->stdio_stream);
685     else if(fp->fcgx_stream) {
686         if((size * nmemb) == 0) {
687             return 0;
688         }
689         n = FCGX_GetStr((char *) ptr, size * nmemb, fp->fcgx_stream);
690         return (n/size);
691     }
692     return (size_t)EOF;
693 }
694
695 size_t FCGI_fwrite(void *ptr, size_t size, size_t nmemb, FCGI_FILE *fp)
696 {
697     int n;
698     if(fp->stdio_stream)
699         return fwrite(ptr, size, nmemb, fp->stdio_stream);
700     else if(fp->fcgx_stream) {
701         if((size * nmemb) == 0) {
702             return 0;
703         }
704         n = FCGX_PutStr((char *) ptr, size * nmemb, fp->fcgx_stream);
705         return (n/size);
706     }
707     return (size_t)EOF;
708 }
709 \f
710 /*
711  *----------------------------------------------------------------------
712  *
713  * FCGI_feof, FCGI_ferror, FCGI_clearerr --
714  *
715  *       Wrappers for functions defined in H&S Section 15.14
716  *
717  *----------------------------------------------------------------------
718  */
719 int FCGI_feof(FCGI_FILE *fp)
720 {
721     if(fp->stdio_stream) {
722         return feof(fp->stdio_stream);
723     } else if (fp->fcgx_stream){
724         return FCGX_HasSeenEOF(fp->fcgx_stream);
725     }
726     return -1;
727
728 }
729
730 int FCGI_ferror(FCGI_FILE *fp)
731 {
732     if(fp->stdio_stream) {
733         return ferror(fp->stdio_stream);
734     } else if(fp->fcgx_stream) {
735         return FCGX_GetError(fp->fcgx_stream);
736     }
737     return -1;
738 }
739
740 void FCGI_clearerr(FCGI_FILE *fp)
741 {
742     if(fp->stdio_stream) {
743         clearerr(fp->stdio_stream);
744     } else if(fp->fcgx_stream) {
745         FCGX_ClearError(fp->fcgx_stream);
746     }
747     return;
748 }
749 \f
750 /*
751  *----------------------------------------------------------------------
752  *
753  * FCGI_tmpfile --
754  *
755  *       Wrappers for function defined in H&S Section 15.16
756  *
757  *----------------------------------------------------------------------
758  */
759 FCGI_FILE *FCGI_tmpfile(void)
760 {
761     FILE * file = tmpfile();
762     FCGI_FILE * fcgi_file = FCGI_OpenFromFILE(file);
763
764     if (file && !fcgi_file)
765         fclose(file);
766
767     return fcgi_file;
768 }
769
770 \f
771 /*
772  *----------------------------------------------------------------------
773  *
774  * FCGI_fileno, FCGI_fdopen, FCGI_popen, FCGI_pclose --
775  *
776  *       Wrappers for POSIX, X/OPEN functions not in ISO C
777  *
778  *----------------------------------------------------------------------
779  */
780
781 int FCGI_fileno(FCGI_FILE *fp)
782 {
783     if(fp->stdio_stream)
784         return fileno(fp->stdio_stream);
785     else
786         return -1;
787 }
788
789 FCGI_FILE *FCGI_fdopen(int fd, const char *mode)
790 {
791     FILE * file = fdopen(fd, mode);
792     FCGI_FILE * fcgi_file = FCGI_OpenFromFILE(file);
793
794     if (file && !fcgi_file)
795         fclose(file);
796
797     return fcgi_file;
798 }
799
800 FCGI_FILE *FCGI_popen(const char *cmd, const char *type)
801 {
802     FILE * file = popen(cmd, type);
803     FCGI_FILE * fcgi_file = FCGI_OpenFromFILE(file);
804
805     if (file && !fcgi_file)
806         pclose(file);
807
808     return fcgi_file;
809 }
810
811 int FCGI_pclose(FCGI_FILE *fp)
812 {
813     int n = EOF;
814     if (fp->stdio_stream) {
815         n = pclose(fp->stdio_stream);
816         fp->stdio_stream = NULL;
817     } else if(fp->fcgx_stream) {
818         /*
819          * The caller is deeply confused; don't free the storage.
820          */
821         return EOF;
822     }
823     if((fp != FCGI_stdin) && (fp != FCGI_stdout) && (fp != FCGI_stderr)) {
824         free(fp);
825     }
826     return n;
827 }
828
829 /*
830  *----------------------------------------------------------------------
831  */