Remove a bogus check in last commit.
[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
02231a6f 15static const char rcsid[] = "$Id: fcgi_stdio.c,v 1.10 2001/06/18 14:44:37 robs Exp $";
0198fd3c 16#endif /* not lint */
17
6ad90ad2 18#include "fcgi_config.h"
19
0198fd3c 20#ifdef _WIN32
21#define DLLAPI __declspec(dllexport)
02231a6f 22#define WIN32_LEAN_AND_MEAN
6ad90ad2 23#include <windows.h>
0198fd3c 24#endif
25
6ad90ad2 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 */
0198fd3c 30
0198fd3c 31#ifdef HAVE_UNISTD_H
32#include <unistd.h>
33#endif
34
6ad90ad2 35#define NO_FCGI_DEFINES
36#include "fcgi_stdio.h"
37#undef NO_FCGI_DEFINES
38
0198fd3c 39#include "fcgiapp.h"
40#include "fcgios.h"
41
6ad90ad2 42#ifndef _WIN32
43
44extern 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
49extern int fileno(FILE *stream);
50#endif
51
52extern FILE *fdopen(int fildes, const char *type);
53extern FILE *popen(const char *command, const char *type);
54extern int pclose(FILE *stream);
55
56#else /* _WIN32 */
57
58#define popen _popen
4ca54f3e 59#define pclose _pclose
6ad90ad2 60
61#endif /* _WIN32 */
62
0198fd3c 63#ifndef FALSE
64#define FALSE (0)
65#endif
6ad90ad2 66
0198fd3c 67#ifndef TRUE
68#define TRUE (1)
69#endif
70
0198fd3c 71FCGI_FILE _fcgi_sF[3];
0198fd3c 72
0198fd3c 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 */
119static int acceptCalled = FALSE;
120static int isCGI = FALSE;
0198fd3c 121
122int 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;
ac8a58ac 131 atexit(&FCGI_Finish);
0198fd3c 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 */
189void 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 *
aadcc3c8 206 *
0198fd3c 207 * The current request is for the filter role, and stdin is
aadcc3c8 208 * positioned at EOF of FCGI_STDIN. The call repositions
0198fd3c 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:
aadcc3c8 215 * 0 for a normal return, < 0 for error
0198fd3c 216 *
217 *----------------------------------------------------------------------
218 */
219
220int 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
244void 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
261void 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 *----------------------------------------------------------------------
aadcc3c8 281 */
0198fd3c 282
283static FCGI_FILE *FCGI_OpenFromFILE(FILE *stream)
284{
285 FCGI_FILE *fp;
4ca54f3e 286
287 if (stream == NULL)
0198fd3c 288 return NULL;
4ca54f3e 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
0198fd3c 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
310FCGI_FILE *FCGI_fopen(const char *path, const char *mode)
311{
4ca54f3e 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;
0198fd3c 319}
320
321int 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
337int FCGI_fflush(FCGI_FILE *fp)
338{
ed728efb 339 if(fp == NULL)
340 return fflush(NULL);
0198fd3c 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
348FCGI_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 */
378int 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
387void 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
403int 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
413int 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;
aadcc3c8 420 }
0198fd3c 421}
422
423void 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
432int 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;
aadcc3c8 439 }
0198fd3c 440}
441
442int 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;
aadcc3c8 449 }
0198fd3c 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
466int 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
475int FCGI_getchar(void)
476{
477 return FCGI_fgetc(FCGI_stdin);
478}
479
480int 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
499char *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
514char *FCGI_gets(char *str)
515{
516 char *s;
517 int c;
518 for (s = str; ((c = FCGI_getchar()) != '\n');) {
519 if(c == EOF) {
aadcc3c8 520 if(s == str)
0198fd3c 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
557int FCGI_fputc(int c, FCGI_FILE *fp)
558{
aadcc3c8 559 if(fp->stdio_stream)
0198fd3c 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
566int 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
581int 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
590int 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
619int 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
632int 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
652int 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);
aadcc3c8 656 else if(fp->fcgx_stream)
0198fd3c 657 return FCGX_VFPrintF(fp->fcgx_stream, format, ap);
658 return EOF;
659}
660
661int FCGI_vprintf(const char *format, va_list ap)
662{
663 if(FCGI_stdout->stdio_stream)
664 return vfprintf(FCGI_stdout->stdio_stream, format, ap);
aadcc3c8 665 else if(FCGI_stdout->fcgx_stream)
0198fd3c 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
680size_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
695size_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 */
719int 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
730int 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
740void 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;
ed728efb 748}
17abbc3a 749\f
750/*
751 *----------------------------------------------------------------------
752 *
753 * FCGI_tmpfile --
754 *
755 * Wrappers for function defined in H&S Section 15.16
756 *
757 *----------------------------------------------------------------------
758 */
759FCGI_FILE *FCGI_tmpfile(void)
ed728efb 760{
4ca54f3e 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;
0198fd3c 768}
17abbc3a 769
0198fd3c 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
0198fd3c 781int FCGI_fileno(FCGI_FILE *fp)
782{
783 if(fp->stdio_stream)
784 return fileno(fp->stdio_stream);
785 else
786 return -1;
787}
788
789FCGI_FILE *FCGI_fdopen(int fd, const char *mode)
790{
4ca54f3e 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;
0198fd3c 798}
799
800FCGI_FILE *FCGI_popen(const char *cmd, const char *type)
801{
4ca54f3e 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;
0198fd3c 809}
810
811int FCGI_pclose(FCGI_FILE *fp)
812{
813 int n = EOF;
4ca54f3e 814 if (fp->stdio_stream) {
0198fd3c 815 n = pclose(fp->stdio_stream);
0198fd3c 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 */