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