Commit | Line | Data |
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 |
d90c9248 |
15 | static 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 | |
43 | extern char **environ; |
44 | |
d90c9248 |
45 | #ifdef HAVE_FILENO_PROTO |
46 | #include <stdio.h> |
47 | #else |
6ad90ad2 |
48 | extern int fileno(FILE *stream); |
49 | #endif |
50 | |
51 | extern FILE *fdopen(int fildes, const char *type); |
52 | extern FILE *popen(const char *command, const char *type); |
53 | extern 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 | FCGI_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 | */ |
110 | static int acceptCalled = FALSE; |
111 | static int isCGI = FALSE; |
0198fd3c |
112 | |
113 | int 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 | */ |
180 | void 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 |
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 | } |
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 |
233 | void 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 |
249 | void 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 |
270 | static 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 |
296 | FCGI_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 | |
307 | int 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 | |
323 | int 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 | |
334 | FCGI_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 | */ |
364 | int 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 | |
373 | void 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 |
388 | int 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 | |
398 | int 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 | |
408 | void 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 |
417 | int 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 | |
427 | int 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 |
450 | int 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 | |
459 | int FCGI_getchar(void) |
460 | { |
461 | return FCGI_fgetc(FCGI_stdin); |
462 | } |
463 | |
464 | int 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 |
482 | char *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 |
497 | char *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 |
537 | int 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 | |
546 | int 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 |
560 | int 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 | |
569 | int 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 |
597 | int 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 | |
610 | int 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 |
629 | int 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 | |
638 | int 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 |
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 | } |
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 | */ |
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 | } |
4673bf04 |
725 | |
17abbc3a |
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 | { |
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 |
755 | int FCGI_fileno(FCGI_FILE *fp) |
756 | { |
757 | if(fp->stdio_stream) |
758 | return fileno(fp->stdio_stream); |
759 | else |
760 | return -1; |
761 | } |
762 | |
763 | FCGI_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 | |
774 | FCGI_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 | |
785 | int 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 | } |