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