PageRenderTime 46ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 0ms

/ext/standard/formatted_print.c

http://github.com/php/php-src
C | 852 lines | 652 code | 106 blank | 94 comment | 124 complexity | cc0c9c1913758b1dde3cb6e2283c146e MD5 | raw file
Possible License(s): BSD-2-Clause, BSD-3-Clause, MPL-2.0-no-copyleft-exception, LGPL-2.1
  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. | http://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: Stig S�ther Bakken <ssb@php.net> |
  14. +----------------------------------------------------------------------+
  15. */
  16. #include <math.h> /* modf() */
  17. #include "php.h"
  18. #include "ext/standard/head.h"
  19. #include "php_string.h"
  20. #include "zend_execute.h"
  21. #include <stdio.h>
  22. #include <locale.h>
  23. #ifdef ZTS
  24. #include "ext/standard/php_string.h"
  25. #define LCONV_DECIMAL_POINT (*lconv.decimal_point)
  26. #else
  27. #define LCONV_DECIMAL_POINT (*lconv->decimal_point)
  28. #endif
  29. #define ALIGN_LEFT 0
  30. #define ALIGN_RIGHT 1
  31. #define ADJ_WIDTH 1
  32. #define ADJ_PRECISION 2
  33. #define NUM_BUF_SIZE 500
  34. #define FLOAT_PRECISION 6
  35. #define MAX_FLOAT_PRECISION 53
  36. #if 0
  37. /* trick to control varargs functions through cpp */
  38. # define PRINTF_DEBUG(arg) php_printf arg
  39. #else
  40. # define PRINTF_DEBUG(arg)
  41. #endif
  42. static const char hexchars[] = "0123456789abcdef";
  43. static const char HEXCHARS[] = "0123456789ABCDEF";
  44. /* php_spintf_appendchar() {{{ */
  45. inline static void
  46. php_sprintf_appendchar(zend_string **buffer, size_t *pos, char add)
  47. {
  48. if ((*pos + 1) >= ZSTR_LEN(*buffer)) {
  49. PRINTF_DEBUG(("%s(): ereallocing buffer to %d bytes\n", get_active_function_name(), ZSTR_LEN(*buffer)));
  50. *buffer = zend_string_extend(*buffer, ZSTR_LEN(*buffer) << 1, 0);
  51. }
  52. PRINTF_DEBUG(("sprintf: appending '%c', pos=\n", add, *pos));
  53. ZSTR_VAL(*buffer)[(*pos)++] = add;
  54. }
  55. /* }}} */
  56. /* php_spintf_appendchar() {{{ */
  57. inline static void
  58. php_sprintf_appendchars(zend_string **buffer, size_t *pos, char *add, size_t len)
  59. {
  60. if ((*pos + len) >= ZSTR_LEN(*buffer)) {
  61. size_t nlen = ZSTR_LEN(*buffer);
  62. PRINTF_DEBUG(("%s(): ereallocing buffer to %d bytes\n", get_active_function_name(), ZSTR_LEN(*buffer)));
  63. do {
  64. nlen = nlen << 1;
  65. } while ((*pos + len) >= nlen);
  66. *buffer = zend_string_extend(*buffer, nlen, 0);
  67. }
  68. PRINTF_DEBUG(("sprintf: appending \"%s\", pos=\n", add, *pos));
  69. memcpy(ZSTR_VAL(*buffer) + (*pos), add, len);
  70. *pos += len;
  71. }
  72. /* }}} */
  73. /* php_spintf_appendstring() {{{ */
  74. inline static void
  75. php_sprintf_appendstring(zend_string **buffer, size_t *pos, char *add,
  76. size_t min_width, size_t max_width, char padding,
  77. size_t alignment, size_t len, int neg, int expprec, int always_sign)
  78. {
  79. register size_t npad;
  80. size_t req_size;
  81. size_t copy_len;
  82. size_t m_width;
  83. copy_len = (expprec ? MIN(max_width, len) : len);
  84. npad = (min_width < copy_len) ? 0 : min_width - copy_len;
  85. PRINTF_DEBUG(("sprintf: appendstring(%x, %d, %d, \"%s\", %d, '%c', %d)\n",
  86. *buffer, *pos, ZSTR_LEN(*buffer), add, min_width, padding, alignment));
  87. m_width = MAX(min_width, copy_len);
  88. if(m_width > INT_MAX - *pos - 1) {
  89. zend_error_noreturn(E_ERROR, "Field width %zd is too long", m_width);
  90. }
  91. req_size = *pos + m_width + 1;
  92. if (req_size > ZSTR_LEN(*buffer)) {
  93. size_t size = ZSTR_LEN(*buffer);
  94. while (req_size > size) {
  95. if (size > ZEND_SIZE_MAX/2) {
  96. zend_error_noreturn(E_ERROR, "Field width %zd is too long", req_size);
  97. }
  98. size <<= 1;
  99. }
  100. PRINTF_DEBUG(("sprintf ereallocing buffer to %d bytes\n", size));
  101. *buffer = zend_string_extend(*buffer, size, 0);
  102. }
  103. if (alignment == ALIGN_RIGHT) {
  104. if ((neg || always_sign) && padding=='0') {
  105. ZSTR_VAL(*buffer)[(*pos)++] = (neg) ? '-' : '+';
  106. add++;
  107. len--;
  108. copy_len--;
  109. }
  110. while (npad-- > 0) {
  111. ZSTR_VAL(*buffer)[(*pos)++] = padding;
  112. }
  113. }
  114. PRINTF_DEBUG(("sprintf: appending \"%s\"\n", add));
  115. memcpy(&ZSTR_VAL(*buffer)[*pos], add, copy_len + 1);
  116. *pos += copy_len;
  117. if (alignment == ALIGN_LEFT) {
  118. while (npad--) {
  119. ZSTR_VAL(*buffer)[(*pos)++] = padding;
  120. }
  121. }
  122. }
  123. /* }}} */
  124. /* php_spintf_appendint() {{{ */
  125. inline static void
  126. php_sprintf_appendint(zend_string **buffer, size_t *pos, zend_long number,
  127. size_t width, char padding, size_t alignment,
  128. int always_sign)
  129. {
  130. char numbuf[NUM_BUF_SIZE];
  131. register zend_ulong magn, nmagn;
  132. register unsigned int i = NUM_BUF_SIZE - 1, neg = 0;
  133. PRINTF_DEBUG(("sprintf: appendint(%x, %x, %x, %d, %d, '%c', %d)\n",
  134. *buffer, pos, &ZSTR_LEN(*buffer), number, width, padding, alignment));
  135. if (number < 0) {
  136. neg = 1;
  137. magn = ((zend_ulong) -(number + 1)) + 1;
  138. } else {
  139. magn = (zend_ulong) number;
  140. }
  141. /* Can't right-pad 0's on integers */
  142. if(alignment==0 && padding=='0') padding=' ';
  143. numbuf[i] = '\0';
  144. do {
  145. nmagn = magn / 10;
  146. numbuf[--i] = (unsigned char)(magn - (nmagn * 10)) + '0';
  147. magn = nmagn;
  148. }
  149. while (magn > 0 && i > 1);
  150. if (neg) {
  151. numbuf[--i] = '-';
  152. } else if (always_sign) {
  153. numbuf[--i] = '+';
  154. }
  155. PRINTF_DEBUG(("sprintf: appending %d as \"%s\", i=%d\n",
  156. number, &numbuf[i], i));
  157. php_sprintf_appendstring(buffer, pos, &numbuf[i], width, 0,
  158. padding, alignment, (NUM_BUF_SIZE - 1) - i,
  159. neg, 0, always_sign);
  160. }
  161. /* }}} */
  162. /* php_spintf_appenduint() {{{ */
  163. inline static void
  164. php_sprintf_appenduint(zend_string **buffer, size_t *pos,
  165. zend_ulong number,
  166. size_t width, char padding, size_t alignment)
  167. {
  168. char numbuf[NUM_BUF_SIZE];
  169. register zend_ulong magn, nmagn;
  170. register unsigned int i = NUM_BUF_SIZE - 1;
  171. PRINTF_DEBUG(("sprintf: appenduint(%x, %x, %x, %d, %d, '%c', %d)\n",
  172. *buffer, pos, &ZSTR_LEN(*buffer), number, width, padding, alignment));
  173. magn = (zend_ulong) number;
  174. /* Can't right-pad 0's on integers */
  175. if (alignment == 0 && padding == '0') padding = ' ';
  176. numbuf[i] = '\0';
  177. do {
  178. nmagn = magn / 10;
  179. numbuf[--i] = (unsigned char)(magn - (nmagn * 10)) + '0';
  180. magn = nmagn;
  181. } while (magn > 0 && i > 0);
  182. PRINTF_DEBUG(("sprintf: appending %d as \"%s\", i=%d\n", number, &numbuf[i], i));
  183. php_sprintf_appendstring(buffer, pos, &numbuf[i], width, 0,
  184. padding, alignment, (NUM_BUF_SIZE - 1) - i, 0, 0, 0);
  185. }
  186. /* }}} */
  187. /* php_spintf_appenddouble() {{{ */
  188. inline static void
  189. php_sprintf_appenddouble(zend_string **buffer, size_t *pos,
  190. double number,
  191. size_t width, char padding,
  192. size_t alignment, int precision,
  193. int adjust, char fmt,
  194. int always_sign
  195. )
  196. {
  197. char num_buf[NUM_BUF_SIZE];
  198. char *s = NULL;
  199. size_t s_len = 0;
  200. int is_negative = 0;
  201. #ifdef ZTS
  202. struct lconv lconv;
  203. #else
  204. struct lconv *lconv;
  205. #endif
  206. PRINTF_DEBUG(("sprintf: appenddouble(%x, %x, %x, %f, %d, '%c', %d, %c)\n",
  207. *buffer, pos, &ZSTR_LEN(*buffer), number, width, padding, alignment, fmt));
  208. if ((adjust & ADJ_PRECISION) == 0) {
  209. precision = FLOAT_PRECISION;
  210. } else if (precision > MAX_FLOAT_PRECISION) {
  211. php_error_docref(NULL, E_NOTICE, "Requested precision of %d digits was truncated to PHP maximum of %d digits", precision, MAX_FLOAT_PRECISION);
  212. precision = MAX_FLOAT_PRECISION;
  213. }
  214. if (zend_isnan(number)) {
  215. is_negative = (number<0);
  216. php_sprintf_appendstring(buffer, pos, "NaN", 3, 0, padding,
  217. alignment, 3, is_negative, 0, always_sign);
  218. return;
  219. }
  220. if (zend_isinf(number)) {
  221. is_negative = (number<0);
  222. php_sprintf_appendstring(buffer, pos, "INF", 3, 0, padding,
  223. alignment, 3, is_negative, 0, always_sign);
  224. return;
  225. }
  226. switch (fmt) {
  227. case 'e':
  228. case 'E':
  229. case 'f':
  230. case 'F':
  231. #ifdef ZTS
  232. localeconv_r(&lconv);
  233. #else
  234. lconv = localeconv();
  235. #endif
  236. s = php_conv_fp((fmt == 'f')?'F':fmt, number, 0, precision,
  237. (fmt == 'f')?LCONV_DECIMAL_POINT:'.',
  238. &is_negative, &num_buf[1], &s_len);
  239. if (is_negative) {
  240. num_buf[0] = '-';
  241. s = num_buf;
  242. s_len++;
  243. } else if (always_sign) {
  244. num_buf[0] = '+';
  245. s = num_buf;
  246. s_len++;
  247. }
  248. break;
  249. case 'g':
  250. case 'G':
  251. if (precision == 0)
  252. precision = 1;
  253. /*
  254. * * We use &num_buf[ 1 ], so that we have room for the sign
  255. */
  256. #ifdef ZTS
  257. localeconv_r(&lconv);
  258. #else
  259. lconv = localeconv();
  260. #endif
  261. s = php_gcvt(number, precision, LCONV_DECIMAL_POINT, (fmt == 'G')?'E':'e', &num_buf[1]);
  262. is_negative = 0;
  263. if (*s == '-') {
  264. is_negative = 1;
  265. s = &num_buf[1];
  266. } else if (always_sign) {
  267. num_buf[0] = '+';
  268. s = num_buf;
  269. }
  270. s_len = strlen(s);
  271. break;
  272. }
  273. php_sprintf_appendstring(buffer, pos, s, width, 0, padding,
  274. alignment, s_len, is_negative, 0, always_sign);
  275. }
  276. /* }}} */
  277. /* php_spintf_appendd2n() {{{ */
  278. inline static void
  279. php_sprintf_append2n(zend_string **buffer, size_t *pos, zend_long number,
  280. size_t width, char padding, size_t alignment, int n,
  281. const char *chartable, int expprec)
  282. {
  283. char numbuf[NUM_BUF_SIZE];
  284. register zend_ulong num;
  285. register zend_ulong i = NUM_BUF_SIZE - 1;
  286. register int andbits = (1 << n) - 1;
  287. PRINTF_DEBUG(("sprintf: append2n(%x, %x, %x, %d, %d, '%c', %d, %d, %x)\n",
  288. *buffer, pos, &ZSTR_LEN(*buffer), number, width, padding, alignment, n,
  289. chartable));
  290. PRINTF_DEBUG(("sprintf: append2n 2^%d andbits=%x\n", n, andbits));
  291. num = (zend_ulong) number;
  292. numbuf[i] = '\0';
  293. do {
  294. numbuf[--i] = chartable[(num & andbits)];
  295. num >>= n;
  296. }
  297. while (num > 0);
  298. php_sprintf_appendstring(buffer, pos, &numbuf[i], width, 0,
  299. padding, alignment, (NUM_BUF_SIZE - 1) - i,
  300. 0, expprec, 0);
  301. }
  302. /* }}} */
  303. /* php_spintf_getnumber() {{{ */
  304. inline static int
  305. php_sprintf_getnumber(char **buffer, size_t *len)
  306. {
  307. char *endptr;
  308. register zend_long num = ZEND_STRTOL(*buffer, &endptr, 10);
  309. register size_t i;
  310. if (endptr != NULL) {
  311. i = (endptr - *buffer);
  312. *len -= i;
  313. *buffer = endptr;
  314. }
  315. PRINTF_DEBUG(("sprintf_getnumber: number was %d bytes long\n", i));
  316. if (num >= INT_MAX || num < 0) {
  317. return -1;
  318. } else {
  319. return (int) num;
  320. }
  321. }
  322. /* }}} */
  323. /* php_formatted_print() {{{
  324. * New sprintf implementation for PHP.
  325. *
  326. * Modifiers:
  327. *
  328. * " " pad integers with spaces
  329. * "-" left adjusted field
  330. * n field size
  331. * "."n precision (floats only)
  332. * "+" Always place a sign (+ or -) in front of a number
  333. *
  334. * Type specifiers:
  335. *
  336. * "%" literal "%", modifiers are ignored.
  337. * "b" integer argument is printed as binary
  338. * "c" integer argument is printed as a single character
  339. * "d" argument is an integer
  340. * "f" the argument is a float
  341. * "o" integer argument is printed as octal
  342. * "s" argument is a string
  343. * "x" integer argument is printed as lowercase hexadecimal
  344. * "X" integer argument is printed as uppercase hexadecimal
  345. *
  346. * nb_additional_parameters is used for throwing errors:
  347. * - -1: ValueError is thrown (for vsprintf where args originates from an array)
  348. * - 0 or more: ArgumentCountError is thrown
  349. */
  350. static zend_string *
  351. php_formatted_print(char *format, size_t format_len, zval *args, int argc, int nb_additional_parameters)
  352. {
  353. size_t size = 240, outpos = 0;
  354. int alignment, currarg, adjusting, argnum, width, precision;
  355. char *temppos, padding;
  356. zend_string *result;
  357. int always_sign;
  358. int max_missing_argnum = -1;
  359. result = zend_string_alloc(size, 0);
  360. currarg = 0;
  361. argnum = 0;
  362. while (format_len) {
  363. int expprec;
  364. zval *tmp;
  365. temppos = memchr(format, '%', format_len);
  366. if (!temppos) {
  367. php_sprintf_appendchars(&result, &outpos, format, format_len);
  368. break;
  369. } else if (temppos != format) {
  370. php_sprintf_appendchars(&result, &outpos, format, temppos - format);
  371. format_len -= temppos - format;
  372. format = temppos;
  373. }
  374. format++; /* skip the '%' */
  375. format_len--;
  376. if (*format == '%') {
  377. php_sprintf_appendchar(&result, &outpos, '%');
  378. format++;
  379. format_len--;
  380. } else {
  381. /* starting a new format specifier, reset variables */
  382. alignment = ALIGN_RIGHT;
  383. adjusting = 0;
  384. padding = ' ';
  385. always_sign = 0;
  386. expprec = 0;
  387. PRINTF_DEBUG(("sprintf: first looking at '%c', inpos=%d\n",
  388. *format, format - Z_STRVAL_P(z_format)));
  389. if (isalpha((int)*format)) {
  390. width = precision = 0;
  391. argnum = currarg++;
  392. } else {
  393. /* first look for argnum */
  394. temppos = format;
  395. while (isdigit((int)*temppos)) temppos++;
  396. if (*temppos == '$') {
  397. argnum = php_sprintf_getnumber(&format, &format_len);
  398. if (argnum <= 0) {
  399. zend_value_error("Argument number must be greater than zero");
  400. goto fail;
  401. }
  402. argnum--;
  403. format++; /* skip the '$' */
  404. format_len--;
  405. } else {
  406. argnum = currarg++;
  407. }
  408. /* after argnum comes modifiers */
  409. PRINTF_DEBUG(("sprintf: looking for modifiers\n"
  410. "sprintf: now looking at '%c', inpos=%d\n",
  411. *format, format - Z_STRVAL_P(z_format)));
  412. for (;; format++, format_len--) {
  413. if (*format == ' ' || *format == '0') {
  414. padding = *format;
  415. } else if (*format == '-') {
  416. alignment = ALIGN_LEFT;
  417. /* space padding, the default */
  418. } else if (*format == '+') {
  419. always_sign = 1;
  420. } else if (*format == '\'') {
  421. if (format_len > 1) {
  422. format++;
  423. format_len--;
  424. padding = *format;
  425. } else {
  426. zend_value_error("Missing padding character");
  427. goto fail;
  428. }
  429. } else {
  430. PRINTF_DEBUG(("sprintf: end of modifiers\n"));
  431. break;
  432. }
  433. }
  434. PRINTF_DEBUG(("sprintf: padding='%c'\n", padding));
  435. PRINTF_DEBUG(("sprintf: alignment=%s\n",
  436. (alignment == ALIGN_LEFT) ? "left" : "right"));
  437. /* after modifiers comes width */
  438. if (isdigit((int)*format)) {
  439. PRINTF_DEBUG(("sprintf: getting width\n"));
  440. if ((width = php_sprintf_getnumber(&format, &format_len)) < 0) {
  441. zend_value_error("Width must be greater than zero and less than %d", INT_MAX);
  442. goto fail;
  443. }
  444. adjusting |= ADJ_WIDTH;
  445. } else {
  446. width = 0;
  447. }
  448. PRINTF_DEBUG(("sprintf: width=%d\n", width));
  449. /* after width and argnum comes precision */
  450. if (*format == '.') {
  451. format++;
  452. format_len--;
  453. PRINTF_DEBUG(("sprintf: getting precision\n"));
  454. if (isdigit((int)*format)) {
  455. if ((precision = php_sprintf_getnumber(&format, &format_len)) < 0) {
  456. zend_value_error("Precision must be greater than zero and less than %d", INT_MAX);
  457. goto fail;
  458. }
  459. adjusting |= ADJ_PRECISION;
  460. expprec = 1;
  461. } else {
  462. precision = 0;
  463. }
  464. } else {
  465. precision = 0;
  466. }
  467. PRINTF_DEBUG(("sprintf: precision=%d\n", precision));
  468. }
  469. if (*format == 'l') {
  470. format++;
  471. format_len--;
  472. }
  473. PRINTF_DEBUG(("sprintf: format character='%c'\n", *format));
  474. if (argnum >= argc) {
  475. max_missing_argnum = MAX(max_missing_argnum, argnum);
  476. continue;
  477. }
  478. /* now we expect to find a type specifier */
  479. tmp = &args[argnum];
  480. switch (*format) {
  481. case 's': {
  482. zend_string *t;
  483. zend_string *str = zval_get_tmp_string(tmp, &t);
  484. php_sprintf_appendstring(&result, &outpos,
  485. ZSTR_VAL(str),
  486. width, precision, padding,
  487. alignment,
  488. ZSTR_LEN(str),
  489. 0, expprec, 0);
  490. zend_tmp_string_release(t);
  491. break;
  492. }
  493. case 'd':
  494. php_sprintf_appendint(&result, &outpos,
  495. zval_get_long(tmp),
  496. width, padding, alignment,
  497. always_sign);
  498. break;
  499. case 'u':
  500. php_sprintf_appenduint(&result, &outpos,
  501. zval_get_long(tmp),
  502. width, padding, alignment);
  503. break;
  504. case 'g':
  505. case 'G':
  506. case 'e':
  507. case 'E':
  508. case 'f':
  509. case 'F':
  510. php_sprintf_appenddouble(&result, &outpos,
  511. zval_get_double(tmp),
  512. width, padding, alignment,
  513. precision, adjusting,
  514. *format, always_sign
  515. );
  516. break;
  517. case 'c':
  518. php_sprintf_appendchar(&result, &outpos,
  519. (char) zval_get_long(tmp));
  520. break;
  521. case 'o':
  522. php_sprintf_append2n(&result, &outpos,
  523. zval_get_long(tmp),
  524. width, padding, alignment, 3,
  525. hexchars, expprec);
  526. break;
  527. case 'x':
  528. php_sprintf_append2n(&result, &outpos,
  529. zval_get_long(tmp),
  530. width, padding, alignment, 4,
  531. hexchars, expprec);
  532. break;
  533. case 'X':
  534. php_sprintf_append2n(&result, &outpos,
  535. zval_get_long(tmp),
  536. width, padding, alignment, 4,
  537. HEXCHARS, expprec);
  538. break;
  539. case 'b':
  540. php_sprintf_append2n(&result, &outpos,
  541. zval_get_long(tmp),
  542. width, padding, alignment, 1,
  543. hexchars, expprec);
  544. break;
  545. case '%':
  546. php_sprintf_appendchar(&result, &outpos, '%');
  547. break;
  548. case '\0':
  549. if (!format_len) {
  550. zend_value_error("Missing format specifier at end of string");
  551. goto fail;
  552. }
  553. /* break missing intentionally */
  554. default:
  555. zend_value_error("Unknown format specifier '%c'", *format);
  556. goto fail;
  557. }
  558. format++;
  559. format_len--;
  560. }
  561. }
  562. if (max_missing_argnum >= 0) {
  563. if (nb_additional_parameters == -1) {
  564. zend_value_error("The arguments array must contain %d items, %d given", max_missing_argnum + 1, argc);
  565. } else {
  566. zend_argument_count_error("%d parameters are required, %d given", max_missing_argnum + nb_additional_parameters + 1, argc + nb_additional_parameters);
  567. }
  568. goto fail;
  569. }
  570. /* possibly, we have to make sure we have room for the terminating null? */
  571. ZSTR_VAL(result)[outpos]=0;
  572. ZSTR_LEN(result) = outpos;
  573. return result;
  574. fail:
  575. zend_string_efree(result);
  576. return NULL;
  577. }
  578. /* }}} */
  579. /* php_formatted_print_get_array() {{{ */
  580. static zval*
  581. php_formatted_print_get_array(zval *array, int *argc)
  582. {
  583. zval *args, *zv;
  584. int n;
  585. if (Z_TYPE_P(array) != IS_ARRAY) {
  586. convert_to_array(array);
  587. }
  588. n = zend_hash_num_elements(Z_ARRVAL_P(array));
  589. args = (zval *)safe_emalloc(n, sizeof(zval), 0);
  590. n = 0;
  591. ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(array), zv) {
  592. ZVAL_COPY_VALUE(&args[n], zv);
  593. n++;
  594. } ZEND_HASH_FOREACH_END();
  595. *argc = n;
  596. return args;
  597. }
  598. /* }}} */
  599. /* {{{ proto string sprintf(string format [, mixed arg1 [, mixed ...]])
  600. Return a formatted string */
  601. PHP_FUNCTION(sprintf)
  602. {
  603. zend_string *result;
  604. char *format;
  605. size_t format_len;
  606. zval *args;
  607. int argc;
  608. ZEND_PARSE_PARAMETERS_START(1, -1)
  609. Z_PARAM_STRING(format, format_len)
  610. Z_PARAM_VARIADIC('*', args, argc)
  611. ZEND_PARSE_PARAMETERS_END();
  612. result = php_formatted_print(format, format_len, args, argc, 1);
  613. if (result == NULL) {
  614. return;
  615. }
  616. RETVAL_STR(result);
  617. }
  618. /* }}} */
  619. /* {{{ proto string vsprintf(string format, array args)
  620. Return a formatted string */
  621. PHP_FUNCTION(vsprintf)
  622. {
  623. zend_string *result;
  624. char *format;
  625. size_t format_len;
  626. zval *array, *args;
  627. int argc;
  628. ZEND_PARSE_PARAMETERS_START(2, 2)
  629. Z_PARAM_STRING(format, format_len)
  630. Z_PARAM_ZVAL(array)
  631. ZEND_PARSE_PARAMETERS_END();
  632. args = php_formatted_print_get_array(array, &argc);
  633. result = php_formatted_print(format, format_len, args, argc, -1);
  634. efree(args);
  635. if (result == NULL) {
  636. return;
  637. }
  638. RETVAL_STR(result);
  639. }
  640. /* }}} */
  641. /* {{{ proto int printf(string format [, mixed arg1 [, mixed ...]])
  642. Output a formatted string */
  643. PHP_FUNCTION(printf)
  644. {
  645. zend_string *result;
  646. size_t rlen;
  647. char *format;
  648. size_t format_len;
  649. zval *args;
  650. int argc;
  651. ZEND_PARSE_PARAMETERS_START(1, -1)
  652. Z_PARAM_STRING(format, format_len)
  653. Z_PARAM_VARIADIC('*', args, argc)
  654. ZEND_PARSE_PARAMETERS_END();
  655. result = php_formatted_print(format, format_len, args, argc, 1);
  656. if (result == NULL) {
  657. return;
  658. }
  659. rlen = PHPWRITE(ZSTR_VAL(result), ZSTR_LEN(result));
  660. zend_string_efree(result);
  661. RETURN_LONG(rlen);
  662. }
  663. /* }}} */
  664. /* {{{ proto int vprintf(string format, array args)
  665. Output a formatted string */
  666. PHP_FUNCTION(vprintf)
  667. {
  668. zend_string *result;
  669. size_t rlen;
  670. char *format;
  671. size_t format_len;
  672. zval *array, *args;
  673. int argc;
  674. ZEND_PARSE_PARAMETERS_START(2, 2)
  675. Z_PARAM_STRING(format, format_len)
  676. Z_PARAM_ZVAL(array)
  677. ZEND_PARSE_PARAMETERS_END();
  678. args = php_formatted_print_get_array(array, &argc);
  679. result = php_formatted_print(format, format_len, args, argc, -1);
  680. efree(args);
  681. if (result == NULL) {
  682. return;
  683. }
  684. rlen = PHPWRITE(ZSTR_VAL(result), ZSTR_LEN(result));
  685. zend_string_efree(result);
  686. RETURN_LONG(rlen);
  687. }
  688. /* }}} */
  689. /* {{{ proto int fprintf(resource stream, string format [, mixed arg1 [, mixed ...]])
  690. Output a formatted string into a stream */
  691. PHP_FUNCTION(fprintf)
  692. {
  693. php_stream *stream;
  694. char *format;
  695. size_t format_len;
  696. zval *arg1, *args;
  697. int argc;
  698. zend_string *result;
  699. if (ZEND_NUM_ARGS() < 2) {
  700. WRONG_PARAM_COUNT;
  701. }
  702. ZEND_PARSE_PARAMETERS_START(2, -1)
  703. Z_PARAM_RESOURCE(arg1)
  704. Z_PARAM_STRING(format, format_len)
  705. Z_PARAM_VARIADIC('*', args, argc)
  706. ZEND_PARSE_PARAMETERS_END();
  707. php_stream_from_zval(stream, arg1);
  708. result = php_formatted_print(format, format_len, args, argc, 2);
  709. if (result == NULL) {
  710. return;
  711. }
  712. php_stream_write(stream, ZSTR_VAL(result), ZSTR_LEN(result));
  713. RETVAL_LONG(ZSTR_LEN(result));
  714. zend_string_efree(result);
  715. }
  716. /* }}} */
  717. /* {{{ proto int vfprintf(resource stream, string format, array args)
  718. Output a formatted string into a stream */
  719. PHP_FUNCTION(vfprintf)
  720. {
  721. php_stream *stream;
  722. char *format;
  723. size_t format_len;
  724. zval *arg1, *array, *args;
  725. int argc;
  726. zend_string *result;
  727. if (ZEND_NUM_ARGS() != 3) {
  728. WRONG_PARAM_COUNT;
  729. }
  730. ZEND_PARSE_PARAMETERS_START(3, 3)
  731. Z_PARAM_RESOURCE(arg1)
  732. Z_PARAM_STRING(format, format_len)
  733. Z_PARAM_ZVAL(array)
  734. ZEND_PARSE_PARAMETERS_END();
  735. php_stream_from_zval(stream, arg1);
  736. args = php_formatted_print_get_array(array, &argc);
  737. result = php_formatted_print(format, format_len, args, argc, -1);
  738. efree(args);
  739. if (result == NULL) {
  740. return;
  741. }
  742. php_stream_write(stream, ZSTR_VAL(result), ZSTR_LEN(result));
  743. RETVAL_LONG(ZSTR_LEN(result));
  744. zend_string_efree(result);
  745. }
  746. /* }}} */