snprintf.c 31 KB

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