Back to index

php5  5.3.10
spprintf.c
Go to the documentation of this file.
00001 /*
00002    +----------------------------------------------------------------------+
00003    | PHP Version 5                                                        |
00004    +----------------------------------------------------------------------+
00005    | Copyright (c) 1997-2012 The PHP Group                                |
00006    +----------------------------------------------------------------------+
00007    | This source file is subject to version 3.01 of the PHP license,      |
00008    | that is bundled with this package in the file LICENSE, and is        |
00009    | available through the world-wide-web at the following url:           |
00010    | http://www.php.net/license/3_01.txt                                  |
00011    | If you did not receive a copy of the PHP license and are unable to   |
00012    | obtain it through the world-wide-web, please send a note to          |
00013    | license@php.net so we can mail you a copy immediately.               |
00014    +----------------------------------------------------------------------+
00015    | Author: Marcus Boerger <helly@php.net>                               |
00016    +----------------------------------------------------------------------+
00017 */
00018 
00019 /* $Id: spprintf.c 321634 2012-01-01 13:15:04Z felipe $ */
00020 
00021 /* This is the spprintf implementation.
00022  * It has emerged from apache snprintf. See original header:
00023  */
00024 
00025 /* ====================================================================
00026  * Copyright (c) 1995-1998 The Apache Group.  All rights reserved.
00027  *
00028  * Redistribution and use in source and binary forms, with or without
00029  * modification, are permitted provided that the following conditions
00030  * are met:
00031  *
00032  * 1. Redistributions of source code must retain the above copyright
00033  *    notice, this list of conditions and the following disclaimer.
00034  *
00035  * 2. Redistributions in binary form must reproduce the above copyright
00036  *    notice, this list of conditions and the following disclaimer in
00037  *    the documentation and/or other materials provided with the
00038  *    distribution.
00039  *
00040  * 3. All advertising materials mentioning features or use of this
00041  *    software must display the following acknowledgment:
00042  *    "This product includes software developed by the Apache Group
00043  *    for use in the Apache HTTP server project (http://www.apache.org/)."
00044  *
00045  * 4. The names "Apache Server" and "Apache Group" must not be used to
00046  *    endorse or promote products derived from this software without
00047  *    prior written permission.
00048  *
00049  * 5. Redistributions of any form whatsoever must retain the following
00050  *    acknowledgment:
00051  *    "This product includes software developed by the Apache Group
00052  *    for use in the Apache HTTP server project (http://www.apache.org/)."
00053  *
00054  * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY
00055  * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00056  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
00057  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE APACHE GROUP OR
00058  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
00059  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
00060  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00061  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00062  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
00063  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
00064  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
00065  * OF THE POSSIBILITY OF SUCH DAMAGE.
00066  * ====================================================================
00067  *
00068  * This software consists of voluntary contributions made by many
00069  * individuals on behalf of the Apache Group and was originally based
00070  * on public domain software written at the National Center for
00071  * Supercomputing Applications, University of Illinois, Urbana-Champaign.
00072  * For more information on the Apache Group and the Apache HTTP server
00073  * project, please see <http://www.apache.org/>.
00074  *
00075  * This code is based on, and used with the permission of, the
00076  * SIO stdio-replacement strx_* functions by Panos Tsirigotis
00077  * <panos@alumni.cs.colorado.edu> for xinetd.
00078  */
00079 #define _GNU_SOURCE
00080 #include "php.h"
00081 
00082 #include <stddef.h>
00083 #include <stdio.h>
00084 #include <ctype.h>
00085 #include <sys/types.h>
00086 #include <stdarg.h>
00087 #include <string.h>
00088 #include <stdlib.h>
00089 #include <math.h>
00090 #ifdef HAVE_INTTYPES_H
00091 #include <inttypes.h>
00092 #endif
00093 
00094 #ifdef HAVE_LOCALE_H
00095 #include <locale.h>
00096 #define LCONV_DECIMAL_POINT (*lconv->decimal_point)
00097 #else
00098 #define LCONV_DECIMAL_POINT '.'
00099 #endif
00100 
00101 #include "snprintf.h"
00102 
00103 #define FALSE           0
00104 #define TRUE            1
00105 #define NUL             '\0'
00106 #define INT_NULL        ((int *)0)
00107 
00108 #define S_NULL          "(null)"
00109 #define S_NULL_LEN      6
00110 
00111 #define FLOAT_DIGITS    6
00112 #define EXPONENT_LENGTH 10
00113 
00114 #include "ext/standard/php_smart_str.h"
00115 
00116 /* {{{ macros */
00117 
00118 /*
00119  * NUM_BUF_SIZE is the size of the buffer used for arithmetic conversions
00120  *
00121  * XXX: this is a magic number; do not decrease it
00122  * Emax = 1023
00123  * NDIG = 320
00124  * NUM_BUF_SIZE >= strlen("-") + Emax + strlrn(".") + NDIG + strlen("E+1023") + 1;
00125  */
00126 #define NUM_BUF_SIZE    2048
00127 
00128 /*
00129  * The INS_CHAR macro inserts a character in the buffer.
00130  *
00131  * NOTE: Evaluation of the ch argument should not have any side-effects
00132  */
00133 #define INS_CHAR_NR(xbuf, ch) do { \
00134        smart_str_appendc(xbuf, ch);       \
00135 } while (0)
00136 
00137 #define INS_STRING(xbuf, s, slen) do {    \
00138        smart_str_appendl(xbuf, s, slen);  \
00139 } while (0)
00140 
00141 #define INS_CHAR(xbuf, ch)          \
00142        INS_CHAR_NR(xbuf, ch)
00143 
00144 /*
00145  * Macro that does padding. The padding is done by printing
00146  * the character ch.
00147  */
00148 #define PAD(xbuf, count, ch) do {                              \
00149        if ((count) > 0) {                                      \
00150               size_t newlen;                                                        \
00151               smart_str_alloc(xbuf, (count), 0);                      \
00152               memset(xbuf->c + xbuf->len, ch, (count)); \
00153               xbuf->len += (count);                            \
00154        }                                                                                   \
00155 } while (0)
00156 
00157 #define NUM(c) (c - '0')
00158 
00159 #define STR_TO_DEC(str, num) do {                \
00160        num = NUM(*str++);                        \
00161        while (isdigit((int)*str)) {              \
00162               num *= 10;                         \
00163               num += NUM(*str++);                \
00164               if (num >= INT_MAX / 10) {                \
00165                      while (isdigit((int)*str++));      \
00166                      break;                                           \
00167               }                                                              \
00168     }                                                                 \
00169 } while (0)
00170 
00171 /*
00172  * This macro does zero padding so that the precision
00173  * requirement is satisfied. The padding is done by
00174  * adding '0's to the left of the string that is going
00175  * to be printed.
00176  */
00177 #define FIX_PRECISION(adjust, precision, s, s_len) do { \
00178     if (adjust)                                                       \
00179               while (s_len < precision) {                      \
00180                      *--s = '0';                               \
00181                      s_len++;                                  \
00182               }                                                                                   \
00183 } while (0)
00184 
00185 /* }}} */
00186 
00187 
00188 #if !HAVE_STRNLEN
00189 static size_t strnlen(const char *s, size_t maxlen) {
00190        char *r = memchr(s, '\0', maxlen);
00191        return r ? r-s : maxlen;
00192 }
00193 #endif
00194 
00195 /*
00196  * Do format conversion placing the output in buffer
00197  */
00198 static void xbuf_format_converter(smart_str *xbuf, const char *fmt, va_list ap) /* {{{ */
00199 {
00200        char *s = NULL;
00201        int s_len, free_zcopy;
00202        zval *zvp, zcopy;
00203 
00204        int min_width = 0;
00205        int precision = 0;
00206        enum {
00207               LEFT, RIGHT
00208        } adjust;
00209        char pad_char;
00210        char prefix_char;
00211 
00212        double fp_num;
00213        wide_int i_num = (wide_int) 0;
00214        u_wide_int ui_num;
00215 
00216        char num_buf[NUM_BUF_SIZE];
00217        char char_buf[2];                  /* for printing %% and %<unknown> */
00218 
00219 #ifdef HAVE_LOCALE_H
00220        struct lconv *lconv = NULL;
00221 #endif
00222 
00223        /*
00224         * Flag variables
00225         */
00226        length_modifier_e modifier;
00227        boolean_e alternate_form;
00228        boolean_e print_sign;
00229        boolean_e print_blank;
00230        boolean_e adjust_precision;
00231        boolean_e adjust_width;
00232        bool_int is_negative;
00233 
00234        while (*fmt) {
00235               if (*fmt != '%') {
00236                      INS_CHAR(xbuf, *fmt);
00237               } else {
00238                      /*
00239                       * Default variable settings
00240                       */
00241                      adjust = RIGHT;
00242                      alternate_form = print_sign = print_blank = NO;
00243                      pad_char = ' ';
00244                      prefix_char = NUL;
00245                      free_zcopy = 0;
00246 
00247                      fmt++;
00248 
00249                      /*
00250                       * Try to avoid checking for flags, width or precision
00251                       */
00252                      if (isascii((int)*fmt) && !islower((int)*fmt)) {
00253                             /*
00254                              * Recognize flags: -, #, BLANK, +
00255                              */
00256                             for (;; fmt++) {
00257                                    if (*fmt == '-')
00258                                           adjust = LEFT;
00259                                    else if (*fmt == '+')
00260                                           print_sign = YES;
00261                                    else if (*fmt == '#')
00262                                           alternate_form = YES;
00263                                    else if (*fmt == ' ')
00264                                           print_blank = YES;
00265                                    else if (*fmt == '0')
00266                                           pad_char = '0';
00267                                    else
00268                                           break;
00269                             }
00270 
00271                             /*
00272                              * Check if a width was specified
00273                              */
00274                             if (isdigit((int)*fmt)) {
00275                                    STR_TO_DEC(fmt, min_width);
00276                                    adjust_width = YES;
00277                             } else if (*fmt == '*') {
00278                                    min_width = va_arg(ap, int);
00279                                    fmt++;
00280                                    adjust_width = YES;
00281                                    if (min_width < 0) {
00282                                           adjust = LEFT;
00283                                           min_width = -min_width;
00284                                    }
00285                             } else
00286                                    adjust_width = NO;
00287 
00288                             /*
00289                              * Check if a precision was specified
00290                              */
00291                             if (*fmt == '.') {
00292                                    adjust_precision = YES;
00293                                    fmt++;
00294                                    if (isdigit((int)*fmt)) {
00295                                           STR_TO_DEC(fmt, precision);
00296                                    } else if (*fmt == '*') {
00297                                           precision = va_arg(ap, int);
00298                                           fmt++;
00299                                           if (precision < 0)
00300                                                  precision = 0;
00301                                    } else
00302                                           precision = 0;
00303                                    
00304                                    if (precision > FORMAT_CONV_MAX_PRECISION) {
00305                                           precision = FORMAT_CONV_MAX_PRECISION;
00306                                    }
00307                             } else
00308                                    adjust_precision = NO;
00309                      } else
00310                             adjust_precision = adjust_width = NO;
00311 
00312                      /*
00313                       * Modifier check
00314                       */
00315                      switch (*fmt) {
00316                             case 'L':
00317                                    fmt++;
00318                                    modifier = LM_LONG_DOUBLE;
00319                                    break;
00320                             case 'I':
00321                                    fmt++;
00322 #if SIZEOF_LONG_LONG
00323                                    if (*fmt == '6' && *(fmt+1) == '4') {
00324                                           fmt += 2;
00325                                           modifier = LM_LONG_LONG;
00326                                    } else
00327 #endif
00328                                           if (*fmt == '3' && *(fmt+1) == '2') {
00329                                                  fmt += 2;
00330                                                  modifier = LM_LONG;
00331                                           } else {
00332 #ifdef _WIN64
00333                                                  modifier = LM_LONG_LONG;
00334 #else
00335                                                  modifier = LM_LONG;
00336 #endif
00337                                           }
00338                                    break;
00339                             case 'l':
00340                                    fmt++;
00341 #if SIZEOF_LONG_LONG
00342                                    if (*fmt == 'l') {
00343                                           fmt++;
00344                                           modifier = LM_LONG_LONG;
00345                                    } else
00346 #endif
00347                                           modifier = LM_LONG;
00348                                    break;
00349                             case 'z':
00350                                    fmt++;
00351                                    modifier = LM_SIZE_T;
00352                                    break;
00353                             case 'j':
00354                                    fmt++;
00355 #if SIZEOF_INTMAX_T
00356                                    modifier = LM_INTMAX_T;
00357 #else
00358                                    modifier = LM_SIZE_T;
00359 #endif
00360                                    break;
00361                             case 't':
00362                                    fmt++;
00363 #if SIZEOF_PTRDIFF_T
00364                                    modifier = LM_PTRDIFF_T;
00365 #else
00366                                    modifier = LM_SIZE_T;
00367 #endif
00368                                    break;
00369                             case 'h':
00370                                    fmt++;
00371                                    if (*fmt == 'h') {
00372                                           fmt++;
00373                                    }
00374                                    /* these are promoted to int, so no break */
00375                             default:
00376                                    modifier = LM_STD;
00377                                    break;
00378                      }
00379 
00380                      /*
00381                       * Argument extraction and printing.
00382                       * First we determine the argument type.
00383                       * Then, we convert the argument to a string.
00384                       * On exit from the switch, s points to the string that
00385                       * must be printed, s_len has the length of the string
00386                       * The precision requirements, if any, are reflected in s_len.
00387                       *
00388                       * NOTE: pad_char may be set to '0' because of the 0 flag.
00389                       *   It is reset to ' ' by non-numeric formats
00390                       */
00391                      switch (*fmt) {
00392                             case 'Z':
00393                                    zvp = (zval*) va_arg(ap, zval*);
00394                                    zend_make_printable_zval(zvp, &zcopy, &free_zcopy);
00395                                    if (free_zcopy) {
00396                                           zvp = &zcopy;
00397                                    }
00398                                    s_len = Z_STRLEN_P(zvp);
00399                                    s = Z_STRVAL_P(zvp);
00400                                    if (adjust_precision && precision < s_len) {
00401                                           s_len = precision;
00402                                    }
00403                                    break;
00404                             case 'u':
00405                                    switch(modifier) {
00406                                           default:
00407                                                  i_num = (wide_int) va_arg(ap, unsigned int);
00408                                                  break;
00409                                           case LM_LONG_DOUBLE:
00410                                                  goto fmt_error;
00411                                           case LM_LONG:
00412                                                  i_num = (wide_int) va_arg(ap, unsigned long int);
00413                                                  break;
00414                                           case LM_SIZE_T:
00415                                                  i_num = (wide_int) va_arg(ap, size_t);
00416                                                  break;
00417 #if SIZEOF_LONG_LONG
00418                                           case LM_LONG_LONG:
00419                                                  i_num = (wide_int) va_arg(ap, u_wide_int);
00420                                                  break;
00421 #endif
00422 #if SIZEOF_INTMAX_T
00423                                           case LM_INTMAX_T:
00424                                                  i_num = (wide_int) va_arg(ap, uintmax_t);
00425                                                  break;
00426 #endif
00427 #if SIZEOF_PTRDIFF_T
00428                                           case LM_PTRDIFF_T:
00429                                                  i_num = (wide_int) va_arg(ap, ptrdiff_t);
00430                                                  break;
00431 #endif
00432                                    }
00433                                    /*
00434                                     * The rest also applies to other integer formats, so fall
00435                                     * into that case.
00436                                     */
00437                             case 'd':
00438                             case 'i':
00439                                    /*
00440                                     * Get the arg if we haven't already.
00441                                     */
00442                                    if ((*fmt) != 'u') {
00443                                           switch(modifier) {
00444                                                  default:
00445                                                         i_num = (wide_int) va_arg(ap, int);
00446                                                         break;
00447                                                  case LM_LONG_DOUBLE:
00448                                                         goto fmt_error;
00449                                                  case LM_LONG:
00450                                                         i_num = (wide_int) va_arg(ap, long int);
00451                                                         break;
00452                                                  case LM_SIZE_T:
00453 #if SIZEOF_SSIZE_T
00454                                                         i_num = (wide_int) va_arg(ap, ssize_t);
00455 #else
00456                                                         i_num = (wide_int) va_arg(ap, size_t);
00457 #endif
00458                                                         break;
00459 #if SIZEOF_LONG_LONG
00460                                                  case LM_LONG_LONG:
00461                                                         i_num = (wide_int) va_arg(ap, wide_int);
00462                                                         break;
00463 #endif
00464 #if SIZEOF_INTMAX_T
00465                                                  case LM_INTMAX_T:
00466                                                         i_num = (wide_int) va_arg(ap, intmax_t);
00467                                                         break;
00468 #endif
00469 #if SIZEOF_PTRDIFF_T
00470                                                  case LM_PTRDIFF_T:
00471                                                         i_num = (wide_int) va_arg(ap, ptrdiff_t);
00472                                                         break;
00473 #endif
00474                                           }
00475                                    }
00476                                    s = ap_php_conv_10(i_num, (*fmt) == 'u', &is_negative,
00477                                                         &num_buf[NUM_BUF_SIZE], &s_len);
00478                                    FIX_PRECISION(adjust_precision, precision, s, s_len);
00479 
00480                                    if (*fmt != 'u') {
00481                                           if (is_negative)
00482                                                  prefix_char = '-';
00483                                           else if (print_sign)
00484                                                  prefix_char = '+';
00485                                           else if (print_blank)
00486                                                  prefix_char = ' ';
00487                                    }
00488                                    break;
00489 
00490 
00491                             case 'o':
00492                                    switch(modifier) {
00493                                           default:
00494                                                  ui_num = (u_wide_int) va_arg(ap, unsigned int);
00495                                                  break;
00496                                           case LM_LONG_DOUBLE:
00497                                                  goto fmt_error;
00498                                           case LM_LONG:
00499                                                  ui_num = (u_wide_int) va_arg(ap, unsigned long int);
00500                                                  break;
00501                                           case LM_SIZE_T:
00502                                                  ui_num = (u_wide_int) va_arg(ap, size_t);
00503                                                  break;
00504 #if SIZEOF_LONG_LONG
00505                                           case LM_LONG_LONG:
00506                                                  ui_num = (u_wide_int) va_arg(ap, u_wide_int);
00507                                                  break;
00508 #endif
00509 #if SIZEOF_INTMAX_T
00510                                           case LM_INTMAX_T:
00511                                                  ui_num = (u_wide_int) va_arg(ap, uintmax_t);
00512                                                  break;
00513 #endif
00514 #if SIZEOF_PTRDIFF_T
00515                                           case LM_PTRDIFF_T:
00516                                                  ui_num = (u_wide_int) va_arg(ap, ptrdiff_t);
00517                                                  break;
00518 #endif
00519                                    }
00520                                    s = ap_php_conv_p2(ui_num, 3, *fmt,
00521                                                         &num_buf[NUM_BUF_SIZE], &s_len);
00522                                    FIX_PRECISION(adjust_precision, precision, s, s_len);
00523                                    if (alternate_form && *s != '0') {
00524                                           *--s = '0';
00525                                           s_len++;
00526                                    }
00527                                    break;
00528 
00529 
00530                             case 'x':
00531                             case 'X':
00532                                    switch(modifier) {
00533                                           default:
00534                                                  ui_num = (u_wide_int) va_arg(ap, unsigned int);
00535                                                  break;
00536                                           case LM_LONG_DOUBLE:
00537                                                  goto fmt_error;
00538                                           case LM_LONG:
00539                                                  ui_num = (u_wide_int) va_arg(ap, unsigned long int);
00540                                                  break;
00541                                           case LM_SIZE_T:
00542                                                  ui_num = (u_wide_int) va_arg(ap, size_t);
00543                                                  break;
00544 #if SIZEOF_LONG_LONG
00545                                           case LM_LONG_LONG:
00546                                                  ui_num = (u_wide_int) va_arg(ap, u_wide_int);
00547                                                  break;
00548 #endif
00549 #if SIZEOF_INTMAX_T
00550                                           case LM_INTMAX_T:
00551                                                  ui_num = (u_wide_int) va_arg(ap, uintmax_t);
00552                                                  break;
00553 #endif
00554 #if SIZEOF_PTRDIFF_T
00555                                           case LM_PTRDIFF_T:
00556                                                  ui_num = (u_wide_int) va_arg(ap, ptrdiff_t);
00557                                                  break;
00558 #endif
00559                                    }
00560                                    s = ap_php_conv_p2(ui_num, 4, *fmt,
00561                                                         &num_buf[NUM_BUF_SIZE], &s_len);
00562                                    FIX_PRECISION(adjust_precision, precision, s, s_len);
00563                                    if (alternate_form && i_num != 0) {
00564                                           *--s = *fmt;  /* 'x' or 'X' */
00565                                           *--s = '0';
00566                                           s_len += 2;
00567                                    }
00568                                    break;
00569 
00570 
00571                             case 's':
00572                             case 'v':
00573                                    s = va_arg(ap, char *);
00574                                    if (s != NULL) {
00575                                           if (!adjust_precision) {
00576                                                  s_len = strlen(s);
00577                                           } else {
00578                                                  s_len = strnlen(s, precision);
00579                                           }
00580                                    } else {
00581                                           s = S_NULL;
00582                                           s_len = S_NULL_LEN;
00583                                    }
00584                                    pad_char = ' ';
00585                                    break;
00586 
00587 
00588                             case 'f':
00589                             case 'F':
00590                             case 'e':
00591                             case 'E':
00592                                    switch(modifier) {
00593                                           case LM_LONG_DOUBLE:
00594                                                  fp_num = (double) va_arg(ap, long double);
00595                                                  break;
00596                                           case LM_STD:
00597                                                  fp_num = va_arg(ap, double);
00598                                                  break;
00599                                           default:
00600                                                  goto fmt_error;
00601                                    }
00602 
00603                                    if (zend_isnan(fp_num)) {
00604                                           s = "nan";
00605                                           s_len = 3;
00606                                    } else if (zend_isinf(fp_num)) {
00607                                           s = "inf";
00608                                           s_len = 3;
00609                                    } else {
00610 #ifdef HAVE_LOCALE_H
00611                                           if (!lconv) {
00612                                                  lconv = localeconv();
00613                                           }
00614 #endif
00615                                           s = php_conv_fp((*fmt == 'f')?'F':*fmt, fp_num, alternate_form,
00616                                            (adjust_precision == NO) ? FLOAT_DIGITS : precision,
00617                                            (*fmt == 'f')?LCONV_DECIMAL_POINT:'.',
00618                                                                &is_negative, &num_buf[1], &s_len);
00619                                           if (is_negative)
00620                                                  prefix_char = '-';
00621                                           else if (print_sign)
00622                                                  prefix_char = '+';
00623                                           else if (print_blank)
00624                                                  prefix_char = ' ';
00625                                    }
00626                                    break;
00627 
00628 
00629                             case 'g':
00630                             case 'k':
00631                             case 'G':
00632                             case 'H':
00633                                    switch(modifier) {
00634                                           case LM_LONG_DOUBLE:
00635                                                  fp_num = (double) va_arg(ap, long double);
00636                                                  break;
00637                                           case LM_STD:
00638                                                  fp_num = va_arg(ap, double);
00639                                                  break;
00640                                           default:
00641                                                  goto fmt_error;
00642                                    }
00643 
00644                                    if (zend_isnan(fp_num)) {
00645                                           s = "NAN";
00646                                           s_len = 3;
00647                                           break;
00648                                    } else if (zend_isinf(fp_num)) {
00649                                           if (fp_num > 0) {
00650                                                  s = "INF";
00651                                                  s_len = 3;
00652                                           } else {
00653                                                  s = "-INF";
00654                                                  s_len = 4;
00655                                           }
00656                                           break;
00657                                    }
00658 
00659                                    if (adjust_precision == NO)
00660                                           precision = FLOAT_DIGITS;
00661                                    else if (precision == 0)
00662                                           precision = 1;
00663                                    /*
00664                                     * * We use &num_buf[ 1 ], so that we have room for the sign
00665                                     */
00666 #ifdef HAVE_LOCALE_H
00667                                    if (!lconv) {
00668                                           lconv = localeconv();
00669                                    }
00670 #endif
00671                                    s = php_gcvt(fp_num, precision, (*fmt=='H' || *fmt == 'k') ? '.' : LCONV_DECIMAL_POINT, (*fmt == 'G' || *fmt == 'H')?'E':'e', &num_buf[1]);
00672                                    if (*s == '-')
00673                                           prefix_char = *s++;
00674                                    else if (print_sign)
00675                                           prefix_char = '+';
00676                                    else if (print_blank)
00677                                           prefix_char = ' ';
00678 
00679                                    s_len = strlen(s);
00680 
00681                                    if (alternate_form && (strchr(s, '.')) == NULL)
00682                                           s[s_len++] = '.';
00683                                    break;
00684 
00685 
00686                             case 'c':
00687                                    char_buf[0] = (char) (va_arg(ap, int));
00688                                    s = &char_buf[0];
00689                                    s_len = 1;
00690                                    pad_char = ' ';
00691                                    break;
00692 
00693 
00694                             case '%':
00695                                    char_buf[0] = '%';
00696                                    s = &char_buf[0];
00697                                    s_len = 1;
00698                                    pad_char = ' ';
00699                                    break;
00700 
00701 
00702                             case 'n':
00703                                    *(va_arg(ap, int *)) = xbuf->len;
00704                                    goto skip_output;
00705 
00706                                    /*
00707                                     * Always extract the argument as a "char *" pointer. We
00708                                     * should be using "void *" but there are still machines
00709                                     * that don't understand it.
00710                                     * If the pointer size is equal to the size of an unsigned
00711                                     * integer we convert the pointer to a hex number, otherwise
00712                                     * we print "%p" to indicate that we don't handle "%p".
00713                                     */
00714                             case 'p':
00715                                    if (sizeof(char *) <= sizeof(u_wide_int)) {
00716                                           ui_num = (u_wide_int)((size_t) va_arg(ap, char *));
00717                                           s = ap_php_conv_p2(ui_num, 4, 'x',
00718                                                         &num_buf[NUM_BUF_SIZE], &s_len);
00719                                           if (ui_num != 0) {
00720                                                  *--s = 'x';
00721                                                  *--s = '0';
00722                                                  s_len += 2;
00723                                           }
00724                                    } else {
00725                                           s = "%p";
00726                                           s_len = 2;
00727                                    }
00728                                    pad_char = ' ';
00729                                    break;
00730 
00731 
00732                             case NUL:
00733                                    /*
00734                                     * The last character of the format string was %.
00735                                     * We ignore it.
00736                                     */
00737                                    continue;
00738 
00739 
00740 fmt_error:
00741                             php_error(E_ERROR, "Illegal length modifier specified '%c' in s[np]printf call", *fmt);
00742                                    /*
00743                                     * The default case is for unrecognized %'s.
00744                                     * We print %<char> to help the user identify what
00745                                     * option is not understood.
00746                                     * This is also useful in case the user wants to pass
00747                                     * the output of format_converter to another function
00748                                     * that understands some other %<char> (like syslog).
00749                                     * Note that we can't point s inside fmt because the
00750                                     * unknown <char> could be preceded by width etc.
00751                                     */
00752                             default:
00753                                    char_buf[0] = '%';
00754                                    char_buf[1] = *fmt;
00755                                    s = char_buf;
00756                                    s_len = 2;
00757                                    pad_char = ' ';
00758                                    break;
00759                      }
00760 
00761                      if (prefix_char != NUL) {
00762                             *--s = prefix_char;
00763                             s_len++;
00764                      }
00765                      if (adjust_width && adjust == RIGHT && min_width > s_len) {
00766                             if (pad_char == '0' && prefix_char != NUL) {
00767                                    INS_CHAR(xbuf, *s);
00768                                    s++;
00769                                    s_len--;
00770                                    min_width--;
00771                             }
00772                             PAD(xbuf, min_width - s_len, pad_char);
00773                      }
00774                      /*
00775                       * Print the string s.
00776                       */
00777                      INS_STRING(xbuf, s, s_len);
00778 
00779                      if (adjust_width && adjust == LEFT && min_width > s_len)
00780                             PAD(xbuf, min_width - s_len, pad_char);
00781                      if (free_zcopy) {
00782                             zval_dtor(&zcopy);
00783                      }
00784               }
00785 skip_output:
00786               fmt++;
00787        }
00788        return;
00789 }
00790 /* }}} */
00791 
00792 /*
00793  * This is the general purpose conversion function.
00794  */
00795 PHPAPI int vspprintf(char **pbuf, size_t max_len, const char *format, va_list ap) /* {{{ */
00796 {
00797        smart_str xbuf = {0};
00798 
00799        xbuf_format_converter(&xbuf, format, ap);
00800 
00801        if (max_len && xbuf.len > max_len) {
00802               xbuf.len = max_len;
00803        }
00804        smart_str_0(&xbuf);
00805 
00806        *pbuf = xbuf.c;
00807 
00808        return xbuf.len;
00809 }
00810 /* }}} */
00811 
00812 PHPAPI int spprintf(char **pbuf, size_t max_len, const char *format, ...) /* {{{ */
00813 {
00814        int cc;
00815        va_list ap;
00816 
00817        va_start(ap, format);
00818        cc = vspprintf(pbuf, max_len, format, ap);
00819        va_end(ap);
00820        return (cc);
00821 }
00822 /* }}} */
00823 
00824 /*
00825  * Local variables:
00826  * tab-width: 4
00827  * c-basic-offset: 4
00828  * End:
00829  * vim600: sw=4 ts=4 fdm=marker
00830  * vim<600: sw=4 ts=4
00831  */