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

   1 /*
   2    +----------------------------------------------------------------------+
   3    | PHP Version 5                                                        |
   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 "ext/standard/php_smart_str.h"
 120 
 121 /* {{{ macros */
 122 
 123 /*
 124  * NUM_BUF_SIZE is the size of the buffer used for arithmetic conversions
 125  *
 126  * XXX: this is a magic number; do not decrease it
 127  * Emax = 1023
 128  * NDIG = 320
 129  * NUM_BUF_SIZE >= strlen("-") + Emax + strlrn(".") + NDIG + strlen("E+1023") + 1;
 130  */
 131 #define NUM_BUF_SIZE            2048
 132 
 133 /*
 134  * The INS_CHAR macro inserts a character in the buffer.
 135  *
 136  * NOTE: Evaluation of the ch argument should not have any side-effects
 137  */
 138 #define INS_CHAR_NR(xbuf, ch) do {      \
 139         smart_str_appendc(xbuf, ch);    \
 140 } while (0)
 141 
 142 #define INS_STRING(xbuf, s, slen) do {  \
 143         smart_str_appendl(xbuf, s, slen);       \
 144 } while (0)
 145 
 146 #define INS_CHAR(xbuf, ch)          \
 147         INS_CHAR_NR(xbuf, ch)
 148 
 149 /*
 150  * Macro that does padding. The padding is done by printing
 151  * the character ch.
 152  */
 153 #define PAD(xbuf, count, ch) do {                                       \
 154         if ((count) > 0) {                                      \
 155                 size_t newlen;                                                          \
 156                 smart_str_alloc(xbuf, (count), 0);                      \
 157                 memset(xbuf->c + xbuf->len, ch, (count));       \
 158                 xbuf->len += (count);                           \
 159         }                                                                                               \
 160 } while (0)
 161 
 162 #define NUM(c) (c - '0')
 163 
 164 #define STR_TO_DEC(str, num) do {                       \
 165         num = NUM(*str++);                      \
 166         while (isdigit((int)*str)) {            \
 167                 num *= 10;                              \
 168                 num += NUM(*str++);                     \
 169                 if (num >= INT_MAX / 10) {                      \
 170                         while (isdigit((int)*str++));   \
 171                         break;                                                  \
 172                 }                                                                       \
 173     }                                                                           \
 174 } while (0)
 175 
 176 /*
 177  * This macro does zero padding so that the precision
 178  * requirement is satisfied. The padding is done by
 179  * adding '0's to the left of the string that is going
 180  * to be printed.
 181  */
 182 #define FIX_PRECISION(adjust, precision, s, s_len) do { \
 183     if (adjust)                                                         \
 184                 while (s_len < precision) {                     \
 185                         *--s = '0';                                     \
 186                         s_len++;                                        \
 187                 }                                                                                               \
 188 } while (0)
 189 
 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(smart_str *xbuf, const char *fmt, va_list ap) /* {{{ */
 204 {
 205         char *s = NULL;
 206         int s_len, free_zcopy;
 207         zval *zvp, zcopy;
 208 
 209         int min_width = 0;
 210         int precision = 0;
 211         enum {
 212                 LEFT, RIGHT
 213         } adjust;
 214         char pad_char;
 215         char prefix_char;
 216 
 217         double fp_num;
 218         wide_int i_num = (wide_int) 0;
 219         u_wide_int ui_num = (u_wide_int) 0;
 220 
 221         char num_buf[NUM_BUF_SIZE];
 222         char char_buf[2];                       /* for printing %% and %<unknown> */
 223 
 224 #ifdef HAVE_LOCALE_H
 225 #ifdef ZTS
 226         struct lconv lconv;
 227 #else
 228         struct lconv *lconv = NULL;
 229 #endif
 230 #endif
 231 
 232         /*
 233          * Flag variables
 234          */
 235         length_modifier_e modifier;
 236         boolean_e alternate_form;
 237         boolean_e print_sign;
 238         boolean_e print_blank;
 239         boolean_e adjust_precision;
 240         boolean_e adjust_width;
 241         bool_int is_negative;
 242 
 243         while (*fmt) {
 244                 if (*fmt != '%') {
 245                         INS_CHAR(xbuf, *fmt);
 246                 } else {
 247                         /*
 248                          * Default variable settings
 249                          */
 250                         adjust = RIGHT;
 251                         alternate_form = print_sign = print_blank = NO;
 252                         pad_char = ' ';
 253                         prefix_char = NUL;
 254                         free_zcopy = 0;
 255 
 256                         fmt++;
 257 
 258                         /*
 259                          * Try to avoid checking for flags, width or precision
 260                          */
 261                         if (isascii((int)*fmt) && !islower((int)*fmt)) {
 262                                 /*
 263                                  * Recognize flags: -, #, BLANK, +
 264                                  */
 265                                 for (;; fmt++) {
 266                                         if (*fmt == '-')
 267                                                 adjust = LEFT;
 268                                         else if (*fmt == '+')
 269                                                 print_sign = YES;
 270                                         else if (*fmt == '#')
 271                                                 alternate_form = YES;
 272                                         else if (*fmt == ' ')
 273                                                 print_blank = YES;
 274                                         else if (*fmt == '0')
 275                                                 pad_char = '0';
 276                                         else
 277                                                 break;
 278                                 }
 279 
 280                                 /*
 281                                  * Check if a width was specified
 282                                  */
 283                                 if (isdigit((int)*fmt)) {
 284                                         STR_TO_DEC(fmt, min_width);
 285                                         adjust_width = YES;
 286                                 } else if (*fmt == '*') {
 287                                         min_width = va_arg(ap, int);
 288                                         fmt++;
 289                                         adjust_width = YES;
 290                                         if (min_width < 0) {
 291                                                 adjust = LEFT;
 292                                                 min_width = -min_width;
 293                                         }
 294                                 } else
 295                                         adjust_width = NO;
 296 
 297                                 /*
 298                                  * Check if a precision was specified
 299                                  */
 300                                 if (*fmt == '.') {
 301                                         adjust_precision = YES;
 302                                         fmt++;
 303                                         if (isdigit((int)*fmt)) {
 304                                                 STR_TO_DEC(fmt, precision);
 305                                         } else if (*fmt == '*') {
 306                                                 precision = va_arg(ap, int);
 307                                                 fmt++;
 308                                                 if (precision < 0)
 309                                                         precision = 0;
 310                                         } else
 311                                                 precision = 0;
 312                                         
 313                                         if (precision > FORMAT_CONV_MAX_PRECISION) {
 314                                                 precision = FORMAT_CONV_MAX_PRECISION;
 315                                         }
 316                                 } else
 317                                         adjust_precision = NO;
 318                         } else
 319                                 adjust_precision = adjust_width = NO;
 320 
 321                         /*
 322                          * Modifier check
 323                          */
 324                         switch (*fmt) {
 325                                 case 'L':
 326                                         fmt++;
 327                                         modifier = LM_LONG_DOUBLE;
 328                                         break;
 329                                 case 'I':
 330                                         fmt++;
 331 #if SIZEOF_LONG_LONG
 332                                         if (*fmt == '6' && *(fmt+1) == '4') {
 333                                                 fmt += 2;
 334                                                 modifier = LM_LONG_LONG;
 335                                         } else
 336 #endif
 337                                                 if (*fmt == '3' && *(fmt+1) == '2') {
 338                                                         fmt += 2;
 339                                                         modifier = LM_LONG;
 340                                                 } else {
 341 #ifdef _WIN64
 342                                                         modifier = LM_LONG_LONG;
 343 #else
 344                                                         modifier = LM_LONG;
 345 #endif
 346                                                 }
 347                                         break;
 348                                 case 'l':
 349                                         fmt++;
 350 #if SIZEOF_LONG_LONG
 351                                         if (*fmt == 'l') {
 352                                                 fmt++;
 353                                                 modifier = LM_LONG_LONG;
 354                                         } else
 355 #endif
 356                                                 modifier = LM_LONG;
 357                                         break;
 358                                 case 'z':
 359                                         fmt++;
 360                                         modifier = LM_SIZE_T;
 361                                         break;
 362                                 case 'j':
 363                                         fmt++;
 364 #if SIZEOF_INTMAX_T
 365                                         modifier = LM_INTMAX_T;
 366 #else
 367                                         modifier = LM_SIZE_T;
 368 #endif
 369                                         break;
 370                                 case 't':
 371                                         fmt++;
 372 #if SIZEOF_PTRDIFF_T
 373                                         modifier = LM_PTRDIFF_T;
 374 #else
 375                                         modifier = LM_SIZE_T;
 376 #endif
 377                                         break;
 378                                 case 'h':
 379                                         fmt++;
 380                                         if (*fmt == 'h') {
 381                                                 fmt++;
 382                                         }
 383                                         /* these are promoted to int, so no break */
 384                                 default:
 385                                         modifier = LM_STD;
 386                                         break;
 387                         }
 388 
 389                         /*
 390                          * Argument extraction and printing.
 391                          * First we determine the argument type.
 392                          * Then, we convert the argument to a string.
 393                          * On exit from the switch, s points to the string that
 394                          * must be printed, s_len has the length of the string
 395                          * The precision requirements, if any, are reflected in s_len.
 396                          *
 397                          * NOTE: pad_char may be set to '0' because of the 0 flag.
 398                          *   It is reset to ' ' by non-numeric formats
 399                          */
 400                         switch (*fmt) {
 401                                 case 'Z':
 402                                         zvp = (zval*) va_arg(ap, zval*);
 403                                         zend_make_printable_zval(zvp, &zcopy, &free_zcopy);
 404                                         if (free_zcopy) {
 405                                                 zvp = &zcopy;
 406                                         }
 407                                         s_len = Z_STRLEN_P(zvp);
 408                                         s = Z_STRVAL_P(zvp);
 409                                         if (adjust_precision && precision < s_len) {
 410                                                 s_len = precision;
 411                                         }
 412                                         break;
 413                                 case 'u':
 414                                         switch(modifier) {
 415                                                 default:
 416                                                         i_num = (wide_int) va_arg(ap, unsigned int);
 417                                                         break;
 418                                                 case LM_LONG_DOUBLE:
 419                                                         goto fmt_error;
 420                                                 case LM_LONG:
 421                                                         i_num = (wide_int) va_arg(ap, unsigned long int);
 422                                                         break;
 423                                                 case LM_SIZE_T:
 424                                                         i_num = (wide_int) va_arg(ap, size_t);
 425                                                         break;
 426 #if SIZEOF_LONG_LONG
 427                                                 case LM_LONG_LONG:
 428                                                         i_num = (wide_int) va_arg(ap, u_wide_int);
 429                                                         break;
 430 #endif
 431 #if SIZEOF_INTMAX_T
 432                                                 case LM_INTMAX_T:
 433                                                         i_num = (wide_int) va_arg(ap, uintmax_t);
 434                                                         break;
 435 #endif
 436 #if SIZEOF_PTRDIFF_T
 437                                                 case LM_PTRDIFF_T:
 438                                                         i_num = (wide_int) va_arg(ap, ptrdiff_t);
 439                                                         break;
 440 #endif
 441                                         }
 442                                         /*
 443                                          * The rest also applies to other integer formats, so fall
 444                                          * into that case.
 445                                          */
 446                                 case 'd':
 447                                 case 'i':
 448                                         /*
 449                                          * Get the arg if we haven't already.
 450                                          */
 451                                         if ((*fmt) != 'u') {
 452                                                 switch(modifier) {
 453                                                         default:
 454                                                                 i_num = (wide_int) va_arg(ap, int);
 455                                                                 break;
 456                                                         case LM_LONG_DOUBLE:
 457                                                                 goto fmt_error;
 458                                                         case LM_LONG:
 459                                                                 i_num = (wide_int) va_arg(ap, long int);
 460                                                                 break;
 461                                                         case LM_SIZE_T:
 462 #if SIZEOF_SSIZE_T
 463                                                                 i_num = (wide_int) va_arg(ap, ssize_t);
 464 #else
 465                                                                 i_num = (wide_int) va_arg(ap, size_t);
 466 #endif
 467                                                                 break;
 468 #if SIZEOF_LONG_LONG
 469                                                         case LM_LONG_LONG:
 470                                                                 i_num = (wide_int) va_arg(ap, wide_int);
 471                                                                 break;
 472 #endif
 473 #if SIZEOF_INTMAX_T
 474                                                         case LM_INTMAX_T:
 475                                                                 i_num = (wide_int) va_arg(ap, intmax_t);
 476                                                                 break;
 477 #endif
 478 #if SIZEOF_PTRDIFF_T
 479                                                         case LM_PTRDIFF_T:
 480                                                                 i_num = (wide_int) va_arg(ap, ptrdiff_t);
 481                                                                 break;
 482 #endif
 483                                                 }
 484                                         }
 485                                         s = ap_php_conv_10(i_num, (*fmt) == 'u', &is_negative,
 486                                                                 &num_buf[NUM_BUF_SIZE], &s_len);
 487                                         FIX_PRECISION(adjust_precision, precision, s, s_len);
 488 
 489                                         if (*fmt != 'u') {
 490                                                 if (is_negative)
 491                                                         prefix_char = '-';
 492                                                 else if (print_sign)
 493                                                         prefix_char = '+';
 494                                                 else if (print_blank)
 495                                                         prefix_char = ' ';
 496                                         }
 497                                         break;
 498 
 499 
 500                                 case 'o':
 501                                         switch(modifier) {
 502                                                 default:
 503                                                         ui_num = (u_wide_int) va_arg(ap, unsigned int);
 504                                                         break;
 505                                                 case LM_LONG_DOUBLE:
 506                                                         goto fmt_error;
 507                                                 case LM_LONG:
 508                                                         ui_num = (u_wide_int) va_arg(ap, unsigned long int);
 509                                                         break;
 510                                                 case LM_SIZE_T:
 511                                                         ui_num = (u_wide_int) va_arg(ap, size_t);
 512                                                         break;
 513 #if SIZEOF_LONG_LONG
 514                                                 case LM_LONG_LONG:
 515                                                         ui_num = (u_wide_int) va_arg(ap, u_wide_int);
 516                                                         break;
 517 #endif
 518 #if SIZEOF_INTMAX_T
 519                                                 case LM_INTMAX_T:
 520                                                         ui_num = (u_wide_int) va_arg(ap, uintmax_t);
 521                                                         break;
 522 #endif
 523 #if SIZEOF_PTRDIFF_T
 524                                                 case LM_PTRDIFF_T:
 525                                                         ui_num = (u_wide_int) va_arg(ap, ptrdiff_t);
 526                                                         break;
 527 #endif
 528                                         }
 529                                         s = ap_php_conv_p2(ui_num, 3, *fmt,
 530                                                                 &num_buf[NUM_BUF_SIZE], &s_len);
 531                                         FIX_PRECISION(adjust_precision, precision, s, s_len);
 532                                         if (alternate_form && *s != '0') {
 533                                                 *--s = '0';
 534                                                 s_len++;
 535                                         }
 536                                         break;
 537 
 538 
 539                                 case 'x':
 540                                 case 'X':
 541                                         switch(modifier) {
 542                                                 default:
 543                                                         ui_num = (u_wide_int) va_arg(ap, unsigned int);
 544                                                         break;
 545                                                 case LM_LONG_DOUBLE:
 546                                                         goto fmt_error;
 547                                                 case LM_LONG:
 548                                                         ui_num = (u_wide_int) va_arg(ap, unsigned long int);
 549                                                         break;
 550                                                 case LM_SIZE_T:
 551                                                         ui_num = (u_wide_int) va_arg(ap, size_t);
 552                                                         break;
 553 #if SIZEOF_LONG_LONG
 554                                                 case LM_LONG_LONG:
 555                                                         ui_num = (u_wide_int) va_arg(ap, u_wide_int);
 556                                                         break;
 557 #endif
 558 #if SIZEOF_INTMAX_T
 559                                                 case LM_INTMAX_T:
 560                                                         ui_num = (u_wide_int) va_arg(ap, uintmax_t);
 561                                                         break;
 562 #endif
 563 #if SIZEOF_PTRDIFF_T
 564                                                 case LM_PTRDIFF_T:
 565                                                         ui_num = (u_wide_int) va_arg(ap, ptrdiff_t);
 566                                                         break;
 567 #endif
 568                                         }
 569                                         s = ap_php_conv_p2(ui_num, 4, *fmt,
 570                                                                 &num_buf[NUM_BUF_SIZE], &s_len);
 571                                         FIX_PRECISION(adjust_precision, precision, s, s_len);
 572                                         if (alternate_form && ui_num != 0) {
 573                                                 *--s = *fmt;    /* 'x' or 'X' */
 574                                                 *--s = '0';
 575                                                 s_len += 2;
 576                                         }
 577                                         break;
 578 
 579 
 580                                 case 's':
 581                                 case 'v':
 582                                         s = va_arg(ap, char *);
 583                                         if (s != NULL) {
 584                                                 if (!adjust_precision) {
 585                                                         s_len = strlen(s);
 586                                                 } else {
 587                                                         s_len = strnlen(s, precision);
 588                                                 }
 589                                         } else {
 590                                                 s = S_NULL;
 591                                                 s_len = S_NULL_LEN;
 592                                         }
 593                                         pad_char = ' ';
 594                                         break;
 595 
 596 
 597                                 case 'f':
 598                                 case 'F':
 599                                 case 'e':
 600                                 case 'E':
 601                                         switch(modifier) {
 602                                                 case LM_LONG_DOUBLE:
 603                                                         fp_num = (double) va_arg(ap, long double);
 604                                                         break;
 605                                                 case LM_STD:
 606                                                         fp_num = va_arg(ap, double);
 607                                                         break;
 608                                                 default:
 609                                                         goto fmt_error;
 610                                         }
 611 
 612                                         if (zend_isnan(fp_num)) {
 613                                                 s = "nan";
 614                                                 s_len = 3;
 615                                         } else if (zend_isinf(fp_num)) {
 616                                                 s = "inf";
 617                                                 s_len = 3;
 618                                         } else {
 619 #ifdef HAVE_LOCALE_H
 620 #ifdef ZTS
 621                                                 localeconv_r(&lconv);
 622 #else
 623                                                 if (!lconv) {
 624                                                         lconv = localeconv();
 625                                                 }
 626 #endif
 627 #endif
 628                                                 s = php_conv_fp((*fmt == 'f')?'F':*fmt, fp_num, alternate_form,
 629                                                  (adjust_precision == NO) ? FLOAT_DIGITS : precision,
 630                                                  (*fmt == 'f')?LCONV_DECIMAL_POINT:'.',
 631                                                                         &is_negative, &num_buf[1], &s_len);
 632                                                 if (is_negative)
 633                                                         prefix_char = '-';
 634                                                 else if (print_sign)
 635                                                         prefix_char = '+';
 636                                                 else if (print_blank)
 637                                                         prefix_char = ' ';
 638                                         }
 639                                         break;
 640 
 641 
 642                                 case 'g':
 643                                 case 'k':
 644                                 case 'G':
 645                                 case 'H':
 646                                         switch(modifier) {
 647                                                 case LM_LONG_DOUBLE:
 648                                                         fp_num = (double) va_arg(ap, long double);
 649                                                         break;
 650                                                 case LM_STD:
 651                                                         fp_num = va_arg(ap, double);
 652                                                         break;
 653                                                 default:
 654                                                         goto fmt_error;
 655                                         }
 656 
 657                                         if (zend_isnan(fp_num)) {
 658                                                 s = "NAN";
 659                                                 s_len = 3;
 660                                                 break;
 661                                         } else if (zend_isinf(fp_num)) {
 662                                                 if (fp_num > 0) {
 663                                                         s = "INF";
 664                                                         s_len = 3;
 665                                                 } else {
 666                                                         s = "-INF";
 667                                                         s_len = 4;
 668                                                 }
 669                                                 break;
 670                                         }
 671 
 672                                         if (adjust_precision == NO)
 673                                                 precision = FLOAT_DIGITS;
 674                                         else if (precision == 0)
 675                                                 precision = 1;
 676                                         /*
 677                                          * * We use &num_buf[ 1 ], so that we have room for the sign
 678                                          */
 679 #ifdef HAVE_LOCALE_H
 680 #ifdef ZTS
 681                                         localeconv_r(&lconv);
 682 #else
 683                                         if (!lconv) {
 684                                                 lconv = localeconv();
 685                                         }
 686 #endif
 687 #endif
 688                                         s = php_gcvt(fp_num, precision, (*fmt=='H' || *fmt == 'k') ? '.' : LCONV_DECIMAL_POINT, (*fmt == 'G' || *fmt == 'H')?'E':'e', &num_buf[1]);
 689                                         if (*s == '-')
 690                                                 prefix_char = *s++;
 691                                         else if (print_sign)
 692                                                 prefix_char = '+';
 693                                         else if (print_blank)
 694                                                 prefix_char = ' ';
 695 
 696                                         s_len = strlen(s);
 697 
 698                                         if (alternate_form && (strchr(s, '.')) == NULL)
 699                                                 s[s_len++] = '.';
 700                                         break;
 701 
 702 
 703                                 case 'c':
 704                                         char_buf[0] = (char) (va_arg(ap, int));
 705                                         s = &char_buf[0];
 706                                         s_len = 1;
 707                                         pad_char = ' ';
 708                                         break;
 709 
 710 
 711                                 case '%':
 712                                         char_buf[0] = '%';
 713                                         s = &char_buf[0];
 714                                         s_len = 1;
 715                                         pad_char = ' ';
 716                                         break;
 717 
 718 
 719                                 case 'n':
 720                                         *(va_arg(ap, int *)) = xbuf->len;
 721                                         goto skip_output;
 722 
 723                                         /*
 724                                          * Always extract the argument as a "char *" pointer. We
 725                                          * should be using "void *" but there are still machines
 726                                          * that don't understand it.
 727                                          * If the pointer size is equal to the size of an unsigned
 728                                          * integer we convert the pointer to a hex number, otherwise
 729                                          * we print "%p" to indicate that we don't handle "%p".
 730                                          */
 731                                 case 'p':
 732                                         if (sizeof(char *) <= sizeof(u_wide_int)) {
 733                                                 ui_num = (u_wide_int)((size_t) va_arg(ap, char *));
 734                                                 s = ap_php_conv_p2(ui_num, 4, 'x',
 735                                                                 &num_buf[NUM_BUF_SIZE], &s_len);
 736                                                 if (ui_num != 0) {
 737                                                         *--s = 'x';
 738                                                         *--s = '0';
 739                                                         s_len += 2;
 740                                                 }
 741                                         } else {
 742                                                 s = "%p";
 743                                                 s_len = 2;
 744                                         }
 745                                         pad_char = ' ';
 746                                         break;
 747 
 748 
 749                                 case NUL:
 750                                         /*
 751                                          * The last character of the format string was %.
 752                                          * We ignore it.
 753                                          */
 754                                         continue;
 755 
 756 
 757 fmt_error:
 758                                 php_error(E_ERROR, "Illegal length modifier specified '%c' in s[np]printf call", *fmt);
 759                                         /*
 760                                          * The default case is for unrecognized %'s.
 761                                          * We print %<char> to help the user identify what
 762                                          * option is not understood.
 763                                          * This is also useful in case the user wants to pass
 764                                          * the output of format_converter to another function
 765                                          * that understands some other %<char> (like syslog).
 766                                          * Note that we can't point s inside fmt because the
 767                                          * unknown <char> could be preceded by width etc.
 768                                          */
 769                                 default:
 770                                         char_buf[0] = '%';
 771                                         char_buf[1] = *fmt;
 772                                         s = char_buf;
 773                                         s_len = 2;
 774                                         pad_char = ' ';
 775                                         break;
 776                         }
 777 
 778                         if (prefix_char != NUL) {
 779                                 *--s = prefix_char;
 780                                 s_len++;
 781                         }
 782                         if (adjust_width && adjust == RIGHT && min_width > s_len) {
 783                                 if (pad_char == '0' && prefix_char != NUL) {
 784                                         INS_CHAR(xbuf, *s);
 785                                         s++;
 786                                         s_len--;
 787                                         min_width--;
 788                                 }
 789                                 PAD(xbuf, min_width - s_len, pad_char);
 790                         }
 791                         /*
 792                          * Print the string s.
 793                          */
 794                         INS_STRING(xbuf, s, s_len);
 795 
 796                         if (adjust_width && adjust == LEFT && min_width > s_len)
 797                                 PAD(xbuf, min_width - s_len, pad_char);
 798                         if (free_zcopy) {
 799                                 zval_dtor(&zcopy);
 800                         }
 801                 }
 802 skip_output:
 803                 fmt++;
 804         }
 805         return;
 806 }
 807 /* }}} */
 808 
 809 /*
 810  * This is the general purpose conversion function.
 811  */
 812 PHPAPI int vspprintf(char **pbuf, size_t max_len, const char *format, va_list ap) /* {{{ */
 813 {
 814         smart_str xbuf = {0};
 815 
 816         /* since there are places where (v)spprintf called without checking for null,
 817            a bit of defensive coding here */
 818         if(!pbuf) {
 819                 return 0;
 820         }
 821         xbuf_format_converter(&xbuf, format, ap);
 822 
 823         if (max_len && xbuf.len > max_len) {
 824                 xbuf.len = max_len;
 825         }
 826         smart_str_0(&xbuf);
 827 
 828         *pbuf = xbuf.c;
 829 
 830         return xbuf.len;
 831 }
 832 /* }}} */
 833 
 834 PHPAPI int spprintf(char **pbuf, size_t max_len, const char *format, ...) /* {{{ */
 835 {
 836         int cc;
 837         va_list ap;
 838 
 839         va_start(ap, format);
 840         cc = vspprintf(pbuf, max_len, format, ap);
 841         va_end(ap);
 842         return (cc);
 843 }
 844 /* }}} */
 845 
 846 /*
 847  * Local variables:
 848  * tab-width: 4
 849  * c-basic-offset: 4
 850  * End:
 851  * vim600: sw=4 ts=4 fdm=marker
 852  * vim<600: sw=4 ts=4
 853  */

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