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