spprintf.c 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847
  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: Marcus Boerger <helly@php.net> |
  16. +----------------------------------------------------------------------+
  17. */
  18. /* This is the spprintf implementation.
  19. * It has emerged from apache snprintf. See original header:
  20. */
  21. /* ====================================================================
  22. * Copyright (c) 1995-1998 The Apache Group. All rights reserved.
  23. *
  24. * Redistribution and use in source and binary forms, with or without
  25. * modification, are permitted provided that the following conditions
  26. * are met:
  27. *
  28. * 1. Redistributions of source code must retain the above copyright
  29. * notice, this list of conditions and the following disclaimer.
  30. *
  31. * 2. Redistributions in binary form must reproduce the above copyright
  32. * notice, this list of conditions and the following disclaimer in
  33. * the documentation and/or other materials provided with the
  34. * distribution.
  35. *
  36. * 3. All advertising materials mentioning features or use of this
  37. * software must display the following acknowledgment:
  38. * "This product includes software developed by the Apache Group
  39. * for use in the Apache HTTP server project (http://www.apache.org/)."
  40. *
  41. * 4. The names "Apache Server" and "Apache Group" must not be used to
  42. * endorse or promote products derived from this software without
  43. * prior written permission.
  44. *
  45. * 5. Redistributions of any form whatsoever must retain the following
  46. * acknowledgment:
  47. * "This product includes software developed by the Apache Group
  48. * for use in the Apache HTTP server project (http://www.apache.org/)."
  49. *
  50. * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY
  51. * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  52. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  53. * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR
  54. * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  55. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  56. * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  57. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  58. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
  59. * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  60. * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
  61. * OF THE POSSIBILITY OF SUCH DAMAGE.
  62. * ====================================================================
  63. *
  64. * This software consists of voluntary contributions made by many
  65. * individuals on behalf of the Apache Group and was originally based
  66. * on public domain software written at the National Center for
  67. * Supercomputing Applications, University of Illinois, Urbana-Champaign.
  68. * For more information on the Apache Group and the Apache HTTP server
  69. * project, please see <http://www.apache.org/>.
  70. *
  71. * This code is based on, and used with the permission of, the
  72. * SIO stdio-replacement strx_* functions by Panos Tsirigotis
  73. * <panos@alumni.cs.colorado.edu> for xinetd.
  74. */
  75. #define _GNU_SOURCE
  76. #include "php.h"
  77. #include <stddef.h>
  78. #include <stdio.h>
  79. #include <ctype.h>
  80. #include <sys/types.h>
  81. #include <stdarg.h>
  82. #include <string.h>
  83. #include <stdlib.h>
  84. #include <math.h>
  85. #ifdef HAVE_INTTYPES_H
  86. #include <inttypes.h>
  87. #endif
  88. #ifdef HAVE_LOCALE_H
  89. #include <locale.h>
  90. #ifdef ZTS
  91. #include "ext/standard/php_string.h"
  92. #define LCONV_DECIMAL_POINT (*lconv.decimal_point)
  93. #else
  94. #define LCONV_DECIMAL_POINT (*lconv->decimal_point)
  95. #endif
  96. #else
  97. #define LCONV_DECIMAL_POINT '.'
  98. #endif
  99. #include "snprintf.h"
  100. #define FALSE 0
  101. #define TRUE 1
  102. #define NUL '\0'
  103. #define INT_NULL ((int *)0)
  104. #define S_NULL "(null)"
  105. #define S_NULL_LEN 6
  106. #define FLOAT_DIGITS 6
  107. #define EXPONENT_LENGTH 10
  108. #include "zend_smart_str.h"
  109. #include "zend_smart_string.h"
  110. /* {{{ macros */
  111. #define INS_CHAR(xbuf, ch, is_char) do { \
  112. if ((is_char)) { \
  113. smart_string_appendc((smart_string *)(xbuf), (ch)); \
  114. } else { \
  115. smart_str_appendc((smart_str *)(xbuf), (ch)); \
  116. } \
  117. } while (0);
  118. #define INS_STRING(xbuf, str, len, is_char) do { \
  119. if ((is_char)) { \
  120. smart_string_appendl((smart_string *)(xbuf), (str), (len)); \
  121. } else { \
  122. smart_str_appendl((smart_str *)(xbuf), (str), (len)); \
  123. } \
  124. } while (0);
  125. #define PAD_CHAR(xbuf, ch, count, is_char) do { \
  126. if ((is_char)) { \
  127. smart_string_alloc(((smart_string *)(xbuf)), (count), 0); \
  128. memset(((smart_string *)(xbuf))->c + ((smart_string *)(xbuf))->len, (ch), (count)); \
  129. ((smart_string *)(xbuf))->len += (count); \
  130. } else { \
  131. smart_str_alloc(((smart_str *)(xbuf)), (count), 0); \
  132. memset(ZSTR_VAL(((smart_str *)(xbuf))->s) + ZSTR_LEN(((smart_str *)(xbuf))->s), (ch), (count)); \
  133. ZSTR_LEN(((smart_str *)(xbuf))->s) += (count); \
  134. } \
  135. } while (0);
  136. /*
  137. * NUM_BUF_SIZE is the size of the buffer used for arithmetic conversions
  138. * which can be at most max length of double
  139. */
  140. #define NUM_BUF_SIZE PHP_DOUBLE_MAX_LENGTH
  141. #define NUM(c) (c - '0')
  142. #define STR_TO_DEC(str, num) do { \
  143. num = NUM(*str++); \
  144. while (isdigit((int)*str)) { \
  145. num *= 10; \
  146. num += NUM(*str++); \
  147. if (num >= INT_MAX / 10) { \
  148. while (isdigit((int)*str++)); \
  149. break; \
  150. } \
  151. } \
  152. } while (0)
  153. /*
  154. * This macro does zero padding so that the precision
  155. * requirement is satisfied. The padding is done by
  156. * adding '0's to the left of the string that is going
  157. * to be printed.
  158. */
  159. #define FIX_PRECISION(adjust, precision, s, s_len) do { \
  160. if (adjust) \
  161. while (s_len < (size_t)precision) { \
  162. *--s = '0'; \
  163. s_len++; \
  164. } \
  165. } while (0)
  166. /* }}} */
  167. #if !HAVE_STRNLEN
  168. static size_t strnlen(const char *s, size_t maxlen) {
  169. char *r = memchr(s, '\0', maxlen);
  170. return r ? r-s : maxlen;
  171. }
  172. #endif
  173. /*
  174. * Do format conversion placing the output in buffer
  175. */
  176. static void xbuf_format_converter(void *xbuf, zend_bool is_char, const char *fmt, va_list ap) /* {{{ */
  177. {
  178. char *s = NULL;
  179. size_t s_len;
  180. int free_zcopy;
  181. zval *zvp, zcopy;
  182. int min_width = 0;
  183. int precision = 0;
  184. enum {
  185. LEFT, RIGHT
  186. } adjust;
  187. char pad_char;
  188. char prefix_char;
  189. double fp_num;
  190. wide_int i_num = (wide_int) 0;
  191. u_wide_int ui_num = (u_wide_int) 0;
  192. char num_buf[NUM_BUF_SIZE];
  193. char char_buf[2]; /* for printing %% and %<unknown> */
  194. #ifdef HAVE_LOCALE_H
  195. #ifdef ZTS
  196. struct lconv lconv;
  197. #else
  198. struct lconv *lconv = NULL;
  199. #endif
  200. #endif
  201. /*
  202. * Flag variables
  203. */
  204. length_modifier_e modifier;
  205. boolean_e alternate_form;
  206. boolean_e print_sign;
  207. boolean_e print_blank;
  208. boolean_e adjust_precision;
  209. boolean_e adjust_width;
  210. bool_int is_negative;
  211. while (*fmt) {
  212. if (*fmt != '%') {
  213. INS_CHAR(xbuf, *fmt, is_char);
  214. } else {
  215. /*
  216. * Default variable settings
  217. */
  218. adjust = RIGHT;
  219. alternate_form = print_sign = print_blank = NO;
  220. pad_char = ' ';
  221. prefix_char = NUL;
  222. free_zcopy = 0;
  223. fmt++;
  224. /*
  225. * Try to avoid checking for flags, width or precision
  226. */
  227. if (isascii((int)*fmt) && !islower((int)*fmt)) {
  228. /*
  229. * Recognize flags: -, #, BLANK, +
  230. */
  231. for (;; fmt++) {
  232. if (*fmt == '-')
  233. adjust = LEFT;
  234. else if (*fmt == '+')
  235. print_sign = YES;
  236. else if (*fmt == '#')
  237. alternate_form = YES;
  238. else if (*fmt == ' ')
  239. print_blank = YES;
  240. else if (*fmt == '0')
  241. pad_char = '0';
  242. else
  243. break;
  244. }
  245. /*
  246. * Check if a width was specified
  247. */
  248. if (isdigit((int)*fmt)) {
  249. STR_TO_DEC(fmt, min_width);
  250. adjust_width = YES;
  251. } else if (*fmt == '*') {
  252. min_width = va_arg(ap, int);
  253. fmt++;
  254. adjust_width = YES;
  255. if (min_width < 0) {
  256. adjust = LEFT;
  257. min_width = -min_width;
  258. }
  259. } else
  260. adjust_width = NO;
  261. /*
  262. * Check if a precision was specified
  263. */
  264. if (*fmt == '.') {
  265. adjust_precision = YES;
  266. fmt++;
  267. if (isdigit((int)*fmt)) {
  268. STR_TO_DEC(fmt, precision);
  269. } else if (*fmt == '*') {
  270. precision = va_arg(ap, int);
  271. fmt++;
  272. if (precision < -1)
  273. precision = -1;
  274. } else
  275. precision = 0;
  276. if (precision > FORMAT_CONV_MAX_PRECISION) {
  277. precision = FORMAT_CONV_MAX_PRECISION;
  278. }
  279. } else
  280. adjust_precision = NO;
  281. } else
  282. adjust_precision = adjust_width = NO;
  283. /*
  284. * Modifier check
  285. */
  286. switch (*fmt) {
  287. case 'L':
  288. fmt++;
  289. modifier = LM_LONG_DOUBLE;
  290. break;
  291. case 'I':
  292. fmt++;
  293. #if SIZEOF_LONG_LONG
  294. if (*fmt == '6' && *(fmt+1) == '4') {
  295. fmt += 2;
  296. modifier = LM_LONG_LONG;
  297. } else
  298. #endif
  299. if (*fmt == '3' && *(fmt+1) == '2') {
  300. fmt += 2;
  301. modifier = LM_LONG;
  302. } else {
  303. #ifdef _WIN64
  304. modifier = LM_LONG_LONG;
  305. #else
  306. modifier = LM_LONG;
  307. #endif
  308. }
  309. break;
  310. case 'l':
  311. fmt++;
  312. #if SIZEOF_LONG_LONG
  313. if (*fmt == 'l') {
  314. fmt++;
  315. modifier = LM_LONG_LONG;
  316. } else
  317. #endif
  318. modifier = LM_LONG;
  319. break;
  320. case 'z':
  321. fmt++;
  322. modifier = LM_SIZE_T;
  323. break;
  324. case 'j':
  325. fmt++;
  326. #if SIZEOF_INTMAX_T
  327. modifier = LM_INTMAX_T;
  328. #else
  329. modifier = LM_SIZE_T;
  330. #endif
  331. break;
  332. case 't':
  333. fmt++;
  334. #if SIZEOF_PTRDIFF_T
  335. modifier = LM_PTRDIFF_T;
  336. #else
  337. modifier = LM_SIZE_T;
  338. #endif
  339. break;
  340. case 'p': {
  341. char __next = *(fmt+1);
  342. if ('d' == __next || 'u' == __next || 'x' == __next || 'o' == __next) {
  343. fmt++;
  344. modifier = LM_PHP_INT_T;
  345. } else {
  346. modifier = LM_STD;
  347. }
  348. }
  349. break;
  350. case 'h':
  351. fmt++;
  352. if (*fmt == 'h') {
  353. fmt++;
  354. }
  355. /* these are promoted to int, so no break */
  356. default:
  357. modifier = LM_STD;
  358. break;
  359. }
  360. /*
  361. * Argument extraction and printing.
  362. * First we determine the argument type.
  363. * Then, we convert the argument to a string.
  364. * On exit from the switch, s points to the string that
  365. * must be printed, s_len has the length of the string
  366. * The precision requirements, if any, are reflected in s_len.
  367. *
  368. * NOTE: pad_char may be set to '0' because of the 0 flag.
  369. * It is reset to ' ' by non-numeric formats
  370. */
  371. switch (*fmt) {
  372. case 'Z': {
  373. zvp = (zval*) va_arg(ap, zval*);
  374. free_zcopy = zend_make_printable_zval(zvp, &zcopy);
  375. if (free_zcopy) {
  376. zvp = &zcopy;
  377. }
  378. s_len = Z_STRLEN_P(zvp);
  379. s = Z_STRVAL_P(zvp);
  380. if (adjust_precision && (size_t)precision < s_len) {
  381. s_len = precision;
  382. }
  383. break;
  384. }
  385. case 'u':
  386. switch(modifier) {
  387. default:
  388. i_num = (wide_int) va_arg(ap, unsigned int);
  389. break;
  390. case LM_LONG_DOUBLE:
  391. goto fmt_error;
  392. case LM_LONG:
  393. i_num = (wide_int) va_arg(ap, unsigned long int);
  394. break;
  395. case LM_SIZE_T:
  396. i_num = (wide_int) va_arg(ap, size_t);
  397. break;
  398. #if SIZEOF_LONG_LONG
  399. case LM_LONG_LONG:
  400. i_num = (wide_int) va_arg(ap, u_wide_int);
  401. break;
  402. #endif
  403. #if SIZEOF_INTMAX_T
  404. case LM_INTMAX_T:
  405. i_num = (wide_int) va_arg(ap, uintmax_t);
  406. break;
  407. #endif
  408. #if SIZEOF_PTRDIFF_T
  409. case LM_PTRDIFF_T:
  410. i_num = (wide_int) va_arg(ap, ptrdiff_t);
  411. break;
  412. #endif
  413. case LM_PHP_INT_T:
  414. i_num = (wide_int) va_arg(ap, zend_ulong);
  415. break;
  416. }
  417. /*
  418. * The rest also applies to other integer formats, so fall
  419. * into that case.
  420. */
  421. case 'd':
  422. case 'i':
  423. /*
  424. * Get the arg if we haven't already.
  425. */
  426. if ((*fmt) != 'u') {
  427. switch(modifier) {
  428. default:
  429. i_num = (wide_int) va_arg(ap, int);
  430. break;
  431. case LM_LONG_DOUBLE:
  432. goto fmt_error;
  433. case LM_LONG:
  434. i_num = (wide_int) va_arg(ap, long int);
  435. break;
  436. case LM_SIZE_T:
  437. #if SIZEOF_SSIZE_T
  438. i_num = (wide_int) va_arg(ap, ssize_t);
  439. #else
  440. i_num = (wide_int) va_arg(ap, size_t);
  441. #endif
  442. break;
  443. #if SIZEOF_LONG_LONG
  444. case LM_LONG_LONG:
  445. i_num = (wide_int) va_arg(ap, wide_int);
  446. break;
  447. #endif
  448. #if SIZEOF_INTMAX_T
  449. case LM_INTMAX_T:
  450. i_num = (wide_int) va_arg(ap, intmax_t);
  451. break;
  452. #endif
  453. #if SIZEOF_PTRDIFF_T
  454. case LM_PTRDIFF_T:
  455. i_num = (wide_int) va_arg(ap, ptrdiff_t);
  456. break;
  457. #endif
  458. case LM_PHP_INT_T:
  459. i_num = (wide_int) va_arg(ap, zend_long);
  460. break;
  461. }
  462. }
  463. s = ap_php_conv_10(i_num, (*fmt) == 'u', &is_negative,
  464. &num_buf[NUM_BUF_SIZE], &s_len);
  465. FIX_PRECISION(adjust_precision, precision, s, s_len);
  466. if (*fmt != 'u') {
  467. if (is_negative)
  468. prefix_char = '-';
  469. else if (print_sign)
  470. prefix_char = '+';
  471. else if (print_blank)
  472. prefix_char = ' ';
  473. }
  474. break;
  475. case 'o':
  476. switch(modifier) {
  477. default:
  478. ui_num = (u_wide_int) va_arg(ap, unsigned int);
  479. break;
  480. case LM_LONG_DOUBLE:
  481. goto fmt_error;
  482. case LM_LONG:
  483. ui_num = (u_wide_int) va_arg(ap, unsigned long int);
  484. break;
  485. case LM_SIZE_T:
  486. ui_num = (u_wide_int) va_arg(ap, size_t);
  487. break;
  488. #if SIZEOF_LONG_LONG
  489. case LM_LONG_LONG:
  490. ui_num = (u_wide_int) va_arg(ap, u_wide_int);
  491. break;
  492. #endif
  493. #if SIZEOF_INTMAX_T
  494. case LM_INTMAX_T:
  495. ui_num = (u_wide_int) va_arg(ap, uintmax_t);
  496. break;
  497. #endif
  498. #if SIZEOF_PTRDIFF_T
  499. case LM_PTRDIFF_T:
  500. ui_num = (u_wide_int) va_arg(ap, ptrdiff_t);
  501. break;
  502. #endif
  503. case LM_PHP_INT_T:
  504. ui_num = (u_wide_int) va_arg(ap, zend_ulong);
  505. break;
  506. }
  507. s = ap_php_conv_p2(ui_num, 3, *fmt,
  508. &num_buf[NUM_BUF_SIZE], &s_len);
  509. FIX_PRECISION(adjust_precision, precision, s, s_len);
  510. if (alternate_form && *s != '0') {
  511. *--s = '0';
  512. s_len++;
  513. }
  514. break;
  515. case 'x':
  516. case 'X':
  517. switch(modifier) {
  518. default:
  519. ui_num = (u_wide_int) va_arg(ap, unsigned int);
  520. break;
  521. case LM_LONG_DOUBLE:
  522. goto fmt_error;
  523. case LM_LONG:
  524. ui_num = (u_wide_int) va_arg(ap, unsigned long int);
  525. break;
  526. case LM_SIZE_T:
  527. ui_num = (u_wide_int) va_arg(ap, size_t);
  528. break;
  529. #if SIZEOF_LONG_LONG
  530. case LM_LONG_LONG:
  531. ui_num = (u_wide_int) va_arg(ap, u_wide_int);
  532. break;
  533. #endif
  534. #if SIZEOF_INTMAX_T
  535. case LM_INTMAX_T:
  536. ui_num = (u_wide_int) va_arg(ap, uintmax_t);
  537. break;
  538. #endif
  539. #if SIZEOF_PTRDIFF_T
  540. case LM_PTRDIFF_T:
  541. ui_num = (u_wide_int) va_arg(ap, ptrdiff_t);
  542. break;
  543. #endif
  544. case LM_PHP_INT_T:
  545. ui_num = (u_wide_int) va_arg(ap, zend_ulong);
  546. break;
  547. }
  548. s = ap_php_conv_p2(ui_num, 4, *fmt,
  549. &num_buf[NUM_BUF_SIZE], &s_len);
  550. FIX_PRECISION(adjust_precision, precision, s, s_len);
  551. if (alternate_form && ui_num != 0) {
  552. *--s = *fmt; /* 'x' or 'X' */
  553. *--s = '0';
  554. s_len += 2;
  555. }
  556. break;
  557. case 's':
  558. case 'v':
  559. s = va_arg(ap, char *);
  560. if (s != NULL) {
  561. if (!adjust_precision) {
  562. s_len = strlen(s);
  563. } else {
  564. s_len = strnlen(s, precision);
  565. }
  566. } else {
  567. s = S_NULL;
  568. s_len = S_NULL_LEN;
  569. }
  570. pad_char = ' ';
  571. break;
  572. case 'f':
  573. case 'F':
  574. case 'e':
  575. case 'E':
  576. switch(modifier) {
  577. case LM_LONG_DOUBLE:
  578. fp_num = (double) va_arg(ap, long double);
  579. break;
  580. case LM_STD:
  581. fp_num = va_arg(ap, double);
  582. break;
  583. default:
  584. goto fmt_error;
  585. }
  586. if (zend_isnan(fp_num)) {
  587. s = "nan";
  588. s_len = 3;
  589. } else if (zend_isinf(fp_num)) {
  590. s = "inf";
  591. s_len = 3;
  592. } else {
  593. #ifdef HAVE_LOCALE_H
  594. #ifdef ZTS
  595. localeconv_r(&lconv);
  596. #else
  597. if (!lconv) {
  598. lconv = localeconv();
  599. }
  600. #endif
  601. #endif
  602. s = php_conv_fp((*fmt == 'f')?'F':*fmt, fp_num, alternate_form,
  603. (adjust_precision == NO) ? FLOAT_DIGITS : precision,
  604. (*fmt == 'f')?LCONV_DECIMAL_POINT:'.',
  605. &is_negative, &num_buf[1], &s_len);
  606. if (is_negative)
  607. prefix_char = '-';
  608. else if (print_sign)
  609. prefix_char = '+';
  610. else if (print_blank)
  611. prefix_char = ' ';
  612. }
  613. break;
  614. case 'g':
  615. case 'k':
  616. case 'G':
  617. case 'H':
  618. switch(modifier) {
  619. case LM_LONG_DOUBLE:
  620. fp_num = (double) va_arg(ap, long double);
  621. break;
  622. case LM_STD:
  623. fp_num = va_arg(ap, double);
  624. break;
  625. default:
  626. goto fmt_error;
  627. }
  628. if (zend_isnan(fp_num)) {
  629. s = "NAN";
  630. s_len = 3;
  631. break;
  632. } else if (zend_isinf(fp_num)) {
  633. if (fp_num > 0) {
  634. s = "INF";
  635. s_len = 3;
  636. } else {
  637. s = "-INF";
  638. s_len = 4;
  639. }
  640. break;
  641. }
  642. if (adjust_precision == NO)
  643. precision = FLOAT_DIGITS;
  644. else if (precision == 0)
  645. precision = 1;
  646. /*
  647. * * We use &num_buf[ 1 ], so that we have room for the sign
  648. */
  649. #ifdef HAVE_LOCALE_H
  650. #ifdef ZTS
  651. localeconv_r(&lconv);
  652. #else
  653. if (!lconv) {
  654. lconv = localeconv();
  655. }
  656. #endif
  657. #endif
  658. s = php_gcvt(fp_num, precision, (*fmt=='H' || *fmt == 'k') ? '.' : LCONV_DECIMAL_POINT, (*fmt == 'G' || *fmt == 'H')?'E':'e', &num_buf[1]);
  659. if (*s == '-')
  660. prefix_char = *s++;
  661. else if (print_sign)
  662. prefix_char = '+';
  663. else if (print_blank)
  664. prefix_char = ' ';
  665. s_len = strlen(s);
  666. if (alternate_form && (strchr(s, '.')) == NULL)
  667. s[s_len++] = '.';
  668. break;
  669. case 'c':
  670. char_buf[0] = (char) (va_arg(ap, int));
  671. s = &char_buf[0];
  672. s_len = 1;
  673. pad_char = ' ';
  674. break;
  675. case '%':
  676. char_buf[0] = '%';
  677. s = &char_buf[0];
  678. s_len = 1;
  679. pad_char = ' ';
  680. break;
  681. case 'n':
  682. *(va_arg(ap, int *)) = is_char? (int)((smart_string *)xbuf)->len : (int)ZSTR_LEN(((smart_str *)xbuf)->s);
  683. goto skip_output;
  684. /*
  685. * Always extract the argument as a "char *" pointer. We
  686. * should be using "void *" but there are still machines
  687. * that don't understand it.
  688. * If the pointer size is equal to the size of an unsigned
  689. * integer we convert the pointer to a hex number, otherwise
  690. * we print "%p" to indicate that we don't handle "%p".
  691. */
  692. case 'p':
  693. if (sizeof(char *) <= sizeof(u_wide_int)) {
  694. ui_num = (u_wide_int)((size_t) va_arg(ap, char *));
  695. s = ap_php_conv_p2(ui_num, 4, 'x',
  696. &num_buf[NUM_BUF_SIZE], &s_len);
  697. if (ui_num != 0) {
  698. *--s = 'x';
  699. *--s = '0';
  700. s_len += 2;
  701. }
  702. } else {
  703. s = "%p";
  704. s_len = 2;
  705. }
  706. pad_char = ' ';
  707. break;
  708. case NUL:
  709. /*
  710. * The last character of the format string was %.
  711. * We ignore it.
  712. */
  713. continue;
  714. fmt_error:
  715. php_error(E_ERROR, "Illegal length modifier specified '%c' in s[np]printf call", *fmt);
  716. /*
  717. * The default case is for unrecognized %'s.
  718. * We print %<char> to help the user identify what
  719. * option is not understood.
  720. * This is also useful in case the user wants to pass
  721. * the output of format_converter to another function
  722. * that understands some other %<char> (like syslog).
  723. * Note that we can't point s inside fmt because the
  724. * unknown <char> could be preceded by width etc.
  725. */
  726. default:
  727. char_buf[0] = '%';
  728. char_buf[1] = *fmt;
  729. s = char_buf;
  730. s_len = 2;
  731. pad_char = ' ';
  732. break;
  733. }
  734. if (prefix_char != NUL) {
  735. *--s = prefix_char;
  736. s_len++;
  737. }
  738. if (adjust_width && adjust == RIGHT && (size_t)min_width > s_len) {
  739. if (pad_char == '0' && prefix_char != NUL) {
  740. INS_CHAR(xbuf, *s, is_char);
  741. s++;
  742. s_len--;
  743. min_width--;
  744. }
  745. PAD_CHAR(xbuf, pad_char, min_width - s_len, is_char);
  746. }
  747. /*
  748. * Print the string s.
  749. */
  750. INS_STRING(xbuf, s, s_len, is_char);
  751. if (adjust_width && adjust == LEFT && (size_t)min_width > s_len) {
  752. PAD_CHAR(xbuf, pad_char, min_width - s_len, is_char);
  753. }
  754. if (free_zcopy) {
  755. zval_ptr_dtor_str(&zcopy);
  756. }
  757. }
  758. skip_output:
  759. fmt++;
  760. }
  761. return;
  762. }
  763. /* }}} */
  764. PHPAPI void php_printf_to_smart_string(smart_string *buf, const char *format, va_list ap) /* {{{ */
  765. {
  766. xbuf_format_converter(buf, 1, format, ap);
  767. }
  768. /* }}} */
  769. PHPAPI void php_printf_to_smart_str(smart_str *buf, const char *format, va_list ap) /* {{{ */
  770. {
  771. xbuf_format_converter(buf, 0, format, ap);
  772. }
  773. /* }}} */
  774. /*
  775. * Local variables:
  776. * tab-width: 4
  777. * c-basic-offset: 4
  778. * End:
  779. * vim600: sw=4 ts=4 fdm=marker
  780. * vim<600: sw=4 ts=4
  781. */