PageRenderTime 67ms CodeModel.GetById 29ms RepoModel.GetById 0ms app.codeStats 0ms

/main/snprintf.c

http://github.com/infusion/PHP
C | 1314 lines | 899 code | 118 blank | 297 comment | 244 complexity | a67f8897ec39984eb052b92b6a38b4f9 MD5 | raw file
Possible License(s): MPL-2.0-no-copyleft-exception, LGPL-2.1, BSD-3-Clause
  1. /*
  2. +----------------------------------------------------------------------+
  3. | PHP Version 5 |
  4. +----------------------------------------------------------------------+
  5. | Copyright (c) 1997-2011 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: snprintf.c 308525 2011-02-21 06:53:24Z cataphract $ */
  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. if (*fmt == '.') {
  615. adjust_precision = YES;
  616. fmt++;
  617. if (isdigit((int)*fmt)) {
  618. STR_TO_DEC(fmt, precision);
  619. } else if (*fmt == '*') {
  620. precision = va_arg(ap, int);
  621. fmt++;
  622. if (precision < 0)
  623. precision = 0;
  624. } else
  625. precision = 0;
  626. if (precision > FORMAT_CONV_MAX_PRECISION) {
  627. precision = FORMAT_CONV_MAX_PRECISION;
  628. }
  629. } else
  630. adjust_precision = NO;
  631. } else
  632. adjust_precision = adjust_width = NO;
  633. /*
  634. * Modifier check
  635. */
  636. switch (*fmt) {
  637. case 'L':
  638. fmt++;
  639. modifier = LM_LONG_DOUBLE;
  640. break;
  641. case 'I':
  642. fmt++;
  643. #if SIZEOF_LONG_LONG
  644. if (*fmt == '6' && *(fmt+1) == '4') {
  645. fmt += 2;
  646. modifier = LM_LONG_LONG;
  647. } else
  648. #endif
  649. if (*fmt == '3' && *(fmt+1) == '2') {
  650. fmt += 2;
  651. modifier = LM_LONG;
  652. } else {
  653. #ifdef _WIN64
  654. modifier = LM_LONG_LONG;
  655. #else
  656. modifier = LM_LONG;
  657. #endif
  658. }
  659. break;
  660. case 'l':
  661. fmt++;
  662. #if SIZEOF_LONG_LONG
  663. if (*fmt == 'l') {
  664. fmt++;
  665. modifier = LM_LONG_LONG;
  666. } else
  667. #endif
  668. modifier = LM_LONG;
  669. break;
  670. case 'z':
  671. fmt++;
  672. modifier = LM_SIZE_T;
  673. break;
  674. case 'j':
  675. fmt++;
  676. #if SIZEOF_INTMAX_T
  677. modifier = LM_INTMAX_T;
  678. #else
  679. modifier = LM_SIZE_T;
  680. #endif
  681. break;
  682. case 't':
  683. fmt++;
  684. #if SIZEOF_PTRDIFF_T
  685. modifier = LM_PTRDIFF_T;
  686. #else
  687. modifier = LM_SIZE_T;
  688. #endif
  689. break;
  690. case 'h':
  691. fmt++;
  692. if (*fmt == 'h') {
  693. fmt++;
  694. }
  695. /* these are promoted to int, so no break */
  696. default:
  697. modifier = LM_STD;
  698. break;
  699. }
  700. /*
  701. * Argument extraction and printing.
  702. * First we determine the argument type.
  703. * Then, we convert the argument to a string.
  704. * On exit from the switch, s points to the string that
  705. * must be printed, s_len has the length of the string
  706. * The precision requirements, if any, are reflected in s_len.
  707. *
  708. * NOTE: pad_char may be set to '0' because of the 0 flag.
  709. * It is reset to ' ' by non-numeric formats
  710. */
  711. switch (*fmt) {
  712. case 'Z':
  713. zvp = (zval*) va_arg(ap, zval*);
  714. zend_make_printable_zval(zvp, &zcopy, &free_zcopy);
  715. if (free_zcopy) {
  716. zvp = &zcopy;
  717. }
  718. s_len = Z_STRLEN_P(zvp);
  719. s = Z_STRVAL_P(zvp);
  720. if (adjust_precision && precision < s_len) {
  721. s_len = precision;
  722. }
  723. break;
  724. case 'u':
  725. switch(modifier) {
  726. default:
  727. i_num = (wide_int) va_arg(ap, unsigned int);
  728. break;
  729. case LM_LONG_DOUBLE:
  730. goto fmt_error;
  731. case LM_LONG:
  732. i_num = (wide_int) va_arg(ap, unsigned long int);
  733. break;
  734. case LM_SIZE_T:
  735. i_num = (wide_int) va_arg(ap, size_t);
  736. break;
  737. #if SIZEOF_LONG_LONG
  738. case LM_LONG_LONG:
  739. i_num = (wide_int) va_arg(ap, u_wide_int);
  740. break;
  741. #endif
  742. #if SIZEOF_INTMAX_T
  743. case LM_INTMAX_T:
  744. i_num = (wide_int) va_arg(ap, uintmax_t);
  745. break;
  746. #endif
  747. #if SIZEOF_PTRDIFF_T
  748. case LM_PTRDIFF_T:
  749. i_num = (wide_int) va_arg(ap, ptrdiff_t);
  750. break;
  751. #endif
  752. }
  753. /*
  754. * The rest also applies to other integer formats, so fall
  755. * into that case.
  756. */
  757. case 'd':
  758. case 'i':
  759. /*
  760. * Get the arg if we haven't already.
  761. */
  762. if ((*fmt) != 'u') {
  763. switch(modifier) {
  764. default:
  765. i_num = (wide_int) va_arg(ap, int);
  766. break;
  767. case LM_LONG_DOUBLE:
  768. goto fmt_error;
  769. case LM_LONG:
  770. i_num = (wide_int) va_arg(ap, long int);
  771. break;
  772. case LM_SIZE_T:
  773. #if SIZEOF_SSIZE_T
  774. i_num = (wide_int) va_arg(ap, ssize_t);
  775. #else
  776. i_num = (wide_int) va_arg(ap, size_t);
  777. #endif
  778. break;
  779. #if SIZEOF_LONG_LONG
  780. case LM_LONG_LONG:
  781. i_num = (wide_int) va_arg(ap, wide_int);
  782. break;
  783. #endif
  784. #if SIZEOF_INTMAX_T
  785. case LM_INTMAX_T:
  786. i_num = (wide_int) va_arg(ap, intmax_t);
  787. break;
  788. #endif
  789. #if SIZEOF_PTRDIFF_T
  790. case LM_PTRDIFF_T:
  791. i_num = (wide_int) va_arg(ap, ptrdiff_t);
  792. break;
  793. #endif
  794. }
  795. }
  796. s = ap_php_conv_10(i_num, (*fmt) == 'u', &is_negative,
  797. &num_buf[NUM_BUF_SIZE], &s_len);
  798. FIX_PRECISION(adjust_precision, precision, s, s_len);
  799. if (*fmt != 'u') {
  800. if (is_negative) {
  801. prefix_char = '-';
  802. } else if (print_sign) {
  803. prefix_char = '+';
  804. } else if (print_blank) {
  805. prefix_char = ' ';
  806. }
  807. }
  808. break;
  809. case 'o':
  810. switch(modifier) {
  811. default:
  812. ui_num = (u_wide_int) va_arg(ap, unsigned int);
  813. break;
  814. case LM_LONG_DOUBLE:
  815. goto fmt_error;
  816. case LM_LONG:
  817. ui_num = (u_wide_int) va_arg(ap, unsigned long int);
  818. break;
  819. case LM_SIZE_T:
  820. ui_num = (u_wide_int) va_arg(ap, size_t);
  821. break;
  822. #if SIZEOF_LONG_LONG
  823. case LM_LONG_LONG:
  824. ui_num = (u_wide_int) va_arg(ap, u_wide_int);
  825. break;
  826. #endif
  827. #if SIZEOF_INTMAX_T
  828. case LM_INTMAX_T:
  829. ui_num = (u_wide_int) va_arg(ap, uintmax_t);
  830. break;
  831. #endif
  832. #if SIZEOF_PTRDIFF_T
  833. case LM_PTRDIFF_T:
  834. ui_num = (u_wide_int) va_arg(ap, ptrdiff_t);
  835. break;
  836. #endif
  837. }
  838. s = ap_php_conv_p2(ui_num, 3, *fmt, &num_buf[NUM_BUF_SIZE], &s_len);
  839. FIX_PRECISION(adjust_precision, precision, s, s_len);
  840. if (alternate_form && *s != '0') {
  841. *--s = '0';
  842. s_len++;
  843. }
  844. break;
  845. case 'x':
  846. case 'X':
  847. switch(modifier) {
  848. default:
  849. ui_num = (u_wide_int) va_arg(ap, unsigned int);
  850. break;
  851. case LM_LONG_DOUBLE:
  852. goto fmt_error;
  853. case LM_LONG:
  854. ui_num = (u_wide_int) va_arg(ap, unsigned long int);
  855. break;
  856. case LM_SIZE_T:
  857. ui_num = (u_wide_int) va_arg(ap, size_t);
  858. break;
  859. #if SIZEOF_LONG_LONG
  860. case LM_LONG_LONG:
  861. ui_num = (u_wide_int) va_arg(ap, u_wide_int);
  862. break;
  863. #endif
  864. #if SIZEOF_INTMAX_T
  865. case LM_INTMAX_T:
  866. ui_num = (u_wide_int) va_arg(ap, uintmax_t);
  867. break;
  868. #endif
  869. #if SIZEOF_PTRDIFF_T
  870. case LM_PTRDIFF_T:
  871. ui_num = (u_wide_int) va_arg(ap, ptrdiff_t);
  872. break;
  873. #endif
  874. }
  875. s = ap_php_conv_p2(ui_num, 4, *fmt, &num_buf[NUM_BUF_SIZE], &s_len);
  876. FIX_PRECISION(adjust_precision, precision, s, s_len);
  877. if (alternate_form && i_num != 0) {
  878. *--s = *fmt; /* 'x' or 'X' */
  879. *--s = '0';
  880. s_len += 2;
  881. }
  882. break;
  883. case 's':
  884. case 'v':
  885. s = va_arg(ap, char *);
  886. if (s != NULL) {
  887. s_len = strlen(s);
  888. if (adjust_precision && precision < s_len) {
  889. s_len = precision;
  890. }
  891. } else {
  892. s = S_NULL;
  893. s_len = S_NULL_LEN;
  894. }
  895. pad_char = ' ';
  896. break;
  897. case 'f':
  898. case 'F':
  899. case 'e':
  900. case 'E':
  901. switch(modifier) {
  902. case LM_LONG_DOUBLE:
  903. fp_num = (double) va_arg(ap, long double);
  904. break;
  905. case LM_STD:
  906. fp_num = va_arg(ap, double);
  907. break;
  908. default:
  909. goto fmt_error;
  910. }
  911. if (zend_isnan(fp_num)) {
  912. s = "NAN";
  913. s_len = 3;
  914. } else if (zend_isinf(fp_num)) {
  915. s = "INF";
  916. s_len = 3;
  917. } else {
  918. #ifdef HAVE_LOCALE_H
  919. if (!lconv) {
  920. lconv = localeconv();
  921. }
  922. #endif
  923. s = php_conv_fp((*fmt == 'f')?'F':*fmt, fp_num, alternate_form,
  924. (adjust_precision == NO) ? FLOAT_DIGITS : precision,
  925. (*fmt == 'f')?LCONV_DECIMAL_POINT:'.',
  926. &is_negative, &num_buf[1], &s_len);
  927. if (is_negative)
  928. prefix_char = '-';
  929. else if (print_sign)
  930. prefix_char = '+';
  931. else if (print_blank)
  932. prefix_char = ' ';
  933. }
  934. break;
  935. case 'g':
  936. case 'k':
  937. case 'G':
  938. case 'H':
  939. switch(modifier) {
  940. case LM_LONG_DOUBLE:
  941. fp_num = (double) va_arg(ap, long double);
  942. break;
  943. case LM_STD:
  944. fp_num = va_arg(ap, double);
  945. break;
  946. default:
  947. goto fmt_error;
  948. }
  949. if (zend_isnan(fp_num)) {
  950. s = "NAN";
  951. s_len = 3;
  952. break;
  953. } else if (zend_isinf(fp_num)) {
  954. if (fp_num > 0) {
  955. s = "INF";
  956. s_len = 3;
  957. } else {
  958. s = "-INF";
  959. s_len = 4;
  960. }
  961. break;
  962. }
  963. if (adjust_precision == NO) {
  964. precision = FLOAT_DIGITS;
  965. } else if (precision == 0) {
  966. precision = 1;
  967. }
  968. /*
  969. * * We use &num_buf[ 1 ], so that we have room for the sign
  970. */
  971. #ifdef HAVE_LOCALE_H
  972. if (!lconv) {
  973. lconv = localeconv();
  974. }
  975. #endif
  976. s = php_gcvt(fp_num, precision, (*fmt=='H' || *fmt == 'k') ? '.' : LCONV_DECIMAL_POINT, (*fmt == 'G' || *fmt == 'H')?'E':'e', &num_buf[1]);
  977. if (*s == '-') {
  978. prefix_char = *s++;
  979. } else if (print_sign) {
  980. prefix_char = '+';
  981. } else if (print_blank) {
  982. prefix_char = ' ';
  983. }
  984. s_len = strlen(s);
  985. if (alternate_form && (q = strchr(s, '.')) == NULL) {
  986. s[s_len++] = '.';
  987. }
  988. break;
  989. case 'c':
  990. char_buf[0] = (char) (va_arg(ap, int));
  991. s = &char_buf[0];
  992. s_len = 1;
  993. pad_char = ' ';
  994. break;
  995. case '%':
  996. char_buf[0] = '%';
  997. s = &char_buf[0];
  998. s_len = 1;
  999. pad_char = ' ';
  1000. break;
  1001. case 'n':
  1002. *(va_arg(ap, int *)) = cc;
  1003. goto skip_output;
  1004. /*
  1005. * Always extract the argument as a "char *" pointer. We
  1006. * should be using "void *" but there are still machines
  1007. * that don't understand it.
  1008. * If the pointer size is equal to the size of an unsigned
  1009. * integer we convert the pointer to a hex number, otherwise
  1010. * we print "%p" to indicate that we don't handle "%p".
  1011. */
  1012. case 'p':
  1013. if (sizeof(char *) <= sizeof(u_wide_int)) {
  1014. ui_num = (u_wide_int)((size_t) va_arg(ap, char *));
  1015. s = ap_php_conv_p2(ui_num, 4, 'x',
  1016. &num_buf[NUM_BUF_SIZE], &s_len);
  1017. if (ui_num != 0) {
  1018. *--s = 'x';
  1019. *--s = '0';
  1020. s_len += 2;
  1021. }
  1022. } else {
  1023. s = "%p";
  1024. s_len = 2;
  1025. }
  1026. pad_char = ' ';
  1027. break;
  1028. case NUL:
  1029. /*
  1030. * The last character of the format string was %.
  1031. * We ignore it.
  1032. */
  1033. continue;
  1034. fmt_error:
  1035. php_error(E_ERROR, "Illegal length modifier specified '%c' in s[np]printf call", *fmt);
  1036. /*
  1037. * The default case is for unrecognized %'s.
  1038. * We print %<char> to help the user identify what
  1039. * option is not understood.
  1040. * This is also useful in case the user wants to pass
  1041. * the output of format_converter to another function
  1042. * that understands some other %<char> (like syslog).
  1043. * Note that we can't point s inside fmt because the
  1044. * unknown <char> could be preceded by width etc.
  1045. */
  1046. default:
  1047. char_buf[0] = '%';
  1048. char_buf[1] = *fmt;
  1049. s = char_buf;
  1050. s_len = 2;
  1051. pad_char = ' ';
  1052. break;
  1053. }
  1054. if (prefix_char != NUL) {
  1055. *--s = prefix_char;
  1056. s_len++;
  1057. }
  1058. if (adjust_width && adjust == RIGHT && min_width > s_len) {
  1059. if (pad_char == '0' && prefix_char != NUL) {
  1060. INS_CHAR(*s, sp, bep, cc)
  1061. s++;
  1062. s_len--;
  1063. min_width--;
  1064. }
  1065. PAD(min_width, s_len, pad_char);
  1066. }
  1067. /*
  1068. * Print the string s.
  1069. */
  1070. for (i = s_len; i != 0; i--) {
  1071. INS_CHAR(*s, sp, bep, cc);
  1072. s++;
  1073. }
  1074. if (adjust_width && adjust == LEFT && min_width > s_len)
  1075. PAD(min_width, s_len, pad_char);
  1076. if (free_zcopy) {
  1077. zval_dtor(&zcopy);
  1078. }
  1079. }
  1080. skip_output:
  1081. fmt++;
  1082. }
  1083. odp->nextb = sp;
  1084. return (cc);
  1085. }
  1086. /* }}} */
  1087. /*
  1088. * This is the general purpose conversion function.
  1089. */
  1090. static void strx_printv(int *ccp, char *buf, size_t len, const char *format, va_list ap) /* {{{ */
  1091. {
  1092. buffy od;
  1093. int cc;
  1094. /*
  1095. * First initialize the descriptor
  1096. * Notice that if no length is given, we initialize buf_end to the
  1097. * highest possible address.
  1098. */
  1099. if (len == 0) {
  1100. od.buf_end = (char *) ~0;
  1101. od.nextb = (char *) ~0;
  1102. } else {
  1103. od.buf_end = &buf[len-1];
  1104. od.nextb = buf;
  1105. }
  1106. /*
  1107. * Do the conversion
  1108. */
  1109. cc = format_converter(&od, format, ap);
  1110. if (len != 0 && od.nextb <= od.buf_end) {
  1111. *(od.nextb) = '\0';
  1112. }
  1113. if (ccp) {
  1114. *ccp = cc;
  1115. }
  1116. }
  1117. /* }}} */
  1118. PHPAPI int ap_php_slprintf(char *buf, size_t len, const char *format,...) /* {{{ */
  1119. {
  1120. int cc;
  1121. va_list ap;
  1122. va_start(ap, format);
  1123. strx_printv(&cc, buf, len, format, ap);
  1124. va_end(ap);
  1125. if (cc >= len) {
  1126. cc = len -1;
  1127. buf[cc] = '\0';
  1128. }
  1129. return cc;
  1130. }
  1131. /* }}} */
  1132. PHPAPI int ap_php_vslprintf(char *buf, size_t len, const char *format, va_list ap) /* {{{ */
  1133. {
  1134. int cc;
  1135. strx_printv(&cc, buf, len, format, ap);
  1136. if (cc >= len) {
  1137. cc = len -1;
  1138. buf[cc] = '\0';
  1139. }
  1140. return cc;
  1141. }
  1142. /* }}} */
  1143. PHPAPI int ap_php_snprintf(char *buf, size_t len, const char *format,...) /* {{{ */
  1144. {
  1145. int cc;
  1146. va_list ap;
  1147. va_start(ap, format);
  1148. strx_printv(&cc, buf, len, format, ap);
  1149. va_end(ap);
  1150. return (cc);
  1151. }
  1152. /* }}} */
  1153. PHPAPI int ap_php_vsnprintf(char *buf, size_t len, const char *format, va_list ap) /* {{{ */
  1154. {
  1155. int cc;
  1156. strx_printv(&cc, buf, len, format, ap);
  1157. return (cc);
  1158. }
  1159. /* }}} */
  1160. PHPAPI int ap_php_vasprintf(char **buf, const char *format, va_list ap) /* {{{ */
  1161. {
  1162. va_list ap2;
  1163. int cc;
  1164. va_copy(ap2, ap);
  1165. cc = ap_php_vsnprintf(NULL, 0, format, ap2);
  1166. va_end(ap2);
  1167. *buf = NULL;
  1168. if (cc >= 0) {
  1169. if ((*buf = malloc(++cc)) != NULL) {
  1170. if ((cc = ap_php_vsnprintf(*buf, cc, format, ap)) < 0) {
  1171. free(*buf);
  1172. *buf = NULL;
  1173. }
  1174. }
  1175. }
  1176. return cc;
  1177. }
  1178. /* }}} */
  1179. PHPAPI int ap_php_asprintf(char **buf, const char *format, ...) /* {{{ */
  1180. {
  1181. int cc;
  1182. va_list ap;
  1183. va_start(ap, format);
  1184. cc = vasprintf(buf, format, ap);
  1185. va_end(ap);
  1186. return cc;
  1187. }
  1188. /* }}} */
  1189. /*
  1190. * Local variables:
  1191. * tab-width: 4
  1192. * c-basic-offset: 4
  1193. * End:
  1194. * vim600: sw=4 ts=4 fdm=marker
  1195. * vim<600: sw=4 ts=4
  1196. */