snprintf.c 28 KB

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