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

1.1       misho       1: /*
                      2:    +----------------------------------------------------------------------+
                      3:    | PHP Version 5                                                        |
                      4:    +----------------------------------------------------------------------+
1.1.1.4 ! misho       5:    | Copyright (c) 1997-2014 The PHP Group                                |
1.1       misho       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: 
1.1.1.2   misho      19: /* $Id$ */
1.1       misho      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:  */
1.1.1.2   misho     126: #define NUM_BUF_SIZE           2048
1.1       misho     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;
1.1.1.3   misho     214:        u_wide_int ui_num = (u_wide_int) 0;
1.1       misho     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:                                        zvp = (zval*) va_arg(ap, zval*);
                    394:                                        zend_make_printable_zval(zvp, &zcopy, &free_zcopy);
                    395:                                        if (free_zcopy) {
                    396:                                                zvp = &zcopy;
                    397:                                        }
                    398:                                        s_len = Z_STRLEN_P(zvp);
                    399:                                        s = Z_STRVAL_P(zvp);
                    400:                                        if (adjust_precision && precision < s_len) {
                    401:                                                s_len = precision;
                    402:                                        }
                    403:                                        break;
                    404:                                case 'u':
                    405:                                        switch(modifier) {
                    406:                                                default:
                    407:                                                        i_num = (wide_int) va_arg(ap, unsigned int);
                    408:                                                        break;
                    409:                                                case LM_LONG_DOUBLE:
                    410:                                                        goto fmt_error;
                    411:                                                case LM_LONG:
                    412:                                                        i_num = (wide_int) va_arg(ap, unsigned long int);
                    413:                                                        break;
                    414:                                                case LM_SIZE_T:
                    415:                                                        i_num = (wide_int) va_arg(ap, size_t);
                    416:                                                        break;
                    417: #if SIZEOF_LONG_LONG
                    418:                                                case LM_LONG_LONG:
                    419:                                                        i_num = (wide_int) va_arg(ap, u_wide_int);
                    420:                                                        break;
                    421: #endif
                    422: #if SIZEOF_INTMAX_T
                    423:                                                case LM_INTMAX_T:
                    424:                                                        i_num = (wide_int) va_arg(ap, uintmax_t);
                    425:                                                        break;
                    426: #endif
                    427: #if SIZEOF_PTRDIFF_T
                    428:                                                case LM_PTRDIFF_T:
                    429:                                                        i_num = (wide_int) va_arg(ap, ptrdiff_t);
                    430:                                                        break;
                    431: #endif
                    432:                                        }
                    433:                                        /*
                    434:                                         * The rest also applies to other integer formats, so fall
                    435:                                         * into that case.
                    436:                                         */
                    437:                                case 'd':
                    438:                                case 'i':
                    439:                                        /*
                    440:                                         * Get the arg if we haven't already.
                    441:                                         */
                    442:                                        if ((*fmt) != 'u') {
                    443:                                                switch(modifier) {
                    444:                                                        default:
                    445:                                                                i_num = (wide_int) va_arg(ap, int);
                    446:                                                                break;
                    447:                                                        case LM_LONG_DOUBLE:
                    448:                                                                goto fmt_error;
                    449:                                                        case LM_LONG:
                    450:                                                                i_num = (wide_int) va_arg(ap, long int);
                    451:                                                                break;
                    452:                                                        case LM_SIZE_T:
                    453: #if SIZEOF_SSIZE_T
                    454:                                                                i_num = (wide_int) va_arg(ap, ssize_t);
                    455: #else
                    456:                                                                i_num = (wide_int) va_arg(ap, size_t);
                    457: #endif
                    458:                                                                break;
                    459: #if SIZEOF_LONG_LONG
                    460:                                                        case LM_LONG_LONG:
                    461:                                                                i_num = (wide_int) va_arg(ap, wide_int);
                    462:                                                                break;
                    463: #endif
                    464: #if SIZEOF_INTMAX_T
                    465:                                                        case LM_INTMAX_T:
                    466:                                                                i_num = (wide_int) va_arg(ap, intmax_t);
                    467:                                                                break;
                    468: #endif
                    469: #if SIZEOF_PTRDIFF_T
                    470:                                                        case LM_PTRDIFF_T:
                    471:                                                                i_num = (wide_int) va_arg(ap, ptrdiff_t);
                    472:                                                                break;
                    473: #endif
                    474:                                                }
                    475:                                        }
                    476:                                        s = ap_php_conv_10(i_num, (*fmt) == 'u', &is_negative,
                    477:                                                                &num_buf[NUM_BUF_SIZE], &s_len);
                    478:                                        FIX_PRECISION(adjust_precision, precision, s, s_len);
                    479: 
                    480:                                        if (*fmt != 'u') {
                    481:                                                if (is_negative)
                    482:                                                        prefix_char = '-';
                    483:                                                else if (print_sign)
                    484:                                                        prefix_char = '+';
                    485:                                                else if (print_blank)
                    486:                                                        prefix_char = ' ';
                    487:                                        }
                    488:                                        break;
                    489: 
                    490: 
                    491:                                case 'o':
                    492:                                        switch(modifier) {
                    493:                                                default:
                    494:                                                        ui_num = (u_wide_int) va_arg(ap, unsigned int);
                    495:                                                        break;
                    496:                                                case LM_LONG_DOUBLE:
                    497:                                                        goto fmt_error;
                    498:                                                case LM_LONG:
                    499:                                                        ui_num = (u_wide_int) va_arg(ap, unsigned long int);
                    500:                                                        break;
                    501:                                                case LM_SIZE_T:
                    502:                                                        ui_num = (u_wide_int) va_arg(ap, size_t);
                    503:                                                        break;
                    504: #if SIZEOF_LONG_LONG
                    505:                                                case LM_LONG_LONG:
                    506:                                                        ui_num = (u_wide_int) va_arg(ap, u_wide_int);
                    507:                                                        break;
                    508: #endif
                    509: #if SIZEOF_INTMAX_T
                    510:                                                case LM_INTMAX_T:
                    511:                                                        ui_num = (u_wide_int) va_arg(ap, uintmax_t);
                    512:                                                        break;
                    513: #endif
                    514: #if SIZEOF_PTRDIFF_T
                    515:                                                case LM_PTRDIFF_T:
                    516:                                                        ui_num = (u_wide_int) va_arg(ap, ptrdiff_t);
                    517:                                                        break;
                    518: #endif
                    519:                                        }
                    520:                                        s = ap_php_conv_p2(ui_num, 3, *fmt,
                    521:                                                                &num_buf[NUM_BUF_SIZE], &s_len);
                    522:                                        FIX_PRECISION(adjust_precision, precision, s, s_len);
                    523:                                        if (alternate_form && *s != '0') {
                    524:                                                *--s = '0';
                    525:                                                s_len++;
                    526:                                        }
                    527:                                        break;
                    528: 
                    529: 
                    530:                                case 'x':
                    531:                                case 'X':
                    532:                                        switch(modifier) {
                    533:                                                default:
                    534:                                                        ui_num = (u_wide_int) va_arg(ap, unsigned int);
                    535:                                                        break;
                    536:                                                case LM_LONG_DOUBLE:
                    537:                                                        goto fmt_error;
                    538:                                                case LM_LONG:
                    539:                                                        ui_num = (u_wide_int) va_arg(ap, unsigned long int);
                    540:                                                        break;
                    541:                                                case LM_SIZE_T:
                    542:                                                        ui_num = (u_wide_int) va_arg(ap, size_t);
                    543:                                                        break;
                    544: #if SIZEOF_LONG_LONG
                    545:                                                case LM_LONG_LONG:
                    546:                                                        ui_num = (u_wide_int) va_arg(ap, u_wide_int);
                    547:                                                        break;
                    548: #endif
                    549: #if SIZEOF_INTMAX_T
                    550:                                                case LM_INTMAX_T:
                    551:                                                        ui_num = (u_wide_int) va_arg(ap, uintmax_t);
                    552:                                                        break;
                    553: #endif
                    554: #if SIZEOF_PTRDIFF_T
                    555:                                                case LM_PTRDIFF_T:
                    556:                                                        ui_num = (u_wide_int) va_arg(ap, ptrdiff_t);
                    557:                                                        break;
                    558: #endif
                    559:                                        }
                    560:                                        s = ap_php_conv_p2(ui_num, 4, *fmt,
                    561:                                                                &num_buf[NUM_BUF_SIZE], &s_len);
                    562:                                        FIX_PRECISION(adjust_precision, precision, s, s_len);
1.1.1.3   misho     563:                                        if (alternate_form && ui_num != 0) {
1.1       misho     564:                                                *--s = *fmt;    /* 'x' or 'X' */
                    565:                                                *--s = '0';
                    566:                                                s_len += 2;
                    567:                                        }
                    568:                                        break;
                    569: 
                    570: 
                    571:                                case 's':
                    572:                                case 'v':
                    573:                                        s = va_arg(ap, char *);
                    574:                                        if (s != NULL) {
                    575:                                                if (!adjust_precision) {
                    576:                                                        s_len = strlen(s);
                    577:                                                } else {
                    578:                                                        s_len = strnlen(s, precision);
                    579:                                                }
                    580:                                        } else {
                    581:                                                s = S_NULL;
                    582:                                                s_len = S_NULL_LEN;
                    583:                                        }
                    584:                                        pad_char = ' ';
                    585:                                        break;
                    586: 
                    587: 
                    588:                                case 'f':
                    589:                                case 'F':
                    590:                                case 'e':
                    591:                                case 'E':
                    592:                                        switch(modifier) {
                    593:                                                case LM_LONG_DOUBLE:
                    594:                                                        fp_num = (double) va_arg(ap, long double);
                    595:                                                        break;
                    596:                                                case LM_STD:
                    597:                                                        fp_num = va_arg(ap, double);
                    598:                                                        break;
                    599:                                                default:
                    600:                                                        goto fmt_error;
                    601:                                        }
                    602: 
                    603:                                        if (zend_isnan(fp_num)) {
                    604:                                                s = "nan";
                    605:                                                s_len = 3;
                    606:                                        } else if (zend_isinf(fp_num)) {
                    607:                                                s = "inf";
                    608:                                                s_len = 3;
                    609:                                        } else {
                    610: #ifdef HAVE_LOCALE_H
                    611:                                                if (!lconv) {
                    612:                                                        lconv = localeconv();
                    613:                                                }
                    614: #endif
                    615:                                                s = php_conv_fp((*fmt == 'f')?'F':*fmt, fp_num, alternate_form,
                    616:                                                 (adjust_precision == NO) ? FLOAT_DIGITS : precision,
                    617:                                                 (*fmt == 'f')?LCONV_DECIMAL_POINT:'.',
                    618:                                                                        &is_negative, &num_buf[1], &s_len);
                    619:                                                if (is_negative)
                    620:                                                        prefix_char = '-';
                    621:                                                else if (print_sign)
                    622:                                                        prefix_char = '+';
                    623:                                                else if (print_blank)
                    624:                                                        prefix_char = ' ';
                    625:                                        }
                    626:                                        break;
                    627: 
                    628: 
                    629:                                case 'g':
                    630:                                case 'k':
                    631:                                case 'G':
                    632:                                case 'H':
                    633:                                        switch(modifier) {
                    634:                                                case LM_LONG_DOUBLE:
                    635:                                                        fp_num = (double) va_arg(ap, long double);
                    636:                                                        break;
                    637:                                                case LM_STD:
                    638:                                                        fp_num = va_arg(ap, double);
                    639:                                                        break;
                    640:                                                default:
                    641:                                                        goto fmt_error;
                    642:                                        }
                    643: 
                    644:                                        if (zend_isnan(fp_num)) {
                    645:                                                s = "NAN";
                    646:                                                s_len = 3;
                    647:                                                break;
                    648:                                        } else if (zend_isinf(fp_num)) {
                    649:                                                if (fp_num > 0) {
                    650:                                                        s = "INF";
                    651:                                                        s_len = 3;
                    652:                                                } else {
                    653:                                                        s = "-INF";
                    654:                                                        s_len = 4;
                    655:                                                }
                    656:                                                break;
                    657:                                        }
                    658: 
                    659:                                        if (adjust_precision == NO)
                    660:                                                precision = FLOAT_DIGITS;
                    661:                                        else if (precision == 0)
                    662:                                                precision = 1;
                    663:                                        /*
                    664:                                         * * We use &num_buf[ 1 ], so that we have room for the sign
                    665:                                         */
                    666: #ifdef HAVE_LOCALE_H
                    667:                                        if (!lconv) {
                    668:                                                lconv = localeconv();
                    669:                                        }
                    670: #endif
                    671:                                        s = php_gcvt(fp_num, precision, (*fmt=='H' || *fmt == 'k') ? '.' : LCONV_DECIMAL_POINT, (*fmt == 'G' || *fmt == 'H')?'E':'e', &num_buf[1]);
                    672:                                        if (*s == '-')
                    673:                                                prefix_char = *s++;
                    674:                                        else if (print_sign)
                    675:                                                prefix_char = '+';
                    676:                                        else if (print_blank)
                    677:                                                prefix_char = ' ';
                    678: 
                    679:                                        s_len = strlen(s);
                    680: 
                    681:                                        if (alternate_form && (strchr(s, '.')) == NULL)
                    682:                                                s[s_len++] = '.';
                    683:                                        break;
                    684: 
                    685: 
                    686:                                case 'c':
                    687:                                        char_buf[0] = (char) (va_arg(ap, int));
                    688:                                        s = &char_buf[0];
                    689:                                        s_len = 1;
                    690:                                        pad_char = ' ';
                    691:                                        break;
                    692: 
                    693: 
                    694:                                case '%':
                    695:                                        char_buf[0] = '%';
                    696:                                        s = &char_buf[0];
                    697:                                        s_len = 1;
                    698:                                        pad_char = ' ';
                    699:                                        break;
                    700: 
                    701: 
                    702:                                case 'n':
                    703:                                        *(va_arg(ap, int *)) = xbuf->len;
                    704:                                        goto skip_output;
                    705: 
                    706:                                        /*
                    707:                                         * Always extract the argument as a "char *" pointer. We
                    708:                                         * should be using "void *" but there are still machines
                    709:                                         * that don't understand it.
                    710:                                         * If the pointer size is equal to the size of an unsigned
                    711:                                         * integer we convert the pointer to a hex number, otherwise
                    712:                                         * we print "%p" to indicate that we don't handle "%p".
                    713:                                         */
                    714:                                case 'p':
                    715:                                        if (sizeof(char *) <= sizeof(u_wide_int)) {
                    716:                                                ui_num = (u_wide_int)((size_t) va_arg(ap, char *));
                    717:                                                s = ap_php_conv_p2(ui_num, 4, 'x',
                    718:                                                                &num_buf[NUM_BUF_SIZE], &s_len);
                    719:                                                if (ui_num != 0) {
                    720:                                                        *--s = 'x';
                    721:                                                        *--s = '0';
                    722:                                                        s_len += 2;
                    723:                                                }
                    724:                                        } else {
                    725:                                                s = "%p";
                    726:                                                s_len = 2;
                    727:                                        }
                    728:                                        pad_char = ' ';
                    729:                                        break;
                    730: 
                    731: 
                    732:                                case NUL:
                    733:                                        /*
                    734:                                         * The last character of the format string was %.
                    735:                                         * We ignore it.
                    736:                                         */
                    737:                                        continue;
                    738: 
                    739: 
                    740: fmt_error:
                    741:                                php_error(E_ERROR, "Illegal length modifier specified '%c' in s[np]printf call", *fmt);
                    742:                                        /*
                    743:                                         * The default case is for unrecognized %'s.
                    744:                                         * We print %<char> to help the user identify what
                    745:                                         * option is not understood.
                    746:                                         * This is also useful in case the user wants to pass
                    747:                                         * the output of format_converter to another function
                    748:                                         * that understands some other %<char> (like syslog).
                    749:                                         * Note that we can't point s inside fmt because the
                    750:                                         * unknown <char> could be preceded by width etc.
                    751:                                         */
                    752:                                default:
                    753:                                        char_buf[0] = '%';
                    754:                                        char_buf[1] = *fmt;
                    755:                                        s = char_buf;
                    756:                                        s_len = 2;
                    757:                                        pad_char = ' ';
                    758:                                        break;
                    759:                        }
                    760: 
                    761:                        if (prefix_char != NUL) {
                    762:                                *--s = prefix_char;
                    763:                                s_len++;
                    764:                        }
                    765:                        if (adjust_width && adjust == RIGHT && min_width > s_len) {
                    766:                                if (pad_char == '0' && prefix_char != NUL) {
                    767:                                        INS_CHAR(xbuf, *s);
                    768:                                        s++;
                    769:                                        s_len--;
                    770:                                        min_width--;
                    771:                                }
                    772:                                PAD(xbuf, min_width - s_len, pad_char);
                    773:                        }
                    774:                        /*
                    775:                         * Print the string s.
                    776:                         */
                    777:                        INS_STRING(xbuf, s, s_len);
                    778: 
                    779:                        if (adjust_width && adjust == LEFT && min_width > s_len)
                    780:                                PAD(xbuf, min_width - s_len, pad_char);
                    781:                        if (free_zcopy) {
                    782:                                zval_dtor(&zcopy);
                    783:                        }
                    784:                }
                    785: skip_output:
                    786:                fmt++;
                    787:        }
                    788:        return;
                    789: }
                    790: /* }}} */
                    791: 
                    792: /*
                    793:  * This is the general purpose conversion function.
                    794:  */
                    795: PHPAPI int vspprintf(char **pbuf, size_t max_len, const char *format, va_list ap) /* {{{ */
                    796: {
                    797:        smart_str xbuf = {0};
                    798: 
                    799:        xbuf_format_converter(&xbuf, format, ap);
                    800: 
                    801:        if (max_len && xbuf.len > max_len) {
                    802:                xbuf.len = max_len;
                    803:        }
                    804:        smart_str_0(&xbuf);
                    805: 
                    806:        *pbuf = xbuf.c;
                    807: 
                    808:        return xbuf.len;
                    809: }
                    810: /* }}} */
                    811: 
                    812: PHPAPI int spprintf(char **pbuf, size_t max_len, const char *format, ...) /* {{{ */
                    813: {
                    814:        int cc;
                    815:        va_list ap;
                    816: 
                    817:        va_start(ap, format);
                    818:        cc = vspprintf(pbuf, max_len, format, ap);
                    819:        va_end(ap);
                    820:        return (cc);
                    821: }
                    822: /* }}} */
                    823: 
                    824: /*
                    825:  * Local variables:
                    826:  * tab-width: 4
                    827:  * c-basic-offset: 4
                    828:  * End:
                    829:  * vim600: sw=4 ts=4 fdm=marker
                    830:  * vim<600: sw=4 ts=4
                    831:  */

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