Annotation of embedaddon/php/main/snprintf.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:                                                              |
                     16:   +----------------------------------------------------------------------+
                     17: */
                     18: 
                     19: /* $Id: snprintf.c 321634 2012-01-01 13:15:04Z felipe $ */
                     20: 
                     21: 
                     22: #include "php.h"
                     23: 
                     24: #include <zend_strtod.h>
                     25: 
                     26: #include <stddef.h>
                     27: #include <stdio.h>
                     28: #include <ctype.h>
                     29: #include <sys/types.h>
                     30: #include <stdarg.h>
                     31: #include <string.h>
                     32: #include <stdlib.h>
                     33: #include <math.h>
                     34: 
                     35: #ifdef HAVE_INTTYPES_H
                     36: #include <inttypes.h>
                     37: #endif
                     38: 
                     39: #ifdef HAVE_LOCALE_H
                     40: #include <locale.h>
                     41: #define LCONV_DECIMAL_POINT (*lconv->decimal_point)
                     42: #else
                     43: #define LCONV_DECIMAL_POINT '.'
                     44: #endif
                     45: 
                     46: /*
                     47:  * Copyright (c) 2002, 2006 Todd C. Miller <Todd.Miller@courtesan.com>
                     48:  *
                     49:  * Permission to use, copy, modify, and distribute this software for any
                     50:  * purpose with or without fee is hereby granted, provided that the above
                     51:  * copyright notice and this permission notice appear in all copies.
                     52:  *
                     53:  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
                     54:  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
                     55:  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
                     56:  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
                     57:  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
                     58:  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
                     59:  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
                     60:  *
                     61:  * Sponsored in part by the Defense Advanced Research Projects
                     62:  * Agency (DARPA) and Air Force Research Laboratory, Air Force
                     63:  * Materiel Command, USAF, under agreement number F39502-99-1-0512.
                     64:  */
                     65: 
                     66: static char * __cvt(double value, int ndigit, int *decpt, int *sign, int fmode, int pad) /* {{{ */
                     67: {
                     68:        register char *s = NULL;
                     69:        char *p, *rve, c;
                     70:        size_t siz;
                     71: 
                     72:        if (ndigit < 0) {
                     73:                siz = -ndigit + 1;
                     74:        } else {
                     75:                siz = ndigit + 1;
                     76:        }
                     77: 
                     78:        /* __dtoa() doesn't allocate space for 0 so we do it by hand */
                     79:        if (value == 0.0) {
                     80:                *decpt = 1 - fmode; /* 1 for 'e', 0 for 'f' */
                     81:                *sign = 0;
                     82:                if ((rve = s = (char *)malloc(ndigit?siz:2)) == NULL) {
                     83:                        return(NULL);
                     84:                }
                     85:                *rve++ = '0';
                     86:                *rve = '\0';
                     87:                if (!ndigit) {
                     88:                        return(s);
                     89:                }
                     90:        } else {
                     91:                p = zend_dtoa(value, fmode + 2, ndigit, decpt, sign, &rve);
                     92:                if (*decpt == 9999) {
                     93:                        /* Infinity or Nan, convert to inf or nan like printf */
                     94:                        *decpt = 0;
                     95:                        c = *p;
                     96:                        zend_freedtoa(p);
                     97:                        return(c == 'I' ? "INF" : "NAN");
                     98:                }
                     99:                /* Make a local copy and adjust rve to be in terms of s */
                    100:                if (pad && fmode) {
                    101:                        siz += *decpt;
                    102:                }
                    103:                if ((s = (char *)malloc(siz+1)) == NULL) {
                    104:                        zend_freedtoa(p);
                    105:                        return(NULL);
                    106:                }
                    107:                (void) strlcpy(s, p, siz);
                    108:                rve = s + (rve - p);
                    109:                zend_freedtoa(p);
                    110:        }
                    111: 
                    112:        /* Add trailing zeros */
                    113:        if (pad) {
                    114:                siz -= rve - s;
                    115:                while (--siz) {
                    116:                        *rve++ = '0';
                    117:                }
                    118:                *rve = '\0';
                    119:        }
                    120: 
                    121:        return(s);
                    122: }
                    123: /* }}} */
                    124: 
                    125: static inline char *php_ecvt(double value, int ndigit, int *decpt, int *sign) /* {{{ */
                    126: {
                    127:        return(__cvt(value, ndigit, decpt, sign, 0, 1));
                    128: }
                    129: /* }}} */
                    130: 
                    131: static inline char *php_fcvt(double value, int ndigit, int *decpt, int *sign) /* {{{ */
                    132: {
                    133:     return(__cvt(value, ndigit, decpt, sign, 1, 1));
                    134: }
                    135: /* }}} */
                    136: 
                    137: PHPAPI char *php_gcvt(double value, int ndigit, char dec_point, char exponent, char *buf) /* {{{ */
                    138: {
                    139:        char *digits, *dst, *src;
                    140:        int i, decpt, sign;
                    141: 
                    142:        digits = zend_dtoa(value, 2, ndigit, &decpt, &sign, NULL);
                    143:        if (decpt == 9999) {
                    144:                /*
                    145:                 * Infinity or NaN, convert to inf or nan with sign.
                    146:                 * We assume the buffer is at least ndigit long.
                    147:                 */
                    148:                snprintf(buf, ndigit + 1, "%s%s", (sign && *digits == 'I') ? "-" : "", *digits == 'I' ? "INF" : "NAN");
                    149:                zend_freedtoa(digits);
                    150:                return (buf);
                    151:        }
                    152: 
                    153:        dst = buf;
                    154:        if (sign) {
                    155:                *dst++ = '-';
                    156:        }
                    157: 
                    158:        if ((decpt >= 0 && decpt > ndigit) || decpt < -3) { /* use E-style */
                    159:                /* exponential format (e.g. 1.2345e+13) */
                    160:                if (--decpt < 0) {
                    161:                        sign = 1;
                    162:                        decpt = -decpt;
                    163:                } else {
                    164:                        sign = 0;
                    165:                }
                    166:                src = digits;
                    167:                *dst++ = *src++;
                    168:                *dst++ = dec_point;
                    169:                if (*src == '\0') {
                    170:                        *dst++ = '0';
                    171:                } else {
                    172:                        do {
                    173:                                *dst++ = *src++;
                    174:                        } while (*src != '\0');
                    175:                }
                    176:                *dst++ = exponent;
                    177:                if (sign) {
                    178:                        *dst++ = '-';
                    179:                } else {
                    180:                        *dst++ = '+';
                    181:                }
                    182:                if (decpt < 10) {
                    183:                        *dst++ = '0' + decpt;
                    184:                        *dst = '\0';
                    185:                } else {
                    186:                        /* XXX - optimize */
                    187:                        for (sign = decpt, i = 0; (sign /= 10) != 0; i++)
                    188:                                continue;
                    189:                        dst[i + 1] = '\0';
                    190:                        while (decpt != 0) {
                    191:                                dst[i--] = '0' + decpt % 10;
                    192:                                decpt /= 10;
                    193:                        }
                    194:                }
                    195:        } else if (decpt < 0) {
                    196:                /* standard format 0. */
                    197:                *dst++ = '0';   /* zero before decimal point */
                    198:                *dst++ = dec_point;
                    199:                do {
                    200:                        *dst++ = '0';
                    201:                } while (++decpt < 0);
                    202:                src = digits;
                    203:                while (*src != '\0') {
                    204:                        *dst++ = *src++;
                    205:                }
                    206:                *dst = '\0';
                    207:        } else {
                    208:                /* standard format */
                    209:                for (i = 0, src = digits; i < decpt; i++) {
                    210:                        if (*src != '\0') {
                    211:                                *dst++ = *src++;
                    212:                        } else {
                    213:                                *dst++ = '0';
                    214:                        }
                    215:                }
                    216:                if (*src != '\0') {
                    217:                        if (src == digits) {
                    218:                                *dst++ = '0';   /* zero before decimal point */
                    219:                        }
                    220:                        *dst++ = dec_point;
                    221:                        for (i = decpt; digits[i] != '\0'; i++) {
                    222:                 *dst++ = digits[i];
                    223:             }
                    224:         }
                    225:         *dst = '\0';
                    226:     }
                    227:     zend_freedtoa(digits);
                    228:     return (buf);
                    229: }
                    230: /* }}} */
                    231: 
                    232: /* {{{ Apache license */
                    233: /* ====================================================================
                    234:  * Copyright (c) 1995-1998 The Apache Group.  All rights reserved.
                    235:  *
                    236:  * Redistribution and use in source and binary forms, with or without
                    237:  * modification, are permitted provided that the following conditions
                    238:  * are met:
                    239:  *
                    240:  * 1. Redistributions of source code must retain the above copyright
                    241:  *    notice, this list of conditions and the following disclaimer.
                    242:  *
                    243:  * 2. Redistributions in binary form must reproduce the above copyright
                    244:  *    notice, this list of conditions and the following disclaimer in
                    245:  *    the documentation and/or other materials provided with the
                    246:  *    distribution.
                    247:  *
                    248:  * 3. All advertising materials mentioning features or use of this
                    249:  *    software must display the following acknowledgment:
                    250:  *    "This product includes software developed by the Apache Group
                    251:  *    for use in the Apache HTTP server project (http://www.apache.org/)."
                    252:  *
                    253:  * 4. The names "Apache Server" and "Apache Group" must not be used to
                    254:  *    endorse or promote products derived from this software without
                    255:  *    prior written permission.
                    256:  *
                    257:  * 5. Redistributions of any form whatsoever must retain the following
                    258:  *    acknowledgment:
                    259:  *    "This product includes software developed by the Apache Group
                    260:  *    for use in the Apache HTTP server project (http://www.apache.org/)."
                    261:  *
                    262:  * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY
                    263:  * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                    264:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
                    265:  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE APACHE GROUP OR
                    266:  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
                    267:  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
                    268:  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
                    269:  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                    270:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
                    271:  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
                    272:  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
                    273:  * OF THE POSSIBILITY OF SUCH DAMAGE.
                    274:  * ====================================================================
                    275:  *
                    276:  * This software consists of voluntary contributions made by many
                    277:  * individuals on behalf of the Apache Group and was originally based
                    278:  * on public domain software written at the National Center for
                    279:  * Supercomputing Applications, University of Illinois, Urbana-Champaign.
                    280:  * For more information on the Apache Group and the Apache HTTP server
                    281:  * project, please see <http://www.apache.org/>.
                    282:  *
                    283:  * This code is based on, and used with the permission of, the
                    284:  * SIO stdio-replacement strx_* functions by Panos Tsirigotis
                    285:  * <panos@alumni.cs.colorado.edu> for xinetd.
                    286:  */
                    287: /* }}} */
                    288: 
                    289: #define FALSE                  0
                    290: #define TRUE                   1
                    291: #define NUL                    '\0'
                    292: #define INT_NULL               ((int *)0)
                    293: 
                    294: #define S_NULL                 "(null)"
                    295: #define S_NULL_LEN             6
                    296: 
                    297: #define FLOAT_DIGITS           6
                    298: #define EXPONENT_LENGTH                10
                    299: 
                    300: 
                    301: /*
                    302:  * Convert num to its decimal format.
                    303:  * Return value:
                    304:  *   - a pointer to a string containing the number (no sign)
                    305:  *   - len contains the length of the string
                    306:  *   - is_negative is set to TRUE or FALSE depending on the sign
                    307:  *     of the number (always set to FALSE if is_unsigned is TRUE)
                    308:  *
                    309:  * The caller provides a buffer for the string: that is the buf_end argument
                    310:  * which is a pointer to the END of the buffer + 1 (i.e. if the buffer
                    311:  * is declared as buf[ 100 ], buf_end should be &buf[ 100 ])
                    312:  */
                    313: /* char * ap_php_conv_10() {{{ */
                    314: char * ap_php_conv_10(register wide_int num, register bool_int is_unsigned,
                    315:           register bool_int * is_negative, char *buf_end, register int *len)
                    316: {
                    317:        register char *p = buf_end;
                    318:        register u_wide_int magnitude;
                    319: 
                    320:        if (is_unsigned) {
                    321:                magnitude = (u_wide_int) num;
                    322:                *is_negative = FALSE;
                    323:        } else {
                    324:                *is_negative = (num < 0);
                    325: 
                    326:                /*
                    327:                 * On a 2's complement machine, negating the most negative integer
                    328:                 * results in a number that cannot be represented as a signed integer.
                    329:                 * Here is what we do to obtain the number's magnitude:
                    330:                 *      a. add 1 to the number
                    331:                 *      b. negate it (becomes positive)
                    332:                 *      c. convert it to unsigned
                    333:                 *      d. add 1
                    334:                 */
                    335:                if (*is_negative) {
                    336:                        wide_int t = num + 1;
                    337:                        magnitude = ((u_wide_int) - t) + 1;
                    338:                } else {
                    339:                        magnitude = (u_wide_int) num;
                    340:                }
                    341:        }
                    342: 
                    343:        /*
                    344:         * We use a do-while loop so that we write at least 1 digit
                    345:         */
                    346:        do {
                    347:                register u_wide_int new_magnitude = magnitude / 10;
                    348: 
                    349:                *--p = (char)(magnitude - new_magnitude * 10 + '0');
                    350:                magnitude = new_magnitude;
                    351:        }
                    352:        while (magnitude);
                    353: 
                    354:        *len = buf_end - p;
                    355:        return (p);
                    356: }
                    357: /* }}} */
                    358: 
                    359: /* If you change this value then also change bug24640.phpt.
                    360:  * Also NDIG must be reasonable smaller than NUM_BUF_SIZE.
                    361:  */
                    362: #define        NDIG    320
                    363: 
                    364: 
                    365: /*
                    366:  * Convert a floating point number to a string formats 'f', 'e' or 'E'.
                    367:  * The result is placed in buf, and len denotes the length of the string
                    368:  * The sign is returned in the is_negative argument (and is not placed
                    369:  * in buf).
                    370:  */
                    371: /* PHPAPI char * php_conv_fp() {{{ */
                    372: PHPAPI char * php_conv_fp(register char format, register double num,
                    373:                 boolean_e add_dp, int precision, char dec_point, bool_int * is_negative, char *buf, int *len)
                    374: {
                    375:        register char *s = buf;
                    376:        register char *p, *p_orig;
                    377:        int decimal_point;
                    378: 
                    379:        if (precision >= NDIG - 1) {
                    380:                precision = NDIG - 2;
                    381:        }
                    382: 
                    383:        if (format == 'F') {
                    384:                p_orig = p = php_fcvt(num, precision, &decimal_point, is_negative);
                    385:        } else {                                                /* either e or E format */
                    386:                p_orig = p = php_ecvt(num, precision + 1, &decimal_point, is_negative);
                    387:        }
                    388: 
                    389:        /*
                    390:         * Check for Infinity and NaN
                    391:         */
                    392:        if (isalpha((int)*p)) {
                    393:                *len = strlen(p);
                    394:                memcpy(buf, p, *len + 1);
                    395:                *is_negative = FALSE;
                    396:                free(p_orig);
                    397:                return (buf);
                    398:        }
                    399:        if (format == 'F') {
                    400:                if (decimal_point <= 0) {
                    401:                        if (num != 0 || precision > 0) {
                    402:                                *s++ = '0';
                    403:                                if (precision > 0) {
                    404:                                        *s++ = dec_point;
                    405:                                        while (decimal_point++ < 0) {
                    406:                                                *s++ = '0';
                    407:                                        }
                    408:                                } else if (add_dp) {
                    409:                                        *s++ = dec_point;
                    410:                                }
                    411:                        }
                    412:                } else {
                    413:                        int addz = decimal_point >= NDIG ? decimal_point - NDIG + 1 : 0;
                    414:                        decimal_point -= addz;
                    415:                        while (decimal_point-- > 0) {
                    416:                                *s++ = *p++;
                    417:                        }
                    418:                        while (addz-- > 0) {
                    419:                                *s++ = '0';
                    420:                        }
                    421:                        if (precision > 0 || add_dp) {
                    422:                                *s++ = dec_point;
                    423:                        }
                    424:                }
                    425:        } else {
                    426:                *s++ = *p++;
                    427:                if (precision > 0 || add_dp) {
                    428:                        *s++ = '.';
                    429:                }
                    430:        }
                    431: 
                    432:        /*
                    433:         * copy the rest of p, the NUL is NOT copied
                    434:         */
                    435:        while (*p) {
                    436:                *s++ = *p++;
                    437:        }
                    438: 
                    439:        if (format != 'F') {
                    440:                char temp[EXPONENT_LENGTH];             /* for exponent conversion */
                    441:                int t_len;
                    442:                bool_int exponent_is_negative;
                    443: 
                    444:                *s++ = format;                  /* either e or E */
                    445:                decimal_point--;
                    446:                if (decimal_point != 0) {
                    447:                        p = ap_php_conv_10((wide_int) decimal_point, FALSE, &exponent_is_negative, &temp[EXPONENT_LENGTH], &t_len);
                    448:                        *s++ = exponent_is_negative ? '-' : '+';
                    449: 
                    450:                        /*
                    451:                         * Make sure the exponent has at least 2 digits
                    452:                         */
                    453:                        while (t_len--) {
                    454:                                *s++ = *p++;
                    455:                        }
                    456:                } else {
                    457:                        *s++ = '+';
                    458:                        *s++ = '0';
                    459:                }
                    460:        }
                    461:        *len = s - buf;
                    462:        free(p_orig);
                    463:        return (buf);
                    464: }
                    465: /* }}} */
                    466: 
                    467: /*
                    468:  * Convert num to a base X number where X is a power of 2. nbits determines X.
                    469:  * For example, if nbits is 3, we do base 8 conversion
                    470:  * Return value:
                    471:  *      a pointer to a string containing the number
                    472:  *
                    473:  * The caller provides a buffer for the string: that is the buf_end argument
                    474:  * which is a pointer to the END of the buffer + 1 (i.e. if the buffer
                    475:  * is declared as buf[ 100 ], buf_end should be &buf[ 100 ])
                    476:  */
                    477: char * ap_php_conv_p2(register u_wide_int num, register int nbits, char format, char *buf_end, register int *len) /* {{{ */
                    478: {
                    479:        register int mask = (1 << nbits) - 1;
                    480:        register char *p = buf_end;
                    481:        static char low_digits[] = "0123456789abcdef";
                    482:        static char upper_digits[] = "0123456789ABCDEF";
                    483:        register char *digits = (format == 'X') ? upper_digits : low_digits;
                    484: 
                    485:        do {
                    486:                *--p = digits[num & mask];
                    487:                num >>= nbits;
                    488:        }
                    489:        while (num);
                    490: 
                    491:        *len = buf_end - p;
                    492:        return (p);
                    493: }
                    494: /* }}} */
                    495: 
                    496: /*
                    497:  * NUM_BUF_SIZE is the size of the buffer used for arithmetic conversions
                    498:  *
                    499:  * XXX: this is a magic number; do not decrease it
                    500:  * Emax = 1023
                    501:  * NDIG = 320
                    502:  * NUM_BUF_SIZE >= strlen("-") + Emax + strlrn(".") + NDIG + strlen("E+1023") + 1;
                    503:  */
                    504: #define NUM_BUF_SIZE           2048
                    505: 
                    506: 
                    507: /*
                    508:  * Descriptor for buffer area
                    509:  */
                    510: struct buf_area {
                    511:        char *buf_end;
                    512:        char *nextb;                            /* pointer to next byte to read/write   */
                    513: };
                    514: 
                    515: typedef struct buf_area buffy;
                    516: 
                    517: /*
                    518:  * The INS_CHAR macro inserts a character in the buffer and writes
                    519:  * the buffer back to disk if necessary
                    520:  * It uses the char pointers sp and bep:
                    521:  *      sp points to the next available character in the buffer
                    522:  *      bep points to the end-of-buffer+1
                    523:  * While using this macro, note that the nextb pointer is NOT updated.
                    524:  *
                    525:  * NOTE: Evaluation of the c argument should not have any side-effects
                    526:  */
                    527: #define INS_CHAR(c, sp, bep, cc) \
                    528:        {                            \
                    529:                if (sp < bep)            \
                    530:                {                        \
                    531:                        *sp++ = c;           \
                    532:                }                        \
                    533:                cc++;                    \
                    534:        }
                    535: 
                    536: #define NUM( c )                       ( c - '0' )
                    537: 
                    538: #define STR_TO_DEC( str, num )         \
                    539:     num = NUM( *str++ ) ;              \
                    540:     while ( isdigit((int)*str ) )              \
                    541:     {                                  \
                    542:        num *= 10 ;                     \
                    543:        num += NUM( *str++ ) ;          \
                    544:     }
                    545: 
                    546: /*
                    547:  * This macro does zero padding so that the precision
                    548:  * requirement is satisfied. The padding is done by
                    549:  * adding '0's to the left of the string that is going
                    550:  * to be printed.
                    551:  */
                    552: #define FIX_PRECISION( adjust, precision, s, s_len )   \
                    553:     if ( adjust )                                      \
                    554:        while ( s_len < precision )                     \
                    555:        {                                               \
                    556:            *--s = '0' ;                                \
                    557:            s_len++ ;                                   \
                    558:        }
                    559: 
                    560: /*
                    561:  * Macro that does padding. The padding is done by printing
                    562:  * the character ch.
                    563:  */
                    564: #define PAD( width, len, ch )  do              \
                    565:        {                                       \
                    566:            INS_CHAR( ch, sp, bep, cc ) ;       \
                    567:            width-- ;                           \
                    568:        }                                       \
                    569:        while ( width > len )
                    570: 
                    571: /*
                    572:  * Prefix the character ch to the string str
                    573:  * Increase length
                    574:  * Set the has_prefix flag
                    575:  */
                    576: #define PREFIX( str, length, ch )       *--str = ch ; length++ ; has_prefix = YES
                    577: 
                    578: 
                    579: /*
                    580:  * Do format conversion placing the output in buffer
                    581:  */
                    582: static int format_converter(register buffy * odp, const char *fmt, va_list ap) /* {{{ */
                    583: {
                    584:        char *sp;
                    585:        char *bep;
                    586:        int cc = 0;
                    587:        int i;
                    588: 
                    589:        char *s = NULL;
                    590:        int s_len, free_zcopy;
                    591:        zval *zvp, zcopy;
                    592: 
                    593:        int min_width = 0;
                    594:        int precision = 0;
                    595:        enum {
                    596:                LEFT, RIGHT
                    597:        } adjust;
                    598:        char pad_char;
                    599:        char prefix_char;
                    600: 
                    601:        double fp_num;
                    602:        wide_int i_num = (wide_int) 0;
                    603:        u_wide_int ui_num;
                    604: 
                    605:        char num_buf[NUM_BUF_SIZE];
                    606:        char char_buf[2];                       /* for printing %% and %<unknown> */
                    607: 
                    608: #ifdef HAVE_LOCALE_H
                    609:        struct lconv *lconv = NULL;
                    610: #endif
                    611: 
                    612:        /*
                    613:         * Flag variables
                    614:         */
                    615:        length_modifier_e modifier;
                    616:        boolean_e alternate_form;
                    617:        boolean_e print_sign;
                    618:        boolean_e print_blank;
                    619:        boolean_e adjust_precision;
                    620:        boolean_e adjust_width;
                    621:        bool_int is_negative;
                    622: 
                    623:        sp = odp->nextb;
                    624:        bep = odp->buf_end;
                    625: 
                    626:        while (*fmt) {
                    627:                if (*fmt != '%') {
                    628:                        INS_CHAR(*fmt, sp, bep, cc);
                    629:                } else {
                    630:                        /*
                    631:                         * Default variable settings
                    632:                         */
                    633:                        adjust = RIGHT;
                    634:                        alternate_form = print_sign = print_blank = NO;
                    635:                        pad_char = ' ';
                    636:                        prefix_char = NUL;
                    637:                        free_zcopy = 0;
                    638: 
                    639:                        fmt++;
                    640: 
                    641:                        /*
                    642:                         * Try to avoid checking for flags, width or precision
                    643:                         */
                    644:                        if (isascii((int)*fmt) && !islower((int)*fmt)) {
                    645:                                /*
                    646:                                 * Recognize flags: -, #, BLANK, +
                    647:                                 */
                    648:                                for (;; fmt++) {
                    649:                                        if (*fmt == '-')
                    650:                                                adjust = LEFT;
                    651:                                        else if (*fmt == '+')
                    652:                                                print_sign = YES;
                    653:                                        else if (*fmt == '#')
                    654:                                                alternate_form = YES;
                    655:                                        else if (*fmt == ' ')
                    656:                                                print_blank = YES;
                    657:                                        else if (*fmt == '0')
                    658:                                                pad_char = '0';
                    659:                                        else
                    660:                                                break;
                    661:                                }
                    662: 
                    663:                                /*
                    664:                                 * Check if a width was specified
                    665:                                 */
                    666:                                if (isdigit((int)*fmt)) {
                    667:                                        STR_TO_DEC(fmt, min_width);
                    668:                                        adjust_width = YES;
                    669:                                } else if (*fmt == '*') {
                    670:                                        min_width = va_arg(ap, int);
                    671:                                        fmt++;
                    672:                                        adjust_width = YES;
                    673:                                        if (min_width < 0) {
                    674:                                                adjust = LEFT;
                    675:                                                min_width = -min_width;
                    676:                                        }
                    677:                                } else
                    678:                                        adjust_width = NO;
                    679: 
                    680:                                /*
                    681:                                 * Check if a precision was specified
                    682:                                 */
                    683:                                if (*fmt == '.') {
                    684:                                        adjust_precision = YES;
                    685:                                        fmt++;
                    686:                                        if (isdigit((int)*fmt)) {
                    687:                                                STR_TO_DEC(fmt, precision);
                    688:                                        } else if (*fmt == '*') {
                    689:                                                precision = va_arg(ap, int);
                    690:                                                fmt++;
                    691:                                                if (precision < 0)
                    692:                                                        precision = 0;
                    693:                                        } else
                    694:                                                precision = 0;
                    695:                                        
                    696:                                        if (precision > FORMAT_CONV_MAX_PRECISION) {
                    697:                                                precision = FORMAT_CONV_MAX_PRECISION;
                    698:                                        }
                    699:                                } else
                    700:                                        adjust_precision = NO;
                    701:                        } else
                    702:                                adjust_precision = adjust_width = NO;
                    703: 
                    704:                        /*
                    705:                         * Modifier check
                    706:                         */
                    707:                        switch (*fmt) {
                    708:                                case 'L':
                    709:                                        fmt++;
                    710:                                        modifier = LM_LONG_DOUBLE;
                    711:                                        break;
                    712:                                case 'I':
                    713:                                        fmt++;
                    714: #if SIZEOF_LONG_LONG
                    715:                                        if (*fmt == '6' && *(fmt+1) == '4') {
                    716:                                                fmt += 2;
                    717:                                                modifier = LM_LONG_LONG;
                    718:                                        } else
                    719: #endif
                    720:                                                if (*fmt == '3' && *(fmt+1) == '2') {
                    721:                                                        fmt += 2;
                    722:                                                        modifier = LM_LONG;
                    723:                                                } else {
                    724: #ifdef _WIN64
                    725:                                                        modifier = LM_LONG_LONG;
                    726: #else
                    727:                                                        modifier = LM_LONG;
                    728: #endif
                    729:                                                }
                    730:                                        break;
                    731:                                case 'l':
                    732:                                        fmt++;
                    733: #if SIZEOF_LONG_LONG
                    734:                                        if (*fmt == 'l') {
                    735:                                                fmt++;
                    736:                                                modifier = LM_LONG_LONG;
                    737:                                        } else
                    738: #endif
                    739:                                                modifier = LM_LONG;
                    740:                                        break;
                    741:                                case 'z':
                    742:                                        fmt++;
                    743:                                        modifier = LM_SIZE_T;
                    744:                                        break;
                    745:                                case 'j':
                    746:                                        fmt++;
                    747: #if SIZEOF_INTMAX_T
                    748:                                        modifier = LM_INTMAX_T;
                    749: #else
                    750:                                        modifier = LM_SIZE_T;
                    751: #endif
                    752:                                        break;
                    753:                                case 't':
                    754:                                        fmt++;
                    755: #if SIZEOF_PTRDIFF_T
                    756:                                        modifier = LM_PTRDIFF_T;
                    757: #else
                    758:                                        modifier = LM_SIZE_T;
                    759: #endif
                    760:                                        break;
                    761:                                case 'h':
                    762:                                        fmt++;
                    763:                                        if (*fmt == 'h') {
                    764:                                                fmt++;
                    765:                                        }
                    766:                                        /* these are promoted to int, so no break */
                    767:                                default:
                    768:                                        modifier = LM_STD;
                    769:                                        break;
                    770:                        }
                    771: 
                    772:                        /*
                    773:                         * Argument extraction and printing.
                    774:                         * First we determine the argument type.
                    775:                         * Then, we convert the argument to a string.
                    776:                         * On exit from the switch, s points to the string that
                    777:                         * must be printed, s_len has the length of the string
                    778:                         * The precision requirements, if any, are reflected in s_len.
                    779:                         *
                    780:                         * NOTE: pad_char may be set to '0' because of the 0 flag.
                    781:                         *   It is reset to ' ' by non-numeric formats
                    782:                         */
                    783:                        switch (*fmt) {
                    784:                                case 'Z':
                    785: #if SUHOSIN_PATCH
                    786:                                        zend_suhosin_log(S_MISC, "'Z' specifier within format string");
                    787:                                        goto skip_output;
                    788: #else
                    789:                                        zvp = (zval*) va_arg(ap, zval*);
                    790:                                        zend_make_printable_zval(zvp, &zcopy, &free_zcopy);
                    791:                                        if (free_zcopy) {
                    792:                                                zvp = &zcopy;
                    793:                                        }
                    794:                                        s_len = Z_STRLEN_P(zvp);
                    795:                                        s = Z_STRVAL_P(zvp);
                    796:                                        if (adjust_precision && precision < s_len) {
                    797:                                                s_len = precision;
                    798:                                        }
                    799: #endif
                    800:                                        break;
                    801:                                case 'u':
                    802:                                        switch(modifier) {
                    803:                                                default:
                    804:                                                        i_num = (wide_int) va_arg(ap, unsigned int);
                    805:                                                        break;
                    806:                                                case LM_LONG_DOUBLE:
                    807:                                                        goto fmt_error;
                    808:                                                case LM_LONG:
                    809:                                                        i_num = (wide_int) va_arg(ap, unsigned long int);
                    810:                                                        break;
                    811:                                                case LM_SIZE_T:
                    812:                                                        i_num = (wide_int) va_arg(ap, size_t);
                    813:                                                        break;
                    814: #if SIZEOF_LONG_LONG
                    815:                                                case LM_LONG_LONG:
                    816:                                                        i_num = (wide_int) va_arg(ap, u_wide_int);
                    817:                                                        break;
                    818: #endif
                    819: #if SIZEOF_INTMAX_T
                    820:                                                case LM_INTMAX_T:
                    821:                                                        i_num = (wide_int) va_arg(ap, uintmax_t);
                    822:                                                        break;
                    823: #endif
                    824: #if SIZEOF_PTRDIFF_T
                    825:                                                case LM_PTRDIFF_T:
                    826:                                                        i_num = (wide_int) va_arg(ap, ptrdiff_t);
                    827:                                                        break;
                    828: #endif
                    829:                                        }
                    830:                                        /*
                    831:                                         * The rest also applies to other integer formats, so fall
                    832:                                         * into that case.
                    833:                                         */
                    834:                                case 'd':
                    835:                                case 'i':
                    836:                                        /*
                    837:                                         * Get the arg if we haven't already.
                    838:                                         */
                    839:                                        if ((*fmt) != 'u') {
                    840:                                                switch(modifier) {
                    841:                                                        default:
                    842:                                                                i_num = (wide_int) va_arg(ap, int);
                    843:                                                                break;
                    844:                                                        case LM_LONG_DOUBLE:
                    845:                                                                goto fmt_error;
                    846:                                                        case LM_LONG:
                    847:                                                                i_num = (wide_int) va_arg(ap, long int);
                    848:                                                                break;
                    849:                                                        case LM_SIZE_T:
                    850: #if SIZEOF_SSIZE_T
                    851:                                                                i_num = (wide_int) va_arg(ap, ssize_t);
                    852: #else
                    853:                                                                i_num = (wide_int) va_arg(ap, size_t);
                    854: #endif
                    855:                                                                break;
                    856: #if SIZEOF_LONG_LONG
                    857:                                                        case LM_LONG_LONG:
                    858:                                                                i_num = (wide_int) va_arg(ap, wide_int);
                    859:                                                                break;
                    860: #endif
                    861: #if SIZEOF_INTMAX_T
                    862:                                                        case LM_INTMAX_T:
                    863:                                                                i_num = (wide_int) va_arg(ap, intmax_t);
                    864:                                                                break;
                    865: #endif
                    866: #if SIZEOF_PTRDIFF_T
                    867:                                                        case LM_PTRDIFF_T:
                    868:                                                                i_num = (wide_int) va_arg(ap, ptrdiff_t);
                    869:                                                                break;
                    870: #endif
                    871:                                                }
                    872:                                        }
                    873:                                        s = ap_php_conv_10(i_num, (*fmt) == 'u', &is_negative,
                    874:                                                                &num_buf[NUM_BUF_SIZE], &s_len);
                    875:                                        FIX_PRECISION(adjust_precision, precision, s, s_len);
                    876: 
                    877:                                        if (*fmt != 'u') {
                    878:                                                if (is_negative) {
                    879:                                                        prefix_char = '-';
                    880:                                                } else if (print_sign) {
                    881:                                                        prefix_char = '+';
                    882:                                                } else if (print_blank) {
                    883:                                                        prefix_char = ' ';
                    884:                                                }
                    885:                                        }
                    886:                                        break;
                    887: 
                    888: 
                    889:                                case 'o':
                    890:                                        switch(modifier) {
                    891:                                                default:
                    892:                                                        ui_num = (u_wide_int) va_arg(ap, unsigned int);
                    893:                                                        break;
                    894:                                                case LM_LONG_DOUBLE:
                    895:                                                        goto fmt_error;
                    896:                                                case LM_LONG:
                    897:                                                        ui_num = (u_wide_int) va_arg(ap, unsigned long int);
                    898:                                                        break;
                    899:                                                case LM_SIZE_T:
                    900:                                                        ui_num = (u_wide_int) va_arg(ap, size_t);
                    901:                                                        break;
                    902: #if SIZEOF_LONG_LONG
                    903:                                                case LM_LONG_LONG:
                    904:                                                        ui_num = (u_wide_int) va_arg(ap, u_wide_int);
                    905:                                                        break;
                    906: #endif
                    907: #if SIZEOF_INTMAX_T
                    908:                                                case LM_INTMAX_T:
                    909:                                                        ui_num = (u_wide_int) va_arg(ap, uintmax_t);
                    910:                                                        break;
                    911: #endif
                    912: #if SIZEOF_PTRDIFF_T
                    913:                                                case LM_PTRDIFF_T:
                    914:                                                        ui_num = (u_wide_int) va_arg(ap, ptrdiff_t);
                    915:                                                        break;
                    916: #endif
                    917:                                        }
                    918:                                        s = ap_php_conv_p2(ui_num, 3, *fmt, &num_buf[NUM_BUF_SIZE], &s_len);
                    919:                                        FIX_PRECISION(adjust_precision, precision, s, s_len);
                    920:                                        if (alternate_form && *s != '0') {
                    921:                                                *--s = '0';
                    922:                                                s_len++;
                    923:                                        }
                    924:                                        break;
                    925: 
                    926: 
                    927:                                case 'x':
                    928:                                case 'X':
                    929:                                        switch(modifier) {
                    930:                                                default:
                    931:                                                        ui_num = (u_wide_int) va_arg(ap, unsigned int);
                    932:                                                        break;
                    933:                                                case LM_LONG_DOUBLE:
                    934:                                                        goto fmt_error;
                    935:                                                case LM_LONG:
                    936:                                                        ui_num = (u_wide_int) va_arg(ap, unsigned long int);
                    937:                                                        break;
                    938:                                                case LM_SIZE_T:
                    939:                                                        ui_num = (u_wide_int) va_arg(ap, size_t);
                    940:                                                        break;
                    941: #if SIZEOF_LONG_LONG
                    942:                                                case LM_LONG_LONG:
                    943:                                                        ui_num = (u_wide_int) va_arg(ap, u_wide_int);
                    944:                                                        break;
                    945: #endif
                    946: #if SIZEOF_INTMAX_T
                    947:                                                case LM_INTMAX_T:
                    948:                                                        ui_num = (u_wide_int) va_arg(ap, uintmax_t);
                    949:                                                        break;
                    950: #endif
                    951: #if SIZEOF_PTRDIFF_T
                    952:                                                case LM_PTRDIFF_T:
                    953:                                                        ui_num = (u_wide_int) va_arg(ap, ptrdiff_t);
                    954:                                                        break;
                    955: #endif
                    956:                                        }
                    957:                                        s = ap_php_conv_p2(ui_num, 4, *fmt, &num_buf[NUM_BUF_SIZE], &s_len);
                    958:                                        FIX_PRECISION(adjust_precision, precision, s, s_len);
                    959:                                        if (alternate_form && i_num != 0) {
                    960:                                                *--s = *fmt;    /* 'x' or 'X' */
                    961:                                                *--s = '0';
                    962:                                                s_len += 2;
                    963:                                        }
                    964:                                        break;
                    965: 
                    966: 
                    967:                                case 's':
                    968:                                case 'v':
                    969:                                        s = va_arg(ap, char *);
                    970:                                        if (s != NULL) {
                    971:                                                s_len = strlen(s);
                    972:                                                if (adjust_precision && precision < s_len) {
                    973:                                                        s_len = precision;
                    974:                                                }
                    975:                                        } else {
                    976:                                                s = S_NULL;
                    977:                                                s_len = S_NULL_LEN;
                    978:                                        }
                    979:                                        pad_char = ' ';
                    980:                                        break;
                    981: 
                    982: 
                    983:                                case 'f':
                    984:                                case 'F':
                    985:                                case 'e':
                    986:                                case 'E':
                    987:                                        switch(modifier) {
                    988:                                                case LM_LONG_DOUBLE:
                    989:                                                        fp_num = (double) va_arg(ap, long double);
                    990:                                                        break;
                    991:                                                case LM_STD:
                    992:                                                        fp_num = va_arg(ap, double);
                    993:                                                        break;
                    994:                                                default:
                    995:                                                        goto fmt_error;
                    996:                                        }
                    997: 
                    998:                                        if (zend_isnan(fp_num)) {
                    999:                                                s = "NAN";
                   1000:                                                s_len = 3;
                   1001:                                        } else if (zend_isinf(fp_num)) {
                   1002:                                                s = "INF";
                   1003:                                                s_len = 3;
                   1004:                                        } else {
                   1005: #ifdef HAVE_LOCALE_H
                   1006:                                                if (!lconv) {
                   1007:                                                        lconv = localeconv();
                   1008:                                                }
                   1009: #endif
                   1010:                                                s = php_conv_fp((*fmt == 'f')?'F':*fmt, fp_num, alternate_form,
                   1011:                                                 (adjust_precision == NO) ? FLOAT_DIGITS : precision,
                   1012:                                                 (*fmt == 'f')?LCONV_DECIMAL_POINT:'.',
                   1013:                                                                        &is_negative, &num_buf[1], &s_len);
                   1014:                                                if (is_negative)
                   1015:                                                        prefix_char = '-';
                   1016:                                                else if (print_sign)
                   1017:                                                        prefix_char = '+';
                   1018:                                                else if (print_blank)
                   1019:                                                        prefix_char = ' ';
                   1020:                                        }
                   1021:                                        break;
                   1022: 
                   1023: 
                   1024:                                case 'g':
                   1025:                                case 'k':
                   1026:                                case 'G':
                   1027:                                case 'H':
                   1028:                                        switch(modifier) {
                   1029:                                                case LM_LONG_DOUBLE:
                   1030:                                                        fp_num = (double) va_arg(ap, long double);
                   1031:                                                        break;
                   1032:                                                case LM_STD:
                   1033:                                                        fp_num = va_arg(ap, double);
                   1034:                                                        break;
                   1035:                                                default:
                   1036:                                                        goto fmt_error;
                   1037:                                        }
                   1038: 
                   1039:                                        if (zend_isnan(fp_num)) {
                   1040:                                                s = "NAN";
                   1041:                                                s_len = 3;
                   1042:                                                break;
                   1043:                                        } else if (zend_isinf(fp_num)) {
                   1044:                                                if (fp_num > 0) {
                   1045:                                                        s = "INF";
                   1046:                                                        s_len = 3;
                   1047:                                                } else {
                   1048:                                                        s = "-INF";
                   1049:                                                        s_len = 4;
                   1050:                                                }
                   1051:                                                break;
                   1052:                                        }
                   1053: 
                   1054:                                        if (adjust_precision == NO) {
                   1055:                                                precision = FLOAT_DIGITS;
                   1056:                                        } else if (precision == 0) {
                   1057:                                                precision = 1;
                   1058:                                        }
                   1059:                                        /*
                   1060:                                         * * We use &num_buf[ 1 ], so that we have room for the sign
                   1061:                                         */
                   1062: #ifdef HAVE_LOCALE_H
                   1063:                                        if (!lconv) {
                   1064:                                                lconv = localeconv();
                   1065:                                        }
                   1066: #endif
                   1067:                                        s = php_gcvt(fp_num, precision, (*fmt=='H' || *fmt == 'k') ? '.' : LCONV_DECIMAL_POINT, (*fmt == 'G' || *fmt == 'H')?'E':'e', &num_buf[1]);
                   1068:                                        if (*s == '-') {
                   1069:                                                prefix_char = *s++;
                   1070:                                        } else if (print_sign) {
                   1071:                                                prefix_char = '+';
                   1072:                                        } else if (print_blank) {
                   1073:                                                prefix_char = ' ';
                   1074:                                        }
                   1075: 
                   1076:                                        s_len = strlen(s);
                   1077: 
                   1078:                                        if (alternate_form && (strchr(s, '.')) == NULL) {
                   1079:                                                s[s_len++] = '.';
                   1080:                                        }
                   1081:                                        break;
                   1082: 
                   1083: 
                   1084:                                case 'c':
                   1085:                                        char_buf[0] = (char) (va_arg(ap, int));
                   1086:                                        s = &char_buf[0];
                   1087:                                        s_len = 1;
                   1088:                                        pad_char = ' ';
                   1089:                                        break;
                   1090: 
                   1091: 
                   1092:                                case '%':
                   1093:                                        char_buf[0] = '%';
                   1094:                                        s = &char_buf[0];
                   1095:                                        s_len = 1;
                   1096:                                        pad_char = ' ';
                   1097:                                        break;
                   1098: 
                   1099: 
                   1100:                                case 'n':
                   1101: #if SUHOSIN_PATCH
                   1102:                                        zend_suhosin_log(S_MISC, "'n' specifier within format string");
                   1103: #else
                   1104:                                        *(va_arg(ap, int *)) = cc;
                   1105: #endif
                   1106:                                        goto skip_output;
                   1107: 
                   1108:                                        /*
                   1109:                                         * Always extract the argument as a "char *" pointer. We
                   1110:                                         * should be using "void *" but there are still machines
                   1111:                                         * that don't understand it.
                   1112:                                         * If the pointer size is equal to the size of an unsigned
                   1113:                                         * integer we convert the pointer to a hex number, otherwise
                   1114:                                         * we print "%p" to indicate that we don't handle "%p".
                   1115:                                         */
                   1116:                                case 'p':
                   1117:                                        if (sizeof(char *) <= sizeof(u_wide_int)) {
                   1118:                                                ui_num = (u_wide_int)((size_t) va_arg(ap, char *));
                   1119:                                                s = ap_php_conv_p2(ui_num, 4, 'x',
                   1120:                                                                &num_buf[NUM_BUF_SIZE], &s_len);
                   1121:                                                if (ui_num != 0) {
                   1122:                                                        *--s = 'x';
                   1123:                                                        *--s = '0';
                   1124:                                                        s_len += 2;
                   1125:                                                }
                   1126:                                        } else {
                   1127:                                                s = "%p";
                   1128:                                                s_len = 2;
                   1129:                                        }
                   1130:                                        pad_char = ' ';
                   1131:                                        break;
                   1132: 
                   1133: 
                   1134:                                case NUL:
                   1135:                                        /*
                   1136:                                         * The last character of the format string was %.
                   1137:                                         * We ignore it.
                   1138:                                         */
                   1139:                                        continue;
                   1140: 
                   1141: 
                   1142: fmt_error:
                   1143:                                php_error(E_ERROR, "Illegal length modifier specified '%c' in s[np]printf call", *fmt);
                   1144:                                        /*
                   1145:                                         * The default case is for unrecognized %'s.
                   1146:                                         * We print %<char> to help the user identify what
                   1147:                                         * option is not understood.
                   1148:                                         * This is also useful in case the user wants to pass
                   1149:                                         * the output of format_converter to another function
                   1150:                                         * that understands some other %<char> (like syslog).
                   1151:                                         * Note that we can't point s inside fmt because the
                   1152:                                         * unknown <char> could be preceded by width etc.
                   1153:                                         */
                   1154:                                default:
                   1155:                                        char_buf[0] = '%';
                   1156:                                        char_buf[1] = *fmt;
                   1157:                                        s = char_buf;
                   1158:                                        s_len = 2;
                   1159:                                        pad_char = ' ';
                   1160:                                        break;
                   1161:                        }
                   1162: 
                   1163:                        if (prefix_char != NUL) {
                   1164:                                *--s = prefix_char;
                   1165:                                s_len++;
                   1166:                        }
                   1167:                        if (adjust_width && adjust == RIGHT && min_width > s_len) {
                   1168:                                if (pad_char == '0' && prefix_char != NUL) {
                   1169:                                        INS_CHAR(*s, sp, bep, cc)
                   1170:                                                s++;
                   1171:                                        s_len--;
                   1172:                                        min_width--;
                   1173:                                }
                   1174:                                PAD(min_width, s_len, pad_char);
                   1175:                        }
                   1176:                        /*
                   1177:                         * Print the string s.
                   1178:                         */
                   1179:                        for (i = s_len; i != 0; i--) {
                   1180:                                INS_CHAR(*s, sp, bep, cc);
                   1181:                                s++;
                   1182:                        }
                   1183: 
                   1184:                        if (adjust_width && adjust == LEFT && min_width > s_len)
                   1185:                                PAD(min_width, s_len, pad_char);
                   1186:                        if (free_zcopy) {
                   1187:                                zval_dtor(&zcopy);
                   1188:                        }
                   1189:                }
                   1190: skip_output:
                   1191:                fmt++;
                   1192:        }
                   1193:        odp->nextb = sp;
                   1194:        return (cc);
                   1195: }
                   1196: /* }}} */
                   1197: 
                   1198: /*
                   1199:  * This is the general purpose conversion function.
                   1200:  */
                   1201: static void strx_printv(int *ccp, char *buf, size_t len, const char *format, va_list ap) /* {{{ */
                   1202: {
                   1203:        buffy od;
                   1204:        int cc;
                   1205: 
                   1206:        /*
                   1207:         * First initialize the descriptor
                   1208:         * Notice that if no length is given, we initialize buf_end to the
                   1209:         * highest possible address.
                   1210:         */
                   1211:        if (len == 0) {
                   1212:                od.buf_end = (char *) ~0;
                   1213:                od.nextb   = (char *) ~0;
                   1214:        } else {
                   1215:                od.buf_end = &buf[len-1];
                   1216:                od.nextb   = buf;
                   1217:        }
                   1218: 
                   1219:        /*
                   1220:         * Do the conversion
                   1221:         */
                   1222:        cc = format_converter(&od, format, ap);
                   1223:        if (len != 0 && od.nextb <= od.buf_end) {
                   1224:                *(od.nextb) = '\0';
                   1225:        }
                   1226:        if (ccp) {
                   1227:                *ccp = cc;
                   1228:        }
                   1229: }
                   1230: /* }}} */
                   1231: 
                   1232: PHPAPI int ap_php_slprintf(char *buf, size_t len, const char *format,...) /* {{{ */
                   1233: {
                   1234:        int cc;
                   1235:        va_list ap;
                   1236: 
                   1237:        va_start(ap, format);
                   1238:        strx_printv(&cc, buf, len, format, ap);
                   1239:        va_end(ap);
                   1240:        if (cc >= len) {
                   1241:                cc = len -1;
                   1242:                buf[cc] = '\0';
                   1243:        }
                   1244:        return cc;
                   1245: }
                   1246: /* }}} */
                   1247: 
                   1248: PHPAPI int ap_php_vslprintf(char *buf, size_t len, const char *format, va_list ap) /* {{{ */
                   1249: {
                   1250:        int cc;
                   1251: 
                   1252:        strx_printv(&cc, buf, len, format, ap);
                   1253:        if (cc >= len) {
                   1254:                cc = len -1;
                   1255:                buf[cc] = '\0';
                   1256:        }
                   1257:        return cc;
                   1258: }
                   1259: /* }}} */
                   1260: 
                   1261: PHPAPI int ap_php_snprintf(char *buf, size_t len, const char *format,...) /* {{{ */
                   1262: {
                   1263:        int cc;
                   1264:        va_list ap;
                   1265: 
                   1266:        va_start(ap, format);
                   1267:        strx_printv(&cc, buf, len, format, ap);
                   1268:        va_end(ap);
                   1269:        return (cc);
                   1270: }
                   1271: /* }}} */
                   1272: 
                   1273: PHPAPI int ap_php_vsnprintf(char *buf, size_t len, const char *format, va_list ap) /* {{{ */
                   1274: {
                   1275:        int cc;
                   1276: 
                   1277:        strx_printv(&cc, buf, len, format, ap);
                   1278:        return (cc);
                   1279: }
                   1280: /* }}} */
                   1281: 
                   1282: PHPAPI int ap_php_vasprintf(char **buf, const char *format, va_list ap) /* {{{ */
                   1283: {
                   1284:        va_list ap2;
                   1285:        int cc;
                   1286: 
                   1287:        va_copy(ap2, ap);
                   1288:        cc = ap_php_vsnprintf(NULL, 0, format, ap2);
                   1289:        va_end(ap2);
                   1290: 
                   1291:        *buf = NULL;
                   1292: 
                   1293:        if (cc >= 0) {
                   1294:                if ((*buf = malloc(++cc)) != NULL) {
                   1295:                        if ((cc = ap_php_vsnprintf(*buf, cc, format, ap)) < 0) {
                   1296:                                free(*buf);
                   1297:                                *buf = NULL;
                   1298:                        }
                   1299:                }
                   1300:        }
                   1301: 
                   1302:        return cc;
                   1303: }
                   1304: /* }}} */
                   1305: 
                   1306: PHPAPI int ap_php_asprintf(char **buf, const char *format, ...) /* {{{ */
                   1307: {
                   1308:        int cc;
                   1309:        va_list ap;
                   1310: 
                   1311:        va_start(ap, format);
                   1312:        cc = vasprintf(buf, format, ap);
                   1313:        va_end(ap);
                   1314:        return cc;
                   1315: }
                   1316: /* }}} */
                   1317: 
                   1318: /*
                   1319:  * Local variables:
                   1320:  * tab-width: 4
                   1321:  * c-basic-offset: 4
                   1322:  * End:
                   1323:  * vim600: sw=4 ts=4 fdm=marker
                   1324:  * vim<600: sw=4 ts=4
                   1325:  */

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