1/*
2 +----------------------------------------------------------------------+
3 | PHP Version 5 |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 1997-2015 The PHP Group |
6 +----------------------------------------------------------------------+
7 | This source file is subject to version 3.01 of the PHP license, |
8 | that is bundled with this package in the file LICENSE, and is |
9 | available through the world-wide-web at the following url: |
10 | http://www.php.net/license/3_01.txt |
11 | If you did not receive a copy of the PHP license and are unable to |
12 | obtain it through the world-wide-web, please send a note to |
13 | license@php.net so we can mail you a copy immediately. |
14 +----------------------------------------------------------------------+
15 | Author: Stig Sæther Bakken <ssb@php.net> |
16 +----------------------------------------------------------------------+
17 */
18
19/* $Id$ */
20
21#include <math.h> /* modf() */
22#include "php.h"
23#include "ext/standard/head.h"
24#include "php_string.h"
25#include "zend_execute.h"
26#include <stdio.h>
27
28#ifdef HAVE_LOCALE_H
29#include <locale.h>
30#ifdef ZTS
31#include "ext/standard/php_string.h"
32#define LCONV_DECIMAL_POINT (*lconv.decimal_point)
33#else
34#define LCONV_DECIMAL_POINT (*lconv->decimal_point)
35#endif
36#else
37#define LCONV_DECIMAL_POINT '.'
38#endif
39
40#define ALIGN_LEFT 0
41#define ALIGN_RIGHT 1
42#define ADJ_WIDTH 1
43#define ADJ_PRECISION 2
44#define NUM_BUF_SIZE 500
45#define FLOAT_PRECISION 6
46#define MAX_FLOAT_PRECISION 53
47
48#if 0
49/* trick to control varargs functions through cpp */
50# define PRINTF_DEBUG(arg) php_printf arg
51#else
52# define PRINTF_DEBUG(arg)
53#endif
54
55static char hexchars[] = "0123456789abcdef";
56static char HEXCHARS[] = "0123456789ABCDEF";
57
58/* php_spintf_appendchar() {{{ */
59inline static void
60php_sprintf_appendchar(char **buffer, int *pos, int *size, char add TSRMLS_DC)
61{
62 if ((*pos + 1) >= *size) {
63 *size <<= 1;
64 PRINTF_DEBUG(("%s(): ereallocing buffer to %d bytes\n", get_active_function_name(TSRMLS_C), *size));
65 *buffer = erealloc(*buffer, *size);
66 }
67 PRINTF_DEBUG(("sprintf: appending '%c', pos=\n", add, *pos));
68 (*buffer)[(*pos)++] = add;
69}
70/* }}} */
71
72/* php_spintf_appendstring() {{{ */
73inline static void
74php_sprintf_appendstring(char **buffer, int *pos, int *size, char *add,
75 int min_width, int max_width, char padding,
76 int alignment, int len, int neg, int expprec, int always_sign)
77{
78 register int npad;
79 int req_size;
80 int copy_len;
81 int m_width;
82
83 copy_len = (expprec ? MIN(max_width, len) : len);
84 npad = min_width - copy_len;
85
86 if (npad < 0) {
87 npad = 0;
88 }
89
90 PRINTF_DEBUG(("sprintf: appendstring(%x, %d, %d, \"%s\", %d, '%c', %d)\n",
91 *buffer, *pos, *size, add, min_width, padding, alignment));
92 m_width = MAX(min_width, copy_len);
93
94 if(m_width > INT_MAX - *pos - 1) {
95 zend_error_noreturn(E_ERROR, "Field width %d is too long", m_width);
96 }
97
98 req_size = *pos + m_width + 1;
99
100 if (req_size > *size) {
101 while (req_size > *size) {
102 if(*size > INT_MAX/2) {
103 zend_error_noreturn(E_ERROR, "Field width %d is too long", req_size);
104 }
105 *size <<= 1;
106 }
107 PRINTF_DEBUG(("sprintf ereallocing buffer to %d bytes\n", *size));
108 *buffer = erealloc(*buffer, *size);
109 }
110 if (alignment == ALIGN_RIGHT) {
111 if ((neg || always_sign) && padding=='0') {
112 (*buffer)[(*pos)++] = (neg) ? '-' : '+';
113 add++;
114 len--;
115 copy_len--;
116 }
117 while (npad-- > 0) {
118 (*buffer)[(*pos)++] = padding;
119 }
120 }
121 PRINTF_DEBUG(("sprintf: appending \"%s\"\n", add));
122 memcpy(&(*buffer)[*pos], add, copy_len + 1);
123 *pos += copy_len;
124 if (alignment == ALIGN_LEFT) {
125 while (npad--) {
126 (*buffer)[(*pos)++] = padding;
127 }
128 }
129}
130/* }}} */
131
132/* php_spintf_appendint() {{{ */
133inline static void
134php_sprintf_appendint(char **buffer, int *pos, int *size, long number,
135 int width, char padding, int alignment,
136 int always_sign)
137{
138 char numbuf[NUM_BUF_SIZE];
139 register unsigned long magn, nmagn;
140 register unsigned int i = NUM_BUF_SIZE - 1, neg = 0;
141
142 PRINTF_DEBUG(("sprintf: appendint(%x, %x, %x, %d, %d, '%c', %d)\n",
143 *buffer, pos, size, number, width, padding, alignment));
144 if (number < 0) {
145 neg = 1;
146 magn = ((unsigned long) -(number + 1)) + 1;
147 } else {
148 magn = (unsigned long) number;
149 }
150
151 /* Can't right-pad 0's on integers */
152 if(alignment==0 && padding=='0') padding=' ';
153
154 numbuf[i] = '\0';
155
156 do {
157 nmagn = magn / 10;
158
159 numbuf[--i] = (unsigned char)(magn - (nmagn * 10)) + '0';
160 magn = nmagn;
161 }
162 while (magn > 0 && i > 0);
163 if (neg) {
164 numbuf[--i] = '-';
165 } else if (always_sign) {
166 numbuf[--i] = '+';
167 }
168 PRINTF_DEBUG(("sprintf: appending %d as \"%s\", i=%d\n",
169 number, &numbuf[i], i));
170 php_sprintf_appendstring(buffer, pos, size, &numbuf[i], width, 0,
171 padding, alignment, (NUM_BUF_SIZE - 1) - i,
172 neg, 0, always_sign);
173}
174/* }}} */
175
176/* php_spintf_appenduint() {{{ */
177inline static void
178php_sprintf_appenduint(char **buffer, int *pos, int *size,
179 unsigned long number,
180 int width, char padding, int alignment)
181{
182 char numbuf[NUM_BUF_SIZE];
183 register unsigned long magn, nmagn;
184 register unsigned int i = NUM_BUF_SIZE - 1;
185
186 PRINTF_DEBUG(("sprintf: appenduint(%x, %x, %x, %d, %d, '%c', %d)\n",
187 *buffer, pos, size, number, width, padding, alignment));
188 magn = (unsigned long) number;
189
190 /* Can't right-pad 0's on integers */
191 if (alignment == 0 && padding == '0') padding = ' ';
192
193 numbuf[i] = '\0';
194
195 do {
196 nmagn = magn / 10;
197
198 numbuf[--i] = (unsigned char)(magn - (nmagn * 10)) + '0';
199 magn = nmagn;
200 } while (magn > 0 && i > 0);
201
202 PRINTF_DEBUG(("sprintf: appending %d as \"%s\", i=%d\n", number, &numbuf[i], i));
203 php_sprintf_appendstring(buffer, pos, size, &numbuf[i], width, 0,
204 padding, alignment, (NUM_BUF_SIZE - 1) - i, 0, 0, 0);
205}
206/* }}} */
207
208/* php_spintf_appenddouble() {{{ */
209inline static void
210php_sprintf_appenddouble(char **buffer, int *pos,
211 int *size, double number,
212 int width, char padding,
213 int alignment, int precision,
214 int adjust, char fmt,
215 int always_sign
216 TSRMLS_DC)
217{
218 char num_buf[NUM_BUF_SIZE];
219 char *s = NULL;
220 int s_len = 0, is_negative = 0;
221#ifdef HAVE_LOCALE_H
222#ifdef ZTS
223 struct lconv lconv;
224#else
225 struct lconv *lconv;
226#endif
227#endif
228
229 PRINTF_DEBUG(("sprintf: appenddouble(%x, %x, %x, %f, %d, '%c', %d, %c)\n",
230 *buffer, pos, size, number, width, padding, alignment, fmt));
231 if ((adjust & ADJ_PRECISION) == 0) {
232 precision = FLOAT_PRECISION;
233 } else if (precision > MAX_FLOAT_PRECISION) {
234 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Requested precision of %d digits was truncated to PHP maximum of %d digits", precision, MAX_FLOAT_PRECISION);
235 precision = MAX_FLOAT_PRECISION;
236 }
237
238 if (zend_isnan(number)) {
239 is_negative = (number<0);
240 php_sprintf_appendstring(buffer, pos, size, "NaN", 3, 0, padding,
241 alignment, 3, is_negative, 0, always_sign);
242 return;
243 }
244
245 if (zend_isinf(number)) {
246 is_negative = (number<0);
247 php_sprintf_appendstring(buffer, pos, size, "INF", 3, 0, padding,
248 alignment, 3, is_negative, 0, always_sign);
249 return;
250 }
251
252 switch (fmt) {
253 case 'e':
254 case 'E':
255 case 'f':
256 case 'F':
257#ifdef HAVE_LOCALE_H
258#ifdef ZTS
259 localeconv_r(&lconv);
260#else
261 lconv = localeconv();
262#endif
263#endif
264 s = php_conv_fp((fmt == 'f')?'F':fmt, number, 0, precision,
265 (fmt == 'f')?LCONV_DECIMAL_POINT:'.',
266 &is_negative, &num_buf[1], &s_len);
267 if (is_negative) {
268 num_buf[0] = '-';
269 s = num_buf;
270 s_len++;
271 } else if (always_sign) {
272 num_buf[0] = '+';
273 s = num_buf;
274 s_len++;
275 }
276 break;
277
278 case 'g':
279 case 'G':
280 if (precision == 0)
281 precision = 1;
282 /*
283 * * We use &num_buf[ 1 ], so that we have room for the sign
284 */
285#ifdef HAVE_LOCALE_H
286#ifdef ZTS
287 localeconv_r(&lconv);
288#else
289 lconv = localeconv();
290#endif
291#endif
292 s = php_gcvt(number, precision, LCONV_DECIMAL_POINT, (fmt == 'G')?'E':'e', &num_buf[1]);
293 is_negative = 0;
294 if (*s == '-') {
295 is_negative = 1;
296 s = &num_buf[1];
297 } else if (always_sign) {
298 num_buf[0] = '+';
299 s = num_buf;
300 }
301
302 s_len = strlen(s);
303 break;
304 }
305
306 php_sprintf_appendstring(buffer, pos, size, s, width, 0, padding,
307 alignment, s_len, is_negative, 0, always_sign);
308}
309/* }}} */
310
311/* php_spintf_appendd2n() {{{ */
312inline static void
313php_sprintf_append2n(char **buffer, int *pos, int *size, long number,
314 int width, char padding, int alignment, int n,
315 char *chartable, int expprec)
316{
317 char numbuf[NUM_BUF_SIZE];
318 register unsigned long num;
319 register unsigned int i = NUM_BUF_SIZE - 1;
320 register int andbits = (1 << n) - 1;
321
322 PRINTF_DEBUG(("sprintf: append2n(%x, %x, %x, %d, %d, '%c', %d, %d, %x)\n",
323 *buffer, pos, size, number, width, padding, alignment, n,
324 chartable));
325 PRINTF_DEBUG(("sprintf: append2n 2^%d andbits=%x\n", n, andbits));
326
327 num = (unsigned long) number;
328 numbuf[i] = '\0';
329
330 do {
331 numbuf[--i] = chartable[(num & andbits)];
332 num >>= n;
333 }
334 while (num > 0);
335
336 php_sprintf_appendstring(buffer, pos, size, &numbuf[i], width, 0,
337 padding, alignment, (NUM_BUF_SIZE - 1) - i,
338 0, expprec, 0);
339}
340/* }}} */
341
342/* php_spintf_getnumber() {{{ */
343inline static int
344php_sprintf_getnumber(char *buffer, int *pos)
345{
346 char *endptr;
347 register long num = strtol(&buffer[*pos], &endptr, 10);
348 register int i = 0;
349
350 if (endptr != NULL) {
351 i = (endptr - &buffer[*pos]);
352 }
353 PRINTF_DEBUG(("sprintf_getnumber: number was %d bytes long\n", i));
354 *pos += i;
355
356 if (num >= INT_MAX || num < 0) {
357 return -1;
358 } else {
359 return (int) num;
360 }
361}
362/* }}} */
363
364/* php_formatted_print() {{{
365 * New sprintf implementation for PHP.
366 *
367 * Modifiers:
368 *
369 * " " pad integers with spaces
370 * "-" left adjusted field
371 * n field size
372 * "."n precision (floats only)
373 * "+" Always place a sign (+ or -) in front of a number
374 *
375 * Type specifiers:
376 *
377 * "%" literal "%", modifiers are ignored.
378 * "b" integer argument is printed as binary
379 * "c" integer argument is printed as a single character
380 * "d" argument is an integer
381 * "f" the argument is a float
382 * "o" integer argument is printed as octal
383 * "s" argument is a string
384 * "x" integer argument is printed as lowercase hexadecimal
385 * "X" integer argument is printed as uppercase hexadecimal
386 *
387 */
388static char *
389php_formatted_print(int ht, int *len, int use_array, int format_offset TSRMLS_DC)
390{
391 zval ***args, **z_format;
392 int argc, size = 240, inpos = 0, outpos = 0, temppos;
393 int alignment, currarg, adjusting, argnum, width, precision;
394 char *format, *result, padding;
395 int always_sign;
396 int format_len;
397
398 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "+", &args, &argc) == FAILURE) {
399 return NULL;
400 }
401
402 /* verify the number of args */
403 if ((use_array && argc != (2 + format_offset))
404 || (!use_array && argc < (1 + format_offset))) {
405 efree(args);
406 WRONG_PARAM_COUNT_WITH_RETVAL(NULL);
407 }
408
409 if (use_array) {
410 int i = 1;
411 zval ***newargs;
412 zval **array;
413
414 z_format = args[format_offset];
415 array = args[1 + format_offset];
416
417 SEPARATE_ZVAL(array);
418 convert_to_array_ex(array);
419
420 argc = 1 + zend_hash_num_elements(Z_ARRVAL_PP(array));
421 newargs = (zval ***)safe_emalloc(argc, sizeof(zval *), 0);
422 newargs[0] = z_format;
423
424 for (zend_hash_internal_pointer_reset(Z_ARRVAL_PP(array));
425 zend_hash_get_current_data(Z_ARRVAL_PP(array), (void **)&newargs[i++]) == SUCCESS;
426 zend_hash_move_forward(Z_ARRVAL_PP(array)));
427
428 efree(args);
429 args = newargs;
430 format_offset = 0;
431 }
432
433 convert_to_string_ex(args[format_offset]);
434 format = Z_STRVAL_PP(args[format_offset]);
435 format_len = Z_STRLEN_PP(args[format_offset]);
436 result = emalloc(size);
437
438 currarg = 1;
439
440 while (inpos<format_len) {
441 int expprec = 0, multiuse = 0;
442 zval *tmp;
443
444 PRINTF_DEBUG(("sprintf: format[%d]='%c'\n", inpos, format[inpos]));
445 PRINTF_DEBUG(("sprintf: outpos=%d\n", outpos));
446 if (format[inpos] != '%') {
447 php_sprintf_appendchar(&result, &outpos, &size, format[inpos++] TSRMLS_CC);
448 } else if (format[inpos + 1] == '%') {
449 php_sprintf_appendchar(&result, &outpos, &size, '%' TSRMLS_CC);
450 inpos += 2;
451 } else {
452 /* starting a new format specifier, reset variables */
453 alignment = ALIGN_RIGHT;
454 adjusting = 0;
455 padding = ' ';
456 always_sign = 0;
457 inpos++; /* skip the '%' */
458
459 PRINTF_DEBUG(("sprintf: first looking at '%c', inpos=%d\n",
460 format[inpos], inpos));
461 if (isascii((int)format[inpos]) && !isalpha((int)format[inpos])) {
462 /* first look for argnum */
463 temppos = inpos;
464 while (isdigit((int)format[temppos])) temppos++;
465 if (format[temppos] == '$') {
466 argnum = php_sprintf_getnumber(format, &inpos);
467
468 if (argnum <= 0) {
469 efree(result);
470 efree(args);
471 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Argument number must be greater than zero");
472 return NULL;
473 }
474
475 multiuse = 1;
476 inpos++; /* skip the '$' */
477 } else {
478 argnum = currarg++;
479 }
480
481 argnum += format_offset;
482
483 /* after argnum comes modifiers */
484 PRINTF_DEBUG(("sprintf: looking for modifiers\n"
485 "sprintf: now looking at '%c', inpos=%d\n",
486 format[inpos], inpos));
487 for (;; inpos++) {
488 if (format[inpos] == ' ' || format[inpos] == '0') {
489 padding = format[inpos];
490 } else if (format[inpos] == '-') {
491 alignment = ALIGN_LEFT;
492 /* space padding, the default */
493 } else if (format[inpos] == '+') {
494 always_sign = 1;
495 } else if (format[inpos] == '\'' && inpos+1<format_len) {
496 padding = format[++inpos];
497 } else {
498 PRINTF_DEBUG(("sprintf: end of modifiers\n"));
499 break;
500 }
501 }
502 PRINTF_DEBUG(("sprintf: padding='%c'\n", padding));
503 PRINTF_DEBUG(("sprintf: alignment=%s\n",
504 (alignment == ALIGN_LEFT) ? "left" : "right"));
505
506
507 /* after modifiers comes width */
508 if (isdigit((int)format[inpos])) {
509 PRINTF_DEBUG(("sprintf: getting width\n"));
510 if ((width = php_sprintf_getnumber(format, &inpos)) < 0) {
511 efree(result);
512 efree(args);
513 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Width must be greater than zero and less than %d", INT_MAX);
514 return NULL;
515 }
516 adjusting |= ADJ_WIDTH;
517 } else {
518 width = 0;
519 }
520 PRINTF_DEBUG(("sprintf: width=%d\n", width));
521
522 /* after width and argnum comes precision */
523 if (format[inpos] == '.') {
524 inpos++;
525 PRINTF_DEBUG(("sprintf: getting precision\n"));
526 if (isdigit((int)format[inpos])) {
527 if ((precision = php_sprintf_getnumber(format, &inpos)) < 0) {
528 efree(result);
529 efree(args);
530 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Precision must be greater than zero and less than %d", INT_MAX);
531 return NULL;
532 }
533 adjusting |= ADJ_PRECISION;
534 expprec = 1;
535 } else {
536 precision = 0;
537 }
538 } else {
539 precision = 0;
540 }
541 PRINTF_DEBUG(("sprintf: precision=%d\n", precision));
542 } else {
543 width = precision = 0;
544 argnum = currarg++ + format_offset;
545 }
546
547 if (argnum >= argc) {
548 efree(result);
549 efree(args);
550 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Too few arguments");
551 return NULL;
552 }
553
554 if (format[inpos] == 'l') {
555 inpos++;
556 }
557 PRINTF_DEBUG(("sprintf: format character='%c'\n", format[inpos]));
558 /* now we expect to find a type specifier */
559 if (multiuse) {
560 MAKE_STD_ZVAL(tmp);
561 *tmp = **(args[argnum]);
562 INIT_PZVAL(tmp);
563 zval_copy_ctor(tmp);
564 } else {
565 SEPARATE_ZVAL(args[argnum]);
566 tmp = *(args[argnum]);
567 }
568
569 switch (format[inpos]) {
570 case 's': {
571 zval *var, var_copy;
572 int use_copy;
573
574 zend_make_printable_zval(tmp, &var_copy, &use_copy);
575 if (use_copy) {
576 var = &var_copy;
577 } else {
578 var = tmp;
579 }
580 php_sprintf_appendstring(&result, &outpos, &size,
581 Z_STRVAL_P(var),
582 width, precision, padding,
583 alignment,
584 Z_STRLEN_P(var),
585 0, expprec, 0);
586 if (use_copy) {
587 zval_dtor(&var_copy);
588 }
589 break;
590 }
591
592 case 'd':
593 convert_to_long(tmp);
594 php_sprintf_appendint(&result, &outpos, &size,
595 Z_LVAL_P(tmp),
596 width, padding, alignment,
597 always_sign);
598 break;
599
600 case 'u':
601 convert_to_long(tmp);
602 php_sprintf_appenduint(&result, &outpos, &size,
603 Z_LVAL_P(tmp),
604 width, padding, alignment);
605 break;
606
607 case 'g':
608 case 'G':
609 case 'e':
610 case 'E':
611 case 'f':
612 case 'F':
613 convert_to_double(tmp);
614 php_sprintf_appenddouble(&result, &outpos, &size,
615 Z_DVAL_P(tmp),
616 width, padding, alignment,
617 precision, adjusting,
618 format[inpos], always_sign
619 TSRMLS_CC);
620 break;
621
622 case 'c':
623 convert_to_long(tmp);
624 php_sprintf_appendchar(&result, &outpos, &size,
625 (char) Z_LVAL_P(tmp) TSRMLS_CC);
626 break;
627
628 case 'o':
629 convert_to_long(tmp);
630 php_sprintf_append2n(&result, &outpos, &size,
631 Z_LVAL_P(tmp),
632 width, padding, alignment, 3,
633 hexchars, expprec);
634 break;
635
636 case 'x':
637 convert_to_long(tmp);
638 php_sprintf_append2n(&result, &outpos, &size,
639 Z_LVAL_P(tmp),
640 width, padding, alignment, 4,
641 hexchars, expprec);
642 break;
643
644 case 'X':
645 convert_to_long(tmp);
646 php_sprintf_append2n(&result, &outpos, &size,
647 Z_LVAL_P(tmp),
648 width, padding, alignment, 4,
649 HEXCHARS, expprec);
650 break;
651
652 case 'b':
653 convert_to_long(tmp);
654 php_sprintf_append2n(&result, &outpos, &size,
655 Z_LVAL_P(tmp),
656 width, padding, alignment, 1,
657 hexchars, expprec);
658 break;
659
660 case '%':
661 php_sprintf_appendchar(&result, &outpos, &size, '%' TSRMLS_CC);
662
663 break;
664 default:
665 break;
666 }
667 if (multiuse) {
668 zval_ptr_dtor(&tmp);
669 }
670 inpos++;
671 }
672 }
673
674 efree(args);
675
676 /* possibly, we have to make sure we have room for the terminating null? */
677 result[outpos]=0;
678 *len = outpos;
679 return result;
680}
681/* }}} */
682
683/* {{{ proto string sprintf(string format [, mixed arg1 [, mixed ...]])
684 Return a formatted string */
685PHP_FUNCTION(user_sprintf)
686{
687 char *result;
688 int len;
689
690 if ((result=php_formatted_print(ht, &len, 0, 0 TSRMLS_CC))==NULL) {
691 RETURN_FALSE;
692 }
693 RETVAL_STRINGL(result, len, 0);
694}
695/* }}} */
696
697/* {{{ proto string vsprintf(string format, array args)
698 Return a formatted string */
699PHP_FUNCTION(vsprintf)
700{
701 char *result;
702 int len;
703
704 if ((result=php_formatted_print(ht, &len, 1, 0 TSRMLS_CC))==NULL) {
705 RETURN_FALSE;
706 }
707 RETVAL_STRINGL(result, len, 0);
708}
709/* }}} */
710
711/* {{{ proto int printf(string format [, mixed arg1 [, mixed ...]])
712 Output a formatted string */
713PHP_FUNCTION(user_printf)
714{
715 char *result;
716 int len, rlen;
717
718 if ((result=php_formatted_print(ht, &len, 0, 0 TSRMLS_CC))==NULL) {
719 RETURN_FALSE;
720 }
721 rlen = PHPWRITE(result, len);
722 efree(result);
723 RETURN_LONG(rlen);
724}
725/* }}} */
726
727/* {{{ proto int vprintf(string format, array args)
728 Output a formatted string */
729PHP_FUNCTION(vprintf)
730{
731 char *result;
732 int len, rlen;
733
734 if ((result=php_formatted_print(ht, &len, 1, 0 TSRMLS_CC))==NULL) {
735 RETURN_FALSE;
736 }
737 rlen = PHPWRITE(result, len);
738 efree(result);
739 RETURN_LONG(rlen);
740}
741/* }}} */
742
743/* {{{ proto int fprintf(resource stream, string format [, mixed arg1 [, mixed ...]])
744 Output a formatted string into a stream */
745PHP_FUNCTION(fprintf)
746{
747 php_stream *stream;
748 zval *arg1;
749 char *result;
750 int len;
751
752 if (ZEND_NUM_ARGS() < 2) {
753 WRONG_PARAM_COUNT;
754 }
755
756 if (zend_parse_parameters(1 TSRMLS_CC, "r", &arg1) == FAILURE) {
757 RETURN_FALSE;
758 }
759
760 php_stream_from_zval(stream, &arg1);
761
762 if ((result=php_formatted_print(ht, &len, 0, 1 TSRMLS_CC))==NULL) {
763 RETURN_FALSE;
764 }
765
766 php_stream_write(stream, result, len);
767
768 efree(result);
769
770 RETURN_LONG(len);
771}
772/* }}} */
773
774/* {{{ proto int vfprintf(resource stream, string format, array args)
775 Output a formatted string into a stream */
776PHP_FUNCTION(vfprintf)
777{
778 php_stream *stream;
779 zval *arg1;
780 char *result;
781 int len;
782
783 if (ZEND_NUM_ARGS() != 3) {
784 WRONG_PARAM_COUNT;
785 }
786
787 if (zend_parse_parameters(1 TSRMLS_CC, "r", &arg1) == FAILURE) {
788 RETURN_FALSE;
789 }
790
791 php_stream_from_zval(stream, &arg1);
792
793 if ((result=php_formatted_print(ht, &len, 1, 1 TSRMLS_CC))==NULL) {
794 RETURN_FALSE;
795 }
796
797 php_stream_write(stream, result, len);
798
799 efree(result);
800
801 RETURN_LONG(len);
802}
803/* }}} */
804
805/*
806 * Local variables:
807 * tab-width: 4
808 * c-basic-offset: 4
809 * End:
810 * vim600: sw=4 ts=4 fdm=marker
811 * vim<600: sw=4 ts=4
812 */
813