xref: /PHP-7.3/main/snprintf.c (revision 8d3f8ca1)
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:                                                              |
16   +----------------------------------------------------------------------+
17 */
18 
19 #define _GNU_SOURCE
20 #include "php.h"
21 
22 #include <zend_strtod.h>
23 
24 #include <stddef.h>
25 #include <stdio.h>
26 #include <ctype.h>
27 #include <sys/types.h>
28 #include <stdarg.h>
29 #include <string.h>
30 #include <stdlib.h>
31 #include <math.h>
32 
33 #ifdef HAVE_INTTYPES_H
34 #include <inttypes.h>
35 #endif
36 
37 #ifdef HAVE_LOCALE_H
38 #include <locale.h>
39 #ifdef ZTS
40 #include "ext/standard/php_string.h"
41 #define LCONV_DECIMAL_POINT (*lconv.decimal_point)
42 #else
43 #define LCONV_DECIMAL_POINT (*lconv->decimal_point)
44 #endif
45 #else
46 #define LCONV_DECIMAL_POINT '.'
47 #endif
48 
49 /*
50  * Copyright (c) 2002, 2006 Todd C. Miller <Todd.Miller@courtesan.com>
51  *
52  * Permission to use, copy, modify, and distribute this software for any
53  * purpose with or without fee is hereby granted, provided that the above
54  * copyright notice and this permission notice appear in all copies.
55  *
56  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
57  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
58  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
59  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
60  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
61  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
62  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
63  *
64  * Sponsored in part by the Defense Advanced Research Projects
65  * Agency (DARPA) and Air Force Research Laboratory, Air Force
66  * Materiel Command, USAF, under agreement number F39502-99-1-0512.
67  */
68 
__cvt(double value,int ndigit,int * decpt,int * sign,int fmode,int pad)69 static char * __cvt(double value, int ndigit, int *decpt, int *sign, int fmode, int pad) /* {{{ */
70 {
71 	register char *s = NULL;
72 	char *p, *rve, c;
73 	size_t siz;
74 
75 	if (ndigit < 0) {
76 		siz = -ndigit + 1;
77 	} else {
78 		siz = ndigit + 1;
79 	}
80 
81 	/* __dtoa() doesn't allocate space for 0 so we do it by hand */
82 	if (value == 0.0) {
83 		*decpt = 1 - fmode; /* 1 for 'e', 0 for 'f' */
84 		*sign = 0;
85 		if ((rve = s = (char *)malloc(ndigit?siz:2)) == NULL) {
86 			return(NULL);
87 		}
88 		*rve++ = '0';
89 		*rve = '\0';
90 		if (!ndigit) {
91 			return(s);
92 		}
93 	} else {
94 		p = zend_dtoa(value, fmode + 2, ndigit, decpt, sign, &rve);
95 		if (*decpt == 9999) {
96 			/* Infinity or Nan, convert to inf or nan like printf */
97 			*decpt = 0;
98 			c = *p;
99 			zend_freedtoa(p);
100 			return strdup((c == 'I' ? "INF" : "NAN"));
101 		}
102 		/* Make a local copy and adjust rve to be in terms of s */
103 		if (pad && fmode) {
104 			siz += *decpt;
105 		}
106 		if ((s = (char *)malloc(siz+1)) == NULL) {
107 			zend_freedtoa(p);
108 			return(NULL);
109 		}
110 		(void) strlcpy(s, p, siz);
111 		rve = s + (rve - p);
112 		zend_freedtoa(p);
113 	}
114 
115 	/* Add trailing zeros */
116 	if (pad) {
117 		siz -= rve - s;
118 		while (--siz) {
119 			*rve++ = '0';
120 		}
121 		*rve = '\0';
122 	}
123 
124 	return(s);
125 }
126 /* }}} */
127 
php_ecvt(double value,int ndigit,int * decpt,int * sign)128 static inline char *php_ecvt(double value, int ndigit, int *decpt, int *sign) /* {{{ */
129 {
130 	return(__cvt(value, ndigit, decpt, sign, 0, 1));
131 }
132 /* }}} */
133 
php_fcvt(double value,int ndigit,int * decpt,int * sign)134 static inline char *php_fcvt(double value, int ndigit, int *decpt, int *sign) /* {{{ */
135 {
136     return(__cvt(value, ndigit, decpt, sign, 1, 1));
137 }
138 /* }}} */
139 
php_gcvt(double value,int ndigit,char dec_point,char exponent,char * buf)140 PHPAPI char *php_gcvt(double value, int ndigit, char dec_point, char exponent, char *buf) /* {{{ */
141 {
142 	char *digits, *dst, *src;
143 	int i, decpt, sign;
144 	int mode = ndigit >= 0 ? 2 : 0;
145 
146 	if (mode == 0) {
147 		ndigit = 17;
148 	}
149 	digits = zend_dtoa(value, mode, ndigit, &decpt, &sign, NULL);
150 	if (decpt == 9999) {
151 		/*
152 		 * Infinity or NaN, convert to inf or nan with sign.
153 		 * We assume the buffer is at least ndigit long.
154 		 */
155 		snprintf(buf, ndigit + 1, "%s%s", (sign && *digits == 'I') ? "-" : "", *digits == 'I' ? "INF" : "NAN");
156 		zend_freedtoa(digits);
157 		return (buf);
158 	}
159 
160 	dst = buf;
161 	if (sign) {
162 		*dst++ = '-';
163 	}
164 
165 	if ((decpt >= 0 && decpt > ndigit) || decpt < -3) { /* use E-style */
166 		/* exponential format (e.g. 1.2345e+13) */
167 		if (--decpt < 0) {
168 			sign = 1;
169 			decpt = -decpt;
170 		} else {
171 			sign = 0;
172 		}
173 		src = digits;
174 		*dst++ = *src++;
175 		*dst++ = dec_point;
176 		if (*src == '\0') {
177 			*dst++ = '0';
178 		} else {
179 			do {
180 				*dst++ = *src++;
181 			} while (*src != '\0');
182 		}
183 		*dst++ = exponent;
184 		if (sign) {
185 			*dst++ = '-';
186 		} else {
187 			*dst++ = '+';
188 		}
189 		if (decpt < 10) {
190 			*dst++ = '0' + decpt;
191 			*dst = '\0';
192 		} else {
193 			/* XXX - optimize */
194 			for (sign = decpt, i = 0; (sign /= 10) != 0; i++)
195 				continue;
196 			dst[i + 1] = '\0';
197 			while (decpt != 0) {
198 				dst[i--] = '0' + decpt % 10;
199 				decpt /= 10;
200 			}
201 		}
202 	} else if (decpt < 0) {
203 		/* standard format 0. */
204 		*dst++ = '0';   /* zero before decimal point */
205 		*dst++ = dec_point;
206 		do {
207 			*dst++ = '0';
208 		} while (++decpt < 0);
209 		src = digits;
210 		while (*src != '\0') {
211 			*dst++ = *src++;
212 		}
213 		*dst = '\0';
214 	} else {
215 		/* standard format */
216 		for (i = 0, src = digits; i < decpt; i++) {
217 			if (*src != '\0') {
218 				*dst++ = *src++;
219 			} else {
220 				*dst++ = '0';
221 			}
222 		}
223 		if (*src != '\0') {
224 			if (src == digits) {
225 				*dst++ = '0';   /* zero before decimal point */
226 			}
227 			*dst++ = dec_point;
228 			for (i = decpt; digits[i] != '\0'; i++) {
229                 *dst++ = digits[i];
230             }
231         }
232         *dst = '\0';
233     }
234     zend_freedtoa(digits);
235     return (buf);
236 }
237 /* }}} */
238 
239 /* {{{ Apache license */
240 /* ====================================================================
241  * Copyright (c) 1995-1998 The Apache Group.  All rights reserved.
242  *
243  * Redistribution and use in source and binary forms, with or without
244  * modification, are permitted provided that the following conditions
245  * are met:
246  *
247  * 1. Redistributions of source code must retain the above copyright
248  *    notice, this list of conditions and the following disclaimer.
249  *
250  * 2. Redistributions in binary form must reproduce the above copyright
251  *    notice, this list of conditions and the following disclaimer in
252  *    the documentation and/or other materials provided with the
253  *    distribution.
254  *
255  * 3. All advertising materials mentioning features or use of this
256  *    software must display the following acknowledgment:
257  *    "This product includes software developed by the Apache Group
258  *    for use in the Apache HTTP server project (http://www.apache.org/)."
259  *
260  * 4. The names "Apache Server" and "Apache Group" must not be used to
261  *    endorse or promote products derived from this software without
262  *    prior written permission.
263  *
264  * 5. Redistributions of any form whatsoever must retain the following
265  *    acknowledgment:
266  *    "This product includes software developed by the Apache Group
267  *    for use in the Apache HTTP server project (http://www.apache.org/)."
268  *
269  * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY
270  * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
271  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
272  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE APACHE GROUP OR
273  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
274  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
275  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
276  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
277  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
278  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
279  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
280  * OF THE POSSIBILITY OF SUCH DAMAGE.
281  * ====================================================================
282  *
283  * This software consists of voluntary contributions made by many
284  * individuals on behalf of the Apache Group and was originally based
285  * on public domain software written at the National Center for
286  * Supercomputing Applications, University of Illinois, Urbana-Champaign.
287  * For more information on the Apache Group and the Apache HTTP server
288  * project, please see <http://www.apache.org/>.
289  *
290  * This code is based on, and used with the permission of, the
291  * SIO stdio-replacement strx_* functions by Panos Tsirigotis
292  * <panos@alumni.cs.colorado.edu> for xinetd.
293  */
294 /* }}} */
295 
296 #define FALSE			0
297 #define TRUE			1
298 #define NUL			'\0'
299 #define INT_NULL		((int *)0)
300 
301 #define S_NULL			"(null)"
302 #define S_NULL_LEN		6
303 
304 #define FLOAT_DIGITS		6
305 #define EXPONENT_LENGTH		10
306 
307 
308 /*
309  * Convert num to its decimal format.
310  * Return value:
311  *   - a pointer to a string containing the number (no sign)
312  *   - len contains the length of the string
313  *   - is_negative is set to TRUE or FALSE depending on the sign
314  *     of the number (always set to FALSE if is_unsigned is TRUE)
315  *
316  * The caller provides a buffer for the string: that is the buf_end argument
317  * which is a pointer to the END of the buffer + 1 (i.e. if the buffer
318  * is declared as buf[ 100 ], buf_end should be &buf[ 100 ])
319  */
320 /* char * ap_php_conv_10() {{{ */
ap_php_conv_10(register wide_int num,register bool_int is_unsigned,register bool_int * is_negative,char * buf_end,register size_t * len)321 PHPAPI char * ap_php_conv_10(register wide_int num, register bool_int is_unsigned,
322 	   register bool_int * is_negative, char *buf_end, register size_t *len)
323 {
324 	register char *p = buf_end;
325 	register u_wide_int magnitude;
326 
327 	if (is_unsigned) {
328 		magnitude = (u_wide_int) num;
329 		*is_negative = FALSE;
330 	} else {
331 		*is_negative = (num < 0);
332 
333 		/*
334 		 * On a 2's complement machine, negating the most negative integer
335 		 * results in a number that cannot be represented as a signed integer.
336 		 * Here is what we do to obtain the number's magnitude:
337 		 *      a. add 1 to the number
338 		 *      b. negate it (becomes positive)
339 		 *      c. convert it to unsigned
340 		 *      d. add 1
341 		 */
342 		if (*is_negative) {
343 			wide_int t = num + 1;
344 			magnitude = ((u_wide_int) - t) + 1;
345 		} else {
346 			magnitude = (u_wide_int) num;
347 		}
348 	}
349 
350 	/*
351 	 * We use a do-while loop so that we write at least 1 digit
352 	 */
353 	do {
354 		register u_wide_int new_magnitude = magnitude / 10;
355 
356 		*--p = (char)(magnitude - new_magnitude * 10 + '0');
357 		magnitude = new_magnitude;
358 	}
359 	while (magnitude);
360 
361 	*len = buf_end - p;
362 	return (p);
363 }
364 /* }}} */
365 
366 /* If you change this value then also change bug24640.phpt.
367  * Also NDIG must be reasonable smaller than NUM_BUF_SIZE.
368  */
369 #define	NDIG	320
370 
371 
372 /*
373  * Convert a floating point number to a string formats 'f', 'e' or 'E'.
374  * The result is placed in buf, and len denotes the length of the string
375  * The sign is returned in the is_negative argument (and is not placed
376  * in buf).
377  */
378 /* PHPAPI char * php_conv_fp() {{{ */
php_conv_fp(register char format,register double num,boolean_e add_dp,int precision,char dec_point,bool_int * is_negative,char * buf,size_t * len)379 PHPAPI char * php_conv_fp(register char format, register double num,
380 		 boolean_e add_dp, int precision, char dec_point, bool_int * is_negative, char *buf, size_t *len)
381 {
382 	register char *s = buf;
383 	register char *p, *p_orig;
384 	int decimal_point;
385 
386 	if (precision >= NDIG - 1) {
387 		precision = NDIG - 2;
388 	}
389 
390 	if (format == 'F') {
391 		p_orig = p = php_fcvt(num, precision, &decimal_point, is_negative);
392 	} else {						/* either e or E format */
393 		p_orig = p = php_ecvt(num, precision + 1, &decimal_point, is_negative);
394 	}
395 
396 	/*
397 	 * Check for Infinity and NaN
398 	 */
399 	if (isalpha((int)*p)) {
400 		*len = strlen(p);
401 		memcpy(buf, p, *len + 1);
402 		*is_negative = FALSE;
403 		free(p_orig);
404 		return (buf);
405 	}
406 	if (format == 'F') {
407 		if (decimal_point <= 0) {
408 			if (num != 0 || precision > 0) {
409 				*s++ = '0';
410 				if (precision > 0) {
411 					*s++ = dec_point;
412 					while (decimal_point++ < 0) {
413 						*s++ = '0';
414 					}
415 				} else if (add_dp) {
416 					*s++ = dec_point;
417 				}
418 			}
419 		} else {
420 			int addz = decimal_point >= NDIG ? decimal_point - NDIG + 1 : 0;
421 			decimal_point -= addz;
422 			while (decimal_point-- > 0) {
423 				*s++ = *p++;
424 			}
425 			while (addz-- > 0) {
426 				*s++ = '0';
427 			}
428 			if (precision > 0 || add_dp) {
429 				*s++ = dec_point;
430 			}
431 		}
432 	} else {
433 		*s++ = *p++;
434 		if (precision > 0 || add_dp) {
435 			*s++ = '.';
436 		}
437 	}
438 
439 	/*
440 	 * copy the rest of p, the NUL is NOT copied
441 	 */
442 	while (*p) {
443 		*s++ = *p++;
444 	}
445 
446 	if (format != 'F') {
447 		char temp[EXPONENT_LENGTH];		/* for exponent conversion */
448 		size_t t_len;
449 		bool_int exponent_is_negative;
450 
451 		*s++ = format;			/* either e or E */
452 		decimal_point--;
453 		if (decimal_point != 0) {
454 			p = ap_php_conv_10((wide_int) decimal_point, FALSE, &exponent_is_negative, &temp[EXPONENT_LENGTH], &t_len);
455 			*s++ = exponent_is_negative ? '-' : '+';
456 
457 			/*
458 			 * Make sure the exponent has at least 2 digits
459 			 */
460 			while (t_len--) {
461 				*s++ = *p++;
462 			}
463 		} else {
464 			*s++ = '+';
465 			*s++ = '0';
466 		}
467 	}
468 	*len = s - buf;
469 	free(p_orig);
470 	return (buf);
471 }
472 /* }}} */
473 
474 /*
475  * Convert num to a base X number where X is a power of 2. nbits determines X.
476  * For example, if nbits is 3, we do base 8 conversion
477  * Return value:
478  *      a pointer to a string containing the number
479  *
480  * The caller provides a buffer for the string: that is the buf_end argument
481  * which is a pointer to the END of the buffer + 1 (i.e. if the buffer
482  * is declared as buf[ 100 ], buf_end should be &buf[ 100 ])
483  */
ap_php_conv_p2(register u_wide_int num,register int nbits,char format,char * buf_end,register size_t * len)484 PHPAPI char * ap_php_conv_p2(register u_wide_int num, register int nbits, char format, char *buf_end, register size_t *len) /* {{{ */
485 {
486 	register int mask = (1 << nbits) - 1;
487 	register char *p = buf_end;
488 	static const char low_digits[] = "0123456789abcdef";
489 	static const char upper_digits[] = "0123456789ABCDEF";
490 	register const char *digits = (format == 'X') ? upper_digits : low_digits;
491 
492 	do {
493 		*--p = digits[num & mask];
494 		num >>= nbits;
495 	}
496 	while (num);
497 
498 	*len = buf_end - p;
499 	return (p);
500 }
501 /* }}} */
502 
503 /*
504  * NUM_BUF_SIZE is the size of the buffer used for arithmetic conversions
505  *
506  * XXX: this is a magic number; do not decrease it
507  * Emax = 1023
508  * NDIG = 320
509  * NUM_BUF_SIZE >= strlen("-") + Emax + strlrn(".") + NDIG + strlen("E+1023") + 1;
510  */
511 #define NUM_BUF_SIZE		2048
512 
513 
514 /*
515  * Descriptor for buffer area
516  */
517 struct buf_area {
518 	char *buf_end;
519 	char *nextb;				/* pointer to next byte to read/write   */
520 };
521 
522 typedef struct buf_area buffy;
523 
524 /*
525  * The INS_CHAR macro inserts a character in the buffer and writes
526  * the buffer back to disk if necessary
527  * It uses the char pointers sp and bep:
528  *      sp points to the next available character in the buffer
529  *      bep points to the end-of-buffer+1
530  * While using this macro, note that the nextb pointer is NOT updated.
531  *
532  * NOTE: Evaluation of the c argument should not have any side-effects
533  */
534 #define INS_CHAR(c, sp, bep, cc) \
535 	{                            \
536 		if (sp < bep)            \
537 		{                        \
538 			*sp++ = c;           \
539 		}                        \
540 		cc++;                    \
541 	}
542 
543 #define NUM( c )			( c - '0' )
544 
545 #define STR_TO_DEC( str, num )		\
546     num = NUM( *str++ ) ;		\
547     while ( isdigit((int)*str ) )		\
548     {					\
549 	num *= 10 ;			\
550 	num += NUM( *str++ ) ;		\
551     }
552 
553 /*
554  * This macro does zero padding so that the precision
555  * requirement is satisfied. The padding is done by
556  * adding '0's to the left of the string that is going
557  * to be printed.
558  */
559 #define FIX_PRECISION( adjust, precision, s, s_len )	\
560     if ( adjust )						\
561 	while ( s_len < (size_t)precision )	\
562 	{									\
563 	    *--s = '0' ;					\
564 	    s_len++ ;						\
565 	}
566 
567 /*
568  * Macro that does padding. The padding is done by printing
569  * the character ch.
570  */
571 #define PAD( width, len, ch )	do		\
572 	{					\
573 	    INS_CHAR( ch, sp, bep, cc ) ;	\
574 	    width-- ;				\
575 	}					\
576 	while ( width > len )
577 
578 /*
579  * Prefix the character ch to the string str
580  * Increase length
581  * Set the has_prefix flag
582  */
583 #define PREFIX( str, length, ch )	 *--str = ch ; length++ ; has_prefix = YES
584 
585 
586 /*
587  * Do format conversion placing the output in buffer
588  */
format_converter(register buffy * odp,const char * fmt,va_list ap)589 static int format_converter(register buffy * odp, const char *fmt, va_list ap) /* {{{ */
590 {
591 	char *sp;
592 	char *bep;
593 	int cc = 0;
594 	size_t i;
595 
596 	char *s = NULL;
597 	size_t s_len;
598 	int free_zcopy;
599 	zval *zvp, zcopy;
600 
601 	int min_width = 0;
602 	int precision = 0;
603 	enum {
604 		LEFT, RIGHT
605 	} adjust;
606 	char pad_char;
607 	char prefix_char;
608 
609 	double fp_num;
610 	wide_int i_num = (wide_int) 0;
611 	u_wide_int ui_num;
612 
613 	char num_buf[NUM_BUF_SIZE];
614 	char char_buf[2];			/* for printing %% and %<unknown> */
615 
616 #ifdef HAVE_LOCALE_H
617 #ifdef ZTS
618 	struct lconv lconv;
619 #else
620 	struct lconv *lconv = NULL;
621 #endif
622 #endif
623 
624 	/*
625 	 * Flag variables
626 	 */
627 	length_modifier_e modifier;
628 	boolean_e alternate_form;
629 	boolean_e print_sign;
630 	boolean_e print_blank;
631 	boolean_e adjust_precision;
632 	boolean_e adjust_width;
633 	bool_int is_negative;
634 
635 	sp = odp->nextb;
636 	bep = odp->buf_end;
637 
638 	while (*fmt) {
639 		if (*fmt != '%') {
640 			INS_CHAR(*fmt, sp, bep, cc);
641 		} else {
642 			/*
643 			 * Default variable settings
644 			 */
645 			adjust = RIGHT;
646 			alternate_form = print_sign = print_blank = NO;
647 			pad_char = ' ';
648 			prefix_char = NUL;
649 			free_zcopy = 0;
650 
651 			fmt++;
652 
653 			/*
654 			 * Try to avoid checking for flags, width or precision
655 			 */
656 			if (isascii((int)*fmt) && !islower((int)*fmt)) {
657 				/*
658 				 * Recognize flags: -, #, BLANK, +
659 				 */
660 				for (;; fmt++) {
661 					if (*fmt == '-')
662 						adjust = LEFT;
663 					else if (*fmt == '+')
664 						print_sign = YES;
665 					else if (*fmt == '#')
666 						alternate_form = YES;
667 					else if (*fmt == ' ')
668 						print_blank = YES;
669 					else if (*fmt == '0')
670 						pad_char = '0';
671 					else
672 						break;
673 				}
674 
675 				/*
676 				 * Check if a width was specified
677 				 */
678 				if (isdigit((int)*fmt)) {
679 					STR_TO_DEC(fmt, min_width);
680 					adjust_width = YES;
681 				} else if (*fmt == '*') {
682 					min_width = va_arg(ap, int);
683 					fmt++;
684 					adjust_width = YES;
685 					if (min_width < 0) {
686 						adjust = LEFT;
687 						min_width = -min_width;
688 					}
689 				} else
690 					adjust_width = NO;
691 
692 				/*
693 				 * Check if a precision was specified
694 				 */
695 				if (*fmt == '.') {
696 					adjust_precision = YES;
697 					fmt++;
698 					if (isdigit((int)*fmt)) {
699 						STR_TO_DEC(fmt, precision);
700 					} else if (*fmt == '*') {
701 						precision = va_arg(ap, int);
702 						fmt++;
703 						if (precision < 0)
704 							precision = 0;
705 					} else
706 						precision = 0;
707 
708 					if (precision > FORMAT_CONV_MAX_PRECISION) {
709 						precision = FORMAT_CONV_MAX_PRECISION;
710 					}
711 				} else
712 					adjust_precision = NO;
713 			} else
714 				adjust_precision = adjust_width = NO;
715 
716 			/*
717 			 * Modifier check
718 			 */
719 			switch (*fmt) {
720 				case 'L':
721 					fmt++;
722 					modifier = LM_LONG_DOUBLE;
723 					break;
724 				case 'I':
725 					fmt++;
726 #if SIZEOF_LONG_LONG
727 					if (*fmt == '6' && *(fmt+1) == '4') {
728 						fmt += 2;
729 						modifier = LM_LONG_LONG;
730 					} else
731 #endif
732 						if (*fmt == '3' && *(fmt+1) == '2') {
733 							fmt += 2;
734 							modifier = LM_LONG;
735 						} else {
736 #ifdef _WIN64
737 							modifier = LM_LONG_LONG;
738 #else
739 							modifier = LM_LONG;
740 #endif
741 						}
742 					break;
743 				case 'l':
744 					fmt++;
745 #if SIZEOF_LONG_LONG
746 					if (*fmt == 'l') {
747 						fmt++;
748 						modifier = LM_LONG_LONG;
749 					} else
750 #endif
751 						modifier = LM_LONG;
752 					break;
753 				case 'z':
754 					fmt++;
755 					modifier = LM_SIZE_T;
756 					break;
757 				case 'j':
758 					fmt++;
759 #if SIZEOF_INTMAX_T
760 					modifier = LM_INTMAX_T;
761 #else
762 					modifier = LM_SIZE_T;
763 #endif
764 					break;
765 				case 't':
766 					fmt++;
767 #if SIZEOF_PTRDIFF_T
768 					modifier = LM_PTRDIFF_T;
769 #else
770 					modifier = LM_SIZE_T;
771 #endif
772 					break;
773 				case 'p':
774 					fmt++;
775 					modifier = LM_PHP_INT_T;
776 					break;
777 				case 'h':
778 					fmt++;
779 					if (*fmt == 'h') {
780 						fmt++;
781 					}
782 					/* these are promoted to int, so no break */
783 				default:
784 					modifier = LM_STD;
785 					break;
786 			}
787 
788 			/*
789 			 * Argument extraction and printing.
790 			 * First we determine the argument type.
791 			 * Then, we convert the argument to a string.
792 			 * On exit from the switch, s points to the string that
793 			 * must be printed, s_len has the length of the string
794 			 * The precision requirements, if any, are reflected in s_len.
795 			 *
796 			 * NOTE: pad_char may be set to '0' because of the 0 flag.
797 			 *   It is reset to ' ' by non-numeric formats
798 			 */
799 			switch (*fmt) {
800 				case 'Z': {
801 					zvp = (zval*) va_arg(ap, zval*);
802 					free_zcopy = zend_make_printable_zval(zvp, &zcopy);
803 					if (free_zcopy) {
804 						zvp = &zcopy;
805 					}
806 					s_len = Z_STRLEN_P(zvp);
807 					s = Z_STRVAL_P(zvp);
808 					if (adjust_precision && (size_t)precision < s_len) {
809 						s_len = precision;
810 					}
811 					break;
812 				}
813 				case 'u':
814 					switch(modifier) {
815 						default:
816 							i_num = (wide_int) va_arg(ap, unsigned int);
817 							break;
818 						case LM_LONG_DOUBLE:
819 							goto fmt_error;
820 						case LM_LONG:
821 							i_num = (wide_int) va_arg(ap, unsigned long int);
822 							break;
823 						case LM_SIZE_T:
824 							i_num = (wide_int) va_arg(ap, size_t);
825 							break;
826 #if SIZEOF_LONG_LONG
827 						case LM_LONG_LONG:
828 							i_num = (wide_int) va_arg(ap, u_wide_int);
829 							break;
830 #endif
831 #if SIZEOF_INTMAX_T
832 						case LM_INTMAX_T:
833 							i_num = (wide_int) va_arg(ap, uintmax_t);
834 							break;
835 #endif
836 #if SIZEOF_PTRDIFF_T
837 						case LM_PTRDIFF_T:
838 							i_num = (wide_int) va_arg(ap, ptrdiff_t);
839 							break;
840 #endif
841 						case LM_PHP_INT_T:
842 							i_num = (wide_int) va_arg(ap, zend_ulong);
843 							break;
844 					}
845 					/*
846 					 * The rest also applies to other integer formats, so fall
847 					 * into that case.
848 					 */
849 				case 'd':
850 				case 'i':
851 					/*
852 					 * Get the arg if we haven't already.
853 					 */
854 					if ((*fmt) != 'u') {
855 						switch(modifier) {
856 							default:
857 								i_num = (wide_int) va_arg(ap, int);
858 								break;
859 							case LM_LONG_DOUBLE:
860 								goto fmt_error;
861 							case LM_LONG:
862 								i_num = (wide_int) va_arg(ap, long int);
863 								break;
864 							case LM_SIZE_T:
865 #if SIZEOF_SSIZE_T
866 								i_num = (wide_int) va_arg(ap, ssize_t);
867 #else
868 								i_num = (wide_int) va_arg(ap, size_t);
869 #endif
870 								break;
871 #if SIZEOF_LONG_LONG
872 							case LM_LONG_LONG:
873 								i_num = (wide_int) va_arg(ap, wide_int);
874 								break;
875 #endif
876 #if SIZEOF_INTMAX_T
877 							case LM_INTMAX_T:
878 								i_num = (wide_int) va_arg(ap, intmax_t);
879 								break;
880 #endif
881 #if SIZEOF_PTRDIFF_T
882 							case LM_PTRDIFF_T:
883 								i_num = (wide_int) va_arg(ap, ptrdiff_t);
884 								break;
885 #endif
886 							case LM_PHP_INT_T:
887 								i_num = (wide_int) va_arg(ap, zend_long);
888 								break;
889 						}
890 					}
891 					s = ap_php_conv_10(i_num, (*fmt) == 'u', &is_negative,
892 								&num_buf[NUM_BUF_SIZE], &s_len);
893 					FIX_PRECISION(adjust_precision, precision, s, s_len);
894 
895 					if (*fmt != 'u') {
896 						if (is_negative) {
897 							prefix_char = '-';
898 						} else if (print_sign) {
899 							prefix_char = '+';
900 						} else if (print_blank) {
901 							prefix_char = ' ';
902 						}
903 					}
904 					break;
905 
906 
907 				case 'o':
908 					switch(modifier) {
909 						default:
910 							ui_num = (u_wide_int) va_arg(ap, unsigned int);
911 							break;
912 						case LM_LONG_DOUBLE:
913 							goto fmt_error;
914 						case LM_LONG:
915 							ui_num = (u_wide_int) va_arg(ap, unsigned long int);
916 							break;
917 						case LM_SIZE_T:
918 							ui_num = (u_wide_int) va_arg(ap, size_t);
919 							break;
920 #if SIZEOF_LONG_LONG
921 						case LM_LONG_LONG:
922 							ui_num = (u_wide_int) va_arg(ap, u_wide_int);
923 							break;
924 #endif
925 #if SIZEOF_INTMAX_T
926 						case LM_INTMAX_T:
927 							ui_num = (u_wide_int) va_arg(ap, uintmax_t);
928 							break;
929 #endif
930 #if SIZEOF_PTRDIFF_T
931 						case LM_PTRDIFF_T:
932 							ui_num = (u_wide_int) va_arg(ap, ptrdiff_t);
933 							break;
934 #endif
935 						case LM_PHP_INT_T:
936 							ui_num = (u_wide_int) va_arg(ap, zend_ulong);
937 							break;
938 					}
939 					s = ap_php_conv_p2(ui_num, 3, *fmt, &num_buf[NUM_BUF_SIZE], &s_len);
940 					FIX_PRECISION(adjust_precision, precision, s, s_len);
941 					if (alternate_form && *s != '0') {
942 						*--s = '0';
943 						s_len++;
944 					}
945 					break;
946 
947 
948 				case 'x':
949 				case 'X':
950 					switch(modifier) {
951 						default:
952 							ui_num = (u_wide_int) va_arg(ap, unsigned int);
953 							break;
954 						case LM_LONG_DOUBLE:
955 							goto fmt_error;
956 						case LM_LONG:
957 							ui_num = (u_wide_int) va_arg(ap, unsigned long int);
958 							break;
959 						case LM_SIZE_T:
960 							ui_num = (u_wide_int) va_arg(ap, size_t);
961 							break;
962 #if SIZEOF_LONG_LONG
963 						case LM_LONG_LONG:
964 							ui_num = (u_wide_int) va_arg(ap, u_wide_int);
965 							break;
966 #endif
967 #if SIZEOF_INTMAX_T
968 						case LM_INTMAX_T:
969 							ui_num = (u_wide_int) va_arg(ap, uintmax_t);
970 							break;
971 #endif
972 #if SIZEOF_PTRDIFF_T
973 						case LM_PTRDIFF_T:
974 							ui_num = (u_wide_int) va_arg(ap, ptrdiff_t);
975 							break;
976 #endif
977 						case LM_PHP_INT_T:
978 							ui_num = (u_wide_int) va_arg(ap, zend_ulong);
979 							break;
980 					}
981 					s = ap_php_conv_p2(ui_num, 4, *fmt, &num_buf[NUM_BUF_SIZE], &s_len);
982 					FIX_PRECISION(adjust_precision, precision, s, s_len);
983 					if (alternate_form && i_num != 0) {
984 						*--s = *fmt;	/* 'x' or 'X' */
985 						*--s = '0';
986 						s_len += 2;
987 					}
988 					break;
989 
990 
991 				case 's':
992 				case 'v':
993 					s = va_arg(ap, char *);
994 					if (s != NULL) {
995 						s_len = strlen(s);
996 						if (adjust_precision && (size_t)precision < s_len) {
997 							s_len = precision;
998 						}
999 					} else {
1000 						s = S_NULL;
1001 						s_len = S_NULL_LEN;
1002 					}
1003 					pad_char = ' ';
1004 					break;
1005 
1006 
1007 				case 'f':
1008 				case 'F':
1009 				case 'e':
1010 				case 'E':
1011 					switch(modifier) {
1012 						case LM_LONG_DOUBLE:
1013 							fp_num = (double) va_arg(ap, long double);
1014 							break;
1015 						case LM_STD:
1016 							fp_num = va_arg(ap, double);
1017 							break;
1018 						default:
1019 							goto fmt_error;
1020 					}
1021 
1022 					if (zend_isnan(fp_num)) {
1023 						s = "NAN";
1024 						s_len = 3;
1025 					} else if (zend_isinf(fp_num)) {
1026 						s = "INF";
1027 						s_len = 3;
1028 					} else {
1029 #ifdef HAVE_LOCALE_H
1030 #ifdef ZTS
1031 						localeconv_r(&lconv);
1032 #else
1033 						if (!lconv) {
1034 							lconv = localeconv();
1035 						}
1036 #endif
1037 #endif
1038 						s = php_conv_fp((*fmt == 'f')?'F':*fmt, fp_num, alternate_form,
1039 						 (adjust_precision == NO) ? FLOAT_DIGITS : precision,
1040 						 (*fmt == 'f')?LCONV_DECIMAL_POINT:'.',
1041 									&is_negative, &num_buf[1], &s_len);
1042 						if (is_negative)
1043 							prefix_char = '-';
1044 						else if (print_sign)
1045 							prefix_char = '+';
1046 						else if (print_blank)
1047 							prefix_char = ' ';
1048 					}
1049 					break;
1050 
1051 
1052 				case 'g':
1053 				case 'k':
1054 				case 'G':
1055 				case 'H':
1056 					switch(modifier) {
1057 						case LM_LONG_DOUBLE:
1058 							fp_num = (double) va_arg(ap, long double);
1059 							break;
1060 						case LM_STD:
1061 							fp_num = va_arg(ap, double);
1062 							break;
1063 						default:
1064 							goto fmt_error;
1065 					}
1066 
1067 					if (zend_isnan(fp_num)) {
1068 						s = "NAN";
1069 						s_len = 3;
1070 						break;
1071 					} else if (zend_isinf(fp_num)) {
1072 						if (fp_num > 0) {
1073 							s = "INF";
1074 							s_len = 3;
1075 						} else {
1076 							s = "-INF";
1077 							s_len = 4;
1078 						}
1079 						break;
1080 					}
1081 
1082 					if (adjust_precision == NO) {
1083 						precision = FLOAT_DIGITS;
1084 					} else if (precision == 0) {
1085 						precision = 1;
1086 					}
1087 					/*
1088 					 * * We use &num_buf[ 1 ], so that we have room for the sign
1089 					 */
1090 #ifdef HAVE_LOCALE_H
1091 #ifdef ZTS
1092 					localeconv_r(&lconv);
1093 #else
1094 					if (!lconv) {
1095 						lconv = localeconv();
1096 					}
1097 #endif
1098 #endif
1099 					s = php_gcvt(fp_num, precision, (*fmt=='H' || *fmt == 'k') ? '.' : LCONV_DECIMAL_POINT, (*fmt == 'G' || *fmt == 'H')?'E':'e', &num_buf[1]);
1100 					if (*s == '-') {
1101 						prefix_char = *s++;
1102 					} else if (print_sign) {
1103 						prefix_char = '+';
1104 					} else if (print_blank) {
1105 						prefix_char = ' ';
1106 					}
1107 
1108 					s_len = strlen(s);
1109 
1110 					if (alternate_form && (strchr(s, '.')) == NULL) {
1111 						s[s_len++] = '.';
1112 					}
1113 					break;
1114 
1115 
1116 				case 'c':
1117 					char_buf[0] = (char) (va_arg(ap, int));
1118 					s = &char_buf[0];
1119 					s_len = 1;
1120 					pad_char = ' ';
1121 					break;
1122 
1123 
1124 				case '%':
1125 					char_buf[0] = '%';
1126 					s = &char_buf[0];
1127 					s_len = 1;
1128 					pad_char = ' ';
1129 					break;
1130 
1131 
1132 				case 'n':
1133 					*(va_arg(ap, int *)) = cc;
1134 					goto skip_output;
1135 
1136 					/*
1137 					 * Always extract the argument as a "char *" pointer. We
1138 					 * should be using "void *" but there are still machines
1139 					 * that don't understand it.
1140 					 * If the pointer size is equal to the size of an unsigned
1141 					 * integer we convert the pointer to a hex number, otherwise
1142 					 * we print "%p" to indicate that we don't handle "%p".
1143 					 */
1144 				case 'p':
1145 					if (sizeof(char *) <= sizeof(u_wide_int)) {
1146 						ui_num = (u_wide_int)((size_t) va_arg(ap, char *));
1147 						s = ap_php_conv_p2(ui_num, 4, 'x',
1148 								&num_buf[NUM_BUF_SIZE], &s_len);
1149 						if (ui_num != 0) {
1150 							*--s = 'x';
1151 							*--s = '0';
1152 							s_len += 2;
1153 						}
1154 					} else {
1155 						s = "%p";
1156 						s_len = 2;
1157 					}
1158 					pad_char = ' ';
1159 					break;
1160 
1161 
1162 				case NUL:
1163 					/*
1164 					 * The last character of the format string was %.
1165 					 * We ignore it.
1166 					 */
1167 					continue;
1168 
1169 
1170 fmt_error:
1171 				php_error(E_ERROR, "Illegal length modifier specified '%c' in s[np]printf call", *fmt);
1172 					/*
1173 					 * The default case is for unrecognized %'s.
1174 					 * We print %<char> to help the user identify what
1175 					 * option is not understood.
1176 					 * This is also useful in case the user wants to pass
1177 					 * the output of format_converter to another function
1178 					 * that understands some other %<char> (like syslog).
1179 					 * Note that we can't point s inside fmt because the
1180 					 * unknown <char> could be preceded by width etc.
1181 					 */
1182 				default:
1183 					char_buf[0] = '%';
1184 					char_buf[1] = *fmt;
1185 					s = char_buf;
1186 					s_len = 2;
1187 					pad_char = ' ';
1188 					break;
1189 			}
1190 
1191 			if (prefix_char != NUL) {
1192 				*--s = prefix_char;
1193 				s_len++;
1194 			}
1195 			if (adjust_width && adjust == RIGHT && (size_t)min_width > s_len) {
1196 				if (pad_char == '0' && prefix_char != NUL) {
1197 					INS_CHAR(*s, sp, bep, cc)
1198 						s++;
1199 					s_len--;
1200 					min_width--;
1201 				}
1202 				PAD((size_t)min_width, s_len, pad_char);
1203 			}
1204 			/*
1205 			 * Print the string s.
1206 			 */
1207 			for (i = s_len; i != 0; i--) {
1208 				INS_CHAR(*s, sp, bep, cc);
1209 				s++;
1210 			}
1211 
1212 			if (adjust_width && adjust == LEFT && (size_t)min_width > s_len)
1213 				PAD((size_t)min_width, s_len, pad_char);
1214 			if (free_zcopy) {
1215 				zval_ptr_dtor_str(&zcopy);
1216 			}
1217 		}
1218 skip_output:
1219 		fmt++;
1220 	}
1221 	odp->nextb = sp;
1222 	return (cc);
1223 }
1224 /* }}} */
1225 
1226 /*
1227  * This is the general purpose conversion function.
1228  */
strx_printv(int * ccp,char * buf,size_t len,const char * format,va_list ap)1229 static void strx_printv(int *ccp, char *buf, size_t len, const char *format, va_list ap) /* {{{ */
1230 {
1231 	buffy od;
1232 	int cc;
1233 
1234 	/*
1235 	 * First initialize the descriptor
1236 	 * Notice that if no length is given, we initialize buf_end to the
1237 	 * highest possible address.
1238 	 */
1239 	if (len == 0) {
1240 		od.buf_end = (char *) ~0;
1241 		od.nextb   = (char *) ~0;
1242 	} else {
1243 		od.buf_end = &buf[len-1];
1244 		od.nextb   = buf;
1245 	}
1246 
1247 	/*
1248 	 * Do the conversion
1249 	 */
1250 	cc = format_converter(&od, format, ap);
1251 	if (len != 0 && od.nextb <= od.buf_end) {
1252 		*(od.nextb) = '\0';
1253 	}
1254 	if (ccp) {
1255 		*ccp = cc;
1256 	}
1257 }
1258 /* }}} */
1259 
ap_php_slprintf(char * buf,size_t len,const char * format,...)1260 PHPAPI int ap_php_slprintf(char *buf, size_t len, const char *format,...) /* {{{ */
1261 {
1262 	int cc;
1263 	va_list ap;
1264 
1265 	va_start(ap, format);
1266 	strx_printv(&cc, buf, len, format, ap);
1267 	va_end(ap);
1268 	if ((size_t)cc >= len) {
1269 		cc = (int)len -1;
1270 		buf[cc] = '\0';
1271 	}
1272 	return cc;
1273 }
1274 /* }}} */
1275 
ap_php_vslprintf(char * buf,size_t len,const char * format,va_list ap)1276 PHPAPI int ap_php_vslprintf(char *buf, size_t len, const char *format, va_list ap) /* {{{ */
1277 {
1278 	int cc;
1279 
1280 	strx_printv(&cc, buf, len, format, ap);
1281 	if ((size_t)cc >= len) {
1282 		cc = (int)len -1;
1283 		buf[cc] = '\0';
1284 	}
1285 	return cc;
1286 }
1287 /* }}} */
1288 
ap_php_snprintf(char * buf,size_t len,const char * format,...)1289 PHPAPI int ap_php_snprintf(char *buf, size_t len, const char *format,...) /* {{{ */
1290 {
1291 	int cc;
1292 	va_list ap;
1293 
1294 	va_start(ap, format);
1295 	strx_printv(&cc, buf, len, format, ap);
1296 	va_end(ap);
1297 	return (cc);
1298 }
1299 /* }}} */
1300 
ap_php_vsnprintf(char * buf,size_t len,const char * format,va_list ap)1301 PHPAPI int ap_php_vsnprintf(char *buf, size_t len, const char *format, va_list ap) /* {{{ */
1302 {
1303 	int cc;
1304 
1305 	strx_printv(&cc, buf, len, format, ap);
1306 	return (cc);
1307 }
1308 /* }}} */
1309 
ap_php_vasprintf(char ** buf,const char * format,va_list ap)1310 PHPAPI int ap_php_vasprintf(char **buf, const char *format, va_list ap) /* {{{ */
1311 {
1312 	va_list ap2;
1313 	int cc;
1314 
1315 	va_copy(ap2, ap);
1316 	cc = ap_php_vsnprintf(NULL, 0, format, ap2);
1317 	va_end(ap2);
1318 
1319 	*buf = NULL;
1320 
1321 	if (cc >= 0) {
1322 		if ((*buf = malloc(++cc)) != NULL) {
1323 			if ((cc = ap_php_vsnprintf(*buf, cc, format, ap)) < 0) {
1324 				free(*buf);
1325 				*buf = NULL;
1326 			}
1327 		}
1328 	}
1329 
1330 	return cc;
1331 }
1332 /* }}} */
1333 
ap_php_asprintf(char ** buf,const char * format,...)1334 PHPAPI int ap_php_asprintf(char **buf, const char *format, ...) /* {{{ */
1335 {
1336 	int cc;
1337 	va_list ap;
1338 
1339 	va_start(ap, format);
1340 	cc = vasprintf(buf, format, ap);
1341 	va_end(ap);
1342 	return cc;
1343 }
1344 /* }}} */
1345 
1346 /*
1347  * Local variables:
1348  * tab-width: 4
1349  * c-basic-offset: 4
1350  * End:
1351  * vim600: sw=4 ts=4 fdm=marker
1352  * vim<600: sw=4 ts=4
1353  */
1354