Commit | Line | Data |
0198fd3c |
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 |
f6d1be39 |
15 | static const char rcsid[] = "$Id: fcgi_stdio.c,v 1.6 1999/06/07 05:39:03 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 |
51 | FCGI_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 | */ |
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; |
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 | */ |
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 | { |
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 | |
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; |
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 | */ |
735 | FCGI_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 |
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 | */ |