PHP  
 PHP: Test and Code Coverage Analysis
downloads | QA | documentation | faq | getting help | mailing lists | reporting bugs | php.net sites | links | my php.net 
 

LTP GCOV extension - code coverage report
Current view: directory - var/php_gcov/PHP_HEAD/main - snprintf.c
Test: PHP Code Coverage
Date: 2009-11-23 Instrumented lines: 537
Code covered: 57.5 % Executed lines: 309
Legend: not executed executed

       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:                                                              |
      16                 :   +----------------------------------------------------------------------+
      17                 : */
      18                 : 
      19                 : /* $Id: snprintf.c 286624 2009-08-01 14:45:42Z kalle $ */
      20                 : 
      21                 : 
      22                 : #include "php.h"
      23                 : 
      24                 : #include <zend_strtod.h>
      25                 : 
      26                 : #include <stddef.h>
      27                 : #include <stdio.h>
      28                 : #include <ctype.h>
      29                 : #include <sys/types.h>
      30                 : #include <stdarg.h>
      31                 : #include <string.h>
      32                 : #include <stdlib.h>
      33                 : #include <math.h>
      34                 : 
      35                 : #ifdef HAVE_INTTYPES_H
      36                 : #include <inttypes.h>
      37                 : #endif
      38                 : 
      39                 : #ifdef HAVE_LOCALE_H
      40                 : #include <locale.h>
      41                 : #define LCONV_DECIMAL_POINT (*lconv->decimal_point)
      42                 : #else
      43                 : #define LCONV_DECIMAL_POINT '.'
      44                 : #endif
      45                 : 
      46                 : /*
      47                 :  * Copyright (c) 2002, 2007 Todd C. Miller <Todd.Miller@courtesan.com>
      48                 :  *
      49                 :  * Permission to use, copy, modify, and distribute this software for any
      50                 :  * purpose with or without fee is hereby granted, provided that the above
      51                 :  * copyright notice and this permission notice appear in all copies.
      52                 :  *
      53                 :  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
      54                 :  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
      55                 :  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
      56                 :  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
      57                 :  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
      58                 :  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
      59                 :  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
      60                 :  *
      61                 :  * Sponsored in part by the Defense Advanced Research Projects
      62                 :  * Agency (DARPA) and Air Force Research Laboratory, Air Force
      63                 :  * Materiel Command, USAF, under agreement number F39502-99-1-0512.
      64                 :  */
      65                 : 
      66                 : static char * __cvt(double value, int ndigit, int *decpt, int *sign, int fmode, int pad) /* {{{ */
      67          105347 : {
      68          105347 :         register char *s = NULL;
      69                 :         char *p, *rve, c;
      70                 :         size_t siz;
      71                 : 
      72          105347 :         if (ndigit < 0) {
      73               0 :                 siz = -ndigit + 1;
      74                 :         } else {
      75          105347 :                 siz = ndigit + 1;
      76                 :         }
      77                 : 
      78                 :         /* __dtoa() doesn't allocate space for 0 so we do it by hand */
      79          105347 :         if (value == 0.0) {
      80             504 :                 *decpt = 1 - fmode; /* 1 for 'e', 0 for 'f' */
      81             504 :                 *sign = 0;
      82             504 :                 if ((rve = s = (char *)malloc(ndigit?siz:2)) == NULL)
      83               0 :                         return(NULL);
      84             504 :                 *rve++ = '0';
      85             504 :                 *rve = '\0';
      86             504 :                 if (!ndigit) {
      87               7 :                         return(s);
      88                 :                 }
      89                 :         } else {
      90          104843 :                 p = zend_dtoa(value, fmode + 2, ndigit, decpt, sign, &rve);
      91          104843 :                 if (*decpt == 9999) {
      92                 :                         /* Infinity or Nan, convert to inf or nan like printf */
      93               0 :                         *decpt = 0;
      94               0 :                         c = *p;
      95               0 :                         zend_freedtoa(p);
      96               0 :                         return(c == 'I' ? "INF" : "NAN");
      97                 :                 }
      98                 :                 /* Make a local copy and adjust rve to be in terms of s */
      99          104843 :                 if (pad && fmode)
     100          104103 :                         siz += *decpt;
     101          104843 :                 if ((s = (char *)malloc(siz+1)) == NULL) {
     102               0 :                         zend_freedtoa(p);
     103               0 :                         return(NULL);
     104                 :                 }
     105          104843 :                 (void) strlcpy(s, p, siz);
     106          104843 :                 rve = s + (rve - p);
     107          104843 :                 zend_freedtoa(p);
     108                 :         }
     109                 : 
     110                 :         /* Add trailing zeros */
     111          105340 :         if (pad) {
     112          105340 :                 siz -= rve - s;
     113          442281 :                 while (--siz)
     114          231601 :                         *rve++ = '0';
     115          105340 :                 *rve = '\0';
     116                 :         }
     117                 : 
     118          105340 :         return(s);
     119                 : }
     120                 : /* }}} */
     121                 : 
     122                 : static inline char *php_ecvt(double value, int ndigit, int *decpt, int *sign) /* {{{ */
     123             970 : {
     124             970 :         return(__cvt(value, ndigit, decpt, sign, 0, 1));
     125                 : }
     126                 : /* }}} */
     127                 : 
     128                 : static inline char *php_fcvt(double value, int ndigit, int *decpt, int *sign) /* {{{ */
     129          104377 : {
     130          104377 :     return(__cvt(value, ndigit, decpt, sign, 1, 1));
     131                 : }
     132                 : /* }}} */
     133                 : 
     134                 : PHPAPI char *php_gcvt(double value, int ndigit, char dec_point, char exponent, char *buf) /* {{{ */
     135            7213 : {
     136                 :         char *digits, *dst, *src;
     137                 :         int i, decpt, sign;
     138                 : 
     139            7213 :         digits = zend_dtoa(value, 2, ndigit, &decpt, &sign, NULL);
     140            7213 :         if (decpt == 9999) {
     141                 :                 /*
     142                 :                  * Infinity or NaN, convert to inf or nan with sign.
     143                 :                  * We assume the buffer is at least ndigit long.
     144                 :                  */
     145              12 :                 snprintf(buf, ndigit + 1, "%s%s", (sign && *digits == 'I') ? "-" : "", *digits == 'I' ? "INF" : "NAN");
     146              12 :                 zend_freedtoa(digits);
     147              12 :                 return (buf);
     148                 :         }
     149                 : 
     150            7201 :         dst = buf;
     151            7201 :         if (sign) {
     152            1659 :                 *dst++ = '-';
     153                 :         }
     154                 : 
     155            7629 :         if ((decpt >= 0 && decpt > ndigit) || decpt < -3) { /* use E-style */
     156                 :                 /* exponential format (e.g. 1.2345e+13) */
     157             428 :                 if (--decpt < 0) {
     158             330 :                         sign = 1;
     159             330 :                         decpt = -decpt;
     160                 :                 } else {
     161              98 :                         sign = 0;
     162                 :                 }
     163             428 :                 src = digits;
     164             428 :                 *dst++ = *src++;
     165             428 :                 *dst++ = dec_point;
     166             428 :                 if (*src == '\0') {
     167             134 :                         *dst++ = '0';
     168                 :                 } else {
     169                 :                         do {
     170            2805 :                                 *dst++ = *src++;
     171            2805 :                         } while (*src != '\0');
     172                 :                 }
     173             428 :                 *dst++ = exponent;
     174             428 :                 if (sign) {
     175             330 :                         *dst++ = '-';
     176                 :                 } else {
     177              98 :                         *dst++ = '+';
     178                 :                 }
     179             428 :                 if (decpt < 10) {
     180             249 :                         *dst++ = '0' + decpt;
     181             249 :                         *dst = '\0';
     182                 :                 } else {
     183                 :                         /* XXX - optimize */
     184             179 :                         for (sign = decpt, i = 0; (sign /= 10) != 0; i++)
     185                 :                                 continue;
     186             179 :                         dst[i + 1] = '\0';
     187             731 :                         while (decpt != 0) {
     188             373 :                                 dst[i--] = '0' + decpt % 10;
     189             373 :                                 decpt /= 10;
     190                 :                         }
     191                 :                 }
     192            6773 :         } else if (decpt < 0) {
     193                 :                 /* standard format 0. */
     194             240 :                 *dst++ = '0';   /* zero before decimal point */
     195             240 :                 *dst++ = dec_point;
     196                 :                 do {
     197             425 :                         *dst++ = '0';
     198             425 :                 } while (++decpt < 0);
     199             240 :                 src = digits;
     200            1945 :                 while (*src != '\0') {
     201            1465 :                         *dst++ = *src++;
     202                 :                 }
     203             240 :                 *dst = '\0';
     204                 :         } else {
     205                 :                 /* standard format */
     206           27267 :                 for (i = 0, src = digits; i < decpt; i++) {
     207           20734 :                         if (*src != '\0') {
     208           17589 :                                 *dst++ = *src++;
     209                 :                         } else {
     210            3145 :                                 *dst++ = '0';
     211                 :                         }
     212                 :                 }
     213            6533 :                 if (*src != '\0') {
     214            3236 :                         if (src == digits) {
     215             622 :                                 *dst++ = '0';   /* zero before decimal point */
     216                 :                         }
     217            3236 :                         *dst++ = dec_point;
     218           17283 :                         for (i = decpt; digits[i] != '\0'; i++) {
     219           14047 :                 *dst++ = digits[i];
     220                 :             }
     221                 :         }
     222            6533 :         *dst = '\0';
     223                 :     }
     224            7201 :     zend_freedtoa(digits);
     225            7201 :     return (buf);
     226                 : }
     227                 : /* }}} */
     228                 : 
     229                 : /* Apache license {{{ */
     230                 : /* ====================================================================
     231                 :  * Copyright (c) 1995-1998 The Apache Group.  All rights reserved.
     232                 :  *
     233                 :  * Redistribution and use in source and binary forms, with or without
     234                 :  * modification, are permitted provided that the following conditions
     235                 :  * are met:
     236                 :  *
     237                 :  * 1. Redistributions of source code must retain the above copyright
     238                 :  *    notice, this list of conditions and the following disclaimer.
     239                 :  *
     240                 :  * 2. Redistributions in binary form must reproduce the above copyright
     241                 :  *    notice, this list of conditions and the following disclaimer in
     242                 :  *    the documentation and/or other materials provided with the
     243                 :  *    distribution.
     244                 :  *
     245                 :  * 3. All advertising materials mentioning features or use of this
     246                 :  *    software must display the following acknowledgment:
     247                 :  *    "This product includes software developed by the Apache Group
     248                 :  *    for use in the Apache HTTP server project (http://www.apache.org/)."
     249                 :  *
     250                 :  * 4. The names "Apache Server" and "Apache Group" must not be used to
     251                 :  *    endorse or promote products derived from this software without
     252                 :  *    prior written permission.
     253                 :  *
     254                 :  * 5. Redistributions of any form whatsoever must retain the following
     255                 :  *    acknowledgment:
     256                 :  *    "This product includes software developed by the Apache Group
     257                 :  *    for use in the Apache HTTP server project (http://www.apache.org/)."
     258                 :  *
     259                 :  * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY
     260                 :  * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     261                 :  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     262                 :  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE APACHE GROUP OR
     263                 :  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     264                 :  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     265                 :  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
     266                 :  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     267                 :  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
     268                 :  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     269                 :  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
     270                 :  * OF THE POSSIBILITY OF SUCH DAMAGE.
     271                 :  * ====================================================================
     272                 :  *
     273                 :  * This software consists of voluntary contributions made by many
     274                 :  * individuals on behalf of the Apache Group and was originally based
     275                 :  * on public domain software written at the National Center for
     276                 :  * Supercomputing Applications, University of Illinois, Urbana-Champaign.
     277                 :  * For more information on the Apache Group and the Apache HTTP server
     278                 :  * project, please see <http://www.apache.org/>.
     279                 :  *
     280                 :  * This code is based on, and used with the permission of, the
     281                 :  * SIO stdio-replacement strx_* functions by Panos Tsirigotis
     282                 :  * <panos@alumni.cs.colorado.edu> for xinetd.
     283                 :  */
     284                 : /* }}} */
     285                 : 
     286                 : #define FALSE                   0
     287                 : #define TRUE                    1
     288                 : #define NUL                     '\0'
     289                 : #define INT_NULL                ((int *)0)
     290                 : 
     291                 : #define S_NULL                  "(null)"
     292                 : #define S_NULL_LEN              6
     293                 : 
     294                 : #define FLOAT_DIGITS            6
     295                 : #define EXPONENT_LENGTH         10
     296                 : 
     297                 : 
     298                 : /*
     299                 :  * Convert num to its decimal format.
     300                 :  * Return value:
     301                 :  *   - a pointer to a string containing the number (no sign)
     302                 :  *   - len contains the length of the string
     303                 :  *   - is_negative is set to TRUE or FALSE depending on the sign
     304                 :  *     of the number (always set to FALSE if is_unsigned is TRUE)
     305                 :  *
     306                 :  * The caller provides a buffer for the string: that is the buf_end argument
     307                 :  * which is a pointer to the END of the buffer + 1 (i.e. if the buffer
     308                 :  * is declared as buf[ 100 ], buf_end should be &buf[ 100 ])
     309                 :  */
     310                 : /* char *ap_php_conv_10() {{{ */
     311                 : char * ap_php_conv_10(register wide_int num, register bool_int is_unsigned,
     312                 :            register bool_int * is_negative, char *buf_end, register int *len)
     313         4014502 : {
     314         4014502 :         register char *p = buf_end;
     315                 :         register u_wide_int magnitude;
     316                 : 
     317         4014502 :         if (is_unsigned) {
     318            1759 :                 magnitude = (u_wide_int) num;
     319            1759 :                 *is_negative = FALSE;
     320                 :         } else {
     321         4012743 :                 *is_negative = (num < 0);
     322                 : 
     323                 :                 /*
     324                 :                  * On a 2's complement machine, negating the most negative integer
     325                 :                  * results in a number that cannot be represented as a signed integer.
     326                 :                  * Here is what we do to obtain the number's magnitude:
     327                 :                  *      a. add 1 to the number
     328                 :                  *      b. negate it (becomes positive)
     329                 :                  *      c. convert it to unsigned
     330                 :                  *      d. add 1
     331                 :                  */
     332         4012743 :                 if (*is_negative) {
     333            2765 :                         wide_int t = num + 1;
     334                 : 
     335            2765 :                         magnitude = ((u_wide_int) - t) + 1;
     336                 :                 } else
     337         4009978 :                         magnitude = (u_wide_int) num;
     338                 :         }
     339                 : 
     340                 :         /*
     341                 :          * We use a do-while loop so that we write at least 1 digit
     342                 :          */
     343                 :         do {
     344        19437001 :                 register u_wide_int new_magnitude = magnitude / 10;
     345                 : 
     346        19437001 :                 *--p = (char)(magnitude - new_magnitude * 10 + '0');
     347        19437001 :                 magnitude = new_magnitude;
     348                 :         }
     349        19437001 :         while (magnitude);
     350                 : 
     351         4014502 :         *len = buf_end - p;
     352         4014502 :         return (p);
     353                 : }
     354                 : /* }}} */
     355                 : 
     356                 : /* If you change this value then also change bug24640.phpt.
     357                 :  * Also NDIG must be reasonable smaller than NUM_BUF_SIZE.
     358                 :  */
     359                 : #define NDIG    320
     360                 : 
     361                 : 
     362                 : /*
     363                 :  * Convert a floating point number to a string formats 'f', 'e' or 'E'.
     364                 :  * The result is placed in buf, and len denotes the length of the string
     365                 :  * The sign is returned in the is_negative argument (and is not placed
     366                 :  * in buf).
     367                 :  */
     368                 : /* PHPAPI char *php_conf_fp() {{{ */
     369                 : PHPAPI char * php_conv_fp(register char format, register double num,
     370                 :                  boolean_e add_dp, int precision, char dec_point, bool_int * is_negative, char *buf, int *len)
     371          105347 : {
     372          105347 :         register char *s = buf;
     373                 :         register char *p, *p_orig;
     374                 :         int decimal_point;
     375                 : 
     376          105347 :         if (precision >= NDIG - 1) {
     377               1 :                 precision = NDIG - 2;
     378                 :         }
     379                 : 
     380          105347 :         if (format == 'F')
     381          104377 :                 p_orig = p = php_fcvt(num, precision, &decimal_point, is_negative);
     382                 :         else                                            /* either e or E format */
     383             970 :                 p_orig = p = php_ecvt(num, precision + 1, &decimal_point, is_negative);
     384                 : 
     385                 :         /*
     386                 :          * Check for Infinity and NaN
     387                 :          */
     388          105347 :         if (isalpha((int)*p)) {
     389               0 :                 *len = strlen(p);
     390               0 :                 memcpy(buf, p, *len + 1);
     391               0 :                 *is_negative = FALSE;
     392               0 :                 free(p_orig);
     393               0 :                 return (buf);
     394                 :         }
     395          105347 :         if (format == 'F') {
     396          104377 :                 if (decimal_point <= 0) {
     397          100432 :                         if (num != 0 || precision > 0) {
     398          100425 :                                 *s++ = '0';
     399          100425 :                                 if (precision > 0) {
     400          100425 :                                         *s++ = dec_point;
     401          212172 :                                         while (decimal_point++ < 0)
     402           11322 :                                                 *s++ = '0';
     403               0 :                                 } else if (add_dp) {
     404               0 :                                         *s++ = dec_point;
     405                 :                                 }
     406                 :                         }
     407                 :                 } else {
     408            3945 :                         int addz = decimal_point >= NDIG ? decimal_point - NDIG + 1 : 0;
     409            3945 :                         decimal_point -= addz;
     410           25014 :                         while (decimal_point-- > 0) {
     411           17124 :                                 *s++ = *p++;
     412                 :                         }
     413            7890 :                         while (addz-- > 0) {
     414               0 :                                 *s++ = '0';
     415                 :                         }
     416            3945 :                         if (precision > 0 || add_dp) {
     417            2592 :                                 *s++ = dec_point;
     418                 :                         }
     419                 :                 }
     420                 :         } else {
     421             970 :                 *s++ = *p++;
     422             970 :                 if (precision > 0 || add_dp)
     423             969 :                         *s++ = '.';
     424                 :         }
     425                 : 
     426                 :         /*
     427                 :          * copy the rest of p, the NUL is NOT copied
     428                 :          */
     429         1022790 :         while (*p)
     430          812096 :                 *s++ = *p++;
     431                 : 
     432          105347 :         if (format != 'F') {
     433                 :                 char temp[EXPONENT_LENGTH];             /* for exponent conversion */
     434                 :                 int t_len;
     435                 :                 bool_int exponent_is_negative;
     436                 : 
     437             970 :                 *s++ = format;                  /* either e or E */
     438             970 :                 decimal_point--;
     439             970 :                 if (decimal_point != 0) {
     440             437 :                         p = ap_php_conv_10((wide_int) decimal_point, FALSE, &exponent_is_negative,
     441                 :                                                 &temp[EXPONENT_LENGTH], &t_len);
     442             437 :                         *s++ = exponent_is_negative ? '-' : '+';
     443                 : 
     444                 :                         /*
     445                 :                          * Make sure the exponent has at least 2 digits
     446                 :                          */
     447            1341 :                         while (t_len--)
     448             467 :                                 *s++ = *p++;
     449                 :                 } else {
     450             533 :                         *s++ = '+';
     451             533 :                         *s++ = '0';
     452                 :                 }
     453                 :         }
     454          105347 :         *len = s - buf;
     455          105347 :         free(p_orig);
     456          105347 :         return (buf);
     457                 : }
     458                 : /* }}} */
     459                 : 
     460                 : /*
     461                 :  * Convert num to a base X number where X is a power of 2. nbits determines X.
     462                 :  * For example, if nbits is 3, we do base 8 conversion
     463                 :  * Return value:
     464                 :  *      a pointer to a string containing the number
     465                 :  *
     466                 :  * The caller provides a buffer for the string: that is the buf_end argument
     467                 :  * which is a pointer to the END of the buffer + 1 (i.e. if the buffer
     468                 :  * is declared as buf[ 100 ], buf_end should be &buf[ 100 ])
     469                 :  */
     470                 : char * ap_php_conv_p2(register u_wide_int num, register int nbits, char format, char *buf_end, register int *len) /* {{{ */
     471            1836 : {
     472            1836 :         register int mask = (1 << nbits) - 1;
     473            1836 :         register char *p = buf_end;
     474                 :         static char low_digits[] = "0123456789abcdef";
     475                 :         static char upper_digits[] = "0123456789ABCDEF";
     476            1836 :         register char *digits = (format == 'X') ? upper_digits : low_digits;
     477                 : 
     478                 :         do {
     479            8791 :                 *--p = digits[num & mask];
     480            8791 :                 num >>= nbits;
     481                 :         }
     482            8791 :         while (num);
     483                 : 
     484            1836 :         *len = buf_end - p;
     485            1836 :         return (p);
     486                 : }
     487                 : /* }}} */
     488                 : 
     489                 : /*
     490                 :  * NUM_BUF_SIZE is the size of the buffer used for arithmetic conversions
     491                 :  *
     492                 :  * XXX: this is a magic number; do not decrease it
     493                 :  */
     494                 : #define NUM_BUF_SIZE            512
     495                 : 
     496                 : 
     497                 : /*
     498                 :  * Descriptor for buffer area
     499                 :  */
     500                 : struct buf_area {
     501                 :         char *buf_end;
     502                 :         char *nextb;                            /* pointer to next byte to read/write   */
     503                 : };
     504                 : 
     505                 : typedef struct buf_area buffy;
     506                 : 
     507                 : /*
     508                 :  * The INS_CHAR macro inserts a character in the buffer and writes
     509                 :  * the buffer back to disk if necessary
     510                 :  * It uses the char pointers sp and bep:
     511                 :  *      sp points to the next available character in the buffer
     512                 :  *      bep points to the end-of-buffer+1
     513                 :  * While using this macro, note that the nextb pointer is NOT updated.
     514                 :  *
     515                 :  * NOTE: Evaluation of the c argument should not have any side-effects
     516                 :  */
     517                 : #define INS_CHAR(c, sp, bep, cc) \
     518                 :         {                            \
     519                 :                 if (sp < bep)            \
     520                 :                 {                        \
     521                 :                         *sp++ = c;           \
     522                 :                 }                        \
     523                 :                 cc++;                    \
     524                 :         }
     525                 : 
     526                 : #define NUM( c )                        ( c - '0' )
     527                 : 
     528                 : #define STR_TO_DEC( str, num )          \
     529                 :     num = NUM( *str++ ) ;               \
     530                 :     while ( isdigit((int)*str ) )               \
     531                 :     {                                   \
     532                 :         num *= 10 ;                     \
     533                 :         num += NUM( *str++ ) ;          \
     534                 :     }
     535                 : 
     536                 : /*
     537                 :  * This macro does zero padding so that the precision
     538                 :  * requirement is satisfied. The padding is done by
     539                 :  * adding '0's to the left of the string that is going
     540                 :  * to be printed.
     541                 :  */
     542                 : #define FIX_PRECISION( adjust, precision, s, s_len )    \
     543                 :     if ( adjust )                                       \
     544                 :         while ( s_len < precision )                  \
     545                 :         {                                               \
     546                 :             *--s = '0' ;                                \
     547                 :             s_len++ ;                                   \
     548                 :         }
     549                 : 
     550                 : /*
     551                 :  * Macro that does padding. The padding is done by printing
     552                 :  * the character ch.
     553                 :  */
     554                 : #define PAD( width, len, ch )   do              \
     555                 :         {                                       \
     556                 :             INS_CHAR( ch, sp, bep, cc ) ;       \
     557                 :             width-- ;                           \
     558                 :         }                                       \
     559                 :         while ( width > len )
     560                 : 
     561                 : /*
     562                 :  * Prefix the character ch to the string str
     563                 :  * Increase length
     564                 :  * Set the has_prefix flag
     565                 :  */
     566                 : #define PREFIX( str, length, ch )        *--str = ch ; length++ ; has_prefix = YES
     567                 : 
     568                 : 
     569                 : /*
     570                 :  * Do format conversion placing the output in buffer
     571                 :  */
     572                 : static int format_converter(register buffy * odp, const char *fmt, va_list ap) /* {{{ */
     573          650010 : {
     574                 :         char *sp;
     575                 :         char *bep;
     576          650010 :         int cc = 0;
     577                 :         int i;
     578                 : 
     579          650010 :         char *s = NULL;
     580          650010 :         UChar *u = NULL;
     581                 :         char *q;
     582                 :         int s_len, s_unicode, u_len, free_zcopy;
     583                 :         zval *zvp, zcopy;
     584                 : 
     585          650010 :         int min_width = 0;
     586          650010 :         int precision = 0;
     587                 :         enum {
     588                 :                 LEFT, RIGHT
     589                 :         } adjust;
     590                 :         char pad_char;
     591                 :         char prefix_char;
     592                 : 
     593                 :         double fp_num;
     594          650010 :         wide_int i_num = (wide_int) 0;
     595                 :         u_wide_int ui_num;
     596                 : 
     597                 :         char num_buf[NUM_BUF_SIZE];
     598                 :         char char_buf[2];                       /* for printing %% and %<unknown> */
     599                 :         char *s_to_free;  /* tmp var to keep the string to be freed in */
     600                 : 
     601                 : #ifdef HAVE_LOCALE_H
     602          650010 :         struct lconv *lconv = NULL;
     603                 : #endif
     604                 : 
     605                 :         /*
     606                 :          * Flag variables
     607                 :          */
     608                 :         length_modifier_e modifier;
     609                 :         boolean_e alternate_form;
     610                 :         boolean_e print_sign;
     611                 :         boolean_e print_blank;
     612                 :         boolean_e adjust_precision;
     613                 :         boolean_e adjust_width;
     614                 :         bool_int is_negative;
     615                 : 
     616                 :         TSRMLS_FETCH();
     617                 : 
     618          650010 :         sp = odp->nextb;
     619          650010 :         bep = odp->buf_end;
     620                 : 
     621         5177713 :         while (*fmt) {
     622         3877693 :                 if (*fmt != '%') {
     623         3023104 :                         INS_CHAR(*fmt, sp, bep, cc);
     624                 :                 } else {
     625                 :                         /*
     626                 :                          * Default variable settings
     627                 :                          */
     628          854589 :                         adjust = RIGHT;
     629          854589 :                         alternate_form = print_sign = print_blank = NO;
     630          854589 :                         pad_char = ' ';
     631          854589 :                         prefix_char = NUL;
     632          854589 :                         s_to_free = NULL;
     633          854589 :                         free_zcopy = 0;
     634          854589 :                         s_unicode = 0;
     635                 : 
     636          854589 :                         fmt++;
     637                 : 
     638                 :                         /*
     639                 :                          * Try to avoid checking for flags, width or precision
     640                 :                          */
     641          954994 :                         if (isascii((int)*fmt) && !islower((int)*fmt)) {
     642                 :                                 /*
     643                 :                                  * Recognize flags: -, #, BLANK, +
     644                 :                                  */
     645             289 :                                 for (;; fmt++) {
     646          100694 :                                         if (*fmt == '-')
     647               1 :                                                 adjust = LEFT;
     648          100693 :                                         else if (*fmt == '+')
     649               0 :                                                 print_sign = YES;
     650          100693 :                                         else if (*fmt == '#')
     651               0 :                                                 alternate_form = YES;
     652          100693 :                                         else if (*fmt == ' ')
     653               0 :                                                 print_blank = YES;
     654          100693 :                                         else if (*fmt == '0')
     655             288 :                                                 pad_char = '0';
     656                 :                                         else
     657          100405 :                                                 break;
     658             289 :                                 }
     659                 : 
     660                 :                                 /*
     661                 :                                  * Check if a width was specified
     662                 :                                  */
     663          100405 :                                 if (isdigit((int)*fmt)) {
     664             189 :                                         STR_TO_DEC(fmt, min_width);
     665             189 :                                         adjust_width = YES;
     666          100216 :                                 } else if (*fmt == '*') {
     667               0 :                                         min_width = va_arg(ap, int);
     668               0 :                                         fmt++;
     669               0 :                                         adjust_width = YES;
     670               0 :                                         if (min_width < 0) {
     671               0 :                                                 adjust = LEFT;
     672               0 :                                                 min_width = -min_width;
     673                 :                                         }
     674                 :                                 } else
     675          100216 :                                         adjust_width = NO;
     676                 : 
     677                 :                                 /*
     678                 :                                  * Check if a precision was specified
     679                 :                                  *
     680                 :                                  * XXX: an unreasonable amount of precision may be specified
     681                 :                                  * resulting in overflow of num_buf. Currently we
     682                 :                                  * ignore this possibility.
     683                 :                                  */
     684          100405 :                                 if (*fmt == '.') {
     685          100216 :                                         adjust_precision = YES;
     686          100216 :                                         fmt++;
     687          100216 :                                         if (isdigit((int)*fmt)) {
     688          100116 :                                                 STR_TO_DEC(fmt, precision);
     689             100 :                                         } else if (*fmt == '*') {
     690             100 :                                                 precision = va_arg(ap, int);
     691             100 :                                                 fmt++;
     692             100 :                                                 if (precision < 0)
     693               0 :                                                         precision = 0;
     694                 :                                         } else
     695               0 :                                                 precision = 0;
     696                 :                                 } else
     697             189 :                                         adjust_precision = NO;
     698                 :                         } else
     699          754184 :                                 adjust_precision = adjust_width = NO;
     700                 : 
     701                 :                         /*
     702                 :                          * Modifier check
     703                 :                          */
     704          854589 :                         switch (*fmt) {
     705                 :                                 case 'L':
     706               0 :                                         fmt++;
     707               0 :                                         modifier = LM_LONG_DOUBLE;
     708               0 :                                         break;
     709                 :                                 case 'I':
     710               0 :                                         fmt++;
     711                 : #if SIZEOF_LONG_LONG
     712               0 :                                         if (*fmt == '6' && *(fmt+1) == '4') {
     713               0 :                                                 fmt += 2;
     714               0 :                                                 modifier = LM_LONG_LONG;
     715                 :                                         } else
     716                 : #endif
     717               0 :                                                 if (*fmt == '3' && *(fmt+1) == '2') {
     718               0 :                                                         fmt += 2;
     719               0 :                                                         modifier = LM_LONG;
     720                 :                                                 } else {
     721                 : #ifdef _WIN64
     722                 :                                                         modifier = LM_LONG_LONG;
     723                 : #else
     724               0 :                                                         modifier = LM_LONG;
     725                 : #endif
     726                 :                                                 }
     727               0 :                                         break;
     728                 :                                 case 'l':
     729          100880 :                                         fmt++;
     730                 : #if SIZEOF_LONG_LONG
     731          100880 :                                         if (*fmt == 'l') {
     732               0 :                                                 fmt++;
     733               0 :                                                 modifier = LM_LONG_LONG;
     734                 :                                         } else
     735                 : #endif
     736          100880 :                                                 modifier = LM_LONG;
     737          100880 :                                         break;
     738                 :                                 case 'z':
     739               0 :                                         fmt++;
     740               0 :                                         modifier = LM_SIZE_T;
     741               0 :                                         break;
     742                 :                                 case 'j':
     743               0 :                                         fmt++;
     744                 : #if SIZEOF_INTMAX_T
     745               0 :                                         modifier = LM_INTMAX_T;
     746                 : #else
     747                 :                                         modifier = LM_SIZE_T;
     748                 : #endif
     749               0 :                                         break;
     750                 :                                 case 't':
     751               0 :                                         fmt++;
     752                 : #if SIZEOF_PTRDIFF_T
     753               0 :                                         modifier = LM_PTRDIFF_T;
     754                 : #else
     755                 :                                         modifier = LM_SIZE_T;
     756                 : #endif
     757               0 :                                         break;
     758                 :                                 case 'h':
     759               0 :                                         fmt++;
     760               0 :                                         if (*fmt == 'h') {
     761               0 :                                                 fmt++;
     762                 :                                         }
     763                 :                                         /* these are promoted to int, so no break */
     764                 :                                 default:
     765          753709 :                                         modifier = LM_STD;
     766                 :                                         break;
     767                 :                         }
     768                 : 
     769                 :                         /*
     770                 :                          * Argument extraction and printing.
     771                 :                          * First we determine the argument type.
     772                 :                          * Then, we convert the argument to a string.
     773                 :                          * On exit from the switch, s points to the string that
     774                 :                          * must be printed, s_len has the length of the string
     775                 :                          * The precision requirements, if any, are reflected in s_len.
     776                 :                          *
     777                 :                          * NOTE: pad_char may be set to '0' because of the 0 flag.
     778                 :                          *   It is reset to ' ' by non-numeric formats
     779                 :                          */
     780          854589 :                         switch (*fmt) {
     781                 :                                 case 'Z':
     782               0 :                                         zvp = (zval*) va_arg(ap, zval*);
     783               0 :                                         zend_make_string_zval(zvp, &zcopy, &free_zcopy);
     784               0 :                                         if (free_zcopy) {
     785               0 :                                                 zvp = &zcopy;
     786                 :                                         }
     787               0 :                                         s_len = Z_UNILEN_P(zvp);
     788               0 :                                         s = Z_STRVAL_P(zvp);
     789               0 :                                         if (adjust_precision && precision < s_len) {
     790               0 :                                                 s_len = precision;
     791                 :                                         }
     792               0 :                                         break;
     793                 :                                 case 'u':
     794             732 :                                         switch(modifier) {
     795                 :                                                 default:
     796             732 :                                                         i_num = (wide_int) va_arg(ap, unsigned int);
     797             732 :                                                         break;
     798                 :                                                 case LM_LONG_DOUBLE:
     799               0 :                                                         goto fmt_error;
     800                 :                                                 case LM_LONG:
     801               0 :                                                         i_num = (wide_int) va_arg(ap, unsigned long int);
     802               0 :                                                         break;
     803                 :                                                 case LM_SIZE_T:
     804               0 :                                                         i_num = (wide_int) va_arg(ap, size_t);
     805               0 :                                                         break;
     806                 : #if SIZEOF_LONG_LONG
     807                 :                                                 case LM_LONG_LONG:
     808               0 :                                                         i_num = (wide_int) va_arg(ap, u_wide_int);
     809               0 :                                                         break;
     810                 : #endif
     811                 : #if SIZEOF_INTMAX_T
     812                 :                                                 case LM_INTMAX_T:
     813               0 :                                                         i_num = (wide_int) va_arg(ap, uintmax_t);
     814               0 :                                                         break;
     815                 : #endif
     816                 : #if SIZEOF_PTRDIFF_T
     817                 :                                                 case LM_PTRDIFF_T:
     818               0 :                                                         i_num = (wide_int) va_arg(ap, ptrdiff_t);
     819                 :                                                         break;
     820                 : #endif
     821                 :                                         }
     822                 :                                         /*
     823                 :                                          * The rest also applies to other integer formats, so fall
     824                 :                                          * into that case.
     825                 :                                          */
     826                 :                                 case 'd':
     827                 :                                 case 'i':
     828                 :                                         /*
     829                 :                                          * Get the arg if we haven't already.
     830                 :                                          */
     831          103682 :                                         if ((*fmt) != 'u') {
     832          102950 :                                                 switch(modifier) {
     833                 :                                                         default:
     834            2076 :                                                                 i_num = (wide_int) va_arg(ap, int);
     835            2076 :                                                                 break;
     836                 :                                                         case LM_LONG_DOUBLE:
     837               0 :                                                                 goto fmt_error;
     838                 :                                                         case LM_LONG:
     839          100874 :                                                                 i_num = (wide_int) va_arg(ap, long int);
     840          100874 :                                                                 break;
     841                 :                                                         case LM_SIZE_T:
     842                 : #if SIZEOF_SSIZE_T
     843               0 :                                                                 i_num = (wide_int) va_arg(ap, ssize_t);
     844                 : #else
     845                 :                                                                 i_num = (wide_int) va_arg(ap, size_t);
     846                 : #endif
     847               0 :                                                                 break;
     848                 : #if SIZEOF_LONG_LONG
     849                 :                                                         case LM_LONG_LONG:
     850               0 :                                                                 i_num = (wide_int) va_arg(ap, wide_int);
     851               0 :                                                                 break;
     852                 : #endif
     853                 : #if SIZEOF_INTMAX_T
     854                 :                                                         case LM_INTMAX_T:
     855               0 :                                                                 i_num = (wide_int) va_arg(ap, intmax_t);
     856               0 :                                                                 break;
     857                 : #endif
     858                 : #if SIZEOF_PTRDIFF_T
     859                 :                                                         case LM_PTRDIFF_T:
     860               0 :                                                                 i_num = (wide_int) va_arg(ap, ptrdiff_t);
     861                 :                                                                 break;
     862                 : #endif
     863                 :                                                 }
     864                 :                                         }
     865          103682 :                                         s = ap_php_conv_10(i_num, (*fmt) == 'u', &is_negative,
     866                 :                                                                 &num_buf[NUM_BUF_SIZE], &s_len);
     867          103682 :                                         FIX_PRECISION(adjust_precision, precision, s, s_len);
     868                 : 
     869          103682 :                                         if (*fmt != 'u') {
     870          102950 :                                                 if (is_negative)
     871               5 :                                                         prefix_char = '-';
     872          102945 :                                                 else if (print_sign)
     873               0 :                                                         prefix_char = '+';
     874          102945 :                                                 else if (print_blank)
     875               0 :                                                         prefix_char = ' ';
     876                 :                                         }
     877          103682 :                                         break;
     878                 : 
     879                 : 
     880                 :                                 case 'o':
     881               0 :                                         switch(modifier) {
     882                 :                                                 default:
     883               0 :                                                         ui_num = (u_wide_int) va_arg(ap, unsigned int);
     884               0 :                                                         break;
     885                 :                                                 case LM_LONG_DOUBLE:
     886               0 :                                                         goto fmt_error;
     887                 :                                                 case LM_LONG:
     888               0 :                                                         ui_num = (u_wide_int) va_arg(ap, unsigned long int);
     889               0 :                                                         break;
     890                 :                                                 case LM_SIZE_T:
     891               0 :                                                         ui_num = (u_wide_int) va_arg(ap, size_t);
     892               0 :                                                         break;
     893                 : #if SIZEOF_LONG_LONG
     894                 :                                                 case LM_LONG_LONG:
     895               0 :                                                         ui_num = (u_wide_int) va_arg(ap, u_wide_int);
     896               0 :                                                         break;
     897                 : #endif
     898                 : #if SIZEOF_INTMAX_T
     899                 :                                                 case LM_INTMAX_T:
     900               0 :                                                         ui_num = (u_wide_int) va_arg(ap, uintmax_t);
     901               0 :                                                         break;
     902                 : #endif
     903                 : #if SIZEOF_PTRDIFF_T
     904                 :                                                 case LM_PTRDIFF_T:
     905               0 :                                                         ui_num = (u_wide_int) va_arg(ap, ptrdiff_t);
     906                 :                                                         break;
     907                 : #endif
     908                 :                                         }
     909               0 :                                         s = ap_php_conv_p2(ui_num, 3, *fmt,
     910                 :                                                                 &num_buf[NUM_BUF_SIZE], &s_len);
     911               0 :                                         FIX_PRECISION(adjust_precision, precision, s, s_len);
     912               0 :                                         if (alternate_form && *s != '0') {
     913               0 :                                                 *--s = '0';
     914               0 :                                                 s_len++;
     915                 :                                         }
     916               0 :                                         break;
     917                 : 
     918                 : 
     919                 :                                 case 'x':
     920                 :                                 case 'X':
     921               6 :                                         switch(modifier) {
     922                 :                                                 default:
     923               0 :                                                         ui_num = (u_wide_int) va_arg(ap, unsigned int);
     924               0 :                                                         break;
     925                 :                                                 case LM_LONG_DOUBLE:
     926               0 :                                                         goto fmt_error;
     927                 :                                                 case LM_LONG:
     928               6 :                                                         ui_num = (u_wide_int) va_arg(ap, unsigned long int);
     929               6 :                                                         break;
     930                 :                                                 case LM_SIZE_T:
     931               0 :                                                         ui_num = (u_wide_int) va_arg(ap, size_t);
     932               0 :                                                         break;
     933                 : #if SIZEOF_LONG_LONG
     934                 :                                                 case LM_LONG_LONG:
     935               0 :                                                         ui_num = (u_wide_int) va_arg(ap, u_wide_int);
     936               0 :                                                         break;
     937                 : #endif
     938                 : #if SIZEOF_INTMAX_T
     939                 :                                                 case LM_INTMAX_T:
     940               0 :                                                         ui_num = (u_wide_int) va_arg(ap, uintmax_t);
     941               0 :                                                         break;
     942                 : #endif
     943                 : #if SIZEOF_PTRDIFF_T
     944                 :                                                 case LM_PTRDIFF_T:
     945               0 :                                                         ui_num = (u_wide_int) va_arg(ap, ptrdiff_t);
     946                 :                                                         break;
     947                 : #endif
     948                 :                                         }
     949               6 :                                         s = ap_php_conv_p2(ui_num, 4, *fmt,
     950                 :                                                                 &num_buf[NUM_BUF_SIZE], &s_len);
     951               6 :                                         FIX_PRECISION(adjust_precision, precision, s, s_len);
     952               6 :                                         if (alternate_form && i_num != 0) {
     953               0 :                                                 *--s = *fmt;    /* 'x' or 'X' */
     954               0 :                                                 *--s = '0';
     955               0 :                                                 s_len += 2;
     956                 :                                         }
     957               6 :                                         break;
     958                 : 
     959                 :                                 case 'v':
     960               0 :                                         goto fmt_unicode;
     961                 :                                         break;
     962                 : 
     963                 :                                 case 'R':
     964                 :                                 {
     965               0 :                                         int type = va_arg(ap, int);
     966               0 :                                         if (type != IS_UNICODE) {
     967               0 :                                                 if (alternate_form) {
     968               0 :                                                         va_arg(ap, UConverter *);
     969                 :                                                 }
     970               0 :                                                 goto fmt_string;
     971                 :                                         }
     972                 :                                 }
     973                 :                                 /* break omitted */
     974                 : 
     975                 :                                 case 'r':
     976               0 : fmt_unicode:
     977                 :                                 {
     978               0 :                                         UConverter *conv = ZEND_U_CONVERTER(UG(output_encoding_conv));
     979               0 :                                         UErrorCode status = U_ZERO_ERROR;
     980               0 :                                         char *res = NULL;
     981                 : 
     982               0 :                                         if (alternate_form) {
     983               0 :                                                 conv = va_arg(ap, UConverter *);
     984                 :                                         }
     985                 : 
     986               0 :                                         u = va_arg(ap, UChar *);
     987               0 :                                         if (u == NULL) {
     988               0 :                                                 s = S_NULL;
     989               0 :                                                 s_len = S_NULL_LEN;
     990               0 :                                                 break;
     991                 :                                         }
     992                 : 
     993               0 :                                         u_len = u_strlen(u);
     994               0 :                                         zend_unicode_to_string_ex(conv, &res, &s_len, u, u_len, &status);
     995               0 :                                         if (U_FAILURE(status)) {
     996               0 :                                                 php_error(E_WARNING, "Could not convert Unicode to printable form in s[np]printf call");
     997               0 :                                                 return (cc);
     998                 :                                         }
     999               0 :                                         s = res;
    1000               0 :                                         s_to_free = s;
    1001                 : 
    1002               0 :                                         pad_char = ' ';
    1003               0 :                                         break;
    1004                 :                                 }
    1005                 : 
    1006                 :                                 case 's':
    1007          650355 : fmt_string:
    1008          650355 :                                         s = va_arg(ap, char *);
    1009          650355 :                                         if (s != NULL) {
    1010          650340 :                                                 s_len = strlen(s);
    1011          650340 :                                                 if (adjust_precision && precision < s_len)
    1012               0 :                                                         s_len = precision;
    1013                 :                                         } else {
    1014              15 :                                                 s = S_NULL;
    1015              15 :                                                 s_len = S_NULL_LEN;
    1016                 :                                         }
    1017          650355 :                                         pad_char = ' ';
    1018          650355 :                                         break;
    1019                 : 
    1020                 :                                 case 'f':
    1021                 :                                 case 'F':
    1022                 :                                 case 'e':
    1023                 :                                 case 'E':
    1024          100124 :                                         switch(modifier) {
    1025                 :                                                 case LM_LONG_DOUBLE:
    1026               0 :                                                         fp_num = (double) va_arg(ap, long double);
    1027               0 :                                                         break;
    1028                 :                                                 case LM_STD:
    1029          100124 :                                                         fp_num = va_arg(ap, double);
    1030          100124 :                                                         break;
    1031                 :                                                 default:
    1032               0 :                                                         goto fmt_error;
    1033                 :                                         }
    1034                 : 
    1035          100124 :                                         if (zend_isnan(fp_num)) {
    1036               0 :                                                 s = "NAN";
    1037               0 :                                                 s_len = 3;
    1038          100124 :                                         } else if (zend_isinf(fp_num)) {
    1039               0 :                                                 s = "INF";
    1040               0 :                                                 s_len = 3;
    1041                 :                                         } else {
    1042                 : #ifdef HAVE_LOCALE_H
    1043          100124 :                                                 if (!lconv) {
    1044          100124 :                                                         lconv = localeconv();
    1045                 :                                                 }
    1046                 : #endif
    1047          100124 :                                                 s = php_conv_fp((*fmt == 'f')?'F':*fmt, fp_num, alternate_form,
    1048                 :                                                  (adjust_precision == NO) ? FLOAT_DIGITS : precision,
    1049                 :                                                  (*fmt == 'f')?LCONV_DECIMAL_POINT:'.',
    1050                 :                                                                         &is_negative, &num_buf[1], &s_len);
    1051          100124 :                                                 if (is_negative)
    1052               0 :                                                         prefix_char = '-';
    1053          100124 :                                                 else if (print_sign)
    1054               0 :                                                         prefix_char = '+';
    1055          100124 :                                                 else if (print_blank)
    1056               0 :                                                         prefix_char = ' ';
    1057                 :                                         }
    1058          100124 :                                         break;
    1059                 : 
    1060                 : 
    1061                 :                                 case 'g':
    1062                 :                                 case 'k':
    1063                 :                                 case 'G':
    1064                 :                                 case 'H':
    1065               2 :                                         switch(modifier) {
    1066                 :                                                 case LM_LONG_DOUBLE:
    1067               0 :                                                         fp_num = (double) va_arg(ap, long double);
    1068               0 :                                                         break;
    1069                 :                                                 case LM_STD:
    1070               2 :                                                         fp_num = va_arg(ap, double);
    1071               2 :                                                         break;
    1072                 :                                                 default:
    1073               0 :                                                         goto fmt_error;
    1074                 :                                         }
    1075                 : 
    1076               2 :                                         if (zend_isnan(fp_num)) {
    1077               0 :                                                 s = "NAN";
    1078               0 :                                                 s_len = 3;
    1079               0 :                                                 break;
    1080               2 :                                         } else if (zend_isinf(fp_num)) {
    1081               0 :                                                 if (fp_num > 0) {
    1082               0 :                                                         s = "INF";
    1083               0 :                                                         s_len = 3;
    1084                 :                                                 } else {
    1085               0 :                                                         s = "-INF";
    1086               0 :                                                         s_len = 4;
    1087                 :                                                 }
    1088               0 :                                                 break;
    1089                 :                                         }
    1090                 : 
    1091               2 :                                         if (adjust_precision == NO)
    1092               0 :                                                 precision = FLOAT_DIGITS;
    1093               2 :                                         else if (precision == 0)
    1094               0 :                                                 precision = 1;
    1095                 :                                         /*
    1096                 :                                          * * We use &num_buf[ 1 ], so that we have room for the sign
    1097                 :                                          */
    1098                 : #ifdef HAVE_LOCALE_H
    1099               2 :                                         if (!lconv) {
    1100               2 :                                                 lconv = localeconv();
    1101                 :                                         }
    1102                 : #endif
    1103               2 :                                         s = php_gcvt(fp_num, precision, (*fmt == 'H' || *fmt == 'k') ? '.' : LCONV_DECIMAL_POINT, (*fmt == 'G' || *fmt == 'H')?'E':'e', &num_buf[1]);
    1104               2 :                                         if (*s == '-')
    1105               0 :                                                 prefix_char = *s++;
    1106               2 :                                         else if (print_sign)
    1107               0 :                                                 prefix_char = '+';
    1108               2 :                                         else if (print_blank)
    1109               0 :                                                 prefix_char = ' ';
    1110                 : 
    1111               2 :                                         s_len = strlen(s);
    1112                 : 
    1113               2 :                                         if (alternate_form && (q = strchr(s, '.')) == NULL)
    1114               0 :                                                 s[s_len++] = '.';
    1115               2 :                                         break;
    1116                 : 
    1117                 : 
    1118                 :                                 case 'c':
    1119             420 :                                         char_buf[0] = (char) (va_arg(ap, int));
    1120             420 :                                         s = &char_buf[0];
    1121             420 :                                         s_len = 1;
    1122             420 :                                         pad_char = ' ';
    1123             420 :                                         break;
    1124                 : 
    1125                 : 
    1126                 :                                 case '%':
    1127               0 :                                         char_buf[0] = '%';
    1128               0 :                                         s = &char_buf[0];
    1129               0 :                                         s_len = 1;
    1130               0 :                                         pad_char = ' ';
    1131               0 :                                         break;
    1132                 : 
    1133                 : 
    1134                 :                                 case 'n':
    1135               0 :                                         *(va_arg(ap, int *)) = cc;
    1136               0 :                                         goto skip_output;
    1137                 : 
    1138                 :                                         /*
    1139                 :                                          * Always extract the argument as a "char *" pointer. We
    1140                 :                                          * should be using "void *" but there are still machines
    1141                 :                                          * that don't understand it.
    1142                 :                                          * If the pointer size is equal to the size of an unsigned
    1143                 :                                          * integer we convert the pointer to a hex number, otherwise
    1144                 :                                          * we print "%p" to indicate that we don't handle "%p".
    1145                 :                                          */
    1146                 :                                 case 'p':
    1147                 :                                         if (sizeof(char *) <= sizeof(u_wide_int)) {
    1148               0 :                                                 ui_num = (u_wide_int)((size_t) va_arg(ap, char *));
    1149               0 :                                                 s = ap_php_conv_p2(ui_num, 4, 'x',
    1150                 :                                                                 &num_buf[NUM_BUF_SIZE], &s_len);
    1151               0 :                                                 if (ui_num != 0) {
    1152               0 :                                                         *--s = 'x';
    1153               0 :                                                         *--s = '0';
    1154               0 :                                                         s_len += 2;
    1155                 :                                                 }
    1156                 :                                         } else {
    1157                 :                                                 s = "%p";
    1158                 :                                                 s_len = 2;
    1159                 :                                         }
    1160               0 :                                         pad_char = ' ';
    1161               0 :                                         break;
    1162                 : 
    1163                 : 
    1164                 :                                 case NUL:
    1165                 :                                         /*
    1166                 :                                          * The last character of the format string was %.
    1167                 :                                          * We ignore it.
    1168                 :                                          */
    1169               0 :                                         continue;
    1170                 : 
    1171                 : 
    1172               0 : fmt_error:
    1173               0 :                                 php_error(E_ERROR, "Illegal length modifier specified '%c' in s[np]printf call", *fmt);
    1174                 :                                         /*
    1175                 :                                          * The default case is for unrecognized %'s.
    1176                 :                                          * We print %<char> to help the user identify what
    1177                 :                                          * option is not understood.
    1178                 :                                          * This is also useful in case the user wants to pass
    1179                 :                                          * the output of format_converter to another function
    1180                 :                                          * that understands some other %<char> (like syslog).
    1181                 :                                          * Note that we can't point s inside fmt because the
    1182                 :                                          * unknown <char> could be preceded by width etc.
    1183                 :                                          */
    1184                 :                                 default:
    1185               0 :                                         char_buf[0] = '%';
    1186               0 :                                         char_buf[1] = *fmt;
    1187               0 :                                         s = char_buf;
    1188               0 :                                         s_len = 2;
    1189               0 :                                         pad_char = ' ';
    1190                 :                                         break;
    1191                 :                         }
    1192                 : 
    1193          854589 :                         if (prefix_char != NUL) {
    1194               5 :                                 *--s = prefix_char;
    1195               5 :                                 s_len++;
    1196                 :                         }
    1197          854589 :                         if (adjust_width && adjust == RIGHT && min_width > s_len) {
    1198             175 :                                 if (pad_char == '0' && prefix_char != NUL) {
    1199               0 :                                         INS_CHAR(*s, sp, bep, cc)
    1200               0 :                                         s++;
    1201               0 :                                         s_len--;
    1202               0 :                                         min_width--;
    1203                 :                                 }
    1204             233 :                                 PAD(min_width, s_len, pad_char);
    1205                 :                         }
    1206                 :                         /*
    1207                 :                          * Print the string s.
    1208                 :                          */
    1209         8647161 :                         for (i = s_len; i != 0; i--) {
    1210         7792572 :                                 INS_CHAR(*s, sp, bep, cc);
    1211         7792572 :                                 s++;
    1212                 :                         }
    1213                 : 
    1214          854589 :                         if (s_to_free) {
    1215               0 :                                 efree(s_to_free);
    1216                 :                         }
    1217          854589 :                         if (free_zcopy) {
    1218               0 :                                 zval_dtor(&zcopy);
    1219                 :                         }
    1220                 : 
    1221          854589 :                         if (adjust_width && adjust == LEFT && min_width > s_len)
    1222               0 :                                 PAD(min_width, s_len, pad_char);
    1223                 :                 }
    1224         3877693 : skip_output:
    1225         3877693 :                 fmt++;
    1226                 :         }
    1227          650010 :         odp->nextb = sp;
    1228          650010 :         return (cc);
    1229                 : }
    1230                 : /* }}} */
    1231                 : 
    1232                 : /*
    1233                 :  * This is the general purpose conversion function.
    1234                 :  */
    1235                 : static void strx_printv(int *ccp, char *buf, size_t len, const char *format, va_list ap) /* {{{ */
    1236          650010 : {
    1237                 :         buffy od;
    1238                 :         int cc;
    1239                 : 
    1240                 :         /*
    1241                 :          * First initialize the descriptor
    1242                 :          * Notice that if no length is given, we initialize buf_end to the
    1243                 :          * highest possible address.
    1244                 :          */
    1245          650010 :         if (len == 0) {
    1246               0 :                 od.buf_end = (char *) ~0;
    1247               0 :                 od.nextb   = (char *) ~0;
    1248                 :         } else {
    1249          650010 :                 od.buf_end = &buf[len-1];
    1250          650010 :                 od.nextb   = buf;
    1251                 :         }
    1252                 : 
    1253                 :         /*
    1254                 :          * Do the conversion
    1255                 :          */
    1256          650010 :         cc = format_converter(&od, format, ap);
    1257          650010 :         if (len != 0 && od.nextb <= od.buf_end)
    1258          650010 :                 *(od.nextb) = '\0';
    1259          650010 :         if (ccp)
    1260          650010 :                 *ccp = cc;
    1261          650010 : }
    1262                 : /* }}} */
    1263                 : 
    1264                 : PHPAPI int ap_php_slprintf(char *buf, size_t len, const char *format,...) /* {{{ */
    1265          444533 : {
    1266                 :         unsigned int cc;
    1267                 :         va_list ap;
    1268                 : 
    1269          444533 :         va_start(ap, format);
    1270          444533 :         strx_printv(&cc, buf, len, format, ap);
    1271          444533 :         va_end(ap);
    1272          444533 :         if (cc >= len) {
    1273               0 :                 cc = len -1;
    1274               0 :                 buf[cc] = '\0';
    1275                 :         }
    1276          444533 :         return cc;
    1277                 : }
    1278                 : /* }}} */
    1279                 : 
    1280                 : PHPAPI int ap_php_vslprintf(char *buf, size_t len, const char *format, va_list ap) /* {{{ */
    1281               0 : {
    1282                 :         unsigned int cc;
    1283                 : 
    1284               0 :         strx_printv(&cc, buf, len, format, ap);
    1285               0 :         if (cc >= len) {
    1286               0 :                 cc = len -1;
    1287               0 :                 buf[cc] = '\0';
    1288                 :         }
    1289               0 :         return cc;
    1290                 : }
    1291                 : /* }}} */
    1292                 : 
    1293                 : PHPAPI int ap_php_snprintf(char *buf, size_t len, const char *format,...) /* {{{ */
    1294          205477 : {
    1295                 :         int cc;
    1296                 :         va_list ap;
    1297                 : 
    1298          205477 :         va_start(ap, format);
    1299          205477 :         strx_printv(&cc, buf, len, format, ap);
    1300          205477 :         va_end(ap);
    1301          205477 :         return (cc);
    1302                 : }
    1303                 : /* }}} */
    1304                 : 
    1305                 : PHPAPI int ap_php_vsnprintf(char *buf, size_t len, const char *format, va_list ap) /* {{{ */
    1306               0 : {
    1307                 :         int cc;
    1308                 : 
    1309               0 :         strx_printv(&cc, buf, len, format, ap);
    1310               0 :         return (cc);
    1311                 : }
    1312                 : /* }}} */
    1313                 : 
    1314                 : PHPAPI int ap_php_vasprintf(char **buf, const char *format, va_list ap) /* {{{ */
    1315               0 : {
    1316                 :         va_list ap2;
    1317                 :         int cc;
    1318                 : 
    1319               0 :         va_copy(ap2, ap);
    1320               0 :         cc = ap_php_vsnprintf(NULL, 0, format, ap2);
    1321               0 :         va_end(ap2);
    1322                 : 
    1323               0 :         *buf = NULL;
    1324                 : 
    1325               0 :         if (cc >= 0) {
    1326               0 :                 if ((*buf = malloc(++cc)) != NULL) {
    1327               0 :                         if ((cc = ap_php_vsnprintf(*buf, cc, format, ap)) < 0) {
    1328               0 :                                 free(*buf);
    1329               0 :                                 *buf = NULL;
    1330                 :                         }
    1331                 :                 }
    1332                 :         }
    1333                 : 
    1334               0 :         return cc;
    1335                 : }
    1336                 : /* }}} */
    1337                 : 
    1338                 : PHPAPI int ap_php_asprintf(char **buf, const char *format, ...) /* {{{ */
    1339               0 : {
    1340                 :         int cc;
    1341                 :         va_list ap;
    1342                 : 
    1343               0 :         va_start(ap, format);
    1344               0 :         cc = vasprintf(buf, format, ap);
    1345               0 :         va_end(ap);
    1346               0 :         return cc;
    1347                 : }
    1348                 : /* }}} */
    1349                 : 
    1350                 : /*
    1351                 :  * Local variables:
    1352                 :  * tab-width: 4
    1353                 :  * c-basic-offset: 4
    1354                 :  * End:
    1355                 :  * vim600: sw=4 ts=4 fdm=marker
    1356                 :  * vim<600: sw=4 ts=4
    1357                 :  */

Generated by: LTP GCOV extension version 1.5

Generated at Mon, 23 Nov 2009 17:39:47 +0000 (34 hours ago)

Copyright © 2005-2009 The PHP Group
All rights reserved.