root/main/spprintf.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. strnlen
  2. xbuf_format_converter
  3. vspprintf
  4. spprintf
  5. vstrpprintf
  6. strpprintf

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

/* [<][>][^][v][top][bottom][index][help] */