File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / php / main / snprintf.c
Revision 1.1.1.3 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Mon Jul 22 01:32:11 2013 UTC (10 years, 11 months ago) by misho
Branches: php, MAIN
CVS tags: v5_4_29p0, v5_4_20p0, v5_4_20, v5_4_17, HEAD
5.4.17

    1: /*
    2:   +----------------------------------------------------------------------+
    3:   | PHP Version 5                                                        |
    4:   +----------------------------------------------------------------------+
    5:   | Copyright (c) 1997-2013 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,v 1.1.1.3 2013/07/22 01:32:11 misho Exp $ */
   20: 
   21: #define _GNU_SOURCE
   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 strdup((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: 					zvp = (zval*) va_arg(ap, zval*);
  786: 					zend_make_printable_zval(zvp, &zcopy, &free_zcopy);
  787: 					if (free_zcopy) {
  788: 						zvp = &zcopy;
  789: 					}
  790: 					s_len = Z_STRLEN_P(zvp);
  791: 					s = Z_STRVAL_P(zvp);
  792: 					if (adjust_precision && precision < s_len) {
  793: 						s_len = precision;
  794: 					}
  795: 					break;
  796: 				case 'u':
  797: 					switch(modifier) {
  798: 						default:
  799: 							i_num = (wide_int) va_arg(ap, unsigned int);
  800: 							break;
  801: 						case LM_LONG_DOUBLE:
  802: 							goto fmt_error;
  803: 						case LM_LONG:
  804: 							i_num = (wide_int) va_arg(ap, unsigned long int);
  805: 							break;
  806: 						case LM_SIZE_T:
  807: 							i_num = (wide_int) va_arg(ap, size_t);
  808: 							break;
  809: #if SIZEOF_LONG_LONG
  810: 						case LM_LONG_LONG:
  811: 							i_num = (wide_int) va_arg(ap, u_wide_int);
  812: 							break;
  813: #endif
  814: #if SIZEOF_INTMAX_T
  815: 						case LM_INTMAX_T:
  816: 							i_num = (wide_int) va_arg(ap, uintmax_t);
  817: 							break;
  818: #endif
  819: #if SIZEOF_PTRDIFF_T
  820: 						case LM_PTRDIFF_T:
  821: 							i_num = (wide_int) va_arg(ap, ptrdiff_t);
  822: 							break;
  823: #endif
  824: 					}
  825: 					/*
  826: 					 * The rest also applies to other integer formats, so fall
  827: 					 * into that case.
  828: 					 */
  829: 				case 'd':
  830: 				case 'i':
  831: 					/*
  832: 					 * Get the arg if we haven't already.
  833: 					 */
  834: 					if ((*fmt) != 'u') {
  835: 						switch(modifier) {
  836: 							default:
  837: 								i_num = (wide_int) va_arg(ap, int);
  838: 								break;
  839: 							case LM_LONG_DOUBLE:
  840: 								goto fmt_error;
  841: 							case LM_LONG:
  842: 								i_num = (wide_int) va_arg(ap, long int);
  843: 								break;
  844: 							case LM_SIZE_T:
  845: #if SIZEOF_SSIZE_T
  846: 								i_num = (wide_int) va_arg(ap, ssize_t);
  847: #else
  848: 								i_num = (wide_int) va_arg(ap, size_t);
  849: #endif
  850: 								break;
  851: #if SIZEOF_LONG_LONG
  852: 							case LM_LONG_LONG:
  853: 								i_num = (wide_int) va_arg(ap, wide_int);
  854: 								break;
  855: #endif
  856: #if SIZEOF_INTMAX_T
  857: 							case LM_INTMAX_T:
  858: 								i_num = (wide_int) va_arg(ap, intmax_t);
  859: 								break;
  860: #endif
  861: #if SIZEOF_PTRDIFF_T
  862: 							case LM_PTRDIFF_T:
  863: 								i_num = (wide_int) va_arg(ap, ptrdiff_t);
  864: 								break;
  865: #endif
  866: 						}
  867: 					}
  868: 					s = ap_php_conv_10(i_num, (*fmt) == 'u', &is_negative,
  869: 								&num_buf[NUM_BUF_SIZE], &s_len);
  870: 					FIX_PRECISION(adjust_precision, precision, s, s_len);
  871: 
  872: 					if (*fmt != 'u') {
  873: 						if (is_negative) {
  874: 							prefix_char = '-';
  875: 						} else if (print_sign) {
  876: 							prefix_char = '+';
  877: 						} else if (print_blank) {
  878: 							prefix_char = ' ';
  879: 						}
  880: 					}
  881: 					break;
  882: 
  883: 
  884: 				case 'o':
  885: 					switch(modifier) {
  886: 						default:
  887: 							ui_num = (u_wide_int) va_arg(ap, unsigned int);
  888: 							break;
  889: 						case LM_LONG_DOUBLE:
  890: 							goto fmt_error;
  891: 						case LM_LONG:
  892: 							ui_num = (u_wide_int) va_arg(ap, unsigned long int);
  893: 							break;
  894: 						case LM_SIZE_T:
  895: 							ui_num = (u_wide_int) va_arg(ap, size_t);
  896: 							break;
  897: #if SIZEOF_LONG_LONG
  898: 						case LM_LONG_LONG:
  899: 							ui_num = (u_wide_int) va_arg(ap, u_wide_int);
  900: 							break;
  901: #endif
  902: #if SIZEOF_INTMAX_T
  903: 						case LM_INTMAX_T:
  904: 							ui_num = (u_wide_int) va_arg(ap, uintmax_t);
  905: 							break;
  906: #endif
  907: #if SIZEOF_PTRDIFF_T
  908: 						case LM_PTRDIFF_T:
  909: 							ui_num = (u_wide_int) va_arg(ap, ptrdiff_t);
  910: 							break;
  911: #endif
  912: 					}
  913: 					s = ap_php_conv_p2(ui_num, 3, *fmt, &num_buf[NUM_BUF_SIZE], &s_len);
  914: 					FIX_PRECISION(adjust_precision, precision, s, s_len);
  915: 					if (alternate_form && *s != '0') {
  916: 						*--s = '0';
  917: 						s_len++;
  918: 					}
  919: 					break;
  920: 
  921: 
  922: 				case 'x':
  923: 				case 'X':
  924: 					switch(modifier) {
  925: 						default:
  926: 							ui_num = (u_wide_int) va_arg(ap, unsigned int);
  927: 							break;
  928: 						case LM_LONG_DOUBLE:
  929: 							goto fmt_error;
  930: 						case LM_LONG:
  931: 							ui_num = (u_wide_int) va_arg(ap, unsigned long int);
  932: 							break;
  933: 						case LM_SIZE_T:
  934: 							ui_num = (u_wide_int) va_arg(ap, size_t);
  935: 							break;
  936: #if SIZEOF_LONG_LONG
  937: 						case LM_LONG_LONG:
  938: 							ui_num = (u_wide_int) va_arg(ap, u_wide_int);
  939: 							break;
  940: #endif
  941: #if SIZEOF_INTMAX_T
  942: 						case LM_INTMAX_T:
  943: 							ui_num = (u_wide_int) va_arg(ap, uintmax_t);
  944: 							break;
  945: #endif
  946: #if SIZEOF_PTRDIFF_T
  947: 						case LM_PTRDIFF_T:
  948: 							ui_num = (u_wide_int) va_arg(ap, ptrdiff_t);
  949: 							break;
  950: #endif
  951: 					}
  952: 					s = ap_php_conv_p2(ui_num, 4, *fmt, &num_buf[NUM_BUF_SIZE], &s_len);
  953: 					FIX_PRECISION(adjust_precision, precision, s, s_len);
  954: 					if (alternate_form && i_num != 0) {
  955: 						*--s = *fmt;	/* 'x' or 'X' */
  956: 						*--s = '0';
  957: 						s_len += 2;
  958: 					}
  959: 					break;
  960: 
  961: 
  962: 				case 's':
  963: 				case 'v':
  964: 					s = va_arg(ap, char *);
  965: 					if (s != NULL) {
  966: 						s_len = strlen(s);
  967: 						if (adjust_precision && precision < s_len) {
  968: 							s_len = precision;
  969: 						}
  970: 					} else {
  971: 						s = S_NULL;
  972: 						s_len = S_NULL_LEN;
  973: 					}
  974: 					pad_char = ' ';
  975: 					break;
  976: 
  977: 
  978: 				case 'f':
  979: 				case 'F':
  980: 				case 'e':
  981: 				case 'E':
  982: 					switch(modifier) {
  983: 						case LM_LONG_DOUBLE:
  984: 							fp_num = (double) va_arg(ap, long double);
  985: 							break;
  986: 						case LM_STD:
  987: 							fp_num = va_arg(ap, double);
  988: 							break;
  989: 						default:
  990: 							goto fmt_error;
  991: 					}
  992: 
  993: 					if (zend_isnan(fp_num)) {
  994: 						s = "NAN";
  995: 						s_len = 3;
  996: 					} else if (zend_isinf(fp_num)) {
  997: 						s = "INF";
  998: 						s_len = 3;
  999: 					} else {
 1000: #ifdef HAVE_LOCALE_H
 1001: 						if (!lconv) {
 1002: 							lconv = localeconv();
 1003: 						}
 1004: #endif
 1005: 						s = php_conv_fp((*fmt == 'f')?'F':*fmt, fp_num, alternate_form,
 1006: 						 (adjust_precision == NO) ? FLOAT_DIGITS : precision,
 1007: 						 (*fmt == 'f')?LCONV_DECIMAL_POINT:'.',
 1008: 									&is_negative, &num_buf[1], &s_len);
 1009: 						if (is_negative)
 1010: 							prefix_char = '-';
 1011: 						else if (print_sign)
 1012: 							prefix_char = '+';
 1013: 						else if (print_blank)
 1014: 							prefix_char = ' ';
 1015: 					}
 1016: 					break;
 1017: 
 1018: 
 1019: 				case 'g':
 1020: 				case 'k':
 1021: 				case 'G':
 1022: 				case 'H':
 1023: 					switch(modifier) {
 1024: 						case LM_LONG_DOUBLE:
 1025: 							fp_num = (double) va_arg(ap, long double);
 1026: 							break;
 1027: 						case LM_STD:
 1028: 							fp_num = va_arg(ap, double);
 1029: 							break;
 1030: 						default:
 1031: 							goto fmt_error;
 1032: 					}
 1033: 
 1034: 					if (zend_isnan(fp_num)) {
 1035: 						s = "NAN";
 1036: 						s_len = 3;
 1037: 						break;
 1038: 					} else if (zend_isinf(fp_num)) {
 1039: 						if (fp_num > 0) {
 1040: 							s = "INF";
 1041: 							s_len = 3;
 1042: 						} else {
 1043: 							s = "-INF";
 1044: 							s_len = 4;
 1045: 						}
 1046: 						break;
 1047: 					}
 1048: 
 1049: 					if (adjust_precision == NO) {
 1050: 						precision = FLOAT_DIGITS;
 1051: 					} else if (precision == 0) {
 1052: 						precision = 1;
 1053: 					}
 1054: 					/*
 1055: 					 * * We use &num_buf[ 1 ], so that we have room for the sign
 1056: 					 */
 1057: #ifdef HAVE_LOCALE_H
 1058: 					if (!lconv) {
 1059: 						lconv = localeconv();
 1060: 					}
 1061: #endif
 1062: 					s = php_gcvt(fp_num, precision, (*fmt=='H' || *fmt == 'k') ? '.' : LCONV_DECIMAL_POINT, (*fmt == 'G' || *fmt == 'H')?'E':'e', &num_buf[1]);
 1063: 					if (*s == '-') {
 1064: 						prefix_char = *s++;
 1065: 					} else if (print_sign) {
 1066: 						prefix_char = '+';
 1067: 					} else if (print_blank) {
 1068: 						prefix_char = ' ';
 1069: 					}
 1070: 
 1071: 					s_len = strlen(s);
 1072: 
 1073: 					if (alternate_form && (strchr(s, '.')) == NULL) {
 1074: 						s[s_len++] = '.';
 1075: 					}
 1076: 					break;
 1077: 
 1078: 
 1079: 				case 'c':
 1080: 					char_buf[0] = (char) (va_arg(ap, int));
 1081: 					s = &char_buf[0];
 1082: 					s_len = 1;
 1083: 					pad_char = ' ';
 1084: 					break;
 1085: 
 1086: 
 1087: 				case '%':
 1088: 					char_buf[0] = '%';
 1089: 					s = &char_buf[0];
 1090: 					s_len = 1;
 1091: 					pad_char = ' ';
 1092: 					break;
 1093: 
 1094: 
 1095: 				case 'n':
 1096: 					*(va_arg(ap, int *)) = cc;
 1097: 					goto skip_output;
 1098: 
 1099: 					/*
 1100: 					 * Always extract the argument as a "char *" pointer. We
 1101: 					 * should be using "void *" but there are still machines
 1102: 					 * that don't understand it.
 1103: 					 * If the pointer size is equal to the size of an unsigned
 1104: 					 * integer we convert the pointer to a hex number, otherwise
 1105: 					 * we print "%p" to indicate that we don't handle "%p".
 1106: 					 */
 1107: 				case 'p':
 1108: 					if (sizeof(char *) <= sizeof(u_wide_int)) {
 1109: 						ui_num = (u_wide_int)((size_t) va_arg(ap, char *));
 1110: 						s = ap_php_conv_p2(ui_num, 4, 'x',
 1111: 								&num_buf[NUM_BUF_SIZE], &s_len);
 1112: 						if (ui_num != 0) {
 1113: 							*--s = 'x';
 1114: 							*--s = '0';
 1115: 							s_len += 2;
 1116: 						}
 1117: 					} else {
 1118: 						s = "%p";
 1119: 						s_len = 2;
 1120: 					}
 1121: 					pad_char = ' ';
 1122: 					break;
 1123: 
 1124: 
 1125: 				case NUL:
 1126: 					/*
 1127: 					 * The last character of the format string was %.
 1128: 					 * We ignore it.
 1129: 					 */
 1130: 					continue;
 1131: 
 1132: 
 1133: fmt_error:
 1134: 				php_error(E_ERROR, "Illegal length modifier specified '%c' in s[np]printf call", *fmt);
 1135: 					/*
 1136: 					 * The default case is for unrecognized %'s.
 1137: 					 * We print %<char> to help the user identify what
 1138: 					 * option is not understood.
 1139: 					 * This is also useful in case the user wants to pass
 1140: 					 * the output of format_converter to another function
 1141: 					 * that understands some other %<char> (like syslog).
 1142: 					 * Note that we can't point s inside fmt because the
 1143: 					 * unknown <char> could be preceded by width etc.
 1144: 					 */
 1145: 				default:
 1146: 					char_buf[0] = '%';
 1147: 					char_buf[1] = *fmt;
 1148: 					s = char_buf;
 1149: 					s_len = 2;
 1150: 					pad_char = ' ';
 1151: 					break;
 1152: 			}
 1153: 
 1154: 			if (prefix_char != NUL) {
 1155: 				*--s = prefix_char;
 1156: 				s_len++;
 1157: 			}
 1158: 			if (adjust_width && adjust == RIGHT && min_width > s_len) {
 1159: 				if (pad_char == '0' && prefix_char != NUL) {
 1160: 					INS_CHAR(*s, sp, bep, cc)
 1161: 						s++;
 1162: 					s_len--;
 1163: 					min_width--;
 1164: 				}
 1165: 				PAD(min_width, s_len, pad_char);
 1166: 			}
 1167: 			/*
 1168: 			 * Print the string s.
 1169: 			 */
 1170: 			for (i = s_len; i != 0; i--) {
 1171: 				INS_CHAR(*s, sp, bep, cc);
 1172: 				s++;
 1173: 			}
 1174: 
 1175: 			if (adjust_width && adjust == LEFT && min_width > s_len)
 1176: 				PAD(min_width, s_len, pad_char);
 1177: 			if (free_zcopy) {
 1178: 				zval_dtor(&zcopy);
 1179: 			}
 1180: 		}
 1181: skip_output:
 1182: 		fmt++;
 1183: 	}
 1184: 	odp->nextb = sp;
 1185: 	return (cc);
 1186: }
 1187: /* }}} */
 1188: 
 1189: /*
 1190:  * This is the general purpose conversion function.
 1191:  */
 1192: static void strx_printv(int *ccp, char *buf, size_t len, const char *format, va_list ap) /* {{{ */
 1193: {
 1194: 	buffy od;
 1195: 	int cc;
 1196: 
 1197: 	/*
 1198: 	 * First initialize the descriptor
 1199: 	 * Notice that if no length is given, we initialize buf_end to the
 1200: 	 * highest possible address.
 1201: 	 */
 1202: 	if (len == 0) {
 1203: 		od.buf_end = (char *) ~0;
 1204: 		od.nextb   = (char *) ~0;
 1205: 	} else {
 1206: 		od.buf_end = &buf[len-1];
 1207: 		od.nextb   = buf;
 1208: 	}
 1209: 
 1210: 	/*
 1211: 	 * Do the conversion
 1212: 	 */
 1213: 	cc = format_converter(&od, format, ap);
 1214: 	if (len != 0 && od.nextb <= od.buf_end) {
 1215: 		*(od.nextb) = '\0';
 1216: 	}
 1217: 	if (ccp) {
 1218: 		*ccp = cc;
 1219: 	}
 1220: }
 1221: /* }}} */
 1222: 
 1223: PHPAPI int ap_php_slprintf(char *buf, size_t len, const char *format,...) /* {{{ */
 1224: {
 1225: 	unsigned int cc;
 1226: 	va_list ap;
 1227: 
 1228: 	va_start(ap, format);
 1229: 	strx_printv(&cc, buf, len, format, ap);
 1230: 	va_end(ap);
 1231: 	if (cc >= len) {
 1232: 		cc = len -1;
 1233: 		buf[cc] = '\0';
 1234: 	}
 1235: 	return cc;
 1236: }
 1237: /* }}} */
 1238: 
 1239: PHPAPI int ap_php_vslprintf(char *buf, size_t len, const char *format, va_list ap) /* {{{ */
 1240: {
 1241: 	unsigned int cc;
 1242: 
 1243: 	strx_printv(&cc, buf, len, format, ap);
 1244: 	if (cc >= len) {
 1245: 		cc = len -1;
 1246: 		buf[cc] = '\0';
 1247: 	}
 1248: 	return cc;
 1249: }
 1250: /* }}} */
 1251: 
 1252: PHPAPI int ap_php_snprintf(char *buf, size_t len, const char *format,...) /* {{{ */
 1253: {
 1254: 	int cc;
 1255: 	va_list ap;
 1256: 
 1257: 	va_start(ap, format);
 1258: 	strx_printv(&cc, buf, len, format, ap);
 1259: 	va_end(ap);
 1260: 	return (cc);
 1261: }
 1262: /* }}} */
 1263: 
 1264: PHPAPI int ap_php_vsnprintf(char *buf, size_t len, const char *format, va_list ap) /* {{{ */
 1265: {
 1266: 	int cc;
 1267: 
 1268: 	strx_printv(&cc, buf, len, format, ap);
 1269: 	return (cc);
 1270: }
 1271: /* }}} */
 1272: 
 1273: PHPAPI int ap_php_vasprintf(char **buf, const char *format, va_list ap) /* {{{ */
 1274: {
 1275: 	va_list ap2;
 1276: 	int cc;
 1277: 
 1278: 	va_copy(ap2, ap);
 1279: 	cc = ap_php_vsnprintf(NULL, 0, format, ap2);
 1280: 	va_end(ap2);
 1281: 
 1282: 	*buf = NULL;
 1283: 
 1284: 	if (cc >= 0) {
 1285: 		if ((*buf = malloc(++cc)) != NULL) {
 1286: 			if ((cc = ap_php_vsnprintf(*buf, cc, format, ap)) < 0) {
 1287: 				free(*buf);
 1288: 				*buf = NULL;
 1289: 			}
 1290: 		}
 1291: 	}
 1292: 
 1293: 	return cc;
 1294: }
 1295: /* }}} */
 1296: 
 1297: PHPAPI int ap_php_asprintf(char **buf, const char *format, ...) /* {{{ */
 1298: {
 1299: 	int cc;
 1300: 	va_list ap;
 1301: 
 1302: 	va_start(ap, format);
 1303: 	cc = vasprintf(buf, format, ap);
 1304: 	va_end(ap);
 1305: 	return cc;
 1306: }
 1307: /* }}} */
 1308: 
 1309: /*
 1310:  * Local variables:
 1311:  * tab-width: 4
 1312:  * c-basic-offset: 4
 1313:  * End:
 1314:  * vim600: sw=4 ts=4 fdm=marker
 1315:  * vim<600: sw=4 ts=4
 1316:  */

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