Remove references in the comments to fcgio2.h.
[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
4ca54f3e 15static const char rcsid[] = "$Id: fcgi_stdio.c,v 1.9 2000/10/30 22:52:24 robs Exp $";
0198fd3c 16#endif /* not lint */
17
6ad90ad2 18#include "fcgi_config.h"
19
0198fd3c 20#ifdef _WIN32
21#define DLLAPI __declspec(dllexport)
6ad90ad2 22#include <windows.h>
0198fd3c 23#endif
24
6ad90ad2 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 */
0198fd3c 29
0198fd3c 30#ifdef HAVE_UNISTD_H
31#include <unistd.h>
32#endif
33
6ad90ad2 34#define NO_FCGI_DEFINES
35#include "fcgi_stdio.h"
36#undef NO_FCGI_DEFINES
37
0198fd3c 38#include "fcgiapp.h"
39#include "fcgios.h"
40
6ad90ad2 41#ifndef _WIN32
42
43extern 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
48extern int fileno(FILE *stream);
49#endif
50
51extern FILE *fdopen(int fildes, const char *type);
52extern FILE *popen(const char *command, const char *type);
53extern int pclose(FILE *stream);
54
55#else /* _WIN32 */
56
57#define popen _popen
4ca54f3e 58#define pclose _pclose
6ad90ad2 59
60#endif /* _WIN32 */
61
0198fd3c 62#ifndef FALSE
63#define FALSE (0)
64#endif
6ad90ad2 65
0198fd3c 66#ifndef TRUE
67#define TRUE (1)
68#endif
69
0198fd3c 70FCGI_FILE _fcgi_sF[3];
0198fd3c 71
0198fd3c 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 */
118static int acceptCalled = FALSE;
119static int isCGI = FALSE;
0198fd3c 120
121int 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;
ac8a58ac 130 atexit(&FCGI_Finish);
0198fd3c 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 */
188void 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 *
aadcc3c8 205 *
0198fd3c 206 * The current request is for the filter role, and stdin is
aadcc3c8 207 * positioned at EOF of FCGI_STDIN. The call repositions
0198fd3c 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:
aadcc3c8 214 * 0 for a normal return, < 0 for error
0198fd3c 215 *
216 *----------------------------------------------------------------------
217 */
218
219int 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
243void 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
260void 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 *----------------------------------------------------------------------
aadcc3c8 280 */
0198fd3c 281
282static FCGI_FILE *FCGI_OpenFromFILE(FILE *stream)
283{
284 FCGI_FILE *fp;
4ca54f3e 285
286 if (stream == NULL)
0198fd3c 287 return NULL;
4ca54f3e 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
0198fd3c 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
309FCGI_FILE *FCGI_fopen(const char *path, const char *mode)
310{
4ca54f3e 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;
0198fd3c 318}
319
320int 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
336int FCGI_fflush(FCGI_FILE *fp)
337{
ed728efb 338 if(fp == NULL)
339 return fflush(NULL);
0198fd3c 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
347FCGI_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 */
377int 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
386void 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
402int 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
412int 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;
aadcc3c8 419 }
0198fd3c 420}
421
422void 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
431int 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;
aadcc3c8 438 }
0198fd3c 439}
440
441int 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;
aadcc3c8 448 }
0198fd3c 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
465int 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
474int FCGI_getchar(void)
475{
476 return FCGI_fgetc(FCGI_stdin);
477}
478
479int 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
498char *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
513char *FCGI_gets(char *str)
514{
515 char *s;
516 int c;
517 for (s = str; ((c = FCGI_getchar()) != '\n');) {
518 if(c == EOF) {
aadcc3c8 519 if(s == str)
0198fd3c 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
556int FCGI_fputc(int c, FCGI_FILE *fp)
557{
aadcc3c8 558 if(fp->stdio_stream)
0198fd3c 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
565int 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
580int 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
589int 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
618int 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
631int 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
651int 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);
aadcc3c8 655 else if(fp->fcgx_stream)
0198fd3c 656 return FCGX_VFPrintF(fp->fcgx_stream, format, ap);
657 return EOF;
658}
659
660int FCGI_vprintf(const char *format, va_list ap)
661{
662 if(FCGI_stdout->stdio_stream)
663 return vfprintf(FCGI_stdout->stdio_stream, format, ap);
aadcc3c8 664 else if(FCGI_stdout->fcgx_stream)
0198fd3c 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
679size_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
694size_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 */
718int 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
729int 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
739void 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;
ed728efb 747}
17abbc3a 748\f
749/*
750 *----------------------------------------------------------------------
751 *
752 * FCGI_tmpfile --
753 *
754 * Wrappers for function defined in H&S Section 15.16
755 *
756 *----------------------------------------------------------------------
757 */
758FCGI_FILE *FCGI_tmpfile(void)
ed728efb 759{
4ca54f3e 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;
0198fd3c 767}
17abbc3a 768
0198fd3c 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
0198fd3c 780int FCGI_fileno(FCGI_FILE *fp)
781{
782 if(fp->stdio_stream)
783 return fileno(fp->stdio_stream);
784 else
785 return -1;
786}
787
788FCGI_FILE *FCGI_fdopen(int fd, const char *mode)
789{
4ca54f3e 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;
0198fd3c 797}
798
799FCGI_FILE *FCGI_popen(const char *cmd, const char *type)
800{
4ca54f3e 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;
0198fd3c 808}
809
810int FCGI_pclose(FCGI_FILE *fp)
811{
812 int n = EOF;
4ca54f3e 813 if (fp->stdio_stream) {
0198fd3c 814 n = pclose(fp->stdio_stream);
0198fd3c 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 */