formatted_print.c 20 KB

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