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