php-internal-docs 8.4.8
Unofficial docs for php/php-src
Loading...
Searching...
No Matches
formatted_print.c
Go to the documentation of this file.
1/*
2 +----------------------------------------------------------------------+
3 | Copyright (c) The PHP Group |
4 +----------------------------------------------------------------------+
5 | This source file is subject to version 3.01 of the PHP license, |
6 | that is bundled with this package in the file LICENSE, and is |
7 | available through the world-wide-web at the following url: |
8 | https://www.php.net/license/3_01.txt |
9 | If you did not receive a copy of the PHP license and are unable to |
10 | obtain it through the world-wide-web, please send a note to |
11 | license@php.net so we can mail you a copy immediately. |
12 +----------------------------------------------------------------------+
13 | Author: Stig S�ther Bakken <ssb@php.net> |
14 +----------------------------------------------------------------------+
15 */
16
17#include <math.h> /* modf() */
18#include "php.h"
19#include "zend_execute.h"
20
21#include <locale.h>
22#ifdef ZTS
23#include "ext/standard/php_string.h" /* for localeconv_r() */
24#define LCONV_DECIMAL_POINT (*lconv.decimal_point)
25#else
26#define LCONV_DECIMAL_POINT (*lconv->decimal_point)
27#endif
28
29#define ALIGN_LEFT 0
30#define ALIGN_RIGHT 1
31#define ADJ_WIDTH 1
32#define ADJ_PRECISION 2
33#define NUM_BUF_SIZE 500
34#define FLOAT_PRECISION 6
35#define MAX_FLOAT_PRECISION 53
36
37#if 0
38/* trick to control varargs functions through cpp */
39# define PRINTF_DEBUG(arg) php_printf arg
40#else
41# define PRINTF_DEBUG(arg)
42#endif
43
44static const char hexchars[] = "0123456789abcdef";
45static const char HEXCHARS[] = "0123456789ABCDEF";
46
47/* php_spintf_appendchar() {{{ */
48inline static void
49php_sprintf_appendchar(zend_string **buffer, size_t *pos, char add)
50{
51 if ((*pos + 1) >= ZSTR_LEN(*buffer)) {
52 PRINTF_DEBUG(("%s(): ereallocing buffer to %d bytes\n", get_active_function_name(), ZSTR_LEN(*buffer)));
53 *buffer = zend_string_extend(*buffer, ZSTR_LEN(*buffer) << 1, 0);
54 }
55 PRINTF_DEBUG(("sprintf: appending '%c', pos=\n", add, *pos));
56 ZSTR_VAL(*buffer)[(*pos)++] = add;
57}
58/* }}} */
59
60/* php_spintf_appendchar() {{{ */
61inline static void
62php_sprintf_appendchars(zend_string **buffer, size_t *pos, char *add, size_t len)
63{
64 if ((*pos + len) >= ZSTR_LEN(*buffer)) {
65 size_t nlen = ZSTR_LEN(*buffer);
66
67 PRINTF_DEBUG(("%s(): ereallocing buffer to %d bytes\n", get_active_function_name(), ZSTR_LEN(*buffer)));
68 do {
69 nlen = nlen << 1;
70 } while ((*pos + len) >= nlen);
71 *buffer = zend_string_extend(*buffer, nlen, 0);
72 }
73 PRINTF_DEBUG(("sprintf: appending \"%s\", pos=\n", add, *pos));
74 memcpy(ZSTR_VAL(*buffer) + (*pos), add, len);
75 *pos += len;
76}
77/* }}} */
78
79/* php_spintf_appendstring() {{{ */
80inline static void
81php_sprintf_appendstring(zend_string **buffer, size_t *pos, char *add,
82 size_t min_width, size_t max_width, char padding,
83 size_t alignment, size_t len, bool neg, int expprec, int always_sign)
84{
85 size_t npad;
86 size_t req_size;
87 size_t copy_len;
88 size_t m_width;
89
90 copy_len = (expprec ? MIN(max_width, len) : len);
91 npad = (min_width < copy_len) ? 0 : min_width - copy_len;
92
93 PRINTF_DEBUG(("sprintf: appendstring(%x, %d, %d, \"%s\", %d, '%c', %d)\n",
94 *buffer, *pos, ZSTR_LEN(*buffer), add, min_width, padding, alignment));
95 m_width = MAX(min_width, copy_len);
96
97 if(m_width > INT_MAX - *pos - 1) {
98 zend_error_noreturn(E_ERROR, "Field width %zd is too long", m_width);
99 }
100
101 req_size = *pos + m_width + 1;
102
103 if (req_size > ZSTR_LEN(*buffer)) {
104 size_t size = ZSTR_LEN(*buffer);
105 while (req_size > size) {
106 if (size > ZEND_SIZE_MAX/2) {
107 zend_error_noreturn(E_ERROR, "Field width %zd is too long", req_size);
108 }
109 size <<= 1;
110 }
111 PRINTF_DEBUG(("sprintf ereallocing buffer to %d bytes\n", size));
112 *buffer = zend_string_extend(*buffer, size, 0);
113 }
114 if (alignment == ALIGN_RIGHT) {
115 if ((neg || always_sign) && padding=='0') {
116 ZSTR_VAL(*buffer)[(*pos)++] = (neg) ? '-' : '+';
117 add++;
118 len--;
119 copy_len--;
120 }
121 while (npad-- > 0) {
122 ZSTR_VAL(*buffer)[(*pos)++] = padding;
123 }
124 }
125 PRINTF_DEBUG(("sprintf: appending \"%s\"\n", add));
126 memcpy(&ZSTR_VAL(*buffer)[*pos], add, copy_len + 1);
127 *pos += copy_len;
128 if (alignment == ALIGN_LEFT) {
129 while (npad--) {
130 ZSTR_VAL(*buffer)[(*pos)++] = padding;
131 }
132 }
133}
134/* }}} */
135
136/* php_spintf_appendint() {{{ */
137inline static void
138php_sprintf_appendint(zend_string **buffer, size_t *pos, zend_long number,
139 size_t width, char padding, size_t alignment,
140 int always_sign)
141{
142 char numbuf[NUM_BUF_SIZE];
143 zend_ulong magn, nmagn;
144 unsigned int i = NUM_BUF_SIZE - 1, neg = 0;
145
146 PRINTF_DEBUG(("sprintf: appendint(%x, %x, %x, %d, %d, '%c', %d)\n",
147 *buffer, pos, &ZSTR_LEN(*buffer), number, width, padding, alignment));
148 if (number < 0) {
149 neg = 1;
150 magn = ((zend_ulong) -(number + 1)) + 1;
151 } else {
152 magn = (zend_ulong) number;
153 }
154
155 /* Can't right-pad 0's on integers */
156 if(alignment==0 && padding=='0') padding=' ';
157
158 numbuf[i] = '\0';
159
160 do {
161 nmagn = magn / 10;
162
163 numbuf[--i] = (unsigned char)(magn - (nmagn * 10)) + '0';
164 magn = nmagn;
165 }
166 while (magn > 0 && i > 1);
167 if (neg) {
168 numbuf[--i] = '-';
169 } else if (always_sign) {
170 numbuf[--i] = '+';
171 }
172 PRINTF_DEBUG(("sprintf: appending %d as \"%s\", i=%d\n",
173 number, &numbuf[i], i));
174 php_sprintf_appendstring(buffer, pos, &numbuf[i], width, 0,
175 padding, alignment, (NUM_BUF_SIZE - 1) - i,
176 neg, 0, always_sign);
177}
178/* }}} */
179
180/* php_spintf_appenduint() {{{ */
181inline static void
182php_sprintf_appenduint(zend_string **buffer, size_t *pos,
183 zend_ulong number,
184 size_t width, char padding, size_t alignment)
185{
186 char numbuf[NUM_BUF_SIZE];
187 zend_ulong magn, nmagn;
188 unsigned int i = NUM_BUF_SIZE - 1;
189
190 PRINTF_DEBUG(("sprintf: appenduint(%x, %x, %x, %d, %d, '%c', %d)\n",
191 *buffer, pos, &ZSTR_LEN(*buffer), number, width, padding, alignment));
192 magn = (zend_ulong) number;
193
194 /* Can't right-pad 0's on integers */
195 if (alignment == 0 && padding == '0') padding = ' ';
196
197 numbuf[i] = '\0';
198
199 do {
200 nmagn = magn / 10;
201
202 numbuf[--i] = (unsigned char)(magn - (nmagn * 10)) + '0';
203 magn = nmagn;
204 } while (magn > 0 && i > 0);
205
206 PRINTF_DEBUG(("sprintf: appending %d as \"%s\", i=%d\n", number, &numbuf[i], i));
207 php_sprintf_appendstring(buffer, pos, &numbuf[i], width, 0,
208 padding, alignment, (NUM_BUF_SIZE - 1) - i, /* neg */ false, 0, 0);
209}
210/* }}} */
211
212/* php_spintf_appenddouble() {{{ */
213inline static void
214php_sprintf_appenddouble(zend_string **buffer, size_t *pos,
215 double number,
216 size_t width, char padding,
217 size_t alignment, int precision,
218 int adjust, char fmt,
219 int always_sign
220 )
221{
222 char num_buf[NUM_BUF_SIZE];
223 char *s = NULL;
224 size_t s_len = 0;
225 bool is_negative = false;
226#ifdef ZTS
227 struct lconv lconv;
228#else
229 struct lconv *lconv;
230#endif
231
232 PRINTF_DEBUG(("sprintf: appenddouble(%x, %x, %x, %f, %d, '%c', %d, %c)\n",
233 *buffer, pos, &ZSTR_LEN(*buffer), number, width, padding, alignment, fmt));
234 if ((adjust & ADJ_PRECISION) == 0) {
235 precision = FLOAT_PRECISION;
236 } else if (precision > MAX_FLOAT_PRECISION) {
237 php_error_docref(NULL, E_NOTICE, "Requested precision of %d digits was truncated to PHP maximum of %d digits", precision, MAX_FLOAT_PRECISION);
238 precision = MAX_FLOAT_PRECISION;
239 }
240
241 if (zend_isnan(number)) {
242 is_negative = (number<0);
243 php_sprintf_appendstring(buffer, pos, "NaN", 3, 0, padding,
244 alignment, 3, is_negative, 0, always_sign);
245 return;
246 }
247
248 if (zend_isinf(number)) {
249 is_negative = (number<0);
250 char *str = is_negative ? "-INF" : "INF";
251 php_sprintf_appendstring(buffer, pos, str, strlen(str), 0, padding,
252 alignment, strlen(str), is_negative, 0, always_sign);
253 return;
254 }
255
256 switch (fmt) {
257 case 'e':
258 case 'E':
259 case 'f':
260 case 'F':
261#ifdef ZTS
262 localeconv_r(&lconv);
263#else
264 lconv = localeconv();
265#endif
266 s = php_conv_fp((fmt == 'f')?'F':fmt, number, 0, precision,
267 (fmt == 'f')?LCONV_DECIMAL_POINT:'.',
268 &is_negative, &num_buf[1], &s_len);
269 if (is_negative) {
270 num_buf[0] = '-';
271 s = num_buf;
272 s_len++;
273 } else if (always_sign) {
274 num_buf[0] = '+';
275 s = num_buf;
276 s_len++;
277 }
278 break;
279
280 case 'g':
281 case 'G':
282 case 'h':
283 case 'H':
284 {
285 if (precision == 0)
286 precision = 1;
287
288 char decimal_point = '.';
289 if (fmt == 'g' || fmt == 'G') {
290#ifdef ZTS
291 localeconv_r(&lconv);
292#else
293 lconv = localeconv();
294#endif
295 decimal_point = LCONV_DECIMAL_POINT;
296 }
297
298 char exp_char = fmt == 'G' || fmt == 'H' ? 'E' : 'e';
299 /* We use &num_buf[ 1 ], so that we have room for the sign. */
300 s = zend_gcvt(number, precision, decimal_point, exp_char, &num_buf[1]);
301 is_negative = 0;
302 if (*s == '-') {
303 is_negative = 1;
304 s = &num_buf[1];
305 } else if (always_sign) {
306 num_buf[0] = '+';
307 s = num_buf;
308 }
309
310 s_len = strlen(s);
311 break;
312 }
313 }
314
315 php_sprintf_appendstring(buffer, pos, s, width, 0, padding,
316 alignment, s_len, is_negative, 0, always_sign);
317}
318/* }}} */
319
320/* php_spintf_appendd2n() {{{ */
321inline static void
322php_sprintf_append2n(zend_string **buffer, size_t *pos, zend_long number,
323 size_t width, char padding, size_t alignment, int n,
324 const char *chartable, int expprec)
325{
326 char numbuf[NUM_BUF_SIZE];
327 zend_ulong num;
328 zend_ulong i = NUM_BUF_SIZE - 1;
329 int andbits = (1 << n) - 1;
330
331 PRINTF_DEBUG(("sprintf: append2n(%x, %x, %x, %d, %d, '%c', %d, %d, %x)\n",
332 *buffer, pos, &ZSTR_LEN(*buffer), number, width, padding, alignment, n,
333 chartable));
334 PRINTF_DEBUG(("sprintf: append2n 2^%d andbits=%x\n", n, andbits));
335
336 num = (zend_ulong) number;
337 numbuf[i] = '\0';
338
339 do {
340 numbuf[--i] = chartable[(num & andbits)];
341 num >>= n;
342 }
343 while (num > 0);
344
345 php_sprintf_appendstring(buffer, pos, &numbuf[i], width, 0,
346 padding, alignment, (NUM_BUF_SIZE - 1) - i,
347 /* neg */ false, expprec, 0);
348}
349/* }}} */
350
351/* php_spintf_getnumber() {{{ */
352inline static int
353php_sprintf_getnumber(char **buffer, size_t *len)
354{
355 char *endptr;
356 zend_long num = ZEND_STRTOL(*buffer, &endptr, 10);
357 size_t i;
358
359 if (endptr != NULL) {
360 i = (endptr - *buffer);
361 *len -= i;
362 *buffer = endptr;
363 }
364 PRINTF_DEBUG(("sprintf_getnumber: number was %d bytes long\n", i));
365
366 if (num >= INT_MAX || num < 0) {
367 return -1;
368 } else {
369 return (int) num;
370 }
371}
372/* }}} */
373
374#define ARG_NUM_NEXT -1
375#define ARG_NUM_INVALID -2
376
377int php_sprintf_get_argnum(char **format, size_t *format_len) {
378 char *temppos = *format;
379 while (isdigit((int) *temppos)) temppos++;
380 if (*temppos != '$') {
381 return ARG_NUM_NEXT;
382 }
383
384 int argnum = php_sprintf_getnumber(format, format_len);
385 if (argnum <= 0) {
386 zend_value_error("Argument number specifier must be greater than zero and less than %d", INT_MAX);
387 return ARG_NUM_INVALID;
388 }
389
390 (*format)++; /* skip the '$' */
391 (*format_len)--;
392 return argnum - 1;
393}
394
395/* php_formatted_print() {{{
396 * New sprintf implementation for PHP.
397 *
398 * Modifiers:
399 *
400 * " " pad integers with spaces
401 * "-" left adjusted field
402 * n field size
403 * "."n precision (floats only)
404 * "+" Always place a sign (+ or -) in front of a number
405 *
406 * Type specifiers:
407 *
408 * "%" literal "%", modifiers are ignored.
409 * "b" integer argument is printed as binary
410 * "c" integer argument is printed as a single character
411 * "d" argument is an integer
412 * "f" the argument is a float
413 * "o" integer argument is printed as octal
414 * "s" argument is a string
415 * "x" integer argument is printed as lowercase hexadecimal
416 * "X" integer argument is printed as uppercase hexadecimal
417 *
418 * nb_additional_parameters is used for throwing errors:
419 * - -1: ValueError is thrown (for vsprintf where args originates from an array)
420 * - 0 or more: ArgumentCountError is thrown
421 */
422static zend_string *
423php_formatted_print(char *format, size_t format_len, zval *args, int argc, int nb_additional_parameters)
424{
425 size_t size = 240, outpos = 0;
426 int alignment, currarg, adjusting, argnum, width, precision;
427 char *temppos, padding;
429 int always_sign;
430 int max_missing_argnum = -1;
431
432 result = zend_string_alloc(size, 0);
433
434 currarg = 0;
435 argnum = 0;
436
437 while (format_len) {
438 int expprec;
439 zval *tmp;
440
441 temppos = memchr(format, '%', format_len);
442 if (!temppos) {
443 php_sprintf_appendchars(&result, &outpos, format, format_len);
444 break;
445 } else if (temppos != format) {
446 php_sprintf_appendchars(&result, &outpos, format, temppos - format);
447 format_len -= temppos - format;
448 format = temppos;
449 }
450 format++; /* skip the '%' */
451 format_len--;
452
453 if (*format == '%') {
454 php_sprintf_appendchar(&result, &outpos, '%');
455 format++;
456 format_len--;
457 } else {
458 /* starting a new format specifier, reset variables */
459 alignment = ALIGN_RIGHT;
460 adjusting = 0;
461 padding = ' ';
462 always_sign = 0;
463 expprec = 0;
464
465 PRINTF_DEBUG(("sprintf: first looking at '%c', inpos=%d\n",
466 *format, format - Z_STRVAL_P(z_format)));
467 if (isalpha((int)*format)) {
468 width = precision = 0;
469 argnum = ARG_NUM_NEXT;
470 } else {
471 /* first look for argnum */
472 argnum = php_sprintf_get_argnum(&format, &format_len);
473 if (argnum == ARG_NUM_INVALID) {
474 goto fail;
475 }
476
477 /* after argnum comes modifiers */
478 PRINTF_DEBUG(("sprintf: looking for modifiers\n"
479 "sprintf: now looking at '%c', inpos=%d\n",
480 *format, format - Z_STRVAL_P(z_format)));
481 for (;; format++, format_len--) {
482 if (*format == ' ' || *format == '0') {
483 padding = *format;
484 } else if (*format == '-') {
485 alignment = ALIGN_LEFT;
486 /* space padding, the default */
487 } else if (*format == '+') {
488 always_sign = 1;
489 } else if (*format == '\'') {
490 if (format_len > 1) {
491 format++;
492 format_len--;
493 padding = *format;
494 } else {
495 zend_value_error("Missing padding character");
496 goto fail;
497 }
498 } else {
499 PRINTF_DEBUG(("sprintf: end of modifiers\n"));
500 break;
501 }
502 }
503 PRINTF_DEBUG(("sprintf: padding='%c'\n", padding));
504 PRINTF_DEBUG(("sprintf: alignment=%s\n",
505 (alignment == ALIGN_LEFT) ? "left" : "right"));
506
507
508 /* after modifiers comes width */
509 if (*format == '*') {
510 format++;
511 format_len--;
512
513 int width_argnum = php_sprintf_get_argnum(&format, &format_len);
514 if (width_argnum == ARG_NUM_INVALID) {
515 goto fail;
516 }
517 if (width_argnum == ARG_NUM_NEXT) {
518 width_argnum = currarg++;
519 }
520 if (width_argnum >= argc) {
521 max_missing_argnum = MAX(max_missing_argnum, width_argnum);
522 continue;
523 }
524 tmp = &args[width_argnum];
525 ZVAL_DEREF(tmp);
526 if (Z_TYPE_P(tmp) != IS_LONG) {
527 zend_value_error("Width must be an integer");
528 goto fail;
529 }
530 if (Z_LVAL_P(tmp) < 0 || Z_LVAL_P(tmp) > INT_MAX) {
531 zend_value_error("Width must be greater than zero and less than %d", INT_MAX);
532 goto fail;
533 }
534 width = Z_LVAL_P(tmp);
535 adjusting |= ADJ_WIDTH;
536 } else if (isdigit((int)*format)) {
537 PRINTF_DEBUG(("sprintf: getting width\n"));
538 if ((width = php_sprintf_getnumber(&format, &format_len)) < 0) {
539 zend_value_error("Width must be greater than zero and less than %d", INT_MAX);
540 goto fail;
541 }
542 adjusting |= ADJ_WIDTH;
543 } else {
544 width = 0;
545 }
546 PRINTF_DEBUG(("sprintf: width=%d\n", width));
547
548 /* after width and argnum comes precision */
549 if (*format == '.') {
550 format++;
551 format_len--;
552 PRINTF_DEBUG(("sprintf: getting precision\n"));
553 if (*format == '*') {
554 format++;
555 format_len--;
556
557 int prec_argnum = php_sprintf_get_argnum(&format, &format_len);
558 if (prec_argnum == ARG_NUM_INVALID) {
559 goto fail;
560 }
561 if (prec_argnum == ARG_NUM_NEXT) {
562 prec_argnum = currarg++;
563 }
564 if (prec_argnum >= argc) {
565 max_missing_argnum = MAX(max_missing_argnum, prec_argnum);
566 continue;
567 }
568 tmp = &args[prec_argnum];
569 ZVAL_DEREF(tmp);
570 if (Z_TYPE_P(tmp) != IS_LONG) {
571 zend_value_error("Precision must be an integer");
572 goto fail;
573 }
574 if (Z_LVAL_P(tmp) < -1 || Z_LVAL_P(tmp) > INT_MAX) {
575 zend_value_error("Precision must be between -1 and %d", INT_MAX);
576 goto fail;
577 }
578 precision = Z_LVAL_P(tmp);
579 adjusting |= ADJ_PRECISION;
580 expprec = 1;
581 } else if (isdigit((int)*format)) {
582 if ((precision = php_sprintf_getnumber(&format, &format_len)) < 0) {
583 zend_value_error("Precision must be greater than zero and less than %d", INT_MAX);
584 goto fail;
585 }
586 adjusting |= ADJ_PRECISION;
587 expprec = 1;
588 } else {
589 precision = 0;
590 }
591 } else {
592 precision = 0;
593 }
594 PRINTF_DEBUG(("sprintf: precision=%d\n", precision));
595 }
596
597 if (*format == 'l') {
598 format++;
599 format_len--;
600 }
601 PRINTF_DEBUG(("sprintf: format character='%c'\n", *format));
602
603 if (argnum == ARG_NUM_NEXT) {
604 argnum = currarg++;
605 }
606 if (argnum >= argc) {
607 max_missing_argnum = MAX(max_missing_argnum, argnum);
608 continue;
609 }
610
611 if (expprec && precision == -1
612 && *format != 'g' && *format != 'G' && *format != 'h' && *format != 'H') {
613 zend_value_error("Precision -1 is only supported for %%g, %%G, %%h and %%H");
614 goto fail;
615 }
616
617 /* now we expect to find a type specifier */
618 tmp = &args[argnum];
619 switch (*format) {
620 case 's': {
621 zend_string *t;
622 zend_string *str = zval_get_tmp_string(tmp, &t);
623 php_sprintf_appendstring(&result, &outpos,
624 ZSTR_VAL(str),
625 width, precision, padding,
626 alignment,
627 ZSTR_LEN(str),
628 /* neg */ false, expprec, 0);
629 zend_tmp_string_release(t);
630 break;
631 }
632
633 case 'd':
634 php_sprintf_appendint(&result, &outpos,
635 zval_get_long(tmp),
636 width, padding, alignment,
637 always_sign);
638 break;
639
640 case 'u':
641 php_sprintf_appenduint(&result, &outpos,
642 zval_get_long(tmp),
643 width, padding, alignment);
644 break;
645
646 case 'e':
647 case 'E':
648 case 'f':
649 case 'F':
650 case 'g':
651 case 'G':
652 case 'h':
653 case 'H':
654 php_sprintf_appenddouble(&result, &outpos,
655 zval_get_double(tmp),
656 width, padding, alignment,
657 precision, adjusting,
658 *format, always_sign
659 );
660 break;
661
662 case 'c':
663 php_sprintf_appendchar(&result, &outpos,
664 (char) zval_get_long(tmp));
665 break;
666
667 case 'o':
668 php_sprintf_append2n(&result, &outpos,
669 zval_get_long(tmp),
670 width, padding, alignment, 3,
671 hexchars, expprec);
672 break;
673
674 case 'x':
675 php_sprintf_append2n(&result, &outpos,
676 zval_get_long(tmp),
677 width, padding, alignment, 4,
678 hexchars, expprec);
679 break;
680
681 case 'X':
682 php_sprintf_append2n(&result, &outpos,
683 zval_get_long(tmp),
684 width, padding, alignment, 4,
685 HEXCHARS, expprec);
686 break;
687
688 case 'b':
689 php_sprintf_append2n(&result, &outpos,
690 zval_get_long(tmp),
691 width, padding, alignment, 1,
692 hexchars, expprec);
693 break;
694
695 case '%':
696 php_sprintf_appendchar(&result, &outpos, '%');
697
698 break;
699
700 case '\0':
701 if (!format_len) {
702 zend_value_error("Missing format specifier at end of string");
703 goto fail;
704 }
706
707 default:
708 zend_value_error("Unknown format specifier \"%c\"", *format);
709 goto fail;
710 }
711 format++;
712 format_len--;
713 }
714 }
715
716 if (max_missing_argnum >= 0) {
717 if (nb_additional_parameters == -1) {
718 zend_value_error("The arguments array must contain %d items, %d given", max_missing_argnum + 1, argc);
719 } else {
720 zend_argument_count_error("%d arguments are required, %d given", max_missing_argnum + nb_additional_parameters + 1, argc + nb_additional_parameters);
721 }
722 goto fail;
723 }
724
725 /* possibly, we have to make sure we have room for the terminating null? */
726 ZSTR_VAL(result)[outpos]=0;
727 ZSTR_LEN(result) = outpos;
728 return result;
729
730fail:
731 zend_string_efree(result);
732 return NULL;
733}
734/* }}} */
735
736/* php_formatted_print_get_array() {{{ */
737static zval *php_formatted_print_get_array(zend_array *array, int *argc)
738{
739 zval *args, *zv;
740 int n;
741
742 n = zend_hash_num_elements(array);
743 args = (zval *)safe_emalloc(n, sizeof(zval), 0);
744 n = 0;
745 ZEND_HASH_FOREACH_VAL(array, zv) {
747 n++;
749
750 *argc = n;
751 return args;
752}
753/* }}} */
754
755/* {{{ Return a formatted string */
757{
759 char *format;
760 size_t format_len;
761 zval *args;
762 int argc;
763
765 Z_PARAM_STRING(format, format_len)
766 Z_PARAM_VARIADIC('*', args, argc)
768
769 result = php_formatted_print(format, format_len, args, argc, 1);
770 if (result == NULL) {
772 }
774}
775/* }}} */
776
777/* {{{ Return a formatted string */
779{
781 char *format;
782 size_t format_len;
783 zval *args;
784 zend_array *array;
785 int argc;
786
788 Z_PARAM_STRING(format, format_len)
789 Z_PARAM_ARRAY_HT(array)
791
792 args = php_formatted_print_get_array(array, &argc);
793
794 result = php_formatted_print(format, format_len, args, argc, -1);
795 efree(args);
796 if (result == NULL) {
798 }
800}
801/* }}} */
802
803/* {{{ Output a formatted string */
805{
807 size_t rlen;
808 char *format;
809 size_t format_len;
810 zval *args;
811 int argc;
812
814 Z_PARAM_STRING(format, format_len)
815 Z_PARAM_VARIADIC('*', args, argc)
817
818 result = php_formatted_print(format, format_len, args, argc, 1);
819 if (result == NULL) {
821 }
823 zend_string_efree(result);
824 RETURN_LONG(rlen);
825}
826/* }}} */
827
828/* {{{ Output a formatted string */
830{
832 size_t rlen;
833 char *format;
834 size_t format_len;
835 zval *args;
836 zend_array *array;
837 int argc;
838
840 Z_PARAM_STRING(format, format_len)
841 Z_PARAM_ARRAY_HT(array)
843
844 args = php_formatted_print_get_array(array, &argc);
845
846 result = php_formatted_print(format, format_len, args, argc, -1);
847 efree(args);
848 if (result == NULL) {
850 }
852 zend_string_efree(result);
853 RETURN_LONG(rlen);
854}
855/* }}} */
856
857/* {{{ Output a formatted string into a stream */
859{
860 php_stream *stream;
861 char *format;
862 size_t format_len;
863 zval *arg1, *args;
864 int argc;
866
869 Z_PARAM_STRING(format, format_len)
870 Z_PARAM_VARIADIC('*', args, argc)
872
873 php_stream_from_zval(stream, arg1);
874
875 result = php_formatted_print(format, format_len, args, argc, 2);
876 if (result == NULL) {
878 }
879
881
883 zend_string_efree(result);
884}
885/* }}} */
886
887/* {{{ Output a formatted string into a stream */
889{
890 php_stream *stream;
891 char *format;
892 size_t format_len;
893 zval *arg1, *args;
894 zend_array *array;
895 int argc;
897
900 Z_PARAM_STRING(format, format_len)
901 Z_PARAM_ARRAY_HT(array)
903
904 php_stream_from_zval(stream, arg1);
905
906 args = php_formatted_print_get_array(array, &argc);
907
908 result = php_formatted_print(format, format_len, args, argc, -1);
909 efree(args);
910 if (result == NULL) {
912 }
913
915
917 zend_string_efree(result);
918}
919/* }}} */
size_t len
Definition apprentice.c:174
vprintf(string $format, array $values)
fprintf($stream, string $format, mixed ... $values)
printf(string $format, mixed ... $values)
vfprintf($stream, string $format, array $values)
vsprintf(string $format, array $values)
char s[4]
Definition cdf.c:77
zval * zv
Definition ffi.c:3975
zend_long n
Definition ffi.c:4979
new_type size
Definition ffi.c:4365
memcpy(ptr1, ptr2, size)
#define ADJ_WIDTH
#define MAX_FLOAT_PRECISION
#define ALIGN_LEFT
#define PRINTF_DEBUG(arg)
#define ADJ_PRECISION
#define ARG_NUM_INVALID
#define ALIGN_RIGHT
#define ARG_NUM_NEXT
#define FLOAT_PRECISION
int php_sprintf_get_argnum(char **format, size_t *format_len)
#define NULL
Definition gdcache.h:45
sprintf("0x%X", $numelems)
PHPAPI ZEND_COLD void php_error_docref(const char *docref, int type, const char *format,...)
Definition main.c:1173
#define PHP_FUNCTION
Definition php.h:364
#define INT_MAX
Definition php.h:237
#define add(i, ts)
unsigned const char * pos
Definition php_ffi.h:52
#define PHPWRITE(str, str_len)
struct _php_stream php_stream
Definition php_streams.h:96
#define php_stream_from_zval(xstr, pzval)
#define php_stream_write(stream, buf, count)
PHPAPI struct lconv * localeconv_r(struct lconv *out)
Definition string.c:119
bool fail
Definition session.c:1065
const char * endptr
Definition session.c:1021
#define NUM_BUF_SIZE
Definition snprintf.c:403
#define LCONV_DECIMAL_POINT
Definition snprintf.c:39
PHPAPI char * php_conv_fp(char format, double num, bool add_dp, int precision, char dec_point, bool *is_negative, char *buf, size_t *len)
Definition snprintf.c:271
Definition file.h:177
ZEND_API ZEND_COLD ZEND_NORETURN void zend_error_noreturn(int type, const char *format,...)
Definition zend.c:1703
ZEND_API ZEND_COLD void zend_argument_count_error(const char *format,...)
Definition zend.c:1836
ZEND_API ZEND_COLD void zend_value_error(const char *format,...)
Definition zend.c:1849
#define ZEND_PARSE_PARAMETERS_END()
Definition zend_API.h:1641
#define Z_PARAM_RESOURCE(dest)
Definition zend_API.h:2056
#define Z_PARAM_STRING(dest, dest_len)
Definition zend_API.h:2071
#define ZEND_PARSE_PARAMETERS_START(min_num_args, max_num_args)
Definition zend_API.h:1620
#define Z_PARAM_VARIADIC(spec, dest, dest_num)
Definition zend_API.h:2124
#define RETURN_LONG(l)
Definition zend_API.h:1037
#define RETURN_THROWS()
Definition zend_API.h:1060
#define Z_PARAM_ARRAY_HT(dest)
Definition zend_API.h:1852
#define RETVAL_LONG(l)
Definition zend_API.h:1011
#define RETVAL_STR(s)
Definition zend_API.h:1013
#define efree(ptr)
Definition zend_alloc.h:155
#define safe_emalloc(nmemb, size, offset)
Definition zend_alloc.h:154
struct _zval_struct zval
strlen(string $string)
zval * args
#define E_NOTICE
Definition zend_errors.h:26
#define E_ERROR
Definition zend_errors.h:23
ZEND_API const char * get_active_function_name(void)
#define ZEND_HASH_FOREACH_END()
Definition zend_hash.h:1086
#define ZEND_HASH_FOREACH_VAL(ht, _val)
Definition zend_hash.h:1102
int32_t zend_long
Definition zend_long.h:42
uint32_t zend_ulong
Definition zend_long.h:43
#define ZEND_STRTOL(s0, s1, base)
Definition zend_long.h:85
struct _zend_string zend_string
#define zend_isinf(a)
#define MIN(a, b)
#define ZEND_FALLTHROUGH
#define zend_isnan(a)
#define MAX(a, b)
struct _zend_array zend_array
#define ZSTR_VAL(zstr)
Definition zend_string.h:68
#define ZSTR_LEN(zstr)
Definition zend_string.h:69
ZEND_API char * zend_gcvt(double value, int ndigit, char dec_point, char exponent, char *buf)
#define Z_TYPE_P(zval_p)
Definition zend_types.h:660
#define Z_STRVAL_P(zval_p)
Definition zend_types.h:975
#define ZVAL_DEREF(z)
#define IS_LONG
Definition zend_types.h:604
#define ZEND_SIZE_MAX
Definition zend_types.h:76
#define Z_LVAL_P(zval_p)
Definition zend_types.h:966
#define ZVAL_COPY_VALUE(z, v)
zval * arg1
bool result