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