You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1314 lines
31 KiB

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