1 : /*
2 : +----------------------------------------------------------------------+
3 : | PHP Version 6 |
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 : #define PHP_OUTPUT 0
47 : #define PHP_RUNTIME 1
48 :
49 : #if 0
50 : /* trick to control varargs functions through cpp */
51 : # define PRINTF_DEBUG(arg) php_printf arg
52 : #else
53 : # define PRINTF_DEBUG(arg)
54 : #endif
55 :
56 : static char hexchars[] = "0123456789abcdef";
57 : static char HEXCHARS[] = "0123456789ABCDEF";
58 :
59 : static UChar u_hexchars[] = {0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66};
60 : static UChar u_HEXCHARS[] = {0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46};
61 :
62 : /* php_sprintf_appendchar() {{{ */
63 : inline static void
64 : php_sprintf_appendchar(char **buffer, int *pos, int *size, char add TSRMLS_DC)
65 0 : {
66 0 : if ((*pos + 1) >= *size) {
67 0 : *size <<= 1;
68 : PRINTF_DEBUG(("%s(): ereallocing buffer to %d bytes\n", get_active_function_name(TSRMLS_C), *size));
69 0 : *buffer = erealloc(*buffer, *size);
70 : }
71 : PRINTF_DEBUG(("sprintf: appending '%c', pos=\n", add, *pos));
72 0 : (*buffer)[(*pos)++] = add;
73 0 : }
74 : /* }}} */
75 :
76 : /* php_u_sprintf_appendchar() {{{ */
77 : inline static void
78 : php_u_sprintf_appendchar(UChar **buffer, int *pos, int *size, UChar add TSRMLS_DC)
79 857101 : {
80 857101 : if ((*pos + 1) >= *size) {
81 0 : *size <<= 1;
82 0 : *buffer = eurealloc(*buffer, *size);
83 : }
84 857101 : (*buffer)[(*pos)++] = add;
85 857101 : }
86 : /* }}} */
87 :
88 : /* php_sprintf_appendstring() {{{ */
89 : inline static void
90 : php_sprintf_appendstring(char **buffer, int *pos, int *size, char *add,
91 : int min_width, int max_width, char padding,
92 : int alignment, int len, int neg, int expprec, int always_sign)
93 0 : {
94 : register int npad;
95 : int req_size;
96 : int copy_len;
97 : int m_width;
98 :
99 0 : copy_len = (expprec ? MIN(max_width, len) : len);
100 0 : npad = min_width - copy_len;
101 :
102 0 : if (npad < 0) {
103 0 : npad = 0;
104 : }
105 :
106 : PRINTF_DEBUG(("sprintf: appendstring(%x, %d, %d, \"%s\", %d, '%c', %d)\n",
107 : *buffer, *pos, *size, add, min_width, padding, alignment));
108 0 : m_width = MAX(min_width, copy_len);
109 :
110 0 : if(m_width > INT_MAX - *pos - 1) {
111 0 : zend_error_noreturn(E_ERROR, "Field width %d is too long", m_width);
112 : }
113 :
114 0 : req_size = *pos + m_width + 1;
115 :
116 0 : if (req_size > *size) {
117 0 : while (req_size > *size) {
118 0 : if(*size > INT_MAX/2) {
119 0 : zend_error_noreturn(E_ERROR, "Field width %d is too long", req_size);
120 : }
121 0 : *size <<= 1;
122 : }
123 : PRINTF_DEBUG(("sprintf ereallocing buffer to %d bytes\n", *size));
124 0 : *buffer = erealloc(*buffer, *size);
125 : }
126 0 : if (alignment == ALIGN_RIGHT) {
127 0 : if ((neg || always_sign) && padding=='0') {
128 0 : (*buffer)[(*pos)++] = (neg) ? '-' : '+';
129 0 : add++;
130 0 : len--;
131 0 : copy_len--;
132 : }
133 0 : while (npad-- > 0) {
134 0 : (*buffer)[(*pos)++] = padding;
135 : }
136 : }
137 : PRINTF_DEBUG(("sprintf: appending \"%s\"\n", add));
138 0 : memcpy(&(*buffer)[*pos], add, copy_len + 1);
139 0 : *pos += copy_len;
140 0 : if (alignment == ALIGN_LEFT) {
141 0 : while (npad--) {
142 0 : (*buffer)[(*pos)++] = padding;
143 : }
144 : }
145 0 : }
146 : /* }}} */
147 :
148 : /* php_u_sprintf_appendstring() {{{ */
149 : inline static void
150 : php_u_sprintf_appendstring(UChar **buffer, int *pos, int *size, UChar *add,
151 : int min_width, int max_width, UChar padding,
152 : int alignment, int len, int neg, int expprec, int always_sign)
153 109656 : {
154 : register int npad;
155 : int req_size;
156 : int copy_len;
157 :
158 109656 : copy_len = (expprec ? MIN(max_width, len) : len);
159 109656 : npad = min_width - copy_len;
160 :
161 109656 : if (npad < 0) {
162 70874 : npad = 0;
163 : }
164 :
165 109656 : req_size = *pos + MAX(min_width, copy_len) + 1;
166 :
167 109656 : if (req_size > *size) {
168 6335 : while (req_size > *size) {
169 2147 : *size <<= 1;
170 : }
171 2094 : *buffer = eurealloc(*buffer, *size);
172 : }
173 109656 : if (alignment == ALIGN_RIGHT) {
174 108301 : if ((neg || always_sign) && padding == 0x30 /* '0' */) {
175 36 : (*buffer)[(*pos)++] = (neg) ? 0x2D /* '-' */ : 0x2B /* '+' */;
176 36 : add++;
177 36 : len--;
178 36 : copy_len--;
179 : }
180 255412 : while (npad-- > 0) {
181 38810 : (*buffer)[(*pos)++] = padding;
182 : }
183 : }
184 109656 : u_memcpy(&(*buffer)[*pos], add, copy_len + 1);
185 109656 : *pos += copy_len;
186 109656 : if (alignment == ALIGN_LEFT) {
187 6478 : while (npad--) {
188 3768 : (*buffer)[(*pos)++] = padding;
189 : }
190 : }
191 109656 : }
192 : /* }}} */
193 :
194 : /* php_sprintf_appendint() {{{ */
195 : inline static void
196 : php_sprintf_appendint(char **buffer, int *pos, int *size, long number,
197 : int width, char padding, int alignment,
198 : int always_sign)
199 0 : {
200 : char numbuf[NUM_BUF_SIZE];
201 : register unsigned long magn, nmagn;
202 0 : register unsigned int i = NUM_BUF_SIZE - 1, neg = 0;
203 :
204 : PRINTF_DEBUG(("sprintf: appendint(%x, %x, %x, %d, %d, '%c', %d)\n",
205 : *buffer, pos, size, number, width, padding, alignment));
206 0 : if (number < 0) {
207 0 : neg = 1;
208 0 : magn = ((unsigned long) -(number + 1)) + 1;
209 : } else {
210 0 : magn = (unsigned long) number;
211 : }
212 :
213 : /* Can't right-pad 0's on integers */
214 0 : if(alignment==0 && padding=='0') padding=' ';
215 :
216 0 : numbuf[i] = '\0';
217 :
218 : do {
219 0 : nmagn = magn / 10;
220 :
221 0 : numbuf[--i] = (unsigned char)(magn - (nmagn * 10)) + '0';
222 0 : magn = nmagn;
223 : }
224 0 : while (magn > 0 && i > 0);
225 0 : if (neg) {
226 0 : numbuf[--i] = '-';
227 0 : } else if (always_sign) {
228 0 : numbuf[--i] = '+';
229 : }
230 : PRINTF_DEBUG(("sprintf: appending %d as \"%s\", i=%d\n",
231 : number, &numbuf[i], i));
232 0 : php_sprintf_appendstring(buffer, pos, size, &numbuf[i], width, 0,
233 : padding, alignment, (NUM_BUF_SIZE - 1) - i,
234 : neg, 0, always_sign);
235 0 : }
236 : /* }}} */
237 :
238 : /* php_u_sprintf_appendint() {{{ */
239 : inline static void
240 : php_u_sprintf_appendint(UChar **buffer, int *pos, int *size, long number,
241 : int width, UChar padding, int alignment,
242 : int always_sign)
243 76152 : {
244 : UChar numbuf[NUM_BUF_SIZE];
245 : register unsigned long magn, nmagn;
246 76152 : register unsigned int i = NUM_BUF_SIZE - 1, neg = 0;
247 :
248 76152 : if (number < 0) {
249 699 : neg = 1;
250 699 : magn = ((unsigned long) -(number + 1)) + 1;
251 : } else {
252 75453 : magn = (unsigned long) number;
253 : }
254 :
255 : /* Can't right-pad 0's on integers */
256 76152 : if (alignment==0 && padding== 0x30 /* '0' */) padding = 0x20 /* ' ' */;
257 :
258 76152 : numbuf[i] = 0x0A /* '\0' */;
259 :
260 : do {
261 235451 : nmagn = magn / 10;
262 :
263 235451 : numbuf[--i] = (UChar)(magn - (nmagn * 10)) + 0x30 /* '0' */;
264 235451 : magn = nmagn;
265 : }
266 235451 : while (magn > 0 && i > 0);
267 76152 : if (neg) {
268 699 : numbuf[--i] = 0x2D /* '-' */;
269 75453 : } else if (always_sign) {
270 24 : numbuf[--i] = 0x2B /* '+' */;
271 : }
272 76152 : php_u_sprintf_appendstring(buffer, pos, size, &numbuf[i], width, 0,
273 : padding, alignment, (NUM_BUF_SIZE - 1) - i,
274 : neg, 0, always_sign);
275 76152 : }
276 : /* }}} */
277 :
278 : /* php_sprintf_appenduint() {{{ */
279 : inline static void
280 : php_sprintf_appenduint(char **buffer, int *pos, int *size,
281 : unsigned long number,
282 : int width, char padding, int alignment)
283 0 : {
284 : char numbuf[NUM_BUF_SIZE];
285 : register unsigned long magn, nmagn;
286 0 : register unsigned int i = NUM_BUF_SIZE - 1;
287 :
288 : PRINTF_DEBUG(("sprintf: appenduint(%x, %x, %x, %d, %d, '%c', %d)\n",
289 : *buffer, pos, size, number, width, padding, alignment));
290 0 : magn = (unsigned long) number;
291 :
292 : /* Can't right-pad 0's on integers */
293 0 : if (alignment == 0 && padding == '0') padding = ' ';
294 :
295 0 : numbuf[i] = '\0';
296 :
297 : do {
298 0 : nmagn = magn / 10;
299 :
300 0 : numbuf[--i] = (unsigned char)(magn - (nmagn * 10)) + '0';
301 0 : magn = nmagn;
302 0 : } while (magn > 0 && i > 0);
303 :
304 : PRINTF_DEBUG(("sprintf: appending %d as \"%s\", i=%d\n", number, &numbuf[i], i));
305 0 : php_sprintf_appendstring(buffer, pos, size, &numbuf[i], width, 0,
306 : padding, alignment, (NUM_BUF_SIZE - 1) - i, 0, 0, 0);
307 0 : }
308 : /* }}} */
309 :
310 : /* php_u_sprintf_appenduint() {{{ */
311 : inline static void
312 : php_u_sprintf_appenduint(UChar **buffer, int *pos, int *size,
313 : unsigned long number,
314 : int width, UChar padding, int alignment)
315 927 : {
316 : UChar numbuf[NUM_BUF_SIZE];
317 : register unsigned long magn, nmagn;
318 927 : register unsigned int i = NUM_BUF_SIZE - 1;
319 :
320 927 : magn = (unsigned long) number;
321 :
322 : /* Can't right-pad 0's on integers */
323 927 : if (alignment == 0 && padding == 0x30 /* '0' */) padding = 0x20 /* ' ' */;
324 :
325 927 : numbuf[i] = 0x0A /* '\0' */;
326 :
327 : do {
328 3300 : nmagn = magn / 10;
329 :
330 3300 : numbuf[--i] = (UChar)(magn - (nmagn * 10)) + 0x30 /* '0' */;
331 3300 : magn = nmagn;
332 3300 : } while (magn > 0 && i > 0);
333 :
334 927 : php_u_sprintf_appendstring(buffer, pos, size, &numbuf[i], width, 0,
335 : padding, alignment, (NUM_BUF_SIZE - 1) - i, 0, 0, 0);
336 927 : }
337 : /* }}} */
338 :
339 : /* php_sprintf_appenddouble() {{{ */
340 : inline static void
341 : php_sprintf_appenddouble(char **buffer, int *pos,
342 : int *size, double number,
343 : int width, char padding,
344 : int alignment, int precision,
345 : int adjust, char fmt,
346 : int always_sign
347 : TSRMLS_DC)
348 0 : {
349 : char num_buf[NUM_BUF_SIZE];
350 0 : char *s = NULL;
351 0 : int s_len = 0, is_negative = 0;
352 : #ifdef HAVE_LOCALE_H
353 : struct lconv *lconv;
354 : #endif
355 :
356 : PRINTF_DEBUG(("sprintf: appenddouble(%x, %x, %x, %f, %d, '%c', %d, %c)\n",
357 : *buffer, pos, size, number, width, padding, alignment, fmt));
358 0 : if ((adjust & ADJ_PRECISION) == 0) {
359 0 : precision = FLOAT_PRECISION;
360 0 : } else if (precision > MAX_FLOAT_PRECISION) {
361 0 : 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);
362 0 : precision = MAX_FLOAT_PRECISION;
363 : }
364 :
365 0 : if (zend_isnan(number)) {
366 0 : is_negative = (number<0);
367 0 : php_sprintf_appendstring(buffer, pos, size, "NaN", 3, 0, padding,
368 : alignment, 3, is_negative, 0, always_sign);
369 0 : return;
370 : }
371 :
372 0 : if (zend_isinf(number)) {
373 0 : is_negative = (number<0);
374 0 : php_sprintf_appendstring(buffer, pos, size, "INF", 3, 0, padding,
375 : alignment, 3, is_negative, 0, always_sign);
376 0 : return;
377 : }
378 :
379 0 : switch (fmt) {
380 : case 'e':
381 : case 'E':
382 : case 'f':
383 : case 'F':
384 : #ifdef HAVE_LOCALE_H
385 0 : lconv = localeconv();
386 : #endif
387 0 : s = php_conv_fp((fmt == 'f')?'F':fmt, number, NO, precision,
388 : (fmt == 'f')?LCONV_DECIMAL_POINT:'.',
389 : &is_negative, &num_buf[1], &s_len);
390 0 : if (is_negative) {
391 0 : num_buf[0] = '-';
392 0 : s = num_buf;
393 0 : s_len++;
394 0 : } else if (always_sign) {
395 0 : num_buf[0] = '+';
396 0 : s = num_buf;
397 0 : s_len++;
398 : }
399 0 : break;
400 :
401 : case 'g':
402 : case 'G':
403 0 : if (precision == 0)
404 0 : precision = 1;
405 : /*
406 : * * We use &num_buf[ 1 ], so that we have room for the sign
407 : */
408 : #ifdef HAVE_LOCALE_H
409 0 : lconv = localeconv();
410 : #endif
411 0 : s = php_gcvt(number, precision, LCONV_DECIMAL_POINT, (fmt == 'G')?'E':'e', &num_buf[1]);
412 0 : is_negative = 0;
413 0 : if (*s == '-') {
414 0 : is_negative = 1;
415 0 : s = &num_buf[1];
416 0 : } else if (always_sign) {
417 0 : num_buf[0] = '+';
418 0 : s = num_buf;
419 : }
420 :
421 0 : s_len = strlen(s);
422 : break;
423 : }
424 :
425 0 : php_sprintf_appendstring(buffer, pos, size, s, width, 0, padding,
426 : alignment, s_len, is_negative, 0, always_sign);
427 : }
428 : /* }}} */
429 :
430 : /* php_u_sprintf_appenddouble() {{{ */
431 : inline static void
432 : php_u_sprintf_appenddouble(UChar **buffer, int *pos,
433 : int *size, double number,
434 : int width, UChar padding,
435 : int alignment, int precision,
436 : int adjust, UChar fmt,
437 : int always_sign
438 : TSRMLS_DC)
439 3776 : {
440 : char num_buf[NUM_BUF_SIZE];
441 3776 : char *s = NULL, s_fmt;
442 : UChar *uni_s;
443 3776 : int s_len = 0, is_negative = 0;
444 : #ifdef HAVE_LOCALE_H
445 : struct lconv *lconv;
446 : #endif
447 :
448 3776 : if ((adjust & ADJ_PRECISION) == 0) {
449 3463 : precision = FLOAT_PRECISION;
450 313 : } else if (precision > MAX_FLOAT_PRECISION) {
451 2 : precision = MAX_FLOAT_PRECISION;
452 : }
453 :
454 3776 : if (zend_isnan(number)) {
455 40 : UChar *nan = USTR_MAKE("NaN");
456 40 : is_negative = (number<0);
457 40 : php_u_sprintf_appendstring(buffer, pos, size, nan, 3, 0, padding,
458 : alignment, 3, is_negative, 0, always_sign);
459 40 : efree(nan);
460 40 : return;
461 : }
462 :
463 3736 : if (zend_isinf(number)) {
464 0 : UChar *inf = USTR_MAKE("INF");
465 0 : is_negative = (number<0);
466 0 : php_u_sprintf_appendstring(buffer, pos, size, inf, 3, 0, padding,
467 : alignment, 3, is_negative, 0, always_sign);
468 0 : efree(inf);
469 0 : return;
470 : }
471 :
472 3736 : switch (fmt) {
473 : case 0x66 /* 'f' */:
474 2691 : s_fmt = 'f';
475 2691 : break;
476 : case 0x46 /* 'F' */:
477 51 : s_fmt = 'F';
478 51 : break;
479 : case 0x65 /* 'e' */:
480 953 : s_fmt = 'e';
481 953 : break;
482 : case 0x45 /* 'E' */:
483 17 : s_fmt = 'E';
484 17 : break;
485 : case 0x67 /* 'g' */:
486 12 : s_fmt = 'g';
487 12 : break;
488 : case 0x47 /* 'G' */:
489 12 : s_fmt = 'G';
490 : break;
491 : }
492 :
493 3736 : switch (fmt) {
494 : case 0x65 /* 'e' */:
495 : case 0x45 /* 'E' */:
496 : case 0x46 /* 'F' */:
497 : case 0x66 /* 'f' */:
498 : #ifdef HAVE_LOCALE_H
499 3712 : lconv = localeconv();
500 : #endif
501 3712 : s = php_conv_fp((s_fmt == 'f')?'F':s_fmt, number, NO, precision,
502 : (s_fmt == 'f')?LCONV_DECIMAL_POINT:'.',
503 : &is_negative, &num_buf[1], &s_len);
504 3712 : if (is_negative) {
505 872 : num_buf[0] = '-';
506 872 : s = num_buf;
507 872 : s_len++;
508 2840 : } else if (always_sign) {
509 36 : num_buf[0] = '+';
510 36 : s = num_buf;
511 36 : s_len++;
512 : }
513 3712 : break;
514 :
515 : case 0x67 /* 'g' */:
516 : case 0x47 /* 'G' */:
517 24 : if (precision == 0)
518 4 : precision = 1;
519 : /*
520 : * * We use &num_buf[ 1 ], so that we have room for the sign
521 : */
522 : #ifdef HAVE_LOCALE_H
523 24 : lconv = localeconv();
524 : #endif
525 24 : s = php_gcvt(number, precision, LCONV_DECIMAL_POINT, (s_fmt == 'G')?'E':'e', &num_buf[1]);
526 24 : is_negative = 0;
527 24 : if (*s == '-') {
528 12 : is_negative = 1;
529 12 : s = &num_buf[1];
530 12 : } else if (always_sign) {
531 4 : num_buf[0] = '+';
532 4 : s = num_buf;
533 : }
534 :
535 24 : s_len = strlen(s);
536 : break;
537 : }
538 :
539 3736 : uni_s = zend_ascii_to_unicode(s, s_len + 1 ZEND_FILE_LINE_CC);
540 3736 : php_u_sprintf_appendstring(buffer, pos, size, uni_s, width, 0, padding,
541 : alignment, s_len, is_negative, 0, always_sign);
542 3736 : efree(uni_s);
543 : }
544 : /* }}} */
545 :
546 : /* php_sprintf_append2n() {{{ */
547 : inline static void
548 : php_sprintf_append2n(char **buffer, int *pos, int *size, long number,
549 : int width, char padding, int alignment, int n,
550 : char *chartable, int expprec)
551 0 : {
552 : char numbuf[NUM_BUF_SIZE];
553 : register unsigned long num;
554 0 : register unsigned int i = NUM_BUF_SIZE - 1;
555 0 : register int andbits = (1 << n) - 1;
556 :
557 : PRINTF_DEBUG(("sprintf: append2n(%x, %x, %x, %d, %d, '%c', %d, %d, %x)\n",
558 : *buffer, pos, size, number, width, padding, alignment, n,
559 : chartable));
560 : PRINTF_DEBUG(("sprintf: append2n 2^%d andbits=%x\n", n, andbits));
561 :
562 0 : num = (unsigned long) number;
563 0 : numbuf[i] = '\0';
564 :
565 : do {
566 0 : numbuf[--i] = chartable[(num & andbits)];
567 0 : num >>= n;
568 : }
569 0 : while (num > 0);
570 :
571 0 : php_sprintf_appendstring(buffer, pos, size, &numbuf[i], width, 0,
572 : padding, alignment, (NUM_BUF_SIZE - 1) - i,
573 : 0, expprec, 0);
574 0 : }
575 : /* }}} */
576 :
577 : /* php_u_sprintf_append2n() {{{ */
578 : inline static void
579 : php_u_sprintf_append2n(UChar **buffer, int *pos, int *size, long number,
580 : int width, UChar padding, int alignment, int n,
581 : UChar *chartable, int expprec)
582 5435 : {
583 : UChar numbuf[NUM_BUF_SIZE];
584 : register unsigned long num;
585 5435 : register unsigned int i = NUM_BUF_SIZE - 1;
586 5435 : register int andbits = (1 << n) - 1;
587 :
588 5435 : num = (unsigned long) number;
589 5435 : numbuf[i] = '\0';
590 :
591 : do {
592 21912 : numbuf[--i] = chartable[(num & andbits)];
593 21912 : num >>= n;
594 : }
595 21912 : while (num > 0);
596 :
597 5435 : php_u_sprintf_appendstring(buffer, pos, size, &numbuf[i], width, 0,
598 : padding, alignment, (NUM_BUF_SIZE - 1) - i,
599 : 0, expprec, 0);
600 5435 : }
601 : /* }}} */
602 :
603 : /* php_sprintf_getnumber() {{{ */
604 : inline static int
605 : php_sprintf_getnumber(char *buffer, int *pos)
606 0 : {
607 : char *endptr;
608 0 : register long num = strtol(&buffer[*pos], &endptr, 10);
609 0 : register int i = 0;
610 :
611 0 : if (endptr != NULL) {
612 0 : i = (endptr - &buffer[*pos]);
613 : }
614 : PRINTF_DEBUG(("sprintf_getnumber: number was %d bytes long\n", i));
615 0 : *pos += i;
616 :
617 0 : if (num >= INT_MAX || num < 0) {
618 0 : return -1;
619 : } else {
620 0 : return (int) num;
621 : }
622 : }
623 : /* }}} */
624 :
625 : /* php_u_sprintf_getnumber() {{{ */
626 : inline static long
627 : php_u_sprintf_getnumber(UChar *buffer, int *pos)
628 60579 : {
629 : UChar *endptr;
630 60579 : register long num = zend_u_strtol(&buffer[*pos], &endptr, 10);
631 60579 : register int i = 0;
632 :
633 60579 : if (endptr != NULL) {
634 60579 : i = (endptr - &buffer[*pos]);
635 : }
636 60579 : *pos += i;
637 60579 : return num;
638 : }
639 : /* }}} */
640 :
641 : /* {{{ php_formatted_print()
642 : * New sprintf implementation for PHP.
643 : *
644 : * Modifiers:
645 : *
646 : * " " pad integers with spaces
647 : * "-" left adjusted field
648 : * n field size
649 : * "."n precision (floats only)
650 : * "+" Always place a sign (+ or -) in front of a number
651 : *
652 : * Type specifiers:
653 : *
654 : * "%" literal "%", modifiers are ignored.
655 : * "b" integer argument is printed as binary
656 : * "c" integer argument is printed as a single character
657 : * "d" argument is an integer
658 : * "f" the argument is a float
659 : * "o" integer argument is printed as octal
660 : * "s" argument is a string
661 : * "x" integer argument is printed as lowercase hexadecimal
662 : * "X" integer argument is printed as uppercase hexadecimal
663 : *
664 : */
665 : static char * php_formatted_print(int ht, int *len, int use_array, int format_offset, int type TSRMLS_DC)
666 0 : {
667 : zval ***args, **z_format;
668 0 : int argc, size = 240, inpos = 0, outpos = 0, temppos;
669 : int alignment, currarg, adjusting, argnum, width, precision;
670 : char *format, *result, padding;
671 : int always_sign;
672 :
673 0 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "+", &args, &argc) == FAILURE) {
674 0 : return NULL;
675 : }
676 :
677 : /* verify the number of args */
678 0 : if ((use_array && argc != (2 + format_offset))
679 : || (!use_array && argc < (1 + format_offset))) {
680 0 : efree(args);
681 0 : WRONG_PARAM_COUNT_WITH_RETVAL(NULL);
682 : }
683 :
684 0 : if (use_array) {
685 0 : int i = 1;
686 : zval ***newargs;
687 : zval **array;
688 :
689 0 : z_format = args[format_offset];
690 0 : array = args[1 + format_offset];
691 :
692 0 : SEPARATE_ZVAL(array);
693 0 : convert_to_array_ex(array);
694 :
695 0 : argc = 1 + zend_hash_num_elements(Z_ARRVAL_PP(array));
696 0 : newargs = (zval ***)safe_emalloc(argc, sizeof(zval *), 0);
697 0 : newargs[0] = z_format;
698 :
699 0 : for (zend_hash_internal_pointer_reset(Z_ARRVAL_PP(array));
700 0 : zend_hash_get_current_data(Z_ARRVAL_PP(array), (void **)&newargs[i++]) == SUCCESS;
701 0 : zend_hash_move_forward(Z_ARRVAL_PP(array)));
702 :
703 0 : efree(args);
704 0 : args = newargs;
705 0 : format_offset = 0;
706 : }
707 :
708 0 : convert_to_string_ex(args[format_offset]);
709 0 : format = Z_STRVAL_PP(args[format_offset]);
710 0 : result = emalloc(size);
711 :
712 0 : currarg = 1;
713 :
714 0 : while (inpos<Z_STRLEN_PP(args[format_offset])) {
715 0 : int expprec = 0, multiuse = 0;
716 : zval *tmp;
717 :
718 : PRINTF_DEBUG(("sprintf: format[%d]='%c'\n", inpos, format[inpos]));
719 : PRINTF_DEBUG(("sprintf: outpos=%d\n", outpos));
720 0 : if (format[inpos] != '%') {
721 0 : php_sprintf_appendchar(&result, &outpos, &size, format[inpos++] TSRMLS_CC);
722 0 : } else if (format[inpos + 1] == '%') {
723 0 : php_sprintf_appendchar(&result, &outpos, &size, '%' TSRMLS_CC);
724 0 : inpos += 2;
725 : } else {
726 : /* starting a new format specifier, reset variables */
727 0 : alignment = ALIGN_RIGHT;
728 0 : adjusting = 0;
729 0 : padding = ' ';
730 0 : always_sign = 0;
731 0 : inpos++; /* skip the '%' */
732 :
733 : PRINTF_DEBUG(("sprintf: first looking at '%c', inpos=%d\n",
734 : format[inpos], inpos));
735 0 : if (isascii((int)format[inpos]) && !isalpha((int)format[inpos])) {
736 : /* first look for argnum */
737 0 : temppos = inpos;
738 0 : while (isdigit((int)format[temppos])) temppos++;
739 0 : if (format[temppos] == '$') {
740 0 : argnum = php_sprintf_getnumber(format, &inpos);
741 :
742 0 : if (argnum <= 0) {
743 0 : efree(result);
744 0 : efree(args);
745 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Argument number must be greater than zero");
746 0 : return NULL;
747 : }
748 :
749 0 : multiuse = 1;
750 0 : inpos++; /* skip the '$' */
751 : } else {
752 0 : argnum = currarg++;
753 : }
754 :
755 0 : argnum += format_offset;
756 :
757 : /* after argnum comes modifiers */
758 : PRINTF_DEBUG(("sprintf: looking for modifiers\n"
759 : "sprintf: now looking at '%c', inpos=%d\n",
760 : format[inpos], inpos));
761 0 : for (;; inpos++) {
762 0 : if (format[inpos] == ' ' || format[inpos] == '0') {
763 0 : padding = format[inpos];
764 0 : } else if (format[inpos] == '-') {
765 0 : alignment = ALIGN_LEFT;
766 : /* space padding, the default */
767 0 : } else if (format[inpos] == '+') {
768 0 : always_sign = 1;
769 0 : } else if (format[inpos] == '\'') {
770 0 : padding = format[++inpos];
771 : } else {
772 : PRINTF_DEBUG(("sprintf: end of modifiers\n"));
773 0 : break;
774 : }
775 0 : }
776 : PRINTF_DEBUG(("sprintf: padding='%c'\n", padding));
777 : PRINTF_DEBUG(("sprintf: alignment=%s\n",
778 : (alignment == ALIGN_LEFT) ? "left" : "right"));
779 :
780 :
781 : /* after modifiers comes width */
782 0 : if (isdigit((int)format[inpos])) {
783 : PRINTF_DEBUG(("sprintf: getting width\n"));
784 0 : if ((width = php_sprintf_getnumber(format, &inpos)) < 0) {
785 0 : efree(result);
786 0 : efree(args);
787 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Width must be greater than zero and less than %d", INT_MAX);
788 0 : return NULL;
789 : }
790 0 : adjusting |= ADJ_WIDTH;
791 : } else {
792 0 : width = 0;
793 : }
794 : PRINTF_DEBUG(("sprintf: width=%d\n", width));
795 :
796 : /* after width and argnum comes precision */
797 0 : if (format[inpos] == '.') {
798 0 : inpos++;
799 : PRINTF_DEBUG(("sprintf: getting precision\n"));
800 0 : if (isdigit((int)format[inpos])) {
801 0 : if ((precision = php_sprintf_getnumber(format, &inpos)) < 0) {
802 0 : efree(result);
803 0 : efree(args);
804 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Precision must be greater than zero and less than %d", INT_MAX);
805 0 : return NULL;
806 : }
807 0 : adjusting |= ADJ_PRECISION;
808 0 : expprec = 1;
809 : } else {
810 0 : precision = 0;
811 : }
812 : } else {
813 0 : precision = 0;
814 : }
815 : PRINTF_DEBUG(("sprintf: precision=%d\n", precision));
816 : } else {
817 0 : width = precision = 0;
818 0 : argnum = currarg++ + format_offset;
819 : }
820 :
821 0 : if (argnum >= argc) {
822 0 : efree(result);
823 0 : efree(args);
824 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Too few arguments");
825 0 : return NULL;
826 : }
827 :
828 0 : if (format[inpos] == 'l') {
829 0 : inpos++;
830 : }
831 : PRINTF_DEBUG(("sprintf: format character='%c'\n", format[inpos]));
832 : /* now we expect to find a type specifier */
833 0 : if (multiuse) {
834 0 : MAKE_STD_ZVAL(tmp);
835 0 : *tmp = **(args[argnum]);
836 0 : INIT_PZVAL(tmp);
837 0 : zval_copy_ctor(tmp);
838 : } else {
839 0 : SEPARATE_ZVAL(args[argnum]);
840 0 : tmp = *(args[argnum]);
841 : }
842 :
843 0 : switch (format[inpos]) {
844 : case 's': {
845 : zval *var, var_copy;
846 0 : int use_copy = 0;
847 :
848 0 : if (Z_TYPE_P(tmp) != IS_UNICODE) {
849 0 : zend_make_string_zval(tmp, &var_copy, &use_copy);
850 : } else {
851 0 : var_copy = *tmp;
852 0 : zval_copy_ctor(&var_copy);
853 0 : INIT_PZVAL(&var_copy);
854 0 : use_copy = 1;
855 :
856 0 : switch (type) {
857 : case PHP_OUTPUT:
858 0 : convert_to_string_with_converter(&var_copy, ZEND_U_CONVERTER(UG(output_encoding_conv)));
859 0 : break;
860 : case PHP_RUNTIME:
861 : default:
862 0 : convert_to_string_with_converter(&var_copy, ZEND_U_CONVERTER(UG(runtime_encoding_conv)));
863 : break;
864 : }
865 : }
866 0 : if (use_copy) {
867 0 : var = &var_copy;
868 : } else {
869 0 : var = tmp;
870 : }
871 0 : php_sprintf_appendstring(&result, &outpos, &size,
872 : Z_STRVAL_P(var),
873 : width, precision, padding,
874 : alignment,
875 : Z_STRLEN_P(var),
876 : 0, expprec, 0);
877 0 : if (use_copy) {
878 0 : zval_dtor(&var_copy);
879 : }
880 0 : break;
881 : }
882 :
883 : case 'd':
884 0 : convert_to_long(tmp);
885 0 : php_sprintf_appendint(&result, &outpos, &size,
886 : Z_LVAL_P(tmp),
887 : width, padding, alignment,
888 : always_sign);
889 0 : break;
890 :
891 : case 'u':
892 0 : convert_to_long(tmp);
893 0 : php_sprintf_appenduint(&result, &outpos, &size,
894 : Z_LVAL_P(tmp),
895 : width, padding, alignment);
896 0 : break;
897 :
898 : case 'g':
899 : case 'G':
900 : case 'e':
901 : case 'E':
902 : case 'f':
903 : case 'F':
904 0 : convert_to_double(tmp);
905 0 : php_sprintf_appenddouble(&result, &outpos, &size,
906 : Z_DVAL_P(tmp),
907 : width, padding, alignment,
908 : precision, adjusting,
909 : format[inpos], always_sign
910 : TSRMLS_CC);
911 0 : break;
912 :
913 : case 'c':
914 0 : convert_to_long(tmp);
915 0 : php_sprintf_appendchar(&result, &outpos, &size,
916 : (char) Z_LVAL_P(tmp) TSRMLS_CC);
917 0 : break;
918 :
919 : case 'o':
920 0 : convert_to_long(tmp);
921 0 : php_sprintf_append2n(&result, &outpos, &size,
922 : Z_LVAL_P(tmp),
923 : width, padding, alignment, 3,
924 : hexchars, expprec);
925 0 : break;
926 :
927 : case 'x':
928 0 : convert_to_long(tmp);
929 0 : php_sprintf_append2n(&result, &outpos, &size,
930 : Z_LVAL_P(tmp),
931 : width, padding, alignment, 4,
932 : hexchars, expprec);
933 0 : break;
934 :
935 : case 'X':
936 0 : convert_to_long(tmp);
937 0 : php_sprintf_append2n(&result, &outpos, &size,
938 : Z_LVAL_P(tmp),
939 : width, padding, alignment, 4,
940 : HEXCHARS, expprec);
941 0 : break;
942 :
943 : case 'b':
944 0 : convert_to_long(tmp);
945 0 : php_sprintf_append2n(&result, &outpos, &size,
946 : Z_LVAL_P(tmp),
947 : width, padding, alignment, 1,
948 : hexchars, expprec);
949 0 : break;
950 :
951 : case '%':
952 0 : php_sprintf_appendchar(&result, &outpos, &size, '%' TSRMLS_CC);
953 :
954 : break;
955 : default:
956 : break;
957 : }
958 0 : if (multiuse) {
959 0 : zval_ptr_dtor(&tmp);
960 : }
961 0 : inpos++;
962 : }
963 : }
964 :
965 0 : efree(args);
966 :
967 : /* possibly, we have to make sure we have room for the terminating null? */
968 0 : result[outpos]=0;
969 0 : *len = outpos;
970 0 : return result;
971 : }
972 : /* }}} */
973 :
974 : /* php_u_formatted_print() {{{ */
975 : static zstr php_u_formatted_print(int ht, int *len, int use_array, int format_offset, int type TSRMLS_DC)
976 85617 : {
977 : zval ***args, **z_format;
978 85617 : int argc, size = 240, inpos = 0, outpos = 0, temppos;
979 : int alignment, width, precision, currarg, adjusting, argnum;
980 : UChar *format, *result, padding;
981 : int always_sign;
982 : zstr result_str;
983 :
984 85617 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "+", &args, &argc) == FAILURE) {
985 5 : return NULL_ZSTR;
986 : }
987 :
988 : /* verify the number of args */
989 85612 : if ((use_array && argc != (2 + format_offset))
990 : || (!use_array && argc < (1 + format_offset))) {
991 4 : efree(args);
992 4 : WRONG_PARAM_COUNT_WITH_RETVAL(NULL_ZSTR);
993 : }
994 :
995 85608 : if (use_array) {
996 589 : int i = 1;
997 : zval ***newargs;
998 : zval **array;
999 :
1000 589 : z_format = args[format_offset];
1001 589 : array = args[1 + format_offset];
1002 :
1003 589 : SEPARATE_ZVAL(array);
1004 589 : convert_to_array_ex(array);
1005 :
1006 589 : argc = 1 + zend_hash_num_elements(Z_ARRVAL_PP(array));
1007 589 : newargs = (zval ***)safe_emalloc(argc, sizeof(zval *), 0);
1008 589 : newargs[0] = z_format;
1009 :
1010 589 : for (zend_hash_internal_pointer_reset(Z_ARRVAL_PP(array));
1011 4382 : zend_hash_get_current_data(Z_ARRVAL_PP(array), (void **)&newargs[i++]) == SUCCESS;
1012 3204 : zend_hash_move_forward(Z_ARRVAL_PP(array)));
1013 :
1014 589 : efree(args);
1015 589 : args = newargs;
1016 589 : format_offset = 0;
1017 : }
1018 :
1019 85608 : convert_to_unicode_ex(args[format_offset]);
1020 85608 : format = Z_USTRVAL_PP(args[format_offset]);
1021 85608 : result = eumalloc(size);
1022 :
1023 85608 : currarg = 1;
1024 :
1025 1140413 : while (inpos<Z_USTRLEN_PP(args[format_offset])) {
1026 969227 : int expprec = 0, multiuse = 0;
1027 : zval *tmp;
1028 :
1029 969227 : if (format[inpos] != 0x25 /* '%' */) {
1030 856079 : php_u_sprintf_appendchar(&result, &outpos, &size, format[inpos++] TSRMLS_CC);
1031 113148 : } else if (format[inpos + 1] == 0x25 /* '%' */) {
1032 46 : php_u_sprintf_appendchar(&result, &outpos, &size, 0x25 /* '%' */ TSRMLS_CC);
1033 46 : inpos += 2;
1034 : } else {
1035 : /* starting a new format specifier, reset variables */
1036 113102 : alignment = ALIGN_RIGHT;
1037 113102 : adjusting = 0;
1038 113102 : padding = 0x20 /* ' ' */;
1039 113102 : always_sign = 0;
1040 113102 : inpos++; /* skip the '%' */
1041 :
1042 174941 : if ((format[inpos] < 0x7f) && !u_isalpha(format[inpos])) {
1043 : /* first look for argnum */
1044 61840 : temppos = inpos;
1045 61840 : while (format[temppos] >= 0x30 /* '0' */ && format[temppos] <= 0x39 /* '9' */) temppos++;
1046 61840 : if (format[temppos] == 0x24 /* '$' */) {
1047 545 : argnum = php_u_sprintf_getnumber(format, &inpos);
1048 :
1049 545 : if (argnum == 0) {
1050 1 : efree(result);
1051 1 : efree(args);
1052 1 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Zero is not a valid argument number");
1053 1 : return NULL_ZSTR;
1054 : }
1055 :
1056 544 : multiuse = 1;
1057 544 : inpos++; /* skip the '$' */
1058 : } else {
1059 61295 : argnum = currarg++;
1060 : }
1061 :
1062 61839 : argnum += format_offset;
1063 :
1064 : /* after argnum comes modifiers */
1065 57099 : for (;; inpos++) {
1066 173892 : if (u_isspace(format[inpos]) || format[inpos] == 0x30 /* '0' */) {
1067 54954 : padding = format[inpos];
1068 63984 : } else if (format[inpos] == 0x2D /* '-' */) {
1069 1409 : alignment = ALIGN_LEFT;
1070 : /* space padding, the default */
1071 62575 : } else if (format[inpos] == 0x2B /* '+' */) {
1072 179 : always_sign = 1;
1073 62396 : } else if (format[inpos] == 0x27 /* '\'' */) {
1074 557 : padding = format[++inpos];
1075 : } else {
1076 61839 : break;
1077 : }
1078 57099 : }
1079 :
1080 : /* after modifiers comes width */
1081 61839 : if (isdigit((int)format[inpos])) {
1082 59328 : width = php_u_sprintf_getnumber(format, &inpos);
1083 59328 : adjusting |= ADJ_WIDTH;
1084 : } else {
1085 2511 : width = 0;
1086 : }
1087 :
1088 : /* after width and argnum comes precision */
1089 61839 : if (format[inpos] == 0x2E /* '.' */) {
1090 708 : inpos++;
1091 1414 : if (format[inpos] >= 0x30 /* '0' */ && format[inpos] <= 0x39 /* '9' */) {
1092 706 : precision = php_u_sprintf_getnumber(format, &inpos);
1093 706 : adjusting |= ADJ_PRECISION;
1094 706 : expprec = 1;
1095 : } else {
1096 2 : precision = 0;
1097 : }
1098 : } else {
1099 61131 : precision = 0;
1100 : }
1101 : } else {
1102 51262 : width = precision = 0;
1103 51262 : argnum = currarg++ + format_offset;
1104 : }
1105 :
1106 113101 : if (argnum >= argc) {
1107 29 : efree(result);
1108 29 : efree(args);
1109 29 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Too few arguments");
1110 29 : return NULL_ZSTR;
1111 : }
1112 :
1113 113072 : if (format[inpos] == 0x6C /* 'l' */) {
1114 713 : inpos++;
1115 : }
1116 : /* now we expect to find a type specifier */
1117 113072 : if (multiuse) {
1118 544 : MAKE_STD_ZVAL(tmp);
1119 544 : *tmp = **(args[argnum]);
1120 544 : INIT_PZVAL(tmp);
1121 544 : zval_copy_ctor(tmp);
1122 : } else {
1123 112528 : SEPARATE_ZVAL(args[argnum]);
1124 112528 : tmp = *(args[argnum]);
1125 : }
1126 :
1127 113072 : switch (format[inpos]) {
1128 : case 0x73 /* 's' */: {
1129 : zval *var, var_copy;
1130 : int use_copy;
1131 :
1132 23366 : zend_make_unicode_zval(tmp, &var_copy, &use_copy);
1133 23366 : if (use_copy) {
1134 7238 : var = &var_copy;
1135 : } else {
1136 16128 : var = tmp;
1137 : }
1138 23366 : php_u_sprintf_appendstring(&result, &outpos, &size,
1139 : Z_USTRVAL_P(var),
1140 : width, precision, padding,
1141 : alignment,
1142 : Z_USTRLEN_P(var),
1143 : 0, expprec, 0);
1144 23366 : if (use_copy) {
1145 7238 : zval_dtor(&var_copy);
1146 : }
1147 23366 : break;
1148 : }
1149 :
1150 : case 0x64 /* 'd' */:
1151 76152 : convert_to_long(tmp);
1152 76152 : php_u_sprintf_appendint(&result, &outpos, &size,
1153 : Z_LVAL_P(tmp),
1154 : width, padding, alignment,
1155 : always_sign);
1156 76152 : break;
1157 :
1158 : case 0x75 /* 'u' */:
1159 927 : convert_to_long(tmp);
1160 927 : php_u_sprintf_appenduint(&result, &outpos, &size,
1161 : Z_LVAL_P(tmp),
1162 : width, padding, alignment);
1163 927 : break;
1164 :
1165 : case 0x67 /* 'g' */:
1166 : case 0x47 /* 'G' */:
1167 : case 0x65 /* 'e' */:
1168 : case 0x45 /* 'E' */:
1169 : case 0x66 /* 'f' */:
1170 : case 0x46 /* 'F' */:
1171 3776 : convert_to_double(tmp);
1172 3776 : php_u_sprintf_appenddouble(&result, &outpos, &size,
1173 : Z_DVAL_P(tmp),
1174 : width, padding, alignment,
1175 : precision, adjusting,
1176 : format[inpos], always_sign
1177 : TSRMLS_CC);
1178 3776 : break;
1179 :
1180 : case 0x63 /* 'c' */:
1181 964 : convert_to_long(tmp);
1182 964 : php_u_sprintf_appendchar(&result, &outpos, &size,
1183 : (char) Z_LVAL_P(tmp) TSRMLS_CC);
1184 964 : break;
1185 :
1186 : case 0x6F /* 'o' */:
1187 4058 : convert_to_long(tmp);
1188 4058 : php_u_sprintf_append2n(&result, &outpos, &size,
1189 : Z_LVAL_P(tmp),
1190 : width, padding, alignment, 3,
1191 : u_hexchars, expprec);
1192 4058 : break;
1193 :
1194 : case 0x78 /* 'x' */:
1195 997 : convert_to_long(tmp);
1196 997 : php_u_sprintf_append2n(&result, &outpos, &size,
1197 : Z_LVAL_P(tmp),
1198 : width, padding, alignment, 4,
1199 : u_hexchars, expprec);
1200 997 : break;
1201 :
1202 : case 0x58 /* 'X' */:
1203 316 : convert_to_long(tmp);
1204 316 : php_u_sprintf_append2n(&result, &outpos, &size,
1205 : Z_LVAL_P(tmp),
1206 : width, padding, alignment, 4,
1207 : u_HEXCHARS, expprec);
1208 316 : break;
1209 :
1210 : case 0x62 /* 'b' */:
1211 64 : convert_to_long(tmp);
1212 64 : php_u_sprintf_append2n(&result, &outpos, &size,
1213 : Z_LVAL_P(tmp),
1214 : width, padding, alignment, 1,
1215 : u_hexchars, expprec);
1216 64 : break;
1217 :
1218 : case 0x25 /* '%' */:
1219 12 : php_u_sprintf_appendchar(&result, &outpos, &size, 0x25 /* '%' */ TSRMLS_CC);
1220 :
1221 : break;
1222 : default:
1223 : break;
1224 : }
1225 113072 : if (multiuse) {
1226 544 : zval_ptr_dtor(&tmp);
1227 : }
1228 113072 : inpos++;
1229 : }
1230 : }
1231 :
1232 85578 : efree(args);
1233 :
1234 : /* possibly, we have to make sure we have room for the terminating null? */
1235 85578 : result[outpos] = 0;
1236 85578 : *len = outpos;
1237 85578 : result_str.u = result;
1238 :
1239 85578 : switch (type) {
1240 : case PHP_OUTPUT:
1241 : {
1242 9247 : UErrorCode status = U_ZERO_ERROR;
1243 : char *s;
1244 : int s_len;
1245 :
1246 9247 : zend_unicode_to_string_ex(ZEND_U_CONVERTER(UG(output_encoding_conv)), &s, &s_len, result, outpos, &status);
1247 9247 : if(U_FAILURE(status)) {
1248 0 : efree(s);
1249 0 : efree(result);
1250 0 : return NULL_ZSTR;
1251 : }
1252 :
1253 9247 : efree(result_str.v);
1254 9247 : result_str.s = s;
1255 9247 : *len = s_len;
1256 : break;
1257 : }
1258 : case PHP_RUNTIME:
1259 : default:
1260 : /* nothing to be done */
1261 : break;
1262 : }
1263 :
1264 85578 : return result_str;
1265 : }
1266 : /* }}} */
1267 :
1268 : /* {{{ proto string sprintf(string format [, mixed arg1 [, mixed ...]]) U
1269 : Return a formatted string */
1270 : PHP_FUNCTION(user_sprintf)
1271 74186 : {
1272 : int len;
1273 : zstr result;
1274 :
1275 74186 : result = php_u_formatted_print(ht, &len, 0, 0, PHP_RUNTIME TSRMLS_CC);
1276 74186 : if (result.v == NULL) {
1277 7 : RETURN_FALSE;
1278 : }
1279 74179 : RETVAL_UNICODEL(result.u, len, 0);
1280 : }
1281 : /* }}} */
1282 :
1283 : /* {{{ proto string vsprintf(string format, array args) U
1284 : Return a formatted string */
1285 : PHP_FUNCTION(vsprintf)
1286 204 : {
1287 : int len;
1288 : zstr result;
1289 :
1290 204 : result = php_u_formatted_print(ht, &len, 1, 0, PHP_RUNTIME TSRMLS_CC);
1291 204 : if (result.v == NULL) {
1292 8 : RETURN_FALSE;
1293 : }
1294 196 : RETVAL_UNICODEL(result.u, len, 0);
1295 : }
1296 : /* }}} */
1297 :
1298 : /* {{{ proto int printf(string format [, mixed arg1 [, mixed ...]]) U
1299 : Output a formatted string */
1300 : PHP_FUNCTION(user_printf)
1301 9076 : {
1302 : int len, rlen;
1303 : zstr result;
1304 :
1305 9076 : result = php_u_formatted_print(ht, &len, 0, 0, PHP_OUTPUT TSRMLS_CC);
1306 9076 : if (result.v == NULL) {
1307 9 : RETURN_FALSE;
1308 : }
1309 :
1310 9067 : rlen = PHPWRITE(result.s, len);
1311 9067 : efree(result.v);
1312 9067 : RETURN_LONG(rlen);
1313 : }
1314 : /* }}} */
1315 :
1316 : /* {{{ proto int vprintf(string format, array args) U
1317 : Output a formatted string */
1318 : PHP_FUNCTION(vprintf)
1319 188 : {
1320 : int len, rlen;
1321 : zstr result;
1322 :
1323 188 : result = php_u_formatted_print(ht, &len, 1, 0, PHP_OUTPUT TSRMLS_CC);
1324 188 : if (result.v == NULL) {
1325 8 : RETURN_FALSE;
1326 : }
1327 :
1328 180 : rlen = PHPWRITE(result.s, len);
1329 180 : efree(result.v);
1330 180 : RETURN_LONG(rlen);
1331 : }
1332 : /* }}} */
1333 :
1334 : /* {{{ proto int fprintf(resource stream, string format [, mixed arg1 [, mixed ...]]) U
1335 : Output a formatted string into a stream */
1336 : PHP_FUNCTION(fprintf)
1337 1763 : {
1338 : php_stream *stream;
1339 : zval *arg1, **arg2;
1340 : zstr result;
1341 : int len, ret;
1342 :
1343 1763 : if (ZEND_NUM_ARGS() < 2) {
1344 3 : WRONG_PARAM_COUNT;
1345 : }
1346 :
1347 1760 : if (zend_parse_parameters(2 TSRMLS_CC, "rZ", &arg1, &arg2) == FAILURE) {
1348 0 : RETURN_FALSE;
1349 : }
1350 :
1351 1760 : php_stream_from_zval(stream, &arg1);
1352 :
1353 1760 : if (Z_TYPE_PP(arg2) != IS_STRING && Z_TYPE_PP(arg2) != IS_UNICODE) {
1354 436 : convert_to_unicode_ex(arg2);
1355 : }
1356 :
1357 1760 : if (Z_TYPE_PP(arg2) == IS_STRING) {
1358 0 : if ((result.s = php_formatted_print(ht, &len, 0, 1, PHP_RUNTIME TSRMLS_CC))==NULL) {
1359 0 : RETURN_FALSE;
1360 : }
1361 0 : ret = php_stream_write(stream, result.s, len);
1362 : } else {
1363 1760 : result = php_u_formatted_print(ht, &len, 0, 1, PHP_RUNTIME TSRMLS_CC);
1364 1760 : if (result.v == NULL) {
1365 1 : RETURN_FALSE;
1366 : }
1367 1759 : ret = php_stream_write_unicode(stream, result.u, len);
1368 : }
1369 :
1370 1759 : efree(result.v);
1371 :
1372 1759 : RETURN_LONG(ret);
1373 : }
1374 : /* }}} */
1375 :
1376 : /* {{{ proto int vfprintf(resource stream, string format, array args) U
1377 : Output a formatted string into a stream */
1378 : PHP_FUNCTION(vfprintf)
1379 211 : {
1380 : php_stream *stream;
1381 : zval *arg1, **arg2;
1382 : zstr result;
1383 : int len, ret;
1384 :
1385 211 : if (ZEND_NUM_ARGS() != 3) {
1386 5 : WRONG_PARAM_COUNT;
1387 : }
1388 :
1389 206 : if (zend_parse_parameters(2 TSRMLS_CC, "rZ", &arg1, &arg2) == FAILURE) {
1390 3 : RETURN_FALSE;
1391 : }
1392 :
1393 203 : php_stream_from_zval(stream, &arg1);
1394 :
1395 203 : if (Z_TYPE_PP(arg2) != IS_STRING && Z_TYPE_PP(arg2) != IS_UNICODE) {
1396 25 : convert_to_unicode_ex(arg2);
1397 : }
1398 :
1399 203 : if (Z_TYPE_PP(arg2) == IS_STRING) {
1400 0 : if ((result.s = php_formatted_print(ht, &len, 1, 1, PHP_RUNTIME TSRMLS_CC))==NULL) {
1401 0 : RETURN_FALSE;
1402 : }
1403 0 : ret = php_stream_write(stream, result.s, len);
1404 : } else {
1405 203 : result = php_u_formatted_print(ht, &len, 1, 1, PHP_RUNTIME TSRMLS_CC);
1406 203 : if (result.v == NULL) {
1407 6 : RETURN_FALSE;
1408 : }
1409 197 : ret = php_stream_write_unicode(stream, result.u, len);
1410 : }
1411 :
1412 197 : efree(result.v);
1413 :
1414 197 : RETURN_LONG(ret);
1415 : }
1416 : /* }}} */
1417 :
1418 :
1419 : /*
1420 : * Local variables:
1421 : * tab-width: 4
1422 : * c-basic-offset: 4
1423 : * End:
1424 : * vim600: sw=4 ts=4 fdm=marker
1425 : * vim<600: sw=4 ts=4
1426 : */
|