Annotation of embedaddon/php/main/snprintf.c, revision 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>