This should be replaced with Tom Poindexter's TCL lib or a
[catagits/fcgi2.git] / libfcgi / fcgi_stdio.c
CommitLineData
aadcc3c8 1/*
0198fd3c 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
aadcc3c8 15static const char rcsid[] = "$Id: fcgi_stdio.c,v 1.7 1999/07/27 15:00:16 roberts Exp $";
0198fd3c 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
0198fd3c 51FCGI_FILE _fcgi_sF[3];
0198fd3c 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 */
102static int acceptCalled = FALSE;
103static int isCGI = FALSE;
104#ifndef _WIN32
105extern char **environ;
106#endif
107
108int 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;
ac8a58ac 117 atexit(&FCGI_Finish);
0198fd3c 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 */
175void 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 *
aadcc3c8 192 *
0198fd3c 193 * The current request is for the filter role, and stdin is
aadcc3c8 194 * positioned at EOF of FCGI_STDIN. The call repositions
0198fd3c 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:
aadcc3c8 201 * 0 for a normal return, < 0 for error
0198fd3c 202 *
203 *----------------------------------------------------------------------
204 */
205
206int 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
230void 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
247void 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 *----------------------------------------------------------------------
aadcc3c8 267 */
0198fd3c 268
269static FCGI_FILE *FCGI_OpenFromFILE(FILE *stream)
270{
271 FCGI_FILE *fp;
272 if(stream == NULL)
273 return NULL;
aadcc3c8 274 fp = (FCGI_FILE *)malloc(sizeof(FCGI_FILE));
0198fd3c 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
292FCGI_FILE *FCGI_fopen(const char *path, const char *mode)
293{
294 return FCGI_OpenFromFILE(fopen(path, mode));
295}
296
297int 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
313int FCGI_fflush(FCGI_FILE *fp)
314{
ed728efb 315 if(fp == NULL)
316 return fflush(NULL);
0198fd3c 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
324FCGI_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 */
354int 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
363void 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
379int 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
389int 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;
aadcc3c8 396 }
0198fd3c 397}
398
399void 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
408int 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;
aadcc3c8 415 }
0198fd3c 416}
417
418int 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;
aadcc3c8 425 }
0198fd3c 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
442int 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
451int FCGI_getchar(void)
452{
453 return FCGI_fgetc(FCGI_stdin);
454}
455
456int 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
475char *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
490char *FCGI_gets(char *str)
491{
492 char *s;
493 int c;
494 for (s = str; ((c = FCGI_getchar()) != '\n');) {
495 if(c == EOF) {
aadcc3c8 496 if(s == str)
0198fd3c 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
533int FCGI_fputc(int c, FCGI_FILE *fp)
534{
aadcc3c8 535 if(fp->stdio_stream)
0198fd3c 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
542int 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
557int 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
566int 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
595int 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
608int 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
628int 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);
aadcc3c8 632 else if(fp->fcgx_stream)
0198fd3c 633 return FCGX_VFPrintF(fp->fcgx_stream, format, ap);
634 return EOF;
635}
636
637int FCGI_vprintf(const char *format, va_list ap)
638{
639 if(FCGI_stdout->stdio_stream)
640 return vfprintf(FCGI_stdout->stdio_stream, format, ap);
aadcc3c8 641 else if(FCGI_stdout->fcgx_stream)
0198fd3c 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
656size_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
671size_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 */
695int 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
706int 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
716void 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;
ed728efb 724}
17abbc3a 725\f
726/*
727 *----------------------------------------------------------------------
728 *
729 * FCGI_tmpfile --
730 *
731 * Wrappers for function defined in H&S Section 15.16
732 *
733 *----------------------------------------------------------------------
734 */
735FCGI_FILE *FCGI_tmpfile(void)
ed728efb 736{
737 return FCGI_OpenFromFILE(tmpfile());
0198fd3c 738}
17abbc3a 739
0198fd3c 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
760extern int fileno(FILE *stream);
761#endif
762extern FILE *fdopen(int fildes, const char *type);
763extern FILE *popen(const char *command, const char *type);
764extern int pclose(FILE *stream);
765#endif
766
767int FCGI_fileno(FCGI_FILE *fp)
768{
769 if(fp->stdio_stream)
770 return fileno(fp->stdio_stream);
771 else
772 return -1;
773}
774
775FCGI_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
784FCGI_FILE *FCGI_popen(const char *cmd, const char *type)
785{
786 return FCGI_OpenFromFILE(popen(cmd, type));
787}
788
789int 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 */