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 756255 : {
60 756255 : 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 756255 : (*buffer)[(*pos)++] = add;
67 756255 : }
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 64757 : {
76 : register int npad;
77 : int req_size;
78 : int copy_len;
79 : int m_width;
80 :
81 64757 : copy_len = (expprec ? MIN(max_width, len) : len);
82 64757 : npad = min_width - copy_len;
83 :
84 64757 : if (npad < 0) {
85 54250 : 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 64757 : m_width = MAX(min_width, copy_len);
91 :
92 64757 : 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 64757 : req_size = *pos + m_width + 1;
97 :
98 64757 : if (req_size > *size) {
99 18194 : while (req_size > *size) {
100 6100 : if(*size > INT_MAX/2) {
101 0 : zend_error_noreturn(E_ERROR, "Field width %d is too long", req_size);
102 : }
103 6100 : *size <<= 1;
104 : }
105 : PRINTF_DEBUG(("sprintf ereallocing buffer to %d bytes\n", *size));
106 6047 : *buffer = erealloc(*buffer, *size);
107 : }
108 64757 : if (alignment == ALIGN_RIGHT) {
109 63396 : if ((neg || always_sign) && padding=='0') {
110 36 : (*buffer)[(*pos)++] = (neg) ? '-' : '+';
111 36 : add++;
112 36 : len--;
113 36 : copy_len--;
114 : }
115 145967 : while (npad-- > 0) {
116 19175 : (*buffer)[(*pos)++] = padding;
117 : }
118 : }
119 : PRINTF_DEBUG(("sprintf: appending \"%s\"\n", add));
120 64757 : memcpy(&(*buffer)[*pos], add, copy_len + 1);
121 64757 : *pos += copy_len;
122 64757 : if (alignment == ALIGN_LEFT) {
123 6434 : while (npad--) {
124 3712 : (*buffer)[(*pos)++] = padding;
125 : }
126 : }
127 64757 : }
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 27158 : {
136 : char numbuf[NUM_BUF_SIZE];
137 : register unsigned long magn, nmagn;
138 27158 : 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 27158 : if (number < 0) {
143 692 : neg = 1;
144 692 : magn = ((unsigned long) -(number + 1)) + 1;
145 : } else {
146 26466 : magn = (unsigned long) number;
147 : }
148 :
149 : /* Can't right-pad 0's on integers */
150 27158 : if(alignment==0 && padding=='0') padding=' ';
151 :
152 27158 : numbuf[i] = '\0';
153 :
154 : do {
155 86908 : nmagn = magn / 10;
156 :
157 86908 : numbuf[--i] = (unsigned char)(magn - (nmagn * 10)) + '0';
158 86908 : magn = nmagn;
159 : }
160 86908 : while (magn > 0 && i > 0);
161 27158 : if (neg) {
162 692 : numbuf[--i] = '-';
163 26466 : } 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 27158 : php_sprintf_appendstring(buffer, pos, size, &numbuf[i], width, 0,
169 : padding, alignment, (NUM_BUF_SIZE - 1) - i,
170 : neg, 0, always_sign);
171 27158 : }
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 3781 : {
216 : char num_buf[NUM_BUF_SIZE];
217 3781 : char *s = NULL;
218 3781 : 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 3781 : if ((adjust & ADJ_PRECISION) == 0) {
226 3464 : precision = FLOAT_PRECISION;
227 317 : } 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 3781 : 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 3741 : 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 3741 : switch (fmt) {
247 : case 'e':
248 : case 'E':
249 : case 'f':
250 : case 'F':
251 : #ifdef HAVE_LOCALE_H
252 3717 : lconv = localeconv();
253 : #endif
254 3717 : 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 3717 : if (is_negative) {
258 821 : num_buf[0] = '-';
259 821 : s = num_buf;
260 821 : s_len++;
261 2896 : } else if (always_sign) {
262 36 : num_buf[0] = '+';
263 36 : s = num_buf;
264 36 : s_len++;
265 : }
266 3717 : 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 3741 : 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 6539 : {
303 : char numbuf[NUM_BUF_SIZE];
304 : register unsigned long num;
305 6539 : register unsigned int i = NUM_BUF_SIZE - 1;
306 6539 : 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 6539 : num = (unsigned long) number;
314 6539 : numbuf[i] = '\0';
315 :
316 : do {
317 24130 : numbuf[--i] = chartable[(num & andbits)];
318 24130 : num >>= n;
319 : }
320 24130 : while (num > 0);
321 :
322 6539 : php_sprintf_appendstring(buffer, pos, size, &numbuf[i], width, 0,
323 : padding, alignment, (NUM_BUF_SIZE - 1) - i,
324 : 0, expprec, 0);
325 6539 : }
326 : /* }}} */
327 :
328 : /* php_spintf_getnumber() {{{ */
329 : inline static int
330 : php_sprintf_getnumber(char *buffer, int *pos)
331 12637 : {
332 : char *endptr;
333 12637 : register long num = strtol(&buffer[*pos], &endptr, 10);
334 12637 : register int i = 0;
335 :
336 12637 : if (endptr != NULL) {
337 12637 : i = (endptr - &buffer[*pos]);
338 : }
339 : PRINTF_DEBUG(("sprintf_getnumber: number was %d bytes long\n", i));
340 12637 : *pos += i;
341 :
342 12637 : if (num >= INT_MAX || num < 0) {
343 0 : return -1;
344 : } else {
345 12637 : 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 41843 : {
377 : zval ***args, **z_format;
378 41843 : 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 41843 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "+", &args, &argc) == FAILURE) {
384 5 : return NULL;
385 : }
386 :
387 : /* verify the number of args */
388 41838 : if ((use_array && argc != (2 + format_offset))
389 : || (!use_array && argc < (1 + format_offset))) {
390 4 : efree(args);
391 4 : WRONG_PARAM_COUNT_WITH_RETVAL(NULL);
392 : }
393 :
394 41834 : if (use_array) {
395 590 : int i = 1;
396 : zval ***newargs;
397 : zval **array;
398 :
399 590 : z_format = args[format_offset];
400 590 : array = args[1 + format_offset];
401 :
402 590 : SEPARATE_ZVAL(array);
403 590 : convert_to_array_ex(array);
404 :
405 590 : argc = 1 + zend_hash_num_elements(Z_ARRVAL_PP(array));
406 590 : newargs = (zval ***)safe_emalloc(argc, sizeof(zval *), 0);
407 590 : newargs[0] = z_format;
408 :
409 590 : for (zend_hash_internal_pointer_reset(Z_ARRVAL_PP(array));
410 4386 : zend_hash_get_current_data(Z_ARRVAL_PP(array), (void **)&newargs[i++]) == SUCCESS;
411 3206 : zend_hash_move_forward(Z_ARRVAL_PP(array)));
412 :
413 590 : efree(args);
414 590 : args = newargs;
415 590 : format_offset = 0;
416 : }
417 :
418 41834 : convert_to_string_ex(args[format_offset]);
419 41834 : format = Z_STRVAL_PP(args[format_offset]);
420 41834 : result = emalloc(size);
421 :
422 41834 : currarg = 1;
423 :
424 907120 : while (inpos<Z_STRLEN_PP(args[format_offset])) {
425 823483 : int expprec = 0, multiuse = 0;
426 : zval *tmp;
427 :
428 : PRINTF_DEBUG(("sprintf: format[%d]='%c'\n", inpos, format[inpos]));
429 : PRINTF_DEBUG(("sprintf: outpos=%d\n", outpos));
430 823483 : if (format[inpos] != '%') {
431 755201 : php_sprintf_appendchar(&result, &outpos, &size, format[inpos++] TSRMLS_CC);
432 68282 : } else if (format[inpos + 1] == '%') {
433 45 : php_sprintf_appendchar(&result, &outpos, &size, '%' TSRMLS_CC);
434 45 : inpos += 2;
435 : } else {
436 : /* starting a new format specifier, reset variables */
437 68237 : alignment = ALIGN_RIGHT;
438 68237 : adjusting = 0;
439 68237 : padding = ' ';
440 68237 : always_sign = 0;
441 68237 : inpos++; /* skip the '%' */
442 :
443 : PRINTF_DEBUG(("sprintf: first looking at '%c', inpos=%d\n",
444 : format[inpos], inpos));
445 82124 : if (isascii((int)format[inpos]) && !isalpha((int)format[inpos])) {
446 : /* first look for argnum */
447 13889 : temppos = inpos;
448 13889 : while (isdigit((int)format[temppos])) temppos++;
449 13889 : if (format[temppos] == '$') {
450 555 : argnum = php_sprintf_getnumber(format, &inpos);
451 :
452 555 : if (argnum <= 0) {
453 2 : efree(result);
454 2 : efree(args);
455 2 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Argument number must be greater than zero");
456 2 : return NULL;
457 : }
458 :
459 553 : multiuse = 1;
460 553 : inpos++; /* skip the '$' */
461 : } else {
462 13334 : argnum = currarg++;
463 : }
464 :
465 13887 : argnum += format_offset;
466 :
467 : /* after argnum comes modifiers */
468 : PRINTF_DEBUG(("sprintf: looking for modifiers\n"
469 : "sprintf: now looking at '%c', inpos=%d\n",
470 : format[inpos], inpos));
471 9132 : for (;; inpos++) {
472 30000 : if (format[inpos] == ' ' || format[inpos] == '0') {
473 6981 : padding = format[inpos];
474 16038 : } else if (format[inpos] == '-') {
475 1415 : alignment = ALIGN_LEFT;
476 : /* space padding, the default */
477 14623 : } else if (format[inpos] == '+') {
478 179 : always_sign = 1;
479 14444 : } else if (format[inpos] == '\'') {
480 557 : padding = format[++inpos];
481 : } else {
482 : PRINTF_DEBUG(("sprintf: end of modifiers\n"));
483 13887 : break;
484 : }
485 9132 : }
486 : PRINTF_DEBUG(("sprintf: padding='%c'\n", padding));
487 : PRINTF_DEBUG(("sprintf: alignment=%s\n",
488 : (alignment == ALIGN_LEFT) ? "left" : "right"));
489 :
490 :
491 : /* after modifiers comes width */
492 13887 : if (isdigit((int)format[inpos])) {
493 : PRINTF_DEBUG(("sprintf: getting width\n"));
494 11370 : if ((width = php_sprintf_getnumber(format, &inpos)) < 0) {
495 0 : efree(result);
496 0 : efree(args);
497 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Width must be greater than zero and less than %d", INT_MAX);
498 0 : return NULL;
499 : }
500 11370 : adjusting |= ADJ_WIDTH;
501 : } else {
502 2517 : width = 0;
503 : }
504 : PRINTF_DEBUG(("sprintf: width=%d\n", width));
505 :
506 : /* after width and argnum comes precision */
507 13887 : if (format[inpos] == '.') {
508 714 : inpos++;
509 : PRINTF_DEBUG(("sprintf: getting precision\n"));
510 714 : if (isdigit((int)format[inpos])) {
511 712 : if ((precision = php_sprintf_getnumber(format, &inpos)) < 0) {
512 0 : efree(result);
513 0 : efree(args);
514 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Precision must be greater than zero and less than %d", INT_MAX);
515 0 : return NULL;
516 : }
517 712 : adjusting |= ADJ_PRECISION;
518 712 : expprec = 1;
519 : } else {
520 2 : precision = 0;
521 : }
522 : } else {
523 13173 : precision = 0;
524 : }
525 : PRINTF_DEBUG(("sprintf: precision=%d\n", precision));
526 : } else {
527 54348 : width = precision = 0;
528 54348 : argnum = currarg++ + format_offset;
529 : }
530 :
531 68235 : if (argnum >= argc) {
532 29 : efree(result);
533 29 : efree(args);
534 29 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Too few arguments");
535 29 : return NULL;
536 : }
537 :
538 68206 : if (format[inpos] == 'l') {
539 713 : inpos++;
540 : }
541 : PRINTF_DEBUG(("sprintf: format character='%c'\n", format[inpos]));
542 : /* now we expect to find a type specifier */
543 68206 : if (multiuse) {
544 553 : MAKE_STD_ZVAL(tmp);
545 553 : *tmp = **(args[argnum]);
546 553 : INIT_PZVAL(tmp);
547 553 : zval_copy_ctor(tmp);
548 : } else {
549 67653 : SEPARATE_ZVAL(args[argnum]);
550 67653 : tmp = *(args[argnum]);
551 : }
552 :
553 68206 : switch (format[inpos]) {
554 : case 's': {
555 : zval *var, var_copy;
556 : int use_copy;
557 :
558 26352 : zend_make_printable_zval(tmp, &var_copy, &use_copy);
559 26352 : if (use_copy) {
560 3668 : var = &var_copy;
561 : } else {
562 22684 : var = tmp;
563 : }
564 26352 : php_sprintf_appendstring(&result, &outpos, &size,
565 : Z_STRVAL_P(var),
566 : width, precision, padding,
567 : alignment,
568 : Z_STRLEN_P(var),
569 : 0, expprec, 0);
570 26352 : if (use_copy) {
571 3668 : zval_dtor(&var_copy);
572 : }
573 26352 : break;
574 : }
575 :
576 : case 'd':
577 27158 : convert_to_long(tmp);
578 27158 : php_sprintf_appendint(&result, &outpos, &size,
579 : Z_LVAL_P(tmp),
580 : width, padding, alignment,
581 : always_sign);
582 27158 : break;
583 :
584 : case 'u':
585 927 : convert_to_long(tmp);
586 927 : php_sprintf_appenduint(&result, &outpos, &size,
587 : Z_LVAL_P(tmp),
588 : width, padding, alignment);
589 927 : break;
590 :
591 : case 'g':
592 : case 'G':
593 : case 'e':
594 : case 'E':
595 : case 'f':
596 : case 'F':
597 3781 : convert_to_double(tmp);
598 3781 : php_sprintf_appenddouble(&result, &outpos, &size,
599 : Z_DVAL_P(tmp),
600 : width, padding, alignment,
601 : precision, adjusting,
602 : format[inpos], always_sign
603 : TSRMLS_CC);
604 3781 : break;
605 :
606 : case 'c':
607 997 : convert_to_long(tmp);
608 997 : php_sprintf_appendchar(&result, &outpos, &size,
609 : (char) Z_LVAL_P(tmp) TSRMLS_CC);
610 997 : break;
611 :
612 : case 'o':
613 4056 : convert_to_long(tmp);
614 4056 : php_sprintf_append2n(&result, &outpos, &size,
615 : Z_LVAL_P(tmp),
616 : width, padding, alignment, 3,
617 : hexchars, expprec);
618 4056 : break;
619 :
620 : case 'x':
621 2097 : convert_to_long(tmp);
622 2097 : php_sprintf_append2n(&result, &outpos, &size,
623 : Z_LVAL_P(tmp),
624 : width, padding, alignment, 4,
625 : hexchars, expprec);
626 2097 : break;
627 :
628 : case 'X':
629 319 : convert_to_long(tmp);
630 319 : php_sprintf_append2n(&result, &outpos, &size,
631 : Z_LVAL_P(tmp),
632 : width, padding, alignment, 4,
633 : HEXCHARS, expprec);
634 319 : break;
635 :
636 : case 'b':
637 67 : convert_to_long(tmp);
638 67 : php_sprintf_append2n(&result, &outpos, &size,
639 : Z_LVAL_P(tmp),
640 : width, padding, alignment, 1,
641 : hexchars, expprec);
642 67 : break;
643 :
644 : case '%':
645 12 : php_sprintf_appendchar(&result, &outpos, &size, '%' TSRMLS_CC);
646 :
647 : break;
648 : default:
649 : break;
650 : }
651 68206 : if (multiuse) {
652 553 : zval_ptr_dtor(&tmp);
653 : }
654 68206 : inpos++;
655 : }
656 : }
657 :
658 41803 : efree(args);
659 :
660 : /* possibly, we have to make sure we have room for the terminating null? */
661 41803 : result[outpos]=0;
662 41803 : *len = outpos;
663 41803 : return result;
664 : }
665 : /* }}} */
666 :
667 : /* {{{ proto string sprintf(string format [, mixed arg1 [, mixed ...]])
668 : Return a formatted string */
669 : PHP_FUNCTION(user_sprintf)
670 29941 : {
671 : char *result;
672 : int len;
673 :
674 29941 : if ((result=php_formatted_print(ht, &len, 0, 0 TSRMLS_CC))==NULL) {
675 7 : RETURN_FALSE;
676 : }
677 29934 : RETVAL_STRINGL(result, len, 0);
678 : }
679 : /* }}} */
680 :
681 : /* {{{ proto string vsprintf(string format, array args)
682 : Return a formatted string */
683 : PHP_FUNCTION(vsprintf)
684 204 : {
685 : char *result;
686 : int len;
687 :
688 204 : if ((result=php_formatted_print(ht, &len, 1, 0 TSRMLS_CC))==NULL) {
689 8 : RETURN_FALSE;
690 : }
691 196 : RETVAL_STRINGL(result, len, 0);
692 : }
693 : /* }}} */
694 :
695 : /* {{{ proto int printf(string format [, mixed arg1 [, mixed ...]])
696 : Output a formatted string */
697 : PHP_FUNCTION(user_printf)
698 9546 : {
699 : char *result;
700 : int len, rlen;
701 :
702 9546 : if ((result=php_formatted_print(ht, &len, 0, 0 TSRMLS_CC))==NULL) {
703 10 : RETURN_FALSE;
704 : }
705 9536 : rlen = PHPWRITE(result, len);
706 9536 : efree(result);
707 9536 : RETURN_LONG(rlen);
708 : }
709 : /* }}} */
710 :
711 : /* {{{ proto int vprintf(string format, array args)
712 : Output a formatted string */
713 : PHP_FUNCTION(vprintf)
714 189 : {
715 : char *result;
716 : int len, rlen;
717 :
718 189 : if ((result=php_formatted_print(ht, &len, 1, 0 TSRMLS_CC))==NULL) {
719 8 : RETURN_FALSE;
720 : }
721 181 : rlen = PHPWRITE(result, len);
722 181 : efree(result);
723 181 : RETURN_LONG(rlen);
724 : }
725 : /* }}} */
726 :
727 : /* {{{ proto int fprintf(resource stream, string format [, mixed arg1 [, mixed ...]])
728 : Output a formatted string into a stream */
729 : PHP_FUNCTION(fprintf)
730 1763 : {
731 : php_stream *stream;
732 : zval *arg1;
733 : char *result;
734 : int len;
735 :
736 1763 : if (ZEND_NUM_ARGS() < 2) {
737 3 : WRONG_PARAM_COUNT;
738 : }
739 :
740 1760 : if (zend_parse_parameters(1 TSRMLS_CC, "r", &arg1) == FAILURE) {
741 0 : RETURN_FALSE;
742 : }
743 :
744 1760 : php_stream_from_zval(stream, &arg1);
745 :
746 1760 : if ((result=php_formatted_print(ht, &len, 0, 1 TSRMLS_CC))==NULL) {
747 1 : RETURN_FALSE;
748 : }
749 :
750 1759 : php_stream_write(stream, result, len);
751 :
752 1759 : efree(result);
753 :
754 1759 : RETURN_LONG(len);
755 : }
756 : /* }}} */
757 :
758 : /* {{{ proto int vfprintf(resource stream, string format, array args)
759 : Output a formatted string into a stream */
760 : PHP_FUNCTION(vfprintf)
761 211 : {
762 : php_stream *stream;
763 : zval *arg1;
764 : char *result;
765 : int len;
766 :
767 211 : if (ZEND_NUM_ARGS() != 3) {
768 5 : WRONG_PARAM_COUNT;
769 : }
770 :
771 206 : if (zend_parse_parameters(1 TSRMLS_CC, "r", &arg1) == FAILURE) {
772 3 : RETURN_FALSE;
773 : }
774 :
775 203 : php_stream_from_zval(stream, &arg1);
776 :
777 203 : if ((result=php_formatted_print(ht, &len, 1, 1 TSRMLS_CC))==NULL) {
778 6 : RETURN_FALSE;
779 : }
780 :
781 197 : php_stream_write(stream, result, len);
782 :
783 197 : efree(result);
784 :
785 197 : RETURN_LONG(len);
786 : }
787 : /* }}} */
788 :
789 : /*
790 : * Local variables:
791 : * tab-width: 4
792 : * c-basic-offset: 4
793 : * End:
794 : * vim600: sw=4 ts=4 fdm=marker
795 : * vim<600: sw=4 ts=4
796 : */
|