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