summaryrefslogtreecommitdiff
path: root/compat_snprintf.c
diff options
context:
space:
mode:
Diffstat (limited to 'compat_snprintf.c')
-rw-r--r--compat_snprintf.c1001
1 files changed, 1001 insertions, 0 deletions
diff --git a/compat_snprintf.c b/compat_snprintf.c
new file mode 100644
index 0000000..8f3682f
--- /dev/null
+++ b/compat_snprintf.c
@@ -0,0 +1,1001 @@
1/*
2 +----------------------------------------------------------------------+
3 | PHP Version 4 |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 1997-2003 The PHP Group |
6 +----------------------------------------------------------------------+
7 | This source file is subject to version 2.02 of the PHP license, |
8 | that is bundled with this package in the file LICENSE, and is |
9 | available at through the world-wide-web at |
10 | http://www.php.net/license/2_02.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: |
16 +----------------------------------------------------------------------+
17*/
18
19/* $Id: compat_snprintf.c,v 1.1.1.1 2007-11-28 01:15:35 sesser Exp $ */
20
21/* ====================================================================
22 * Copyright (c) 1995-1998 The Apache Group. All rights reserved.
23 *
24 * Redistribution and use in source and binary forms, with or without
25 * modification, are permitted provided that the following conditions
26 * are met:
27 *
28 * 1. Redistributions of source code must retain the above copyright
29 * notice, this list of conditions and the following disclaimer.
30 *
31 * 2. Redistributions in binary form must reproduce the above copyright
32 * notice, this list of conditions and the following disclaimer in
33 * the documentation and/or other materials provided with the
34 * distribution.
35 *
36 * 3. All advertising materials mentioning features or use of this
37 * software must display the following acknowledgment:
38 * "This product includes software developed by the Apache Group
39 * for use in the Apache HTTP server project (http://www.apache.org/)."
40 *
41 * 4. The names "Apache Server" and "Apache Group" must not be used to
42 * endorse or promote products derived from this software without
43 * prior written permission.
44 *
45 * 5. Redistributions of any form whatsoever must retain the following
46 * acknowledgment:
47 * "This product includes software developed by the Apache Group
48 * for use in the Apache HTTP server project (http://www.apache.org/)."
49 *
50 * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY
51 * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
52 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
53 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR
54 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
55 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
56 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
57 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
58 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
59 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
60 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
61 * OF THE POSSIBILITY OF SUCH DAMAGE.
62 * ====================================================================
63 *
64 * This software consists of voluntary contributions made by many
65 * individuals on behalf of the Apache Group and was originally based
66 * on public domain software written at the National Center for
67 * Supercomputing Applications, University of Illinois, Urbana-Champaign.
68 * For more information on the Apache Group and the Apache HTTP server
69 * project, please see <http://www.apache.org/>.
70 *
71 * This code is based on, and used with the permission of, the
72 * SIO stdio-replacement strx_* functions by Panos Tsirigotis
73 * <panos@alumni.cs.colorado.edu> for xinetd.
74 */
75
76#include "php.h"
77
78#if ((PHP_MAJOR_VERSION == 4) && (PHP_MINOR_VERSION == 3) && (PHP_RELEASE_VERSION < 10))
79
80#include <stdio.h>
81#include <ctype.h>
82#include <sys/types.h>
83#include <stdarg.h>
84#include <string.h>
85#include <stdlib.h>
86#include <math.h>
87
88#define FALSE 0
89#define TRUE 1
90#define NUL '\0'
91#define INT_NULL ((int *)0)
92
93#define S_NULL "(null)"
94#define S_NULL_LEN 6
95
96#define FLOAT_DIGITS 6
97#define EXPONENT_LENGTH 10
98
99
100/*
101 * Convert num to its decimal format.
102 * Return value:
103 * - a pointer to a string containing the number (no sign)
104 * - len contains the length of the string
105 * - is_negative is set to TRUE or FALSE depending on the sign
106 * of the number (always set to FALSE if is_unsigned is TRUE)
107 *
108 * The caller provides a buffer for the string: that is the buf_end argument
109 * which is a pointer to the END of the buffer + 1 (i.e. if the buffer
110 * is declared as buf[ 100 ], buf_end should be &buf[ 100 ])
111 */
112char *
113ap_php_conv_10(register wide_int num, register bool_int is_unsigned,
114 register bool_int * is_negative, char *buf_end, register int *len)
115{
116 register char *p = buf_end;
117 register u_wide_int magnitude;
118
119 if (is_unsigned) {
120 magnitude = (u_wide_int) num;
121 *is_negative = FALSE;
122 } else {
123 *is_negative = (num < 0);
124
125 /*
126 * On a 2's complement machine, negating the most negative integer
127 * results in a number that cannot be represented as a signed integer.
128 * Here is what we do to obtain the number's magnitude:
129 * a. add 1 to the number
130 * b. negate it (becomes positive)
131 * c. convert it to unsigned
132 * d. add 1
133 */
134 if (*is_negative) {
135 wide_int t = num + 1;
136
137 magnitude = ((u_wide_int) - t) + 1;
138 } else
139 magnitude = (u_wide_int) num;
140 }
141
142 /*
143 * We use a do-while loop so that we write at least 1 digit
144 */
145 do {
146 register u_wide_int new_magnitude = magnitude / 10;
147
148 *--p = (char)(magnitude - new_magnitude * 10 + '0');
149 magnitude = new_magnitude;
150 }
151 while (magnitude);
152
153 *len = buf_end - p;
154 return (p);
155}
156
157/* If you change this value then also change bug24640.phpt.
158 */
159#define NDIG 80
160
161
162/*
163 * Convert a floating point number to a string formats 'f', 'e' or 'E'.
164 * The result is placed in buf, and len denotes the length of the string
165 * The sign is returned in the is_negative argument (and is not placed
166 * in buf).
167 */
168char *
169 ap_php_conv_fp(register char format, register double num,
170 boolean_e add_dp, int precision, bool_int * is_negative, char *buf, int *len)
171{
172 register char *s = buf;
173 register char *p;
174 int decimal_point;
175 char buf1[NDIG];
176
177 if (format == 'f')
178 p = ap_php_fcvt(num, precision, &decimal_point, is_negative, buf1);
179 else /* either e or E format */
180 p = ap_php_ecvt(num, precision + 1, &decimal_point, is_negative, buf1);
181
182 /*
183 * Check for Infinity and NaN
184 */
185 if (isalpha((int)*p)) {
186 *len = strlen(p);
187 memcpy(buf, p, *len + 1);
188 *is_negative = FALSE;
189 return (buf);
190 }
191 if (format == 'f') {
192 if (decimal_point <= 0) {
193 *s++ = '0';
194 if (precision > 0) {
195 *s++ = '.';
196 while (decimal_point++ < 0)
197 *s++ = '0';
198 } else if (add_dp) {
199 *s++ = '.';
200 }
201 } else {
202 while (decimal_point-- > 0) {
203 *s++ = *p++;
204 }
205 if (precision > 0 || add_dp) {
206 *s++ = '.';
207 }
208 }
209 } else {
210 *s++ = *p++;
211 if (precision > 0 || add_dp)
212 *s++ = '.';
213 }
214
215 /*
216 * copy the rest of p, the NUL is NOT copied
217 */
218 while (*p)
219 *s++ = *p++;
220
221 if (format != 'f') {
222 char temp[EXPONENT_LENGTH]; /* for exponent conversion */
223 int t_len;
224 bool_int exponent_is_negative;
225
226 *s++ = format; /* either e or E */
227 decimal_point--;
228 if (decimal_point != 0) {
229 p = ap_php_conv_10((wide_int) decimal_point, FALSE, &exponent_is_negative,
230 &temp[EXPONENT_LENGTH], &t_len);
231 *s++ = exponent_is_negative ? '-' : '+';
232
233 /*
234 * Make sure the exponent has at least 2 digits
235 */
236 if (t_len == 1)
237 *s++ = '0';
238 while (t_len--)
239 *s++ = *p++;
240 } else {
241 *s++ = '+';
242 *s++ = '0';
243 *s++ = '0';
244 }
245 }
246 *len = s - buf;
247 return (buf);
248}
249
250
251/*
252 * Convert num to a base X number where X is a power of 2. nbits determines X.
253 * For example, if nbits is 3, we do base 8 conversion
254 * Return value:
255 * a pointer to a string containing the number
256 *
257 * The caller provides a buffer for the string: that is the buf_end argument
258 * which is a pointer to the END of the buffer + 1 (i.e. if the buffer
259 * is declared as buf[ 100 ], buf_end should be &buf[ 100 ])
260 */
261char *
262 ap_php_conv_p2(register u_wide_int num, register int nbits,
263 char format, char *buf_end, register int *len)
264{
265 register int mask = (1 << nbits) - 1;
266 register char *p = buf_end;
267 static char low_digits[] = "0123456789abcdef";
268 static char upper_digits[] = "0123456789ABCDEF";
269 register char *digits = (format == 'X') ? upper_digits : low_digits;
270
271 do {
272 *--p = digits[num & mask];
273 num >>= nbits;
274 }
275 while (num);
276
277 *len = buf_end - p;
278 return (p);
279}
280
281/*
282 * cvt.c - IEEE floating point formatting routines for FreeBSD
283 * from GNU libc-4.6.27
284 */
285
286/*
287 * ap_php_ecvt converts to decimal
288 * the number of digits is specified by ndigit
289 * decpt is set to the position of the decimal point
290 * sign is set to 0 for positive, 1 for negative
291 */
292
293
294char *
295ap_php_cvt(double arg, int ndigits, int *decpt, int *sign, int eflag, char *buf)
296{
297 register int r2;
298 int mvl;
299 double fi, fj;
300 register char *p, *p1;
301
302 if (ndigits >= NDIG - 1)
303 ndigits = NDIG - 2;
304 r2 = 0;
305 *sign = 0;
306 p = &buf[0];
307 if (arg < 0) {
308 *sign = 1;
309 arg = -arg;
310 }
311 arg = modf(arg, &fi);
312 p1 = &buf[NDIG];
313 /*
314 * Do integer part
315 */
316 if (fi != 0) {
317 p1 = &buf[NDIG];
318 while (fi != 0) {
319 fj = modf(fi / 10, &fi);
320 if (p1 <= &buf[0]) {
321 mvl = NDIG - ndigits;
322 memmove(&buf[mvl], &buf[0], NDIG-mvl-1);
323 p1 += mvl;
324 }
325 *--p1 = (int) ((fj + .03) * 10) + '0';
326 r2++;
327 }
328 while (p1 < &buf[NDIG])
329 *p++ = *p1++;
330 } else if (arg > 0) {
331 while ((fj = arg * 10) < 1) {
332 if (!eflag && (r2 * -1) < ndigits) {
333 break;
334 }
335 arg = fj;
336 r2--;
337 }
338 }
339 p1 = &buf[ndigits];
340 if (eflag == 0)
341 p1 += r2;
342 *decpt = r2;
343 if (p1 < &buf[0]) {
344 buf[0] = '\0';
345 return (buf);
346 }
347 if (p <= p1 && p < &buf[NDIG]) {
348 arg = modf(arg * 10, &fj);
349 if ((int)fj==10) {
350 *p++ = '1';
351 fj = 0;
352 *decpt = ++r2;
353 }
354 while (p <= p1 && p < &buf[NDIG]) {
355 *p++ = (int) fj + '0';
356 arg = modf(arg * 10, &fj);
357 }
358 }
359 if (p1 >= &buf[NDIG]) {
360 buf[NDIG - 1] = '\0';
361 return (buf);
362 }
363 p = p1;
364 *p1 += 5;
365 while (*p1 > '9') {
366 *p1 = '0';
367 if (p1 > buf)
368 ++ * --p1;
369 else {
370 *p1 = '1';
371 (*decpt)++;
372 if (eflag == 0) {
373 if (p > buf)
374 *p = '0';
375 p++;
376 }
377 }
378 }
379 *p = '\0';
380 return (buf);
381}
382
383char *
384ap_php_ecvt(double arg, int ndigits, int *decpt, int *sign, char *buf)
385{
386 return (ap_php_cvt(arg, ndigits, decpt, sign, 1, buf));
387}
388
389char *
390ap_php_fcvt(double arg, int ndigits, int *decpt, int *sign, char *buf)
391{
392 return (ap_php_cvt(arg, ndigits, decpt, sign, 0, buf));
393}
394
395/*
396 * ap_php_gcvt - Floating output conversion to
397 * minimal length string
398 */
399
400char *
401ap_php_gcvt(double number, int ndigit, char *buf, boolean_e altform)
402{
403 int sign, decpt;
404 register char *p1, *p2;
405 register int i;
406 char buf1[NDIG];
407
408 if (ndigit >= NDIG - 1) {
409 ndigit = NDIG - 2;
410 }
411
412 p1 = ap_php_ecvt(number, ndigit, &decpt, &sign, buf1);
413 p2 = buf;
414 if (sign)
415 *p2++ = '-';
416 for (i = ndigit - 1; i > 0 && p1[i] == '0'; i--)
417 ndigit--;
418 if ((decpt >= 0 && decpt - ndigit > 4)
419 || (decpt < 0 && decpt < -3)) { /* use E-style */
420 decpt--;
421 *p2++ = *p1++;
422 *p2++ = '.';
423 for (i = 1; i < ndigit; i++)
424 *p2++ = *p1++;
425 if (*(p2 - 1) == '.') {
426 *p2++ = '0';
427 }
428 *p2++ = 'e';
429 if (decpt < 0) {
430 decpt = -decpt;
431 *p2++ = '-';
432 } else
433 *p2++ = '+';
434 if (decpt / 100 > 0)
435 *p2++ = decpt / 100 + '0';
436 if (decpt / 10 > 0)
437 *p2++ = (decpt % 100) / 10 + '0';
438 *p2++ = decpt % 10 + '0';
439 } else {
440 if (decpt <= 0) {
441 if (*p1 != '0') {
442 *p2++ = '0';
443 *p2++ = '.';
444 }
445 while (decpt < 0) {
446 decpt++;
447 *p2++ = '0';
448 }
449 }
450 for (i = 1; i <= ndigit; i++) {
451 *p2++ = *p1++;
452 if (i == decpt)
453 *p2++ = '.';
454 }
455 if (ndigit < decpt) {
456 while (ndigit++ < decpt)
457 *p2++ = '0';
458 *p2++ = '.';
459 }
460 }
461 if (p2[-1] == '.' && !altform)
462 p2--;
463 *p2 = '\0';
464 return (buf);
465}
466
467
468/*
469 * NUM_BUF_SIZE is the size of the buffer used for arithmetic conversions
470 *
471 * XXX: this is a magic number; do not decrease it
472 */
473#define NUM_BUF_SIZE 512
474
475
476/*
477 * Descriptor for buffer area
478 */
479struct buf_area {
480 char *buf_end;
481 char *nextb; /* pointer to next byte to read/write */
482};
483
484typedef struct buf_area buffy;
485
486/*
487 * The INS_CHAR macro inserts a character in the buffer and writes
488 * the buffer back to disk if necessary
489 * It uses the char pointers sp and bep:
490 * sp points to the next available character in the buffer
491 * bep points to the end-of-buffer+1
492 * While using this macro, note that the nextb pointer is NOT updated.
493 *
494 * NOTE: Evaluation of the c argument should not have any side-effects
495 */
496#define INS_CHAR(c, sp, bep, cc) \
497 { \
498 if (sp < bep) \
499 { \
500 *sp++ = c; \
501 } \
502 cc++; \
503 }
504
505#define NUM( c ) ( c - '0' )
506
507#define STR_TO_DEC( str, num ) \
508 num = NUM( *str++ ) ; \
509 while ( isdigit((int)*str ) ) \
510 { \
511 num *= 10 ; \
512 num += NUM( *str++ ) ; \
513 }
514
515/*
516 * This macro does zero padding so that the precision
517 * requirement is satisfied. The padding is done by
518 * adding '0's to the left of the string that is going
519 * to be printed.
520 */
521#define FIX_PRECISION( adjust, precision, s, s_len ) \
522 if ( adjust ) \
523 while ( s_len < precision ) \
524 { \
525 *--s = '0' ; \
526 s_len++ ; \
527 }
528
529/*
530 * Macro that does padding. The padding is done by printing
531 * the character ch.
532 */
533#define PAD( width, len, ch ) do \
534 { \
535 INS_CHAR( ch, sp, bep, cc ) ; \
536 width-- ; \
537 } \
538 while ( width > len )
539
540/*
541 * Prefix the character ch to the string str
542 * Increase length
543 * Set the has_prefix flag
544 */
545#define PREFIX( str, length, ch ) *--str = ch ; length++ ; has_prefix = YES
546
547
548/*
549 * Do format conversion placing the output in buffer
550 */
551static int format_converter(register buffy * odp, const char *fmt,
552 va_list ap)
553{
554 register char *sp;
555 register char *bep;
556 register int cc = 0;
557 register int i;
558
559 register char *s = NULL;
560 char *q;
561 int s_len;
562
563 register int min_width = 0;
564 int precision = 0;
565 enum {
566 LEFT, RIGHT
567 } adjust;
568 char pad_char;
569 char prefix_char;
570
571 double fp_num;
572 wide_int i_num = (wide_int) 0;
573 u_wide_int ui_num;
574
575 char num_buf[NUM_BUF_SIZE];
576 char char_buf[2]; /* for printing %% and %<unknown> */
577
578 /*
579 * Flag variables
580 */
581 boolean_e is_long;
582 boolean_e alternate_form;
583 boolean_e print_sign;
584 boolean_e print_blank;
585 boolean_e adjust_precision;
586 boolean_e adjust_width;
587 bool_int is_negative;
588
589 sp = odp->nextb;
590 bep = odp->buf_end;
591
592 while (*fmt) {
593 if (*fmt != '%') {
594 INS_CHAR(*fmt, sp, bep, cc);
595 } else {
596 /*
597 * Default variable settings
598 */
599 adjust = RIGHT;
600 alternate_form = print_sign = print_blank = NO;
601 pad_char = ' ';
602 prefix_char = NUL;
603
604 fmt++;
605
606 /*
607 * Try to avoid checking for flags, width or precision
608 */
609 if (isascii((int)*fmt) && !islower((int)*fmt)) {
610 /*
611 * Recognize flags: -, #, BLANK, +
612 */
613 for (;; fmt++) {
614 if (*fmt == '-')
615 adjust = LEFT;
616 else if (*fmt == '+')
617 print_sign = YES;
618 else if (*fmt == '#')
619 alternate_form = YES;
620 else if (*fmt == ' ')
621 print_blank = YES;
622 else if (*fmt == '0')
623 pad_char = '0';
624 else
625 break;
626 }
627
628 /*
629 * Check if a width was specified
630 */
631 if (isdigit((int)*fmt)) {
632 STR_TO_DEC(fmt, min_width);
633 adjust_width = YES;
634 } else if (*fmt == '*') {
635 min_width = va_arg(ap, int);
636 fmt++;
637 adjust_width = YES;
638 if (min_width < 0) {
639 adjust = LEFT;
640 min_width = -min_width;
641 }
642 } else
643 adjust_width = NO;
644
645 /*
646 * Check if a precision was specified
647 *
648 * XXX: an unreasonable amount of precision may be specified
649 * resulting in overflow of num_buf. Currently we
650 * ignore this possibility.
651 */
652 if (*fmt == '.') {
653 adjust_precision = YES;
654 fmt++;
655 if (isdigit((int)*fmt)) {
656 STR_TO_DEC(fmt, precision);
657 } else if (*fmt == '*') {
658 precision = va_arg(ap, int);
659 fmt++;
660 if (precision < 0)
661 precision = 0;
662 } else
663 precision = 0;
664 } else
665 adjust_precision = NO;
666 } else
667 adjust_precision = adjust_width = NO;
668
669 /*
670 * Modifier check
671 */
672 if (*fmt == 'l') {
673 is_long = YES;
674 fmt++;
675 } else
676 is_long = NO;
677
678 /*
679 * Argument extraction and printing.
680 * First we determine the argument type.
681 * Then, we convert the argument to a string.
682 * On exit from the switch, s points to the string that
683 * must be printed, s_len has the length of the string
684 * The precision requirements, if any, are reflected in s_len.
685 *
686 * NOTE: pad_char may be set to '0' because of the 0 flag.
687 * It is reset to ' ' by non-numeric formats
688 */
689 switch (*fmt) {
690 case 'u':
691 if (is_long)
692 i_num = va_arg(ap, u_wide_int);
693 else
694 i_num = (wide_int) va_arg(ap, unsigned int);
695 /*
696 * The rest also applies to other integer formats, so fall
697 * into that case.
698 */
699 case 'd':
700 case 'i':
701 /*
702 * Get the arg if we haven't already.
703 */
704 if ((*fmt) != 'u') {
705 if (is_long)
706 i_num = va_arg(ap, wide_int);
707 else
708 i_num = (wide_int) va_arg(ap, int);
709 };
710 s = ap_php_conv_10(i_num, (*fmt) == 'u', &is_negative,
711 &num_buf[NUM_BUF_SIZE], &s_len);
712 FIX_PRECISION(adjust_precision, precision, s, s_len);
713
714 if (*fmt != 'u') {
715 if (is_negative)
716 prefix_char = '-';
717 else if (print_sign)
718 prefix_char = '+';
719 else if (print_blank)
720 prefix_char = ' ';
721 }
722 break;
723
724
725 case 'o':
726 if (is_long)
727 ui_num = va_arg(ap, u_wide_int);
728 else
729 ui_num = (u_wide_int) va_arg(ap, unsigned int);
730 s = ap_php_conv_p2(ui_num, 3, *fmt,
731 &num_buf[NUM_BUF_SIZE], &s_len);
732 FIX_PRECISION(adjust_precision, precision, s, s_len);
733 if (alternate_form && *s != '0') {
734 *--s = '0';
735 s_len++;
736 }
737 break;
738
739
740 case 'x':
741 case 'X':
742 if (is_long)
743 ui_num = (u_wide_int) va_arg(ap, u_wide_int);
744 else
745 ui_num = (u_wide_int) va_arg(ap, unsigned int);
746 s = ap_php_conv_p2(ui_num, 4, *fmt,
747 &num_buf[NUM_BUF_SIZE], &s_len);
748 FIX_PRECISION(adjust_precision, precision, s, s_len);
749 if (alternate_form && i_num != 0) {
750 *--s = *fmt; /* 'x' or 'X' */
751 *--s = '0';
752 s_len += 2;
753 }
754 break;
755
756
757 case 's':
758 s = va_arg(ap, char *);
759 if (s != NULL) {
760 s_len = strlen(s);
761 if (adjust_precision && precision < s_len)
762 s_len = precision;
763 } else {
764 s = S_NULL;
765 s_len = S_NULL_LEN;
766 }
767 pad_char = ' ';
768 break;
769
770
771 case 'f':
772 case 'e':
773 case 'E':
774 fp_num = va_arg(ap, double);
775
776 if (zend_isnan(fp_num)) {
777 s = "nan";
778 s_len = 3;
779 } else if (zend_isinf(fp_num)) {
780 s = "inf";
781 s_len = 3;
782 } else {
783 s = ap_php_conv_fp(*fmt, fp_num, alternate_form,
784 (adjust_precision == NO) ? FLOAT_DIGITS : precision,
785 &is_negative, &num_buf[1], &s_len);
786 if (is_negative)
787 prefix_char = '-';
788 else if (print_sign)
789 prefix_char = '+';
790 else if (print_blank)
791 prefix_char = ' ';
792 }
793 break;
794
795
796 case 'g':
797 case 'G':
798 fp_num = va_arg(ap, double);
799
800 if (zend_isnan(fp_num)) {
801 s = "NAN";
802 s_len = 3;
803 break;
804 } else if (zend_isinf(fp_num)) {
805 if (fp_num > 0) {
806 s = "INF";
807 s_len = 3;
808 } else {
809 s = "-INF";
810 s_len = 4;
811 }
812 break;
813 }
814
815 if (adjust_precision == NO)
816 precision = FLOAT_DIGITS;
817 else if (precision == 0)
818 precision = 1;
819 /*
820 * * We use &num_buf[ 1 ], so that we have room for the sign
821 */
822 s = ap_php_gcvt(fp_num, precision, &num_buf[1], alternate_form);
823 if (*s == '-')
824 prefix_char = *s++;
825 else if (print_sign)
826 prefix_char = '+';
827 else if (print_blank)
828 prefix_char = ' ';
829
830 s_len = strlen(s);
831
832 if (alternate_form && (q = strchr(s, '.')) == NULL)
833 s[s_len++] = '.';
834 if (*fmt == 'G' && (q = strchr(s, 'e')) != NULL)
835 *q = 'E';
836 break;
837
838
839 case 'c':
840 char_buf[0] = (char) (va_arg(ap, int));
841 s = &char_buf[0];
842 s_len = 1;
843 pad_char = ' ';
844 break;
845
846
847 case '%':
848 char_buf[0] = '%';
849 s = &char_buf[0];
850 s_len = 1;
851 pad_char = ' ';
852 break;
853
854
855 case 'n':
856 *(va_arg(ap, int *)) = cc;
857 break;
858
859 /*
860 * Always extract the argument as a "char *" pointer. We
861 * should be using "void *" but there are still machines
862 * that don't understand it.
863 * If the pointer size is equal to the size of an unsigned
864 * integer we convert the pointer to a hex number, otherwise
865 * we print "%p" to indicate that we don't handle "%p".
866 */
867 case 'p':
868 ui_num = (u_wide_int) va_arg(ap, char *);
869
870 if (sizeof(char *) <= sizeof(u_wide_int))
871 s = ap_php_conv_p2(ui_num, 4, 'x',
872 &num_buf[NUM_BUF_SIZE], &s_len);
873 else {
874 s = "%p";
875 s_len = 2;
876 }
877 pad_char = ' ';
878 break;
879
880
881 case NUL:
882 /*
883 * The last character of the format string was %.
884 * We ignore it.
885 */
886 continue;
887
888
889 /*
890 * The default case is for unrecognized %'s.
891 * We print %<char> to help the user identify what
892 * option is not understood.
893 * This is also useful in case the user wants to pass
894 * the output of format_converter to another function
895 * that understands some other %<char> (like syslog).
896 * Note that we can't point s inside fmt because the
897 * unknown <char> could be preceded by width etc.
898 */
899 default:
900 char_buf[0] = '%';
901 char_buf[1] = *fmt;
902 s = char_buf;
903 s_len = 2;
904 pad_char = ' ';
905 break;
906 }
907
908 if (prefix_char != NUL) {
909 *--s = prefix_char;
910 s_len++;
911 }
912 if (adjust_width && adjust == RIGHT && min_width > s_len) {
913 if (pad_char == '0' && prefix_char != NUL) {
914 INS_CHAR(*s, sp, bep, cc)
915 s++;
916 s_len--;
917 min_width--;
918 }
919 PAD(min_width, s_len, pad_char);
920 }
921 /*
922 * Print the string s.
923 */
924 for (i = s_len; i != 0; i--) {
925 INS_CHAR(*s, sp, bep, cc);
926 s++;
927 }
928
929 if (adjust_width && adjust == LEFT && min_width > s_len)
930 PAD(min_width, s_len, pad_char);
931 }
932 fmt++;
933 }
934 odp->nextb = sp;
935 return (cc);
936}
937
938
939/*
940 * This is the general purpose conversion function.
941 */
942static void strx_printv(int *ccp, char *buf, size_t len, const char *format,
943 va_list ap)
944{
945 buffy od;
946 int cc;
947
948 /*
949 * First initialize the descriptor
950 * Notice that if no length is given, we initialize buf_end to the
951 * highest possible address.
952 */
953 if (len == 0) {
954 od.buf_end = (char *) ~0;
955 od.nextb = (char *) ~0;
956 } else {
957 od.buf_end = &buf[len-1];
958 od.nextb = buf;
959 }
960
961 /*
962 * Do the conversion
963 */
964 cc = format_converter(&od, format, ap);
965 if (len != 0 && od.nextb <= od.buf_end)
966 *(od.nextb) = '\0';
967 if (ccp)
968 *ccp = cc;
969}
970
971
972int ap_php_snprintf(char *buf, size_t len, const char *format,...)
973{
974 int cc;
975 va_list ap;
976
977 va_start(ap, format);
978 strx_printv(&cc, buf, len, format, ap);
979 va_end(ap);
980 return (cc);
981}
982
983
984int ap_php_vsnprintf(char *buf, size_t len, const char *format, va_list ap)
985{
986 int cc;
987
988 strx_printv(&cc, buf, len, format, ap);
989 return (cc);
990}
991
992#endif
993
994/*
995 * Local variables:
996 * tab-width: 4
997 * c-basic-offset: 4
998 * End:
999 * vim600: sw=4 ts=4 fdm=marker
1000 * vim<600: sw=4 ts=4
1001 */