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: 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 * which can be at most max length of double
156 */
157 #define NUM_BUF_SIZE PHP_DOUBLE_MAX_LENGTH
158
159 #define NUM(c) (c - '0')
160
161 #define STR_TO_DEC(str, num) do { \
162 num = NUM(*str++); \
163 while (isdigit((int)*str)) { \
164 num *= 10; \
165 num += NUM(*str++); \
166 if (num >= INT_MAX / 10) { \
167 while (isdigit((int)*str++)); \
168 break; \
169 } \
170 } \
171 } while (0)
172
173 /*
174 * This macro does zero padding so that the precision
175 * requirement is satisfied. The padding is done by
176 * adding '0's to the left of the string that is going
177 * to be printed.
178 */
179 #define FIX_PRECISION(adjust, precision, s, s_len) do { \
180 if (adjust) \
181 while (s_len < (size_t)precision) { \
182 *--s = '0'; \
183 s_len++; \
184 } \
185 } while (0)
186
187 /* }}} */
188
189 #if !HAVE_STRNLEN
strnlen(const char * s,size_t maxlen)190 static size_t strnlen(const char *s, size_t maxlen) {
191 char *r = memchr(s, '\0', maxlen);
192 return r ? r-s : maxlen;
193 }
194 #endif
195
196 /*
197 * Do format conversion placing the output in buffer
198 */
xbuf_format_converter(void * xbuf,zend_bool is_char,const char * fmt,va_list ap)199 static void xbuf_format_converter(void *xbuf, zend_bool is_char, const char *fmt, va_list ap) /* {{{ */
200 {
201 char *s = NULL;
202 size_t s_len;
203 int free_zcopy;
204 zval *zvp, zcopy;
205
206 int min_width = 0;
207 int precision = 0;
208 enum {
209 LEFT, RIGHT
210 } adjust;
211 char pad_char;
212 char prefix_char;
213
214 double fp_num;
215 wide_int i_num = (wide_int) 0;
216 u_wide_int ui_num = (u_wide_int) 0;
217
218 char num_buf[NUM_BUF_SIZE];
219 char char_buf[2]; /* for printing %% and %<unknown> */
220
221 #ifdef HAVE_LOCALE_H
222 #ifdef ZTS
223 struct lconv lconv;
224 #else
225 struct lconv *lconv = NULL;
226 #endif
227 #endif
228
229 /*
230 * Flag variables
231 */
232 length_modifier_e modifier;
233 boolean_e alternate_form;
234 boolean_e print_sign;
235 boolean_e print_blank;
236 boolean_e adjust_precision;
237 boolean_e adjust_width;
238 bool_int is_negative;
239
240 while (*fmt) {
241 if (*fmt != '%') {
242 INS_CHAR(xbuf, *fmt, is_char);
243 } else {
244 /*
245 * Default variable settings
246 */
247 adjust = RIGHT;
248 alternate_form = print_sign = print_blank = NO;
249 pad_char = ' ';
250 prefix_char = NUL;
251 free_zcopy = 0;
252
253 fmt++;
254
255 /*
256 * Try to avoid checking for flags, width or precision
257 */
258 if (isascii((int)*fmt) && !islower((int)*fmt)) {
259 /*
260 * Recognize flags: -, #, BLANK, +
261 */
262 for (;; fmt++) {
263 if (*fmt == '-')
264 adjust = LEFT;
265 else if (*fmt == '+')
266 print_sign = YES;
267 else if (*fmt == '#')
268 alternate_form = YES;
269 else if (*fmt == ' ')
270 print_blank = YES;
271 else if (*fmt == '0')
272 pad_char = '0';
273 else
274 break;
275 }
276
277 /*
278 * Check if a width was specified
279 */
280 if (isdigit((int)*fmt)) {
281 STR_TO_DEC(fmt, min_width);
282 adjust_width = YES;
283 } else if (*fmt == '*') {
284 min_width = va_arg(ap, int);
285 fmt++;
286 adjust_width = YES;
287 if (min_width < 0) {
288 adjust = LEFT;
289 min_width = -min_width;
290 }
291 } else
292 adjust_width = NO;
293
294 /*
295 * Check if a precision was specified
296 */
297 if (*fmt == '.') {
298 adjust_precision = YES;
299 fmt++;
300 if (isdigit((int)*fmt)) {
301 STR_TO_DEC(fmt, precision);
302 } else if (*fmt == '*') {
303 precision = va_arg(ap, int);
304 fmt++;
305 if (precision < -1)
306 precision = -1;
307 } else
308 precision = 0;
309
310 if (precision > FORMAT_CONV_MAX_PRECISION) {
311 precision = FORMAT_CONV_MAX_PRECISION;
312 }
313 } else
314 adjust_precision = NO;
315 } else
316 adjust_precision = adjust_width = NO;
317
318 /*
319 * Modifier check
320 */
321 switch (*fmt) {
322 case 'L':
323 fmt++;
324 modifier = LM_LONG_DOUBLE;
325 break;
326 case 'I':
327 fmt++;
328 #if SIZEOF_LONG_LONG
329 if (*fmt == '6' && *(fmt+1) == '4') {
330 fmt += 2;
331 modifier = LM_LONG_LONG;
332 } else
333 #endif
334 if (*fmt == '3' && *(fmt+1) == '2') {
335 fmt += 2;
336 modifier = LM_LONG;
337 } else {
338 #ifdef _WIN64
339 modifier = LM_LONG_LONG;
340 #else
341 modifier = LM_LONG;
342 #endif
343 }
344 break;
345 case 'l':
346 fmt++;
347 #if SIZEOF_LONG_LONG
348 if (*fmt == 'l') {
349 fmt++;
350 modifier = LM_LONG_LONG;
351 } else
352 #endif
353 modifier = LM_LONG;
354 break;
355 case 'z':
356 fmt++;
357 modifier = LM_SIZE_T;
358 break;
359 case 'j':
360 fmt++;
361 #if SIZEOF_INTMAX_T
362 modifier = LM_INTMAX_T;
363 #else
364 modifier = LM_SIZE_T;
365 #endif
366 break;
367 case 't':
368 fmt++;
369 #if SIZEOF_PTRDIFF_T
370 modifier = LM_PTRDIFF_T;
371 #else
372 modifier = LM_SIZE_T;
373 #endif
374 break;
375 case 'p': {
376 char __next = *(fmt+1);
377 if ('d' == __next || 'u' == __next || 'x' == __next || 'o' == __next) {
378 fmt++;
379 modifier = LM_PHP_INT_T;
380 } else {
381 modifier = LM_STD;
382 }
383 }
384 break;
385 case 'h':
386 fmt++;
387 if (*fmt == 'h') {
388 fmt++;
389 }
390 /* these are promoted to int, so no break */
391 default:
392 modifier = LM_STD;
393 break;
394 }
395
396 /*
397 * Argument extraction and printing.
398 * First we determine the argument type.
399 * Then, we convert the argument to a string.
400 * On exit from the switch, s points to the string that
401 * must be printed, s_len has the length of the string
402 * The precision requirements, if any, are reflected in s_len.
403 *
404 * NOTE: pad_char may be set to '0' because of the 0 flag.
405 * It is reset to ' ' by non-numeric formats
406 */
407 switch (*fmt) {
408 case 'Z': {
409 zvp = (zval*) va_arg(ap, zval*);
410 free_zcopy = zend_make_printable_zval(zvp, &zcopy);
411 if (free_zcopy) {
412 zvp = &zcopy;
413 }
414 s_len = Z_STRLEN_P(zvp);
415 s = Z_STRVAL_P(zvp);
416 if (adjust_precision && (size_t)precision < s_len) {
417 s_len = precision;
418 }
419 break;
420 }
421 case 'u':
422 switch(modifier) {
423 default:
424 i_num = (wide_int) va_arg(ap, unsigned int);
425 break;
426 case LM_LONG_DOUBLE:
427 goto fmt_error;
428 case LM_LONG:
429 i_num = (wide_int) va_arg(ap, unsigned long int);
430 break;
431 case LM_SIZE_T:
432 i_num = (wide_int) va_arg(ap, size_t);
433 break;
434 #if SIZEOF_LONG_LONG
435 case LM_LONG_LONG:
436 i_num = (wide_int) va_arg(ap, u_wide_int);
437 break;
438 #endif
439 #if SIZEOF_INTMAX_T
440 case LM_INTMAX_T:
441 i_num = (wide_int) va_arg(ap, uintmax_t);
442 break;
443 #endif
444 #if SIZEOF_PTRDIFF_T
445 case LM_PTRDIFF_T:
446 i_num = (wide_int) va_arg(ap, ptrdiff_t);
447 break;
448 #endif
449 case LM_PHP_INT_T:
450 i_num = (wide_int) va_arg(ap, zend_ulong);
451 break;
452 }
453 /*
454 * The rest also applies to other integer formats, so fall
455 * into that case.
456 */
457 case 'd':
458 case 'i':
459 /*
460 * Get the arg if we haven't already.
461 */
462 if ((*fmt) != 'u') {
463 switch(modifier) {
464 default:
465 i_num = (wide_int) va_arg(ap, int);
466 break;
467 case LM_LONG_DOUBLE:
468 goto fmt_error;
469 case LM_LONG:
470 i_num = (wide_int) va_arg(ap, long int);
471 break;
472 case LM_SIZE_T:
473 #if SIZEOF_SSIZE_T
474 i_num = (wide_int) va_arg(ap, ssize_t);
475 #else
476 i_num = (wide_int) va_arg(ap, size_t);
477 #endif
478 break;
479 #if SIZEOF_LONG_LONG
480 case LM_LONG_LONG:
481 i_num = (wide_int) va_arg(ap, wide_int);
482 break;
483 #endif
484 #if SIZEOF_INTMAX_T
485 case LM_INTMAX_T:
486 i_num = (wide_int) va_arg(ap, intmax_t);
487 break;
488 #endif
489 #if SIZEOF_PTRDIFF_T
490 case LM_PTRDIFF_T:
491 i_num = (wide_int) va_arg(ap, ptrdiff_t);
492 break;
493 #endif
494 case LM_PHP_INT_T:
495 i_num = (wide_int) va_arg(ap, zend_long);
496 break;
497 }
498 }
499 s = ap_php_conv_10(i_num, (*fmt) == 'u', &is_negative,
500 &num_buf[NUM_BUF_SIZE], &s_len);
501 FIX_PRECISION(adjust_precision, precision, s, s_len);
502
503 if (*fmt != 'u') {
504 if (is_negative)
505 prefix_char = '-';
506 else if (print_sign)
507 prefix_char = '+';
508 else if (print_blank)
509 prefix_char = ' ';
510 }
511 break;
512
513
514 case 'o':
515 switch(modifier) {
516 default:
517 ui_num = (u_wide_int) va_arg(ap, unsigned int);
518 break;
519 case LM_LONG_DOUBLE:
520 goto fmt_error;
521 case LM_LONG:
522 ui_num = (u_wide_int) va_arg(ap, unsigned long int);
523 break;
524 case LM_SIZE_T:
525 ui_num = (u_wide_int) va_arg(ap, size_t);
526 break;
527 #if SIZEOF_LONG_LONG
528 case LM_LONG_LONG:
529 ui_num = (u_wide_int) va_arg(ap, u_wide_int);
530 break;
531 #endif
532 #if SIZEOF_INTMAX_T
533 case LM_INTMAX_T:
534 ui_num = (u_wide_int) va_arg(ap, uintmax_t);
535 break;
536 #endif
537 #if SIZEOF_PTRDIFF_T
538 case LM_PTRDIFF_T:
539 ui_num = (u_wide_int) va_arg(ap, ptrdiff_t);
540 break;
541 #endif
542 case LM_PHP_INT_T:
543 ui_num = (u_wide_int) va_arg(ap, zend_ulong);
544 break;
545 }
546 s = ap_php_conv_p2(ui_num, 3, *fmt,
547 &num_buf[NUM_BUF_SIZE], &s_len);
548 FIX_PRECISION(adjust_precision, precision, s, s_len);
549 if (alternate_form && *s != '0') {
550 *--s = '0';
551 s_len++;
552 }
553 break;
554
555
556 case 'x':
557 case 'X':
558 switch(modifier) {
559 default:
560 ui_num = (u_wide_int) va_arg(ap, unsigned int);
561 break;
562 case LM_LONG_DOUBLE:
563 goto fmt_error;
564 case LM_LONG:
565 ui_num = (u_wide_int) va_arg(ap, unsigned long int);
566 break;
567 case LM_SIZE_T:
568 ui_num = (u_wide_int) va_arg(ap, size_t);
569 break;
570 #if SIZEOF_LONG_LONG
571 case LM_LONG_LONG:
572 ui_num = (u_wide_int) va_arg(ap, u_wide_int);
573 break;
574 #endif
575 #if SIZEOF_INTMAX_T
576 case LM_INTMAX_T:
577 ui_num = (u_wide_int) va_arg(ap, uintmax_t);
578 break;
579 #endif
580 #if SIZEOF_PTRDIFF_T
581 case LM_PTRDIFF_T:
582 ui_num = (u_wide_int) va_arg(ap, ptrdiff_t);
583 break;
584 #endif
585 case LM_PHP_INT_T:
586 ui_num = (u_wide_int) va_arg(ap, zend_ulong);
587 break;
588 }
589 s = ap_php_conv_p2(ui_num, 4, *fmt,
590 &num_buf[NUM_BUF_SIZE], &s_len);
591 FIX_PRECISION(adjust_precision, precision, s, s_len);
592 if (alternate_form && ui_num != 0) {
593 *--s = *fmt; /* 'x' or 'X' */
594 *--s = '0';
595 s_len += 2;
596 }
597 break;
598
599
600 case 's':
601 case 'v':
602 s = va_arg(ap, char *);
603 if (s != NULL) {
604 if (!adjust_precision) {
605 s_len = strlen(s);
606 } else {
607 s_len = strnlen(s, precision);
608 }
609 } else {
610 s = S_NULL;
611 s_len = S_NULL_LEN;
612 }
613 pad_char = ' ';
614 break;
615
616
617 case 'f':
618 case 'F':
619 case 'e':
620 case 'E':
621 switch(modifier) {
622 case LM_LONG_DOUBLE:
623 fp_num = (double) va_arg(ap, long double);
624 break;
625 case LM_STD:
626 fp_num = va_arg(ap, double);
627 break;
628 default:
629 goto fmt_error;
630 }
631
632 if (zend_isnan(fp_num)) {
633 s = "nan";
634 s_len = 3;
635 } else if (zend_isinf(fp_num)) {
636 s = "inf";
637 s_len = 3;
638 } else {
639 #ifdef HAVE_LOCALE_H
640 #ifdef ZTS
641 localeconv_r(&lconv);
642 #else
643 if (!lconv) {
644 lconv = localeconv();
645 }
646 #endif
647 #endif
648 s = php_conv_fp((*fmt == 'f')?'F':*fmt, fp_num, alternate_form,
649 (adjust_precision == NO) ? FLOAT_DIGITS : precision,
650 (*fmt == 'f')?LCONV_DECIMAL_POINT:'.',
651 &is_negative, &num_buf[1], &s_len);
652 if (is_negative)
653 prefix_char = '-';
654 else if (print_sign)
655 prefix_char = '+';
656 else if (print_blank)
657 prefix_char = ' ';
658 }
659 break;
660
661
662 case 'g':
663 case 'k':
664 case 'G':
665 case 'H':
666 switch(modifier) {
667 case LM_LONG_DOUBLE:
668 fp_num = (double) va_arg(ap, long double);
669 break;
670 case LM_STD:
671 fp_num = va_arg(ap, double);
672 break;
673 default:
674 goto fmt_error;
675 }
676
677 if (zend_isnan(fp_num)) {
678 s = "NAN";
679 s_len = 3;
680 break;
681 } else if (zend_isinf(fp_num)) {
682 if (fp_num > 0) {
683 s = "INF";
684 s_len = 3;
685 } else {
686 s = "-INF";
687 s_len = 4;
688 }
689 break;
690 }
691
692 if (adjust_precision == NO)
693 precision = FLOAT_DIGITS;
694 else if (precision == 0)
695 precision = 1;
696 /*
697 * * We use &num_buf[ 1 ], so that we have room for the sign
698 */
699 #ifdef HAVE_LOCALE_H
700 #ifdef ZTS
701 localeconv_r(&lconv);
702 #else
703 if (!lconv) {
704 lconv = localeconv();
705 }
706 #endif
707 #endif
708 s = php_gcvt(fp_num, precision, (*fmt=='H' || *fmt == 'k') ? '.' : LCONV_DECIMAL_POINT, (*fmt == 'G' || *fmt == 'H')?'E':'e', &num_buf[1]);
709 if (*s == '-')
710 prefix_char = *s++;
711 else if (print_sign)
712 prefix_char = '+';
713 else if (print_blank)
714 prefix_char = ' ';
715
716 s_len = strlen(s);
717
718 if (alternate_form && (strchr(s, '.')) == NULL)
719 s[s_len++] = '.';
720 break;
721
722
723 case 'c':
724 char_buf[0] = (char) (va_arg(ap, int));
725 s = &char_buf[0];
726 s_len = 1;
727 pad_char = ' ';
728 break;
729
730
731 case '%':
732 char_buf[0] = '%';
733 s = &char_buf[0];
734 s_len = 1;
735 pad_char = ' ';
736 break;
737
738
739 case 'n':
740 *(va_arg(ap, int *)) = is_char? (int)((smart_string *)xbuf)->len : (int)ZSTR_LEN(((smart_str *)xbuf)->s);
741 goto skip_output;
742
743 /*
744 * Always extract the argument as a "char *" pointer. We
745 * should be using "void *" but there are still machines
746 * that don't understand it.
747 * If the pointer size is equal to the size of an unsigned
748 * integer we convert the pointer to a hex number, otherwise
749 * we print "%p" to indicate that we don't handle "%p".
750 */
751 case 'p':
752 if (sizeof(char *) <= sizeof(u_wide_int)) {
753 ui_num = (u_wide_int)((size_t) va_arg(ap, char *));
754 s = ap_php_conv_p2(ui_num, 4, 'x',
755 &num_buf[NUM_BUF_SIZE], &s_len);
756 if (ui_num != 0) {
757 *--s = 'x';
758 *--s = '0';
759 s_len += 2;
760 }
761 } else {
762 s = "%p";
763 s_len = 2;
764 }
765 pad_char = ' ';
766 break;
767
768
769 case NUL:
770 /*
771 * The last character of the format string was %.
772 * We ignore it.
773 */
774 continue;
775
776
777 fmt_error:
778 php_error(E_ERROR, "Illegal length modifier specified '%c' in s[np]printf call", *fmt);
779 /*
780 * The default case is for unrecognized %'s.
781 * We print %<char> to help the user identify what
782 * option is not understood.
783 * This is also useful in case the user wants to pass
784 * the output of format_converter to another function
785 * that understands some other %<char> (like syslog).
786 * Note that we can't point s inside fmt because the
787 * unknown <char> could be preceded by width etc.
788 */
789 default:
790 char_buf[0] = '%';
791 char_buf[1] = *fmt;
792 s = char_buf;
793 s_len = 2;
794 pad_char = ' ';
795 break;
796 }
797
798 if (prefix_char != NUL) {
799 *--s = prefix_char;
800 s_len++;
801 }
802 if (adjust_width && adjust == RIGHT && (size_t)min_width > s_len) {
803 if (pad_char == '0' && prefix_char != NUL) {
804 INS_CHAR(xbuf, *s, is_char);
805 s++;
806 s_len--;
807 min_width--;
808 }
809 PAD_CHAR(xbuf, pad_char, min_width - s_len, is_char);
810 }
811 /*
812 * Print the string s.
813 */
814 INS_STRING(xbuf, s, s_len, is_char);
815
816 if (adjust_width && adjust == LEFT && (size_t)min_width > s_len) {
817 PAD_CHAR(xbuf, pad_char, min_width - s_len, is_char);
818 }
819
820 if (free_zcopy) {
821 zval_dtor(&zcopy);
822 }
823 }
824 skip_output:
825 fmt++;
826 }
827 return;
828 }
829 /* }}} */
830
831 /*
832 * This is the general purpose conversion function.
833 */
vspprintf(char ** pbuf,size_t max_len,const char * format,va_list ap)834 PHPAPI size_t vspprintf(char **pbuf, size_t max_len, const char *format, va_list ap) /* {{{ */
835 {
836 smart_string buf = {0};
837
838 /* since there are places where (v)spprintf called without checking for null,
839 a bit of defensive coding here */
840 if(!pbuf) {
841 return 0;
842 }
843 xbuf_format_converter(&buf, 1, format, ap);
844
845 if (max_len && buf.len > max_len) {
846 buf.len = max_len;
847 }
848
849 smart_string_0(&buf);
850
851 if (buf.c) {
852 *pbuf = buf.c;
853 return buf.len;
854 } else {
855 *pbuf = estrndup("", 0);
856 return 0;
857 }
858 }
859 /* }}} */
860
spprintf(char ** pbuf,size_t max_len,const char * format,...)861 PHPAPI size_t spprintf(char **pbuf, size_t max_len, const char *format, ...) /* {{{ */
862 {
863 size_t cc;
864 va_list ap;
865
866 va_start(ap, format);
867 cc = vspprintf(pbuf, max_len, format, ap);
868 va_end(ap);
869 return (cc);
870 }
871 /* }}} */
872
vstrpprintf(size_t max_len,const char * format,va_list ap)873 PHPAPI zend_string *vstrpprintf(size_t max_len, const char *format, va_list ap) /* {{{ */
874 {
875 smart_str buf = {0};
876
877 xbuf_format_converter(&buf, 0, format, ap);
878
879 if (!buf.s) {
880 return ZSTR_EMPTY_ALLOC();
881 }
882
883 if (max_len && ZSTR_LEN(buf.s) > max_len) {
884 ZSTR_LEN(buf.s) = max_len;
885 }
886
887 smart_str_0(&buf);
888 return buf.s;
889 }
890 /* }}} */
891
strpprintf(size_t max_len,const char * format,...)892 PHPAPI zend_string *strpprintf(size_t max_len, const char *format, ...) /* {{{ */
893 {
894 va_list ap;
895 zend_string *str;
896
897 va_start(ap, format);
898 str = vstrpprintf(max_len, format, ap);
899 va_end(ap);
900 return str;
901 }
902 /* }}} */
903
904 /*
905 * Local variables:
906 * tab-width: 4
907 * c-basic-offset: 4
908 * End:
909 * vim600: sw=4 ts=4 fdm=marker
910 * vim<600: sw=4 ts=4
911 */
912