formatted_print.c 20 KB

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