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 |
ac8a58ac |
15 | static const char rcsid[] = "$Id: fcgi_stdio.c,v 1.5 1999/06/07 05:03:48 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 | |
51 | #ifdef _WIN32 |
52 | FCGI_FILE _fcgi_sF[3]; |
53 | #else |
54 | FCGI_FILE _fcgi_sF[3] = {{stdin, NULL}, {stdout, NULL}, {stderr, NULL}}; |
55 | #endif |
56 | |
57 | #ifdef _WIN32 |
58 | #define popen _popen |
59 | #endif |
60 | \f |
61 | /* |
62 | *---------------------------------------------------------------------- |
63 | * |
64 | * FCGI_Accept -- |
65 | * |
66 | * Accepts a new request from the HTTP server and creates |
67 | * a conventional execution environment for the request. |
68 | * |
69 | * If the application was invoked as a FastCGI server, |
70 | * the first call to FCGI_Accept indicates that the application |
71 | * has completed its initialization and is ready to accept |
72 | * a request. Subsequent calls to FCGI_Accept indicate that |
73 | * the application has completed its processing of the |
74 | * current request and is ready to accept a new request. |
75 | * |
76 | * If the application was invoked as a CGI program, the first |
77 | * call to FCGI_Accept is essentially a no-op and the second |
78 | * call returns EOF (-1). |
79 | * |
80 | * Results: |
81 | * 0 for successful call, -1 for error (application should exit). |
82 | * |
83 | * Side effects: |
84 | * If the application was invoked as a FastCGI server, |
85 | * and this is not the first call to this procedure, |
86 | * FCGI_Accept first performs the equivalent of FCGI_Finish. |
87 | * |
88 | * On every call, FCGI_Accept accepts the new request and |
89 | * reads the FCGI_PARAMS stream into an environment array, |
90 | * i.e. a NULL-terminated array of strings of the form |
91 | * ``name=value''. It assigns a pointer to this array |
92 | * to the global variable environ, used by the standard |
93 | * library function getenv. It creates new FCGI_FILE *s |
94 | * representing input from the HTTP server, output to the HTTP |
95 | * server, and error output to the HTTP server, and assigns these |
96 | * new files to stdin, stdout, and stderr respectively. |
97 | * |
98 | * DO NOT mutate or retain pointers to environ or any values |
99 | * contained in it (e.g. to the result of calling getenv(3)), |
100 | * since these are freed by the next call to FCGI_Finish or |
101 | * FCGI_Accept. In particular do not use setenv(3) or putenv(3) |
102 | * in conjunction with FCGI_Accept. |
103 | * |
104 | *---------------------------------------------------------------------- |
105 | */ |
106 | static int acceptCalled = FALSE; |
107 | static int isCGI = FALSE; |
108 | #ifndef _WIN32 |
109 | extern char **environ; |
110 | #endif |
111 | |
112 | int FCGI_Accept(void) |
113 | { |
114 | if(!acceptCalled) { |
115 | /* |
116 | * First call to FCGI_Accept. Is application running |
117 | * as FastCGI or as CGI? |
118 | */ |
119 | isCGI = FCGX_IsCGI(); |
120 | acceptCalled = TRUE; |
ac8a58ac |
121 | atexit(&FCGI_Finish); |
0198fd3c |
122 | } else if(isCGI) { |
123 | /* |
124 | * Not first call to FCGI_Accept and running as CGI means |
125 | * application is done. |
126 | */ |
127 | return(EOF); |
128 | } |
129 | if(isCGI) { |
130 | FCGI_stdin->stdio_stream = stdin; |
131 | FCGI_stdin->fcgx_stream = NULL; |
132 | FCGI_stdout->stdio_stream = stdout; |
133 | FCGI_stdout->fcgx_stream = NULL; |
134 | FCGI_stderr->stdio_stream = stderr; |
135 | FCGI_stderr->fcgx_stream = NULL; |
136 | } else { |
137 | FCGX_Stream *in, *out, *error; |
138 | FCGX_ParamArray envp; |
139 | int acceptResult = FCGX_Accept(&in, &out, &error, &envp); |
140 | if(acceptResult < 0) { |
141 | return acceptResult; |
142 | } |
143 | FCGI_stdin->stdio_stream = NULL; |
144 | FCGI_stdin->fcgx_stream = in; |
145 | FCGI_stdout->stdio_stream = NULL; |
146 | FCGI_stdout->fcgx_stream = out; |
147 | FCGI_stderr->stdio_stream = NULL; |
148 | FCGI_stderr->fcgx_stream = error; |
149 | environ = envp; |
150 | } |
151 | return 0; |
152 | } |
153 | \f |
154 | /* |
155 | *---------------------------------------------------------------------- |
156 | * |
157 | * FCGI_Finish -- |
158 | * |
159 | * Finishes the current request from the HTTP server. |
160 | * |
161 | * Side effects: |
162 | * |
163 | * Flushes any buffered output to the HTTP server. Then frees |
164 | * all storage allocated by the previous call, including all |
165 | * storage reachable from the value of environ set by the previous |
166 | * call to FCGI_Accept. |
167 | * |
168 | * DO NOT use stdin, stdout, stderr, or environ between calling |
169 | * FCGI_Finish and calling FCGI_Accept. |
170 | * |
171 | * DO NOT mutate or retain pointers to environ or any values |
172 | * contained in it (e.g. to the result of calling getenv(3)), |
173 | * since these are freed by the next call to FCGI_Finish or |
174 | * FCGI_Accept. In particular do not use setenv(3) or putenv(3) |
175 | * in conjunction with FCGI_Accept. |
176 | * |
177 | *---------------------------------------------------------------------- |
178 | */ |
179 | void FCGI_Finish(void) |
180 | { |
181 | if(!acceptCalled || isCGI) { |
182 | return; |
183 | } |
184 | FCGX_Finish(); |
185 | FCGI_stdin->fcgx_stream = NULL; |
186 | FCGI_stdout->fcgx_stream = NULL; |
187 | FCGI_stderr->fcgx_stream = NULL; |
188 | environ = NULL; |
189 | } |
190 | \f |
191 | /* |
192 | *---------------------------------------------------------------------- |
193 | * |
194 | * FCGI_StartFilterData -- |
195 | * |
196 | * |
197 | * The current request is for the filter role, and stdin is |
198 | * positioned at EOF of FCGI_STDIN. The call repositions |
199 | * stdin to the start of FCGI_DATA. |
200 | * If the preconditions are not met (e.g. FCGI_STDIN has not |
201 | * been read to EOF), the call sets the stream error code to |
202 | * FCGX_CALL_SEQ_ERROR. |
203 | * |
204 | * Results: |
205 | * 0 for a normal return, < 0 for error |
206 | * |
207 | *---------------------------------------------------------------------- |
208 | */ |
209 | |
210 | int 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 | } |
218 | \f |
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 | */ |
233 | |
234 | void FCGI_SetExitStatus(int status) |
235 | { |
236 | if(FCGI_stdin->fcgx_stream) { |
237 | FCGX_SetExitStatus(status, FCGI_stdin->fcgx_stream); |
238 | } |
239 | } |
240 | \f |
241 | /* |
242 | *---------------------------------------------------------------------- |
243 | * |
244 | * FCGI_perror -- |
245 | * |
246 | * Wrapper for function defined in H&S Section 11.2 |
247 | * |
248 | *---------------------------------------------------------------------- |
249 | */ |
250 | |
251 | void FCGI_perror(const char *str) |
252 | { |
253 | FCGI_fputs(str, FCGI_stderr); |
254 | FCGI_fputs(": ", FCGI_stderr); |
255 | FCGI_fputs(strerror(OS_Errno), FCGI_stderr); |
256 | return; |
257 | } |
258 | \f |
259 | /* |
260 | *---------------------------------------------------------------------- |
261 | * |
262 | * FCGI_OpenFromFILE -- |
263 | * |
264 | * Constructs a new FCGI_FILE * from the FILE *stream. |
265 | * |
266 | * Results: |
267 | * NULL if stream == NULL or storage could not be allocated, |
268 | * otherwise the new FCGI_FILE *. |
269 | * |
270 | *---------------------------------------------------------------------- |
271 | */ |
272 | |
273 | static FCGI_FILE *FCGI_OpenFromFILE(FILE *stream) |
274 | { |
275 | FCGI_FILE *fp; |
276 | if(stream == NULL) |
277 | return NULL; |
278 | fp = malloc(sizeof(FCGI_FILE)); |
279 | if(fp == NULL) |
280 | return NULL; |
281 | fp->stdio_stream = stream; |
282 | fp->fcgx_stream = NULL; |
283 | return fp; |
284 | } |
285 | \f |
286 | /* |
287 | *---------------------------------------------------------------------- |
288 | * |
289 | * FCGI_fopen, FCGI_fclose, FCGI_fflush, FCGI_freopen -- |
290 | * |
291 | * Wrappers for functions defined in H&S Section 15.2 |
292 | * |
293 | *---------------------------------------------------------------------- |
294 | */ |
295 | |
296 | FCGI_FILE *FCGI_fopen(const char *path, const char *mode) |
297 | { |
298 | return FCGI_OpenFromFILE(fopen(path, mode)); |
299 | } |
300 | |
301 | int FCGI_fclose(FCGI_FILE *fp) |
302 | { |
303 | int n = EOF; |
304 | if(fp->stdio_stream) { |
305 | n = fclose(fp->stdio_stream); |
306 | fp->stdio_stream = NULL; |
307 | } else if(fp->fcgx_stream) { |
308 | n = FCGX_FClose(fp->fcgx_stream); |
309 | fp->fcgx_stream = NULL; |
310 | } |
311 | if((fp != FCGI_stdin) && (fp != FCGI_stdout) && (fp != FCGI_stderr)) { |
312 | free(fp); |
313 | } |
314 | return n; |
315 | } |
316 | |
317 | int FCGI_fflush(FCGI_FILE *fp) |
318 | { |
ed728efb |
319 | if(fp == NULL) |
320 | return fflush(NULL); |
0198fd3c |
321 | if(fp->stdio_stream) |
322 | return fflush(fp->stdio_stream); |
323 | else if(fp->fcgx_stream) |
324 | return FCGX_FFlush(fp->fcgx_stream); |
325 | return EOF; |
326 | } |
327 | |
328 | FCGI_FILE *FCGI_freopen(const char *path, const char *mode, |
329 | FCGI_FILE *fp) |
330 | { |
331 | if(fp->stdio_stream) { |
332 | if(freopen(path, mode, fp->stdio_stream) == NULL) |
333 | return NULL; |
334 | else |
335 | return fp; |
336 | } else if(fp->fcgx_stream) { |
337 | (void) FCGX_FClose(fp->fcgx_stream); |
338 | fp->stdio_stream = fopen(path, mode); |
339 | if(fp->stdio_stream == NULL) |
340 | return NULL; |
341 | else { |
342 | fp->fcgx_stream = NULL; |
343 | return fp; |
344 | } |
345 | } |
346 | return NULL; |
347 | } |
348 | \f |
349 | /* |
350 | *---------------------------------------------------------------------- |
351 | * |
352 | * FCGI_setvbuf, FCGI_setbuf -- |
353 | * |
354 | * Wrappers for functions defined in H&S Section 15.3 |
355 | * |
356 | *---------------------------------------------------------------------- |
357 | */ |
358 | int FCGI_setvbuf(FCGI_FILE *fp, char *buf, int bufmode, size_t size) |
359 | { |
360 | if(fp->stdio_stream) |
361 | return setvbuf(fp->stdio_stream, buf, bufmode, size); |
362 | else { |
363 | return -1; |
364 | } |
365 | } |
366 | |
367 | void FCGI_setbuf(FCGI_FILE *fp, char *buf) |
368 | { |
369 | if(fp->stdio_stream) |
370 | setbuf(fp->stdio_stream, buf); |
371 | } |
372 | \f |
373 | /* |
374 | *---------------------------------------------------------------------- |
375 | * |
376 | * FCGI_fseek, FCGI_ftell, FCGI_rewind, FCGI_fgetpos, FCGI_fsetpos -- |
377 | * |
378 | * Wrappers for functions defined in H&S Section 15.5 |
379 | * |
380 | *---------------------------------------------------------------------- |
381 | */ |
382 | |
383 | int FCGI_fseek(FCGI_FILE *fp, long offset, int whence) |
384 | { |
385 | if(fp->stdio_stream) |
386 | return fseek(fp->stdio_stream, offset, whence); |
387 | else { |
388 | OS_SetErrno(ESPIPE); |
389 | return -1; |
390 | } |
391 | } |
392 | |
393 | int FCGI_ftell(FCGI_FILE *fp) |
394 | { |
395 | if(fp->stdio_stream) |
396 | return ftell(fp->stdio_stream); |
397 | else { |
398 | OS_SetErrno(ESPIPE); |
399 | return -1; |
400 | } |
401 | } |
402 | |
403 | void FCGI_rewind(FCGI_FILE *fp) |
404 | { |
405 | if(fp->stdio_stream) |
406 | rewind(fp->stdio_stream); |
407 | else |
408 | OS_SetErrno(ESPIPE); |
409 | } |
410 | |
411 | #ifdef HAVE_FPOS |
412 | int FCGI_fgetpos(FCGI_FILE *fp, fpos_t *pos) |
413 | { |
414 | if(fp->stdio_stream) |
415 | return fgetpos(fp->stdio_stream, pos); |
416 | else { |
417 | OS_SetErrno(ESPIPE); |
418 | return -1; |
419 | } |
420 | } |
421 | |
422 | int FCGI_fsetpos(FCGI_FILE *fp, const fpos_t *pos) |
423 | { |
424 | if(fp->stdio_stream) |
425 | return fsetpos(fp->stdio_stream, pos); |
426 | else { |
427 | OS_SetErrno(ESPIPE); |
428 | return -1; |
429 | } |
430 | } |
431 | #endif |
432 | \f |
433 | /* |
434 | *---------------------------------------------------------------------- |
435 | * |
436 | * FCGI_fgetc, FCGI_getchar, FCGI_ungetc -- |
437 | * |
438 | * Wrappers for functions defined in H&S Section 15.6 |
439 | * |
440 | * XXX: getc and getchar are generally defined as macros |
441 | * for performance reasons |
442 | * |
443 | *---------------------------------------------------------------------- |
444 | */ |
445 | |
446 | int FCGI_fgetc(FCGI_FILE *fp) |
447 | { |
448 | if(fp->stdio_stream) |
449 | return fgetc(fp->stdio_stream); |
450 | else if(fp->fcgx_stream) |
451 | return FCGX_GetChar(fp->fcgx_stream); |
452 | return EOF; |
453 | } |
454 | |
455 | int FCGI_getchar(void) |
456 | { |
457 | return FCGI_fgetc(FCGI_stdin); |
458 | } |
459 | |
460 | int FCGI_ungetc(int c, FCGI_FILE *fp) |
461 | { |
462 | if(fp->stdio_stream) |
463 | return ungetc(c, fp->stdio_stream); |
464 | else if(fp->fcgx_stream) |
465 | return FCGX_UnGetChar(c, fp->fcgx_stream); |
466 | return EOF; |
467 | } |
468 | \f |
469 | /* |
470 | *---------------------------------------------------------------------- |
471 | * |
472 | * FCGI_fgets, FCGI_gets -- |
473 | * |
474 | * Wrappers for functions defined in H&S Section 15.7 |
475 | * |
476 | *---------------------------------------------------------------------- |
477 | */ |
478 | |
479 | char *FCGI_fgets(char *str, int size, FCGI_FILE *fp) |
480 | { |
481 | if(fp->stdio_stream) |
482 | return fgets(str, size, fp->stdio_stream); |
483 | else if(fp->fcgx_stream) |
484 | return FCGX_GetLine(str, size, fp->fcgx_stream); |
485 | return NULL; |
486 | } |
487 | |
488 | /* |
489 | * There is no standard equivalent of gets that takes an explicit |
490 | * FILE * argument, so the following "wrapper" implements |
491 | * gets for both FILE * and FCGX_Stream * in terms of FCGI_getchar. |
492 | */ |
493 | |
494 | char *FCGI_gets(char *str) |
495 | { |
496 | char *s; |
497 | int c; |
498 | for (s = str; ((c = FCGI_getchar()) != '\n');) { |
499 | if(c == EOF) { |
500 | if(s == str) |
501 | return NULL; |
502 | else |
503 | break; |
504 | } else |
505 | *s++ = c; |
506 | } |
507 | *s = 0; |
508 | return str; |
509 | } |
510 | \f |
511 | /* |
512 | *---------------------------------------------------------------------- |
513 | * |
514 | * -- |
515 | * |
516 | * Wrappers for functions defined in H&S Section 15.8 |
517 | * |
518 | * XXX: missing: fscanf, scanf |
519 | * |
520 | *---------------------------------------------------------------------- |
521 | */ |
522 | |
523 | \f |
524 | /* |
525 | *---------------------------------------------------------------------- |
526 | * |
527 | * FCGI_fputc, FCGI_putchar -- |
528 | * |
529 | * Wrappers for functions defined in H&S Section 15.9 |
530 | * |
531 | * XXX: putc and putchar are generally defined as macros |
532 | * for performance reasons |
533 | * |
534 | *---------------------------------------------------------------------- |
535 | */ |
536 | |
537 | int FCGI_fputc(int c, FCGI_FILE *fp) |
538 | { |
539 | if(fp->stdio_stream) |
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 | |
546 | int FCGI_putchar(int c) |
547 | { |
548 | return FCGI_fputc(c, FCGI_stdout); |
549 | } |
550 | \f |
551 | /* |
552 | *---------------------------------------------------------------------- |
553 | * |
554 | * FCGI_fputs, FCGI_puts |
555 | * |
556 | * Wrappers for functions defined in H&S Section 15.10 |
557 | * |
558 | *---------------------------------------------------------------------- |
559 | */ |
560 | |
561 | int FCGI_fputs(const char *str, FCGI_FILE *fp) |
562 | { |
563 | if(fp->stdio_stream) |
564 | return fputs(str, fp->stdio_stream); |
565 | else if(fp->fcgx_stream) |
566 | return FCGX_PutS(str, fp->fcgx_stream); |
567 | return EOF; |
568 | } |
569 | |
570 | int FCGI_puts(const char *str) |
571 | { |
572 | int n; |
573 | if(FCGI_stdout->stdio_stream) { |
574 | n = fputs(str, FCGI_stdout->stdio_stream); |
575 | if(n < 0) |
576 | return n; |
577 | else |
578 | return fputc('\n', FCGI_stdout->stdio_stream); |
579 | } else if(FCGI_stdout->fcgx_stream) { |
580 | n = FCGX_PutS(str, FCGI_stdout->fcgx_stream); |
581 | if(n < 0) |
582 | return n; |
583 | else |
584 | return FCGX_PutChar('\n', FCGI_stdout->fcgx_stream); |
585 | } |
586 | return EOF; |
587 | } |
588 | \f |
589 | /* |
590 | *---------------------------------------------------------------------- |
591 | * |
592 | * FCGI_fprintf, FCGI_printf -- |
593 | * |
594 | * Wrappers for functions defined in H&S Section 15.11 |
595 | * |
596 | *---------------------------------------------------------------------- |
597 | */ |
598 | |
599 | int FCGI_fprintf(FCGI_FILE *fp, const char *format, ...) |
600 | { |
601 | va_list ap; |
602 | int n = 0; |
603 | va_start(ap, format); |
604 | if(fp->stdio_stream) |
605 | n = vfprintf(fp->stdio_stream, format, ap); |
606 | else if(fp->fcgx_stream) |
607 | n = FCGX_VFPrintF(fp->fcgx_stream, format, ap); |
608 | va_end(ap); |
609 | return n; |
610 | } |
611 | |
612 | int FCGI_printf(const char *format, ...) |
613 | { |
614 | va_list ap; |
615 | int n; |
616 | va_start(ap, format); |
617 | n = FCGI_vfprintf(FCGI_stdout, format, ap); |
618 | va_end(ap); |
619 | return n; |
620 | } |
621 | \f |
622 | /* |
623 | *---------------------------------------------------------------------- |
624 | * |
625 | * FCGI_vfprintf, FCGI_vprintf -- |
626 | * |
627 | * Wrappers for functions defined in H&S Section 15.12 |
628 | * |
629 | *---------------------------------------------------------------------- |
630 | */ |
631 | |
632 | int FCGI_vfprintf(FCGI_FILE *fp, const char *format, va_list ap) |
633 | { |
634 | if(fp->stdio_stream) |
635 | return vfprintf(fp->stdio_stream, format, ap); |
636 | else if(fp->fcgx_stream) |
637 | return FCGX_VFPrintF(fp->fcgx_stream, format, ap); |
638 | return EOF; |
639 | } |
640 | |
641 | int FCGI_vprintf(const char *format, va_list ap) |
642 | { |
643 | if(FCGI_stdout->stdio_stream) |
644 | return vfprintf(FCGI_stdout->stdio_stream, format, ap); |
645 | else if(FCGI_stdout->fcgx_stream) |
646 | return FCGX_VFPrintF(FCGI_stdout->fcgx_stream, format, ap); |
647 | return EOF; |
648 | } |
649 | \f |
650 | /* |
651 | *---------------------------------------------------------------------- |
652 | * |
653 | * FCGI_fread, FCGI_fwrite -- |
654 | * |
655 | * Wrappers for functions defined in H&S Section 15.13 |
656 | * |
657 | *---------------------------------------------------------------------- |
658 | */ |
659 | |
660 | size_t FCGI_fread(void *ptr, size_t size, size_t nmemb, FCGI_FILE *fp) |
661 | { |
662 | int n; |
663 | if(fp->stdio_stream) |
664 | return fread(ptr, size, nmemb, fp->stdio_stream); |
665 | else if(fp->fcgx_stream) { |
666 | if((size * nmemb) == 0) { |
667 | return 0; |
668 | } |
669 | n = FCGX_GetStr((char *) ptr, size * nmemb, fp->fcgx_stream); |
670 | return (n/size); |
671 | } |
672 | return (size_t)EOF; |
673 | } |
674 | |
675 | size_t FCGI_fwrite(void *ptr, size_t size, size_t nmemb, FCGI_FILE *fp) |
676 | { |
677 | int n; |
678 | if(fp->stdio_stream) |
679 | return fwrite(ptr, size, nmemb, fp->stdio_stream); |
680 | else if(fp->fcgx_stream) { |
681 | if((size * nmemb) == 0) { |
682 | return 0; |
683 | } |
684 | n = FCGX_PutStr((char *) ptr, size * nmemb, fp->fcgx_stream); |
685 | return (n/size); |
686 | } |
687 | return (size_t)EOF; |
688 | } |
689 | \f |
690 | /* |
691 | *---------------------------------------------------------------------- |
692 | * |
693 | * FCGI_feof, FCGI_ferror, FCGI_clearerr -- |
694 | * |
695 | * Wrappers for functions defined in H&S Section 15.14 |
696 | * |
697 | *---------------------------------------------------------------------- |
698 | */ |
699 | int FCGI_feof(FCGI_FILE *fp) |
700 | { |
701 | if(fp->stdio_stream) { |
702 | return feof(fp->stdio_stream); |
703 | } else if (fp->fcgx_stream){ |
704 | return FCGX_HasSeenEOF(fp->fcgx_stream); |
705 | } |
706 | return -1; |
707 | |
708 | } |
709 | |
710 | int FCGI_ferror(FCGI_FILE *fp) |
711 | { |
712 | if(fp->stdio_stream) { |
713 | return ferror(fp->stdio_stream); |
714 | } else if(fp->fcgx_stream) { |
715 | return FCGX_GetError(fp->fcgx_stream); |
716 | } |
717 | return -1; |
718 | } |
719 | |
720 | void FCGI_clearerr(FCGI_FILE *fp) |
721 | { |
722 | if(fp->stdio_stream) { |
723 | clearerr(fp->stdio_stream); |
724 | } else if(fp->fcgx_stream) { |
725 | FCGX_ClearError(fp->fcgx_stream); |
726 | } |
727 | return; |
ed728efb |
728 | } |
17abbc3a |
729 | \f |
730 | /* |
731 | *---------------------------------------------------------------------- |
732 | * |
733 | * FCGI_tmpfile -- |
734 | * |
735 | * Wrappers for function defined in H&S Section 15.16 |
736 | * |
737 | *---------------------------------------------------------------------- |
738 | */ |
739 | FCGI_FILE *FCGI_tmpfile(void) |
ed728efb |
740 | { |
741 | return FCGI_OpenFromFILE(tmpfile()); |
0198fd3c |
742 | } |
17abbc3a |
743 | |
0198fd3c |
744 | \f |
745 | /* |
746 | *---------------------------------------------------------------------- |
747 | * |
748 | * FCGI_fileno, FCGI_fdopen, FCGI_popen, FCGI_pclose -- |
749 | * |
750 | * Wrappers for POSIX, X/OPEN functions not in ISO C |
751 | * |
752 | *---------------------------------------------------------------------- |
753 | */ |
754 | |
755 | /* |
756 | * These definitions should be supplied by stdio.h but for some |
757 | * reason they get lost on certain platforms. |
758 | */ |
759 | /* |
760 | * XXX: Need to find the right way to handle this for NT |
761 | */ |
762 | #ifndef _WIN32 |
763 | #ifndef fileno |
764 | extern int fileno(FILE *stream); |
765 | #endif |
766 | extern FILE *fdopen(int fildes, const char *type); |
767 | extern FILE *popen(const char *command, const char *type); |
768 | extern int pclose(FILE *stream); |
769 | #endif |
770 | |
771 | int FCGI_fileno(FCGI_FILE *fp) |
772 | { |
773 | if(fp->stdio_stream) |
774 | return fileno(fp->stdio_stream); |
775 | else |
776 | return -1; |
777 | } |
778 | |
779 | FCGI_FILE *FCGI_fdopen(int fd, const char *mode) |
780 | { |
781 | #ifndef _WIN32 |
782 | return FCGI_OpenFromFILE(fdopen(fd, mode)); |
783 | #else |
784 | return NULL; |
785 | #endif |
786 | } |
787 | |
788 | FCGI_FILE *FCGI_popen(const char *cmd, const char *type) |
789 | { |
790 | return FCGI_OpenFromFILE(popen(cmd, type)); |
791 | } |
792 | |
793 | int FCGI_pclose(FCGI_FILE *fp) |
794 | { |
795 | int n = EOF; |
796 | if(fp->stdio_stream) { |
797 | #ifndef _WIN32 |
798 | n = pclose(fp->stdio_stream); |
799 | #endif |
800 | fp->stdio_stream = NULL; |
801 | } else if(fp->fcgx_stream) { |
802 | /* |
803 | * The caller is deeply confused; don't free the storage. |
804 | */ |
805 | return EOF; |
806 | } |
807 | if((fp != FCGI_stdin) && (fp != FCGI_stdout) && (fp != FCGI_stderr)) { |
808 | free(fp); |
809 | } |
810 | return n; |
811 | } |
812 | |
813 | /* |
814 | *---------------------------------------------------------------------- |
815 | */ |