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: Marcus Boerger <helly@php.net> |
16 : +----------------------------------------------------------------------+
17 : */
18 :
19 : /* $Id: spprintf.c 278043 2009-03-30 19:59:08Z iliaa $ */
20 :
21 : /* This is the spprintf implementation.
22 : * It has emerged from apache snprintf. See original header:
23 : */
24 :
25 : /* ====================================================================
26 : * Copyright (c) 1995-1998 The Apache Group. All rights reserved.
27 : *
28 : * Redistribution and use in source and binary forms, with or without
29 : * modification, are permitted provided that the following conditions
30 : * are met:
31 : *
32 : * 1. Redistributions of source code must retain the above copyright
33 : * notice, this list of conditions and the following disclaimer.
34 : *
35 : * 2. Redistributions in binary form must reproduce the above copyright
36 : * notice, this list of conditions and the following disclaimer in
37 : * the documentation and/or other materials provided with the
38 : * distribution.
39 : *
40 : * 3. All advertising materials mentioning features or use of this
41 : * software must display the following acknowledgment:
42 : * "This product includes software developed by the Apache Group
43 : * for use in the Apache HTTP server project (http://www.apache.org/)."
44 : *
45 : * 4. The names "Apache Server" and "Apache Group" must not be used to
46 : * endorse or promote products derived from this software without
47 : * prior written permission.
48 : *
49 : * 5. Redistributions of any form whatsoever must retain the following
50 : * acknowledgment:
51 : * "This product includes software developed by the Apache Group
52 : * for use in the Apache HTTP server project (http://www.apache.org/)."
53 : *
54 : * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY
55 : * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
56 : * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
57 : * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR
58 : * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
59 : * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
60 : * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
61 : * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
62 : * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
63 : * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
64 : * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
65 : * OF THE POSSIBILITY OF SUCH DAMAGE.
66 : * ====================================================================
67 : *
68 : * This software consists of voluntary contributions made by many
69 : * individuals on behalf of the Apache Group and was originally based
70 : * on public domain software written at the National Center for
71 : * Supercomputing Applications, University of Illinois, Urbana-Champaign.
72 : * For more information on the Apache Group and the Apache HTTP server
73 : * project, please see <http://www.apache.org/>.
74 : *
75 : * This code is based on, and used with the permission of, the
76 : * SIO stdio-replacement strx_* functions by Panos Tsirigotis
77 : * <panos@alumni.cs.colorado.edu> for xinetd.
78 : */
79 : #define _GNU_SOURCE
80 : #include "php.h"
81 :
82 : #include <stddef.h>
83 : #include <stdio.h>
84 : #include <ctype.h>
85 : #include <sys/types.h>
86 : #include <stdarg.h>
87 : #include <string.h>
88 : #include <stdlib.h>
89 : #include <math.h>
90 : #ifdef HAVE_INTTYPES_H
91 : #include <inttypes.h>
92 : #endif
93 :
94 : #ifdef HAVE_LOCALE_H
95 : #include <locale.h>
96 : #define LCONV_DECIMAL_POINT (*lconv->decimal_point)
97 : #else
98 : #define LCONV_DECIMAL_POINT '.'
99 : #endif
100 :
101 : #include "snprintf.h"
102 :
103 : #define FALSE 0
104 : #define TRUE 1
105 : #define NUL '\0'
106 : #define INT_NULL ((int *)0)
107 :
108 : #define S_NULL "(null)"
109 : #define S_NULL_LEN 6
110 :
111 : #define FLOAT_DIGITS 6
112 : #define EXPONENT_LENGTH 10
113 :
114 : #include "ext/standard/php_smart_str.h"
115 :
116 : /* {{{ macros */
117 :
118 : /*
119 : * NUM_BUF_SIZE is the size of the buffer used for arithmetic conversions
120 : *
121 : * XXX: this is a magic number; do not decrease it
122 : */
123 : #define NUM_BUF_SIZE 512
124 :
125 : /*
126 : * The INS_CHAR macro inserts a character in the buffer.
127 : *
128 : * NOTE: Evaluation of the ch argument should not have any side-effects
129 : */
130 : #define INS_CHAR_NR(xbuf, ch) do { \
131 : smart_str_appendc(xbuf, ch); \
132 : } while (0)
133 :
134 : #define INS_STRING(xbuf, s, slen) do { \
135 : smart_str_appendl(xbuf, s, slen); \
136 : } while (0)
137 :
138 : #define INS_CHAR(xbuf, ch) \
139 : INS_CHAR_NR(xbuf, ch)
140 :
141 : /*
142 : * Macro that does padding. The padding is done by printing
143 : * the character ch.
144 : */
145 : #define PAD(xbuf, count, ch) do { \
146 : if ((count) > 0) { \
147 : size_t newlen; \
148 : smart_str_alloc(xbuf, (count), 0); \
149 : memset(xbuf->c + xbuf->len, ch, (count)); \
150 : xbuf->len += (count); \
151 : } \
152 : } while (0)
153 :
154 : #define NUM(c) (c - '0')
155 :
156 : #define STR_TO_DEC(str, num) do { \
157 : num = NUM(*str++); \
158 : while (isdigit((int)*str)) { \
159 : num *= 10; \
160 : num += NUM(*str++); \
161 : if (num >= INT_MAX / 10) { \
162 : while (isdigit((int)*str++)); \
163 : break; \
164 : } \
165 : } \
166 : } while (0)
167 :
168 : /*
169 : * This macro does zero padding so that the precision
170 : * requirement is satisfied. The padding is done by
171 : * adding '0's to the left of the string that is going
172 : * to be printed.
173 : */
174 : #define FIX_PRECISION(adjust, precision, s, s_len) do { \
175 : if (adjust) \
176 : while (s_len < precision) { \
177 : *--s = '0'; \
178 : s_len++; \
179 : } \
180 : } while (0)
181 :
182 : /* }}} */
183 :
184 : #if !HAVE_STRNLEN
185 : static size_t strnlen(const char *s, size_t maxlen) {
186 : char *r = memchr(s, '\0', maxlen);
187 : return r ? r-s : maxlen;
188 : }
189 : #endif
190 :
191 : /*
192 : * Do format conversion placing the output in buffer
193 : */
194 : static void xbuf_format_converter(smart_str *xbuf, const char *fmt, va_list ap) /* {{{ */
195 5999551 : {
196 5999551 : register char *s = NULL;
197 : char *q;
198 : int s_len;
199 :
200 5999551 : register int min_width = 0;
201 5999551 : int precision = 0;
202 : enum {
203 : LEFT, RIGHT
204 : } adjust;
205 : char pad_char;
206 : char prefix_char;
207 :
208 : double fp_num;
209 5999551 : wide_int i_num = (wide_int) 0;
210 : u_wide_int ui_num;
211 :
212 : char num_buf[NUM_BUF_SIZE];
213 : char char_buf[2]; /* for printing %% and %<unknown> */
214 :
215 : #ifdef HAVE_LOCALE_H
216 5999551 : struct lconv *lconv = NULL;
217 : #endif
218 :
219 : /*
220 : * Flag variables
221 : */
222 : length_modifier_e modifier;
223 : boolean_e alternate_form;
224 : boolean_e print_sign;
225 : boolean_e print_blank;
226 : boolean_e adjust_precision;
227 : boolean_e adjust_width;
228 : bool_int is_negative;
229 :
230 87964567 : while (*fmt) {
231 75965465 : if (*fmt != '%') {
232 60694908 : INS_CHAR(xbuf, *fmt);
233 : } else {
234 : /*
235 : * Default variable settings
236 : */
237 15270557 : adjust = RIGHT;
238 15270557 : alternate_form = print_sign = print_blank = NO;
239 15270557 : pad_char = ' ';
240 15270557 : prefix_char = NUL;
241 :
242 15270557 : fmt++;
243 :
244 : /*
245 : * Try to avoid checking for flags, width or precision
246 : */
247 15444503 : if (isascii((int)*fmt) && !islower((int)*fmt)) {
248 : /*
249 : * Recognize flags: -, #, BLANK, +
250 : */
251 18570 : for (;; fmt++) {
252 192516 : if (*fmt == '-')
253 17 : adjust = LEFT;
254 192499 : else if (*fmt == '+')
255 0 : print_sign = YES;
256 192499 : else if (*fmt == '#')
257 0 : alternate_form = YES;
258 192499 : else if (*fmt == ' ')
259 0 : print_blank = YES;
260 192499 : else if (*fmt == '0')
261 18553 : pad_char = '0';
262 : else
263 173946 : break;
264 18570 : }
265 :
266 : /*
267 : * Check if a width was specified
268 : */
269 173946 : if (isdigit((int)*fmt)) {
270 18336 : STR_TO_DEC(fmt, min_width);
271 18336 : adjust_width = YES;
272 155610 : } else if (*fmt == '*') {
273 130584 : min_width = va_arg(ap, int);
274 130584 : fmt++;
275 130584 : adjust_width = YES;
276 130584 : if (min_width < 0) {
277 0 : adjust = LEFT;
278 0 : min_width = -min_width;
279 : }
280 : } else
281 25026 : adjust_width = NO;
282 :
283 : /*
284 : * Check if a precision was specified
285 : *
286 : * XXX: an unreasonable amount of precision may be specified
287 : * resulting in overflow of num_buf. Currently we
288 : * ignore this possibility.
289 : */
290 173946 : if (*fmt == '.') {
291 25024 : adjust_precision = YES;
292 25024 : fmt++;
293 25024 : if (isdigit((int)*fmt)) {
294 492 : STR_TO_DEC(fmt, precision);
295 24532 : } else if (*fmt == '*') {
296 24532 : precision = va_arg(ap, int);
297 24532 : fmt++;
298 24532 : if (precision < 0)
299 0 : precision = 0;
300 : } else
301 0 : precision = 0;
302 : } else
303 148922 : adjust_precision = NO;
304 : } else
305 15096611 : adjust_precision = adjust_width = NO;
306 :
307 : /*
308 : * Modifier check
309 : */
310 15270557 : switch (*fmt) {
311 : case 'L':
312 0 : fmt++;
313 0 : modifier = LM_LONG_DOUBLE;
314 0 : break;
315 : case 'I':
316 0 : fmt++;
317 : #if SIZEOF_LONG_LONG
318 0 : if (*fmt == '6' && *(fmt+1) == '4') {
319 0 : fmt += 2;
320 0 : modifier = LM_LONG_LONG;
321 : } else
322 : #endif
323 0 : if (*fmt == '3' && *(fmt+1) == '2') {
324 0 : fmt += 2;
325 0 : modifier = LM_LONG;
326 : } else {
327 : #ifdef _WIN64
328 : modifier = LM_LONG_LONG;
329 : #else
330 0 : modifier = LM_LONG;
331 : #endif
332 : }
333 0 : break;
334 : case 'l':
335 2115663 : fmt++;
336 : #if SIZEOF_LONG_LONG
337 2115663 : if (*fmt == 'l') {
338 1 : fmt++;
339 1 : modifier = LM_LONG_LONG;
340 : } else
341 : #endif
342 2115662 : modifier = LM_LONG;
343 2115663 : break;
344 : case 'z':
345 0 : fmt++;
346 0 : modifier = LM_SIZE_T;
347 0 : break;
348 : case 'j':
349 0 : fmt++;
350 : #if SIZEOF_INTMAX_T
351 0 : modifier = LM_INTMAX_T;
352 : #else
353 : modifier = LM_SIZE_T;
354 : #endif
355 0 : break;
356 : case 't':
357 0 : fmt++;
358 : #if SIZEOF_PTRDIFF_T
359 0 : modifier = LM_PTRDIFF_T;
360 : #else
361 : modifier = LM_SIZE_T;
362 : #endif
363 0 : break;
364 : case 'h':
365 0 : fmt++;
366 0 : if (*fmt == 'h') {
367 0 : fmt++;
368 : }
369 : /* these are promoted to int, so no break */
370 : default:
371 13154894 : modifier = LM_STD;
372 : break;
373 : }
374 :
375 : /*
376 : * Argument extraction and printing.
377 : * First we determine the argument type.
378 : * Then, we convert the argument to a string.
379 : * On exit from the switch, s points to the string that
380 : * must be printed, s_len has the length of the string
381 : * The precision requirements, if any, are reflected in s_len.
382 : *
383 : * NOTE: pad_char may be set to '0' because of the 0 flag.
384 : * It is reset to ' ' by non-numeric formats
385 : */
386 15270557 : switch (*fmt) {
387 : case 'u':
388 652 : switch(modifier) {
389 : default:
390 650 : i_num = (wide_int) va_arg(ap, unsigned int);
391 650 : break;
392 : case LM_LONG_DOUBLE:
393 0 : goto fmt_error;
394 : case LM_LONG:
395 1 : i_num = (wide_int) va_arg(ap, unsigned long int);
396 1 : break;
397 : case LM_SIZE_T:
398 0 : i_num = (wide_int) va_arg(ap, size_t);
399 0 : break;
400 : #if SIZEOF_LONG_LONG
401 : case LM_LONG_LONG:
402 1 : i_num = (wide_int) va_arg(ap, u_wide_int);
403 1 : break;
404 : #endif
405 : #if SIZEOF_INTMAX_T
406 : case LM_INTMAX_T:
407 0 : i_num = (wide_int) va_arg(ap, uintmax_t);
408 0 : break;
409 : #endif
410 : #if SIZEOF_PTRDIFF_T
411 : case LM_PTRDIFF_T:
412 0 : i_num = (wide_int) va_arg(ap, ptrdiff_t);
413 : break;
414 : #endif
415 : }
416 : /*
417 : * The rest also applies to other integer formats, so fall
418 : * into that case.
419 : */
420 : case 'd':
421 : case 'i':
422 : /*
423 : * Get the arg if we haven't already.
424 : */
425 4070091 : if ((*fmt) != 'u') {
426 4069439 : switch(modifier) {
427 : default:
428 1953778 : i_num = (wide_int) va_arg(ap, int);
429 1953778 : break;
430 : case LM_LONG_DOUBLE:
431 0 : goto fmt_error;
432 : case LM_LONG:
433 2115661 : i_num = (wide_int) va_arg(ap, long int);
434 2115661 : break;
435 : case LM_SIZE_T:
436 : #if SIZEOF_SSIZE_T
437 0 : i_num = (wide_int) va_arg(ap, ssize_t);
438 : #else
439 : i_num = (wide_int) va_arg(ap, size_t);
440 : #endif
441 0 : break;
442 : #if SIZEOF_LONG_LONG
443 : case LM_LONG_LONG:
444 0 : i_num = (wide_int) va_arg(ap, wide_int);
445 0 : break;
446 : #endif
447 : #if SIZEOF_INTMAX_T
448 : case LM_INTMAX_T:
449 0 : i_num = (wide_int) va_arg(ap, intmax_t);
450 0 : break;
451 : #endif
452 : #if SIZEOF_PTRDIFF_T
453 : case LM_PTRDIFF_T:
454 0 : i_num = (wide_int) va_arg(ap, ptrdiff_t);
455 : break;
456 : #endif
457 : }
458 : }
459 4070091 : s = ap_php_conv_10(i_num, (*fmt) == 'u', &is_negative,
460 : &num_buf[NUM_BUF_SIZE], &s_len);
461 4070091 : FIX_PRECISION(adjust_precision, precision, s, s_len);
462 :
463 4070091 : if (*fmt != 'u') {
464 4069439 : if (is_negative)
465 4483 : prefix_char = '-';
466 4064956 : else if (print_sign)
467 0 : prefix_char = '+';
468 4064956 : else if (print_blank)
469 0 : prefix_char = ' ';
470 : }
471 4070091 : break;
472 :
473 :
474 : case 'o':
475 2 : switch(modifier) {
476 : default:
477 2 : ui_num = (u_wide_int) va_arg(ap, unsigned int);
478 2 : break;
479 : case LM_LONG_DOUBLE:
480 0 : goto fmt_error;
481 : case LM_LONG:
482 0 : ui_num = (u_wide_int) va_arg(ap, unsigned long int);
483 0 : break;
484 : case LM_SIZE_T:
485 0 : ui_num = (u_wide_int) va_arg(ap, size_t);
486 0 : break;
487 : #if SIZEOF_LONG_LONG
488 : case LM_LONG_LONG:
489 0 : ui_num = (u_wide_int) va_arg(ap, u_wide_int);
490 0 : break;
491 : #endif
492 : #if SIZEOF_INTMAX_T
493 : case LM_INTMAX_T:
494 0 : ui_num = (u_wide_int) va_arg(ap, uintmax_t);
495 0 : break;
496 : #endif
497 : #if SIZEOF_PTRDIFF_T
498 : case LM_PTRDIFF_T:
499 0 : ui_num = (u_wide_int) va_arg(ap, ptrdiff_t);
500 : break;
501 : #endif
502 : }
503 2 : s = ap_php_conv_p2(ui_num, 3, *fmt,
504 : &num_buf[NUM_BUF_SIZE], &s_len);
505 2 : FIX_PRECISION(adjust_precision, precision, s, s_len);
506 2 : if (alternate_form && *s != '0') {
507 0 : *--s = '0';
508 0 : s_len++;
509 : }
510 2 : break;
511 :
512 :
513 : case 'x':
514 : case 'X':
515 17975 : switch(modifier) {
516 : default:
517 17975 : ui_num = (u_wide_int) va_arg(ap, unsigned int);
518 17975 : break;
519 : case LM_LONG_DOUBLE:
520 0 : goto fmt_error;
521 : case LM_LONG:
522 0 : ui_num = (u_wide_int) va_arg(ap, unsigned long int);
523 0 : break;
524 : case LM_SIZE_T:
525 0 : ui_num = (u_wide_int) va_arg(ap, size_t);
526 0 : break;
527 : #if SIZEOF_LONG_LONG
528 : case LM_LONG_LONG:
529 0 : ui_num = (u_wide_int) va_arg(ap, u_wide_int);
530 0 : break;
531 : #endif
532 : #if SIZEOF_INTMAX_T
533 : case LM_INTMAX_T:
534 0 : ui_num = (u_wide_int) va_arg(ap, uintmax_t);
535 0 : break;
536 : #endif
537 : #if SIZEOF_PTRDIFF_T
538 : case LM_PTRDIFF_T:
539 0 : ui_num = (u_wide_int) va_arg(ap, ptrdiff_t);
540 : break;
541 : #endif
542 : }
543 17975 : s = ap_php_conv_p2(ui_num, 4, *fmt,
544 : &num_buf[NUM_BUF_SIZE], &s_len);
545 17975 : FIX_PRECISION(adjust_precision, precision, s, s_len);
546 17975 : if (alternate_form && i_num != 0) {
547 0 : *--s = *fmt; /* 'x' or 'X' */
548 0 : *--s = '0';
549 0 : s_len += 2;
550 : }
551 17975 : break;
552 :
553 :
554 : case 's':
555 : case 'v':
556 11017023 : s = va_arg(ap, char *);
557 11017023 : if (s != NULL) {
558 11017015 : if (!adjust_precision) {
559 11016775 : s_len = strlen(s);
560 : } else {
561 240 : s_len = strnlen(s, precision);
562 : }
563 : } else {
564 8 : s = S_NULL;
565 8 : s_len = S_NULL_LEN;
566 : }
567 11017023 : pad_char = ' ';
568 11017023 : break;
569 :
570 :
571 : case 'f':
572 : case 'F':
573 : case 'e':
574 : case 'E':
575 322 : switch(modifier) {
576 : case LM_LONG_DOUBLE:
577 0 : fp_num = (double) va_arg(ap, long double);
578 0 : break;
579 : case LM_STD:
580 322 : fp_num = va_arg(ap, double);
581 322 : break;
582 : default:
583 0 : goto fmt_error;
584 : }
585 :
586 322 : if (zend_isnan(fp_num)) {
587 0 : s = "nan";
588 0 : s_len = 3;
589 322 : } else if (zend_isinf(fp_num)) {
590 2 : s = "inf";
591 2 : s_len = 3;
592 : } else {
593 : #ifdef HAVE_LOCALE_H
594 320 : if (!lconv) {
595 320 : lconv = localeconv();
596 : }
597 : #endif
598 320 : s = php_conv_fp((*fmt == 'f')?'F':*fmt, fp_num, alternate_form,
599 : (adjust_precision == NO) ? FLOAT_DIGITS : precision,
600 : (*fmt == 'f')?LCONV_DECIMAL_POINT:'.',
601 : &is_negative, &num_buf[1], &s_len);
602 320 : if (is_negative)
603 1 : prefix_char = '-';
604 319 : else if (print_sign)
605 0 : prefix_char = '+';
606 319 : else if (print_blank)
607 0 : prefix_char = ' ';
608 : }
609 322 : break;
610 :
611 :
612 : case 'g':
613 : case 'k':
614 : case 'G':
615 : case 'H':
616 24462 : switch(modifier) {
617 : case LM_LONG_DOUBLE:
618 0 : fp_num = (double) va_arg(ap, long double);
619 0 : break;
620 : case LM_STD:
621 24462 : fp_num = va_arg(ap, double);
622 24462 : break;
623 : default:
624 0 : goto fmt_error;
625 : }
626 :
627 24462 : if (zend_isnan(fp_num)) {
628 1529 : s = "NAN";
629 1529 : s_len = 3;
630 1529 : break;
631 22933 : } else if (zend_isinf(fp_num)) {
632 1545 : if (fp_num > 0) {
633 1515 : s = "INF";
634 1515 : s_len = 3;
635 : } else {
636 30 : s = "-INF";
637 30 : s_len = 4;
638 : }
639 1545 : break;
640 : }
641 :
642 21388 : if (adjust_precision == NO)
643 0 : precision = FLOAT_DIGITS;
644 21388 : else if (precision == 0)
645 0 : precision = 1;
646 : /*
647 : * * We use &num_buf[ 1 ], so that we have room for the sign
648 : */
649 : #ifdef HAVE_LOCALE_H
650 21388 : if (!lconv) {
651 21388 : lconv = localeconv();
652 : }
653 : #endif
654 21388 : s = php_gcvt(fp_num, precision, (*fmt=='H' || *fmt == 'k') ? '.' : LCONV_DECIMAL_POINT, (*fmt == 'G' || *fmt == 'H')?'E':'e', &num_buf[1]);
655 21388 : if (*s == '-')
656 2331 : prefix_char = *s++;
657 19057 : else if (print_sign)
658 0 : prefix_char = '+';
659 19057 : else if (print_blank)
660 0 : prefix_char = ' ';
661 :
662 21388 : s_len = strlen(s);
663 :
664 21388 : if (alternate_form && (q = strchr(s, '.')) == NULL)
665 0 : s[s_len++] = '.';
666 21388 : break;
667 :
668 :
669 : case 'c':
670 140679 : char_buf[0] = (char) (va_arg(ap, int));
671 140679 : s = &char_buf[0];
672 140679 : s_len = 1;
673 140679 : pad_char = ' ';
674 140679 : break;
675 :
676 :
677 : case '%':
678 2 : char_buf[0] = '%';
679 2 : s = &char_buf[0];
680 2 : s_len = 1;
681 2 : pad_char = ' ';
682 2 : break;
683 :
684 :
685 : case 'n':
686 0 : *(va_arg(ap, int *)) = xbuf->len;
687 0 : goto skip_output;
688 :
689 : /*
690 : * Always extract the argument as a "char *" pointer. We
691 : * should be using "void *" but there are still machines
692 : * that don't understand it.
693 : * If the pointer size is equal to the size of an unsigned
694 : * integer we convert the pointer to a hex number, otherwise
695 : * we print "%p" to indicate that we don't handle "%p".
696 : */
697 : case 'p':
698 : if (sizeof(char *) <= sizeof(u_wide_int)) {
699 1 : ui_num = (u_wide_int)((size_t) va_arg(ap, char *));
700 1 : s = ap_php_conv_p2(ui_num, 4, 'x',
701 : &num_buf[NUM_BUF_SIZE], &s_len);
702 1 : if (ui_num != 0) {
703 1 : *--s = 'x';
704 1 : *--s = '0';
705 1 : s_len += 2;
706 : }
707 : } else {
708 : s = "%p";
709 : s_len = 2;
710 : }
711 1 : pad_char = ' ';
712 1 : break;
713 :
714 :
715 : case NUL:
716 : /*
717 : * The last character of the format string was %.
718 : * We ignore it.
719 : */
720 0 : continue;
721 :
722 :
723 0 : fmt_error:
724 0 : php_error(E_ERROR, "Illegal length modifier specified '%c' in s[np]printf call", *fmt);
725 : /*
726 : * The default case is for unrecognized %'s.
727 : * We print %<char> to help the user identify what
728 : * option is not understood.
729 : * This is also useful in case the user wants to pass
730 : * the output of format_converter to another function
731 : * that understands some other %<char> (like syslog).
732 : * Note that we can't point s inside fmt because the
733 : * unknown <char> could be preceded by width etc.
734 : */
735 : default:
736 0 : char_buf[0] = '%';
737 0 : char_buf[1] = *fmt;
738 0 : s = char_buf;
739 0 : s_len = 2;
740 0 : pad_char = ' ';
741 : break;
742 : }
743 :
744 15270557 : if (prefix_char != NUL) {
745 6815 : *--s = prefix_char;
746 6815 : s_len++;
747 : }
748 15270557 : if (adjust_width && adjust == RIGHT && min_width > s_len) {
749 131458 : if (pad_char == '0' && prefix_char != NUL) {
750 0 : INS_CHAR(xbuf, *s);
751 0 : s++;
752 0 : s_len--;
753 0 : min_width--;
754 : }
755 131458 : PAD(xbuf, min_width - s_len, pad_char);
756 : }
757 : /*
758 : * Print the string s.
759 : */
760 15270557 : INS_STRING(xbuf, s, s_len);
761 :
762 15270557 : if (adjust_width && adjust == LEFT && min_width > s_len)
763 17 : PAD(xbuf, min_width - s_len, pad_char);
764 : }
765 75965465 : skip_output:
766 75965465 : fmt++;
767 : }
768 : return;
769 : }
770 : /* }}} */
771 :
772 : /*
773 : * This is the general purpose conversion function.
774 : */
775 : PHPAPI int vspprintf(char **pbuf, size_t max_len, const char *format, va_list ap) /* {{{ */
776 5999551 : {
777 5999551 : smart_str xbuf = {0};
778 :
779 5999551 : xbuf_format_converter(&xbuf, format, ap);
780 :
781 5999551 : if (max_len && xbuf.len > max_len) {
782 0 : xbuf.len = max_len;
783 : }
784 5999551 : smart_str_0(&xbuf);
785 :
786 5999551 : *pbuf = xbuf.c;
787 :
788 5999551 : return xbuf.len;
789 : }
790 : /* }}} */
791 :
792 : PHPAPI int spprintf(char **pbuf, size_t max_len, const char *format, ...) /* {{{ */
793 1406476 : {
794 : int cc;
795 : va_list ap;
796 :
797 1406476 : va_start(ap, format);
798 1406476 : cc = vspprintf(pbuf, max_len, format, ap);
799 1406476 : va_end(ap);
800 1406476 : return (cc);
801 : }
802 : /* }}} */
803 :
804 : /*
805 : * Local variables:
806 : * tab-width: 4
807 : * c-basic-offset: 4
808 : * End:
809 : * vim600: sw=4 ts=4 fdm=marker
810 : * vim<600: sw=4 ts=4
811 : */
|