1 /*
2 +----------------------------------------------------------------------+
3 | PHP Version 7 |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 1997-2017 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: Marcus Boerger <helly@php.net> |
16 +----------------------------------------------------------------------+
17 */
18
19 /* $Id$ */
20
21 /* This is the spprintf implementation.
22 * It has emerged from apache snprintf. See original header:
23 */
24
25 /* ====================================================================
26 * Copyright (c) 1995-1998 The Apache Group. All rights reserved.
27 *
28 * Redistribution and use in source and binary forms, with or without
29 * modification, are permitted provided that the following conditions
30 * are met:
31 *
32 * 1. Redistributions of source code must retain the above copyright
33 * notice, this list of conditions and the following disclaimer.
34 *
35 * 2. Redistributions in binary form must reproduce the above copyright
36 * notice, this list of conditions and the following disclaimer in
37 * the documentation and/or other materials provided with the
38 * distribution.
39 *
40 * 3. All advertising materials mentioning features or use of this
41 * software must display the following acknowledgment:
42 * "This product includes software developed by the Apache Group
43 * for use in the Apache HTTP server project (http://www.apache.org/)."
44 *
45 * 4. The names "Apache Server" and "Apache Group" must not be used to
46 * endorse or promote products derived from this software without
47 * prior written permission.
48 *
49 * 5. Redistributions of any form whatsoever must retain the following
50 * acknowledgment:
51 * "This product includes software developed by the Apache Group
52 * for use in the Apache HTTP server project (http://www.apache.org/)."
53 *
54 * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY
55 * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
56 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
57 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR
58 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
59 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
60 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
61 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
62 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
63 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
64 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
65 * OF THE POSSIBILITY OF SUCH DAMAGE.
66 * ====================================================================
67 *
68 * This software consists of voluntary contributions made by many
69 * individuals on behalf of the Apache Group and was originally based
70 * on public domain software written at the National Center for
71 * Supercomputing Applications, University of Illinois, Urbana-Champaign.
72 * For more information on the Apache Group and the Apache HTTP server
73 * project, please see <http://www.apache.org/>.
74 *
75 * This code is based on, and used with the permission of, the
76 * SIO stdio-replacement strx_* functions by Panos Tsirigotis
77 * <panos@alumni.cs.colorado.edu> for xinetd.
78 */
79 #define _GNU_SOURCE
80 #include "php.h"
81
82 #include <stddef.h>
83 #include <stdio.h>
84 #include <ctype.h>
85 #include <sys/types.h>
86 #include <stdarg.h>
87 #include <string.h>
88 #include <stdlib.h>
89 #include <math.h>
90 #ifdef HAVE_INTTYPES_H
91 #include <inttypes.h>
92 #endif
93
94 #ifdef HAVE_LOCALE_H
95 #include <locale.h>
96 #ifdef ZTS
97 #include "ext/standard/php_string.h"
98 #define LCONV_DECIMAL_POINT (*lconv.decimal_point)
99 #else
100 #define LCONV_DECIMAL_POINT (*lconv->decimal_point)
101 #endif
102 #else
103 #define LCONV_DECIMAL_POINT '.'
104 #endif
105
106 #include "snprintf.h"
107
108 #define FALSE 0
109 #define TRUE 1
110 #define NUL '\0'
111 #define INT_NULL ((int *)0)
112
113 #define S_NULL "(null)"
114 #define S_NULL_LEN 6
115
116 #define FLOAT_DIGITS 6
117 #define EXPONENT_LENGTH 10
118
119 #include "zend_smart_str.h"
120 #include "ext/standard/php_smart_string.h"
121
122 /* {{{ macros */
123
124 #define INS_CHAR(xbuf, ch, is_char) do { \
125 if ((is_char)) { \
126 smart_string_appendc((smart_string *)(xbuf), (ch)); \
127 } else { \
128 smart_str_appendc((smart_str *)(xbuf), (ch)); \
129 } \
130 } while (0);
131
132 #define INS_STRING(xbuf, str, len, is_char) do { \
133 if ((is_char)) { \
134 smart_string_appendl((smart_string *)(xbuf), (str), (len)); \
135 } else { \
136 smart_str_appendl((smart_str *)(xbuf), (str), (len)); \
137 } \
138 } while (0);
139
140 #define PAD_CHAR(xbuf, ch, count, is_char) do { \
141 size_t newlen; \
142 if ((is_char)) { \
143 smart_string_alloc(((smart_string *)(xbuf)), (count), 0); \
144 memset(((smart_string *)(xbuf))->c + ((smart_string *)(xbuf))->len, (ch), (count)); \
145 ((smart_string *)(xbuf))->len += (count); \
146 } else { \
147 smart_str_alloc(((smart_str *)(xbuf)), (count), 0); \
148 memset(ZSTR_VAL(((smart_str *)(xbuf))->s) + ZSTR_LEN(((smart_str *)(xbuf))->s), (ch), (count)); \
149 ZSTR_LEN(((smart_str *)(xbuf))->s) += (count); \
150 } \
151 } while (0);
152
153 /*
154 * NUM_BUF_SIZE is the size of the buffer used for arithmetic conversions
155 *
156 * XXX: this is a magic number; do not decrease it
157 * Emax = 1023
158 * NDIG = 320
159 * NUM_BUF_SIZE >= strlen("-") + Emax + strlrn(".") + NDIG + strlen("E+1023") + 1;
160 */
161 #define NUM_BUF_SIZE 2048
162
163 #define NUM(c) (c - '0')
164
165 #define STR_TO_DEC(str, num) do { \
166 num = NUM(*str++); \
167 while (isdigit((int)*str)) { \
168 num *= 10; \
169 num += NUM(*str++); \
170 if (num >= INT_MAX / 10) { \
171 while (isdigit((int)*str++)); \
172 break; \
173 } \
174 } \
175 } while (0)
176
177 /*
178 * This macro does zero padding so that the precision
179 * requirement is satisfied. The padding is done by
180 * adding '0's to the left of the string that is going
181 * to be printed.
182 */
183 #define FIX_PRECISION(adjust, precision, s, s_len) do { \
184 if (adjust) \
185 while (s_len < precision) { \
186 *--s = '0'; \
187 s_len++; \
188 } \
189 } while (0)
190
191 /* }}} */
192
193 #if !HAVE_STRNLEN
strnlen(const char * s,size_t maxlen)194 static size_t strnlen(const char *s, size_t maxlen) {
195 char *r = memchr(s, '\0', maxlen);
196 return r ? r-s : maxlen;
197 }
198 #endif
199
200 /*
201 * Do format conversion placing the output in buffer
202 */
xbuf_format_converter(void * xbuf,zend_bool is_char,const char * fmt,va_list ap)203 static void xbuf_format_converter(void *xbuf, zend_bool is_char, const char *fmt, va_list ap) /* {{{ */
204 {
205 char *s = NULL;
206 size_t s_len;
207 int free_zcopy;
208 zval *zvp, zcopy;
209
210 int min_width = 0;
211 int precision = 0;
212 enum {
213 LEFT, RIGHT
214 } adjust;
215 char pad_char;
216 char prefix_char;
217
218 double fp_num;
219 wide_int i_num = (wide_int) 0;
220 u_wide_int ui_num = (u_wide_int) 0;
221
222 char num_buf[NUM_BUF_SIZE];
223 char char_buf[2]; /* for printing %% and %<unknown> */
224
225 #ifdef HAVE_LOCALE_H
226 #ifdef ZTS
227 struct lconv lconv;
228 #else
229 struct lconv *lconv = NULL;
230 #endif
231 #endif
232
233 /*
234 * Flag variables
235 */
236 length_modifier_e modifier;
237 boolean_e alternate_form;
238 boolean_e print_sign;
239 boolean_e print_blank;
240 boolean_e adjust_precision;
241 boolean_e adjust_width;
242 bool_int is_negative;
243
244 while (*fmt) {
245 if (*fmt != '%') {
246 INS_CHAR(xbuf, *fmt, is_char);
247 } else {
248 /*
249 * Default variable settings
250 */
251 adjust = RIGHT;
252 alternate_form = print_sign = print_blank = NO;
253 pad_char = ' ';
254 prefix_char = NUL;
255 free_zcopy = 0;
256
257 fmt++;
258
259 /*
260 * Try to avoid checking for flags, width or precision
261 */
262 if (isascii((int)*fmt) && !islower((int)*fmt)) {
263 /*
264 * Recognize flags: -, #, BLANK, +
265 */
266 for (;; fmt++) {
267 if (*fmt == '-')
268 adjust = LEFT;
269 else if (*fmt == '+')
270 print_sign = YES;
271 else if (*fmt == '#')
272 alternate_form = YES;
273 else if (*fmt == ' ')
274 print_blank = YES;
275 else if (*fmt == '0')
276 pad_char = '0';
277 else
278 break;
279 }
280
281 /*
282 * Check if a width was specified
283 */
284 if (isdigit((int)*fmt)) {
285 STR_TO_DEC(fmt, min_width);
286 adjust_width = YES;
287 } else if (*fmt == '*') {
288 min_width = va_arg(ap, int);
289 fmt++;
290 adjust_width = YES;
291 if (min_width < 0) {
292 adjust = LEFT;
293 min_width = -min_width;
294 }
295 } else
296 adjust_width = NO;
297
298 /*
299 * Check if a precision was specified
300 */
301 if (*fmt == '.') {
302 adjust_precision = YES;
303 fmt++;
304 if (isdigit((int)*fmt)) {
305 STR_TO_DEC(fmt, precision);
306 } else if (*fmt == '*') {
307 precision = va_arg(ap, int);
308 fmt++;
309 if (precision < 0)
310 precision = 0;
311 } else
312 precision = 0;
313
314 if (precision > FORMAT_CONV_MAX_PRECISION) {
315 precision = FORMAT_CONV_MAX_PRECISION;
316 }
317 } else
318 adjust_precision = NO;
319 } else
320 adjust_precision = adjust_width = NO;
321
322 /*
323 * Modifier check
324 */
325 switch (*fmt) {
326 case 'L':
327 fmt++;
328 modifier = LM_LONG_DOUBLE;
329 break;
330 case 'I':
331 fmt++;
332 #if SIZEOF_LONG_LONG
333 if (*fmt == '6' && *(fmt+1) == '4') {
334 fmt += 2;
335 modifier = LM_LONG_LONG;
336 } else
337 #endif
338 if (*fmt == '3' && *(fmt+1) == '2') {
339 fmt += 2;
340 modifier = LM_LONG;
341 } else {
342 #ifdef _WIN64
343 modifier = LM_LONG_LONG;
344 #else
345 modifier = LM_LONG;
346 #endif
347 }
348 break;
349 case 'l':
350 fmt++;
351 #if SIZEOF_LONG_LONG
352 if (*fmt == 'l') {
353 fmt++;
354 modifier = LM_LONG_LONG;
355 } else
356 #endif
357 modifier = LM_LONG;
358 break;
359 case 'z':
360 fmt++;
361 modifier = LM_SIZE_T;
362 break;
363 case 'j':
364 fmt++;
365 #if SIZEOF_INTMAX_T
366 modifier = LM_INTMAX_T;
367 #else
368 modifier = LM_SIZE_T;
369 #endif
370 break;
371 case 't':
372 fmt++;
373 #if SIZEOF_PTRDIFF_T
374 modifier = LM_PTRDIFF_T;
375 #else
376 modifier = LM_SIZE_T;
377 #endif
378 break;
379 case 'p': {
380 char __next = *(fmt+1);
381 if ('d' == __next || 'u' == __next || 'x' == __next || 'o' == __next) {
382 fmt++;
383 modifier = LM_PHP_INT_T;
384 } else {
385 modifier = LM_STD;
386 }
387 }
388 break;
389 case 'h':
390 fmt++;
391 if (*fmt == 'h') {
392 fmt++;
393 }
394 /* these are promoted to int, so no break */
395 default:
396 modifier = LM_STD;
397 break;
398 }
399
400 /*
401 * Argument extraction and printing.
402 * First we determine the argument type.
403 * Then, we convert the argument to a string.
404 * On exit from the switch, s points to the string that
405 * must be printed, s_len has the length of the string
406 * The precision requirements, if any, are reflected in s_len.
407 *
408 * NOTE: pad_char may be set to '0' because of the 0 flag.
409 * It is reset to ' ' by non-numeric formats
410 */
411 switch (*fmt) {
412 case 'Z': {
413 zvp = (zval*) va_arg(ap, zval*);
414 free_zcopy = zend_make_printable_zval(zvp, &zcopy);
415 if (free_zcopy) {
416 zvp = &zcopy;
417 }
418 s_len = Z_STRLEN_P(zvp);
419 s = Z_STRVAL_P(zvp);
420 if (adjust_precision && precision < s_len) {
421 s_len = precision;
422 }
423 break;
424 }
425 case 'u':
426 switch(modifier) {
427 default:
428 i_num = (wide_int) va_arg(ap, unsigned int);
429 break;
430 case LM_LONG_DOUBLE:
431 goto fmt_error;
432 case LM_LONG:
433 i_num = (wide_int) va_arg(ap, unsigned long int);
434 break;
435 case LM_SIZE_T:
436 i_num = (wide_int) va_arg(ap, size_t);
437 break;
438 #if SIZEOF_LONG_LONG
439 case LM_LONG_LONG:
440 i_num = (wide_int) va_arg(ap, u_wide_int);
441 break;
442 #endif
443 #if SIZEOF_INTMAX_T
444 case LM_INTMAX_T:
445 i_num = (wide_int) va_arg(ap, uintmax_t);
446 break;
447 #endif
448 #if SIZEOF_PTRDIFF_T
449 case LM_PTRDIFF_T:
450 i_num = (wide_int) va_arg(ap, ptrdiff_t);
451 break;
452 #endif
453 case LM_PHP_INT_T:
454 i_num = (wide_int) va_arg(ap, zend_ulong);
455 break;
456 }
457 /*
458 * The rest also applies to other integer formats, so fall
459 * into that case.
460 */
461 case 'd':
462 case 'i':
463 /*
464 * Get the arg if we haven't already.
465 */
466 if ((*fmt) != 'u') {
467 switch(modifier) {
468 default:
469 i_num = (wide_int) va_arg(ap, int);
470 break;
471 case LM_LONG_DOUBLE:
472 goto fmt_error;
473 case LM_LONG:
474 i_num = (wide_int) va_arg(ap, long int);
475 break;
476 case LM_SIZE_T:
477 #if SIZEOF_SSIZE_T
478 i_num = (wide_int) va_arg(ap, ssize_t);
479 #else
480 i_num = (wide_int) va_arg(ap, size_t);
481 #endif
482 break;
483 #if SIZEOF_LONG_LONG
484 case LM_LONG_LONG:
485 i_num = (wide_int) va_arg(ap, wide_int);
486 break;
487 #endif
488 #if SIZEOF_INTMAX_T
489 case LM_INTMAX_T:
490 i_num = (wide_int) va_arg(ap, intmax_t);
491 break;
492 #endif
493 #if SIZEOF_PTRDIFF_T
494 case LM_PTRDIFF_T:
495 i_num = (wide_int) va_arg(ap, ptrdiff_t);
496 break;
497 #endif
498 case LM_PHP_INT_T:
499 i_num = (wide_int) va_arg(ap, zend_long);
500 break;
501 }
502 }
503 s = ap_php_conv_10(i_num, (*fmt) == 'u', &is_negative,
504 &num_buf[NUM_BUF_SIZE], &s_len);
505 FIX_PRECISION(adjust_precision, precision, s, s_len);
506
507 if (*fmt != 'u') {
508 if (is_negative)
509 prefix_char = '-';
510 else if (print_sign)
511 prefix_char = '+';
512 else if (print_blank)
513 prefix_char = ' ';
514 }
515 break;
516
517
518 case 'o':
519 switch(modifier) {
520 default:
521 ui_num = (u_wide_int) va_arg(ap, unsigned int);
522 break;
523 case LM_LONG_DOUBLE:
524 goto fmt_error;
525 case LM_LONG:
526 ui_num = (u_wide_int) va_arg(ap, unsigned long int);
527 break;
528 case LM_SIZE_T:
529 ui_num = (u_wide_int) va_arg(ap, size_t);
530 break;
531 #if SIZEOF_LONG_LONG
532 case LM_LONG_LONG:
533 ui_num = (u_wide_int) va_arg(ap, u_wide_int);
534 break;
535 #endif
536 #if SIZEOF_INTMAX_T
537 case LM_INTMAX_T:
538 ui_num = (u_wide_int) va_arg(ap, uintmax_t);
539 break;
540 #endif
541 #if SIZEOF_PTRDIFF_T
542 case LM_PTRDIFF_T:
543 ui_num = (u_wide_int) va_arg(ap, ptrdiff_t);
544 break;
545 #endif
546 case LM_PHP_INT_T:
547 ui_num = (u_wide_int) va_arg(ap, zend_ulong);
548 break;
549 }
550 s = ap_php_conv_p2(ui_num, 3, *fmt,
551 &num_buf[NUM_BUF_SIZE], &s_len);
552 FIX_PRECISION(adjust_precision, precision, s, s_len);
553 if (alternate_form && *s != '0') {
554 *--s = '0';
555 s_len++;
556 }
557 break;
558
559
560 case 'x':
561 case 'X':
562 switch(modifier) {
563 default:
564 ui_num = (u_wide_int) va_arg(ap, unsigned int);
565 break;
566 case LM_LONG_DOUBLE:
567 goto fmt_error;
568 case LM_LONG:
569 ui_num = (u_wide_int) va_arg(ap, unsigned long int);
570 break;
571 case LM_SIZE_T:
572 ui_num = (u_wide_int) va_arg(ap, size_t);
573 break;
574 #if SIZEOF_LONG_LONG
575 case LM_LONG_LONG:
576 ui_num = (u_wide_int) va_arg(ap, u_wide_int);
577 break;
578 #endif
579 #if SIZEOF_INTMAX_T
580 case LM_INTMAX_T:
581 ui_num = (u_wide_int) va_arg(ap, uintmax_t);
582 break;
583 #endif
584 #if SIZEOF_PTRDIFF_T
585 case LM_PTRDIFF_T:
586 ui_num = (u_wide_int) va_arg(ap, ptrdiff_t);
587 break;
588 #endif
589 case LM_PHP_INT_T:
590 ui_num = (u_wide_int) va_arg(ap, zend_ulong);
591 break;
592 }
593 s = ap_php_conv_p2(ui_num, 4, *fmt,
594 &num_buf[NUM_BUF_SIZE], &s_len);
595 FIX_PRECISION(adjust_precision, precision, s, s_len);
596 if (alternate_form && ui_num != 0) {
597 *--s = *fmt; /* 'x' or 'X' */
598 *--s = '0';
599 s_len += 2;
600 }
601 break;
602
603
604 case 's':
605 case 'v':
606 s = va_arg(ap, char *);
607 if (s != NULL) {
608 if (!adjust_precision) {
609 s_len = strlen(s);
610 } else {
611 s_len = strnlen(s, precision);
612 }
613 } else {
614 s = S_NULL;
615 s_len = S_NULL_LEN;
616 }
617 pad_char = ' ';
618 break;
619
620
621 case 'f':
622 case 'F':
623 case 'e':
624 case 'E':
625 switch(modifier) {
626 case LM_LONG_DOUBLE:
627 fp_num = (double) va_arg(ap, long double);
628 break;
629 case LM_STD:
630 fp_num = va_arg(ap, double);
631 break;
632 default:
633 goto fmt_error;
634 }
635
636 if (zend_isnan(fp_num)) {
637 s = "nan";
638 s_len = 3;
639 } else if (zend_isinf(fp_num)) {
640 s = "inf";
641 s_len = 3;
642 } else {
643 #ifdef HAVE_LOCALE_H
644 #ifdef ZTS
645 localeconv_r(&lconv);
646 #else
647 if (!lconv) {
648 lconv = localeconv();
649 }
650 #endif
651 #endif
652 s = php_conv_fp((*fmt == 'f')?'F':*fmt, fp_num, alternate_form,
653 (adjust_precision == NO) ? FLOAT_DIGITS : precision,
654 (*fmt == 'f')?LCONV_DECIMAL_POINT:'.',
655 &is_negative, &num_buf[1], &s_len);
656 if (is_negative)
657 prefix_char = '-';
658 else if (print_sign)
659 prefix_char = '+';
660 else if (print_blank)
661 prefix_char = ' ';
662 }
663 break;
664
665
666 case 'g':
667 case 'k':
668 case 'G':
669 case 'H':
670 switch(modifier) {
671 case LM_LONG_DOUBLE:
672 fp_num = (double) va_arg(ap, long double);
673 break;
674 case LM_STD:
675 fp_num = va_arg(ap, double);
676 break;
677 default:
678 goto fmt_error;
679 }
680
681 if (zend_isnan(fp_num)) {
682 s = "NAN";
683 s_len = 3;
684 break;
685 } else if (zend_isinf(fp_num)) {
686 if (fp_num > 0) {
687 s = "INF";
688 s_len = 3;
689 } else {
690 s = "-INF";
691 s_len = 4;
692 }
693 break;
694 }
695
696 if (adjust_precision == NO)
697 precision = FLOAT_DIGITS;
698 else if (precision == 0)
699 precision = 1;
700 /*
701 * * We use &num_buf[ 1 ], so that we have room for the sign
702 */
703 #ifdef HAVE_LOCALE_H
704 #ifdef ZTS
705 localeconv_r(&lconv);
706 #else
707 if (!lconv) {
708 lconv = localeconv();
709 }
710 #endif
711 #endif
712 s = php_gcvt(fp_num, precision, (*fmt=='H' || *fmt == 'k') ? '.' : LCONV_DECIMAL_POINT, (*fmt == 'G' || *fmt == 'H')?'E':'e', &num_buf[1]);
713 if (*s == '-')
714 prefix_char = *s++;
715 else if (print_sign)
716 prefix_char = '+';
717 else if (print_blank)
718 prefix_char = ' ';
719
720 s_len = strlen(s);
721
722 if (alternate_form && (strchr(s, '.')) == NULL)
723 s[s_len++] = '.';
724 break;
725
726
727 case 'c':
728 char_buf[0] = (char) (va_arg(ap, int));
729 s = &char_buf[0];
730 s_len = 1;
731 pad_char = ' ';
732 break;
733
734
735 case '%':
736 char_buf[0] = '%';
737 s = &char_buf[0];
738 s_len = 1;
739 pad_char = ' ';
740 break;
741
742
743 case 'n':
744 *(va_arg(ap, int *)) = is_char? (int)((smart_string *)xbuf)->len : (int)ZSTR_LEN(((smart_str *)xbuf)->s);
745 goto skip_output;
746
747 /*
748 * Always extract the argument as a "char *" pointer. We
749 * should be using "void *" but there are still machines
750 * that don't understand it.
751 * If the pointer size is equal to the size of an unsigned
752 * integer we convert the pointer to a hex number, otherwise
753 * we print "%p" to indicate that we don't handle "%p".
754 */
755 case 'p':
756 if (sizeof(char *) <= sizeof(u_wide_int)) {
757 ui_num = (u_wide_int)((size_t) va_arg(ap, char *));
758 s = ap_php_conv_p2(ui_num, 4, 'x',
759 &num_buf[NUM_BUF_SIZE], &s_len);
760 if (ui_num != 0) {
761 *--s = 'x';
762 *--s = '0';
763 s_len += 2;
764 }
765 } else {
766 s = "%p";
767 s_len = 2;
768 }
769 pad_char = ' ';
770 break;
771
772
773 case NUL:
774 /*
775 * The last character of the format string was %.
776 * We ignore it.
777 */
778 continue;
779
780
781 fmt_error:
782 php_error(E_ERROR, "Illegal length modifier specified '%c' in s[np]printf call", *fmt);
783 /*
784 * The default case is for unrecognized %'s.
785 * We print %<char> to help the user identify what
786 * option is not understood.
787 * This is also useful in case the user wants to pass
788 * the output of format_converter to another function
789 * that understands some other %<char> (like syslog).
790 * Note that we can't point s inside fmt because the
791 * unknown <char> could be preceded by width etc.
792 */
793 default:
794 char_buf[0] = '%';
795 char_buf[1] = *fmt;
796 s = char_buf;
797 s_len = 2;
798 pad_char = ' ';
799 break;
800 }
801
802 if (prefix_char != NUL) {
803 *--s = prefix_char;
804 s_len++;
805 }
806 if (adjust_width && adjust == RIGHT && min_width > s_len) {
807 if (pad_char == '0' && prefix_char != NUL) {
808 INS_CHAR(xbuf, *s, is_char);
809 s++;
810 s_len--;
811 min_width--;
812 }
813 PAD_CHAR(xbuf, pad_char, min_width - s_len, is_char);
814 }
815 /*
816 * Print the string s.
817 */
818 INS_STRING(xbuf, s, s_len, is_char);
819
820 if (adjust_width && adjust == LEFT && min_width > s_len) {
821 PAD_CHAR(xbuf, pad_char, min_width - s_len, is_char);
822 }
823
824 if (free_zcopy) {
825 zval_dtor(&zcopy);
826 }
827 }
828 skip_output:
829 fmt++;
830 }
831 return;
832 }
833 /* }}} */
834
835 /*
836 * This is the general purpose conversion function.
837 */
vspprintf(char ** pbuf,size_t max_len,const char * format,va_list ap)838 PHPAPI size_t vspprintf(char **pbuf, size_t max_len, const char *format, va_list ap) /* {{{ */
839 {
840 smart_string buf = {0};
841
842 /* since there are places where (v)spprintf called without checking for null,
843 a bit of defensive coding here */
844 if(!pbuf) {
845 return 0;
846 }
847 xbuf_format_converter(&buf, 1, format, ap);
848
849 if (max_len && buf.len > max_len) {
850 buf.len = max_len;
851 }
852
853 smart_string_0(&buf);
854
855 if (buf.c) {
856 *pbuf = buf.c;
857 return buf.len;
858 } else {
859 *pbuf = estrndup("", 0);
860 return 0;
861 }
862 }
863 /* }}} */
864
spprintf(char ** pbuf,size_t max_len,const char * format,...)865 PHPAPI size_t spprintf(char **pbuf, size_t max_len, const char *format, ...) /* {{{ */
866 {
867 size_t cc;
868 va_list ap;
869
870 va_start(ap, format);
871 cc = vspprintf(pbuf, max_len, format, ap);
872 va_end(ap);
873 return (cc);
874 }
875 /* }}} */
876
vstrpprintf(size_t max_len,const char * format,va_list ap)877 PHPAPI zend_string *vstrpprintf(size_t max_len, const char *format, va_list ap) /* {{{ */
878 {
879 smart_str buf = {0};
880
881 xbuf_format_converter(&buf, 0, format, ap);
882
883 if (!buf.s) {
884 return ZSTR_EMPTY_ALLOC();
885 }
886
887 if (max_len && ZSTR_LEN(buf.s) > max_len) {
888 ZSTR_LEN(buf.s) = max_len;
889 }
890
891 smart_str_0(&buf);
892 return buf.s;
893 }
894 /* }}} */
895
strpprintf(size_t max_len,const char * format,...)896 PHPAPI zend_string *strpprintf(size_t max_len, const char *format, ...) /* {{{ */
897 {
898 va_list ap;
899 zend_string *str;
900
901 va_start(ap, format);
902 str = vstrpprintf(max_len, format, ap);
903 va_end(ap);
904 return str;
905 }
906 /* }}} */
907
908 /*
909 * Local variables:
910 * tab-width: 4
911 * c-basic-offset: 4
912 * End:
913 * vim600: sw=4 ts=4 fdm=marker
914 * vim<600: sw=4 ts=4
915 */
916