spprintf.c 20 KB

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