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