Annotation of embedaddon/php/main/spprintf.c, revision 1.1.1.1

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

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>