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