Annotation of embedaddon/php/ext/standard/formatted_print.c, revision 1.1.1.1

1.1       misho       1: /*
                      2:    +----------------------------------------------------------------------+
                      3:    | PHP Version 5                                                        |
                      4:    +----------------------------------------------------------------------+
                      5:    | Copyright (c) 1997-2012 The PHP Group                                |
                      6:    +----------------------------------------------------------------------+
                      7:    | This source file is subject to version 3.01 of the PHP license,      |
                      8:    | that is bundled with this package in the file LICENSE, and is        |
                      9:    | available through the world-wide-web at the following url:           |
                     10:    | http://www.php.net/license/3_01.txt                                  |
                     11:    | If you did not receive a copy of the PHP license and are unable to   |
                     12:    | obtain it through the world-wide-web, please send a note to          |
                     13:    | license@php.net so we can mail you a copy immediately.               |
                     14:    +----------------------------------------------------------------------+
                     15:    | Author: Stig Sæther Bakken <ssb@php.net>                             |
                     16:    +----------------------------------------------------------------------+
                     17:  */
                     18: 
                     19: /* $Id: formatted_print.c 321634 2012-01-01 13:15:04Z felipe $ */
                     20: 
                     21: #include <math.h>                              /* modf() */
                     22: #include "php.h"
                     23: #include "ext/standard/head.h"
                     24: #include "php_string.h"
                     25: #include "zend_execute.h"
                     26: #include <stdio.h>
                     27: 
                     28: #ifdef HAVE_LOCALE_H
                     29: #include <locale.h>
                     30: #define LCONV_DECIMAL_POINT (*lconv->decimal_point)
                     31: #else
                     32: #define LCONV_DECIMAL_POINT '.'
                     33: #endif
                     34: 
                     35: #define ALIGN_LEFT 0
                     36: #define ALIGN_RIGHT 1
                     37: #define ADJ_WIDTH 1
                     38: #define ADJ_PRECISION 2
                     39: #define NUM_BUF_SIZE 500
                     40: #define        NDIG 80
                     41: #define FLOAT_DIGITS 6
                     42: #define FLOAT_PRECISION 6
                     43: #define MAX_FLOAT_DIGITS 38
                     44: #define MAX_FLOAT_PRECISION 53
                     45: 
                     46: #if 0
                     47: /* trick to control varargs functions through cpp */
                     48: # define PRINTF_DEBUG(arg) php_printf arg
                     49: #else
                     50: # define PRINTF_DEBUG(arg)
                     51: #endif
                     52: 
                     53: static char hexchars[] = "0123456789abcdef";
                     54: static char HEXCHARS[] = "0123456789ABCDEF";
                     55: 
                     56: /* php_spintf_appendchar() {{{ */
                     57: inline static void
                     58: php_sprintf_appendchar(char **buffer, int *pos, int *size, char add TSRMLS_DC)
                     59: {
                     60:        if ((*pos + 1) >= *size) {
                     61:                *size <<= 1;
                     62:                PRINTF_DEBUG(("%s(): ereallocing buffer to %d bytes\n", get_active_function_name(TSRMLS_C), *size));
                     63:                *buffer = erealloc(*buffer, *size);
                     64:        }
                     65:        PRINTF_DEBUG(("sprintf: appending '%c', pos=\n", add, *pos));
                     66:        (*buffer)[(*pos)++] = add;
                     67: }
                     68: /* }}} */
                     69: 
                     70: /* php_spintf_appendstring() {{{ */
                     71: inline static void
                     72: php_sprintf_appendstring(char **buffer, int *pos, int *size, char *add,
                     73:                                                   int min_width, int max_width, char padding,
                     74:                                                   int alignment, int len, int neg, int expprec, int always_sign)
                     75: {
                     76:        register int npad;
                     77:        int req_size;
                     78:        int copy_len;
                     79:        int m_width;
                     80: 
                     81:        copy_len = (expprec ? MIN(max_width, len) : len);
                     82:        npad = min_width - copy_len;
                     83: 
                     84:        if (npad < 0) {
                     85:                npad = 0;
                     86:        }
                     87:        
                     88:        PRINTF_DEBUG(("sprintf: appendstring(%x, %d, %d, \"%s\", %d, '%c', %d)\n",
                     89:                                  *buffer, *pos, *size, add, min_width, padding, alignment));
                     90:        m_width = MAX(min_width, copy_len);
                     91: 
                     92:        if(m_width > INT_MAX - *pos - 1) {
                     93:                zend_error_noreturn(E_ERROR, "Field width %d is too long", m_width);
                     94:        }
                     95: 
                     96:        req_size = *pos + m_width + 1;
                     97: 
                     98:        if (req_size > *size) {
                     99:                while (req_size > *size) {
                    100:                        if(*size > INT_MAX/2) {
                    101:                                zend_error_noreturn(E_ERROR, "Field width %d is too long", req_size); 
                    102:                        }
                    103:                        *size <<= 1;
                    104:                }
                    105:                PRINTF_DEBUG(("sprintf ereallocing buffer to %d bytes\n", *size));
                    106:                *buffer = erealloc(*buffer, *size);
                    107:        }
                    108:        if (alignment == ALIGN_RIGHT) {
                    109:                if ((neg || always_sign) && padding=='0') {
                    110:                        (*buffer)[(*pos)++] = (neg) ? '-' : '+';
                    111:                        add++;
                    112:                        len--;
                    113:                        copy_len--;
                    114:                }
                    115:                while (npad-- > 0) {
                    116:                        (*buffer)[(*pos)++] = padding;
                    117:                }
                    118:        }
                    119:        PRINTF_DEBUG(("sprintf: appending \"%s\"\n", add));
                    120:        memcpy(&(*buffer)[*pos], add, copy_len + 1);
                    121:        *pos += copy_len;
                    122:        if (alignment == ALIGN_LEFT) {
                    123:                while (npad--) {
                    124:                        (*buffer)[(*pos)++] = padding;
                    125:                }
                    126:        }
                    127: }
                    128: /* }}} */
                    129: 
                    130: /* php_spintf_appendint() {{{ */
                    131: inline static void
                    132: php_sprintf_appendint(char **buffer, int *pos, int *size, long number,
                    133:                                                int width, char padding, int alignment, 
                    134:                                                int always_sign)
                    135: {
                    136:        char numbuf[NUM_BUF_SIZE];
                    137:        register unsigned long magn, nmagn;
                    138:        register unsigned int i = NUM_BUF_SIZE - 1, neg = 0;
                    139: 
                    140:        PRINTF_DEBUG(("sprintf: appendint(%x, %x, %x, %d, %d, '%c', %d)\n",
                    141:                                  *buffer, pos, size, number, width, padding, alignment));
                    142:        if (number < 0) {
                    143:                neg = 1;
                    144:                magn = ((unsigned long) -(number + 1)) + 1;
                    145:        } else {
                    146:                magn = (unsigned long) number;
                    147:        }
                    148: 
                    149:        /* Can't right-pad 0's on integers */
                    150:        if(alignment==0 && padding=='0') padding=' ';
                    151: 
                    152:        numbuf[i] = '\0';
                    153: 
                    154:        do {
                    155:                nmagn = magn / 10;
                    156: 
                    157:                numbuf[--i] = (unsigned char)(magn - (nmagn * 10)) + '0';
                    158:                magn = nmagn;
                    159:        }
                    160:        while (magn > 0 && i > 0);
                    161:        if (neg) {
                    162:                numbuf[--i] = '-';
                    163:        } else if (always_sign) {
                    164:                numbuf[--i] = '+';
                    165:        }
                    166:        PRINTF_DEBUG(("sprintf: appending %d as \"%s\", i=%d\n",
                    167:                                  number, &numbuf[i], i));
                    168:        php_sprintf_appendstring(buffer, pos, size, &numbuf[i], width, 0,
                    169:                                                         padding, alignment, (NUM_BUF_SIZE - 1) - i,
                    170:                                                         neg, 0, always_sign);
                    171: }
                    172: /* }}} */
                    173: 
                    174: /* php_spintf_appenduint() {{{ */
                    175: inline static void
                    176: php_sprintf_appenduint(char **buffer, int *pos, int *size,
                    177:                                           unsigned long number,
                    178:                                           int width, char padding, int alignment)
                    179: {
                    180:        char numbuf[NUM_BUF_SIZE];
                    181:        register unsigned long magn, nmagn;
                    182:        register unsigned int i = NUM_BUF_SIZE - 1;
                    183: 
                    184:        PRINTF_DEBUG(("sprintf: appenduint(%x, %x, %x, %d, %d, '%c', %d)\n",
                    185:                                  *buffer, pos, size, number, width, padding, alignment));
                    186:        magn = (unsigned long) number;
                    187: 
                    188:        /* Can't right-pad 0's on integers */
                    189:        if (alignment == 0 && padding == '0') padding = ' ';
                    190: 
                    191:        numbuf[i] = '\0';
                    192: 
                    193:        do {
                    194:                nmagn = magn / 10;
                    195: 
                    196:                numbuf[--i] = (unsigned char)(magn - (nmagn * 10)) + '0';
                    197:                magn = nmagn;
                    198:        } while (magn > 0 && i > 0);
                    199: 
                    200:        PRINTF_DEBUG(("sprintf: appending %d as \"%s\", i=%d\n", number, &numbuf[i], i));
                    201:        php_sprintf_appendstring(buffer, pos, size, &numbuf[i], width, 0,
                    202:                                                         padding, alignment, (NUM_BUF_SIZE - 1) - i, 0, 0, 0);
                    203: }
                    204: /* }}} */
                    205: 
                    206: /* php_spintf_appenddouble() {{{ */
                    207: inline static void
                    208: php_sprintf_appenddouble(char **buffer, int *pos,
                    209:                                                 int *size, double number,
                    210:                                                 int width, char padding,
                    211:                                                 int alignment, int precision,
                    212:                                                 int adjust, char fmt,
                    213:                                                 int always_sign
                    214:                                                 TSRMLS_DC)
                    215: {
                    216:        char num_buf[NUM_BUF_SIZE];
                    217:        char *s = NULL;
                    218:        int s_len = 0, is_negative = 0;
                    219: #ifdef HAVE_LOCALE_H
                    220:        struct lconv *lconv;
                    221: #endif
                    222: 
                    223:        PRINTF_DEBUG(("sprintf: appenddouble(%x, %x, %x, %f, %d, '%c', %d, %c)\n",
                    224:                                  *buffer, pos, size, number, width, padding, alignment, fmt));
                    225:        if ((adjust & ADJ_PRECISION) == 0) {
                    226:                precision = FLOAT_PRECISION;
                    227:        } else if (precision > MAX_FLOAT_PRECISION) {
                    228:                php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Requested precision of %d digits was truncated to PHP maximum of %d digits", precision, MAX_FLOAT_PRECISION);
                    229:                precision = MAX_FLOAT_PRECISION;
                    230:        }
                    231:        
                    232:        if (zend_isnan(number)) {
                    233:                is_negative = (number<0);
                    234:                php_sprintf_appendstring(buffer, pos, size, "NaN", 3, 0, padding,
                    235:                                                                 alignment, 3, is_negative, 0, always_sign);
                    236:                return;
                    237:        }
                    238: 
                    239:        if (zend_isinf(number)) {
                    240:                is_negative = (number<0);
                    241:                php_sprintf_appendstring(buffer, pos, size, "INF", 3, 0, padding,
                    242:                                                                 alignment, 3, is_negative, 0, always_sign);
                    243:                return;
                    244:        }
                    245: 
                    246:        switch (fmt) {                  
                    247:                case 'e':
                    248:                case 'E':
                    249:                case 'f':
                    250:                case 'F':
                    251: #ifdef HAVE_LOCALE_H
                    252:                        lconv = localeconv();
                    253: #endif
                    254:                        s = php_conv_fp((fmt == 'f')?'F':fmt, number, 0, precision,
                    255:                                                (fmt == 'f')?LCONV_DECIMAL_POINT:'.',
                    256:                                                &is_negative, &num_buf[1], &s_len);
                    257:                        if (is_negative) {
                    258:                                num_buf[0] = '-';
                    259:                                s = num_buf;
                    260:                                s_len++;
                    261:                        } else if (always_sign) {
                    262:                                num_buf[0] = '+';
                    263:                                s = num_buf;
                    264:                                s_len++;
                    265:                        }
                    266:                        break;
                    267: 
                    268:                case 'g':
                    269:                case 'G':
                    270:                        if (precision == 0)
                    271:                                precision = 1;
                    272:                        /*
                    273:                         * * We use &num_buf[ 1 ], so that we have room for the sign
                    274:                         */
                    275: #ifdef HAVE_LOCALE_H
                    276:                        lconv = localeconv();
                    277: #endif
                    278:                        s = php_gcvt(number, precision, LCONV_DECIMAL_POINT, (fmt == 'G')?'E':'e', &num_buf[1]);
                    279:                        is_negative = 0;
                    280:                        if (*s == '-') {
                    281:                                is_negative = 1;
                    282:                                s = &num_buf[1];
                    283:                        } else if (always_sign) {
                    284:                                num_buf[0] = '+';
                    285:                                s = num_buf;
                    286:                        }
                    287: 
                    288:                        s_len = strlen(s);
                    289:                        break;
                    290:        }
                    291: 
                    292:        php_sprintf_appendstring(buffer, pos, size, s, width, 0, padding,
                    293:                                                         alignment, s_len, is_negative, 0, always_sign);
                    294: }
                    295: /* }}} */
                    296: 
                    297: /* php_spintf_appendd2n() {{{ */
                    298: inline static void
                    299: php_sprintf_append2n(char **buffer, int *pos, int *size, long number,
                    300:                                         int width, char padding, int alignment, int n,
                    301:                                         char *chartable, int expprec)
                    302: {
                    303:        char numbuf[NUM_BUF_SIZE];
                    304:        register unsigned long num;
                    305:        register unsigned int  i = NUM_BUF_SIZE - 1;
                    306:        register int andbits = (1 << n) - 1;
                    307: 
                    308:        PRINTF_DEBUG(("sprintf: append2n(%x, %x, %x, %d, %d, '%c', %d, %d, %x)\n",
                    309:                                  *buffer, pos, size, number, width, padding, alignment, n,
                    310:                                  chartable));
                    311:        PRINTF_DEBUG(("sprintf: append2n 2^%d andbits=%x\n", n, andbits));
                    312: 
                    313:        num = (unsigned long) number;
                    314:        numbuf[i] = '\0';
                    315: 
                    316:        do {
                    317:                numbuf[--i] = chartable[(num & andbits)];
                    318:                num >>= n;
                    319:        }
                    320:        while (num > 0);
                    321: 
                    322:        php_sprintf_appendstring(buffer, pos, size, &numbuf[i], width, 0,
                    323:                                                         padding, alignment, (NUM_BUF_SIZE - 1) - i,
                    324:                                                         0, expprec, 0);
                    325: }
                    326: /* }}} */
                    327: 
                    328: /* php_spintf_getnumber() {{{ */
                    329: inline static int
                    330: php_sprintf_getnumber(char *buffer, int *pos)
                    331: {
                    332:        char *endptr;
                    333:        register long num = strtol(&buffer[*pos], &endptr, 10);
                    334:        register int i = 0;
                    335: 
                    336:        if (endptr != NULL) {
                    337:                i = (endptr - &buffer[*pos]);
                    338:        }
                    339:        PRINTF_DEBUG(("sprintf_getnumber: number was %d bytes long\n", i));
                    340:        *pos += i;
                    341: 
                    342:        if (num >= INT_MAX || num < 0) {
                    343:                return -1;
                    344:        } else {
                    345:                return (int) num;
                    346:        }
                    347: }
                    348: /* }}} */
                    349: 
                    350: /* php_formatted_print() {{{
                    351:  * New sprintf implementation for PHP.
                    352:  *
                    353:  * Modifiers:
                    354:  *
                    355:  *  " "   pad integers with spaces
                    356:  *  "-"   left adjusted field
                    357:  *   n    field size
                    358:  *  "."n  precision (floats only)
                    359:  *  "+"   Always place a sign (+ or -) in front of a number
                    360:  *
                    361:  * Type specifiers:
                    362:  *
                    363:  *  "%"   literal "%", modifiers are ignored.
                    364:  *  "b"   integer argument is printed as binary
                    365:  *  "c"   integer argument is printed as a single character
                    366:  *  "d"   argument is an integer
                    367:  *  "f"   the argument is a float
                    368:  *  "o"   integer argument is printed as octal
                    369:  *  "s"   argument is a string
                    370:  *  "x"   integer argument is printed as lowercase hexadecimal
                    371:  *  "X"   integer argument is printed as uppercase hexadecimal
                    372:  *
                    373:  */
                    374: static char *
                    375: php_formatted_print(int ht, int *len, int use_array, int format_offset TSRMLS_DC)
                    376: {
                    377:        zval ***args, **z_format;
                    378:        int argc, size = 240, inpos = 0, outpos = 0, temppos;
                    379:        int alignment, currarg, adjusting, argnum, width, precision;
                    380:        char *format, *result, padding;
                    381:        int always_sign;
                    382: 
                    383:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "+", &args, &argc) == FAILURE) {
                    384:                return NULL;
                    385:        }
                    386: 
                    387:        /* verify the number of args */
                    388:        if ((use_array && argc != (2 + format_offset)) 
                    389:                        || (!use_array && argc < (1 + format_offset))) {
                    390:                efree(args);
                    391:                WRONG_PARAM_COUNT_WITH_RETVAL(NULL);
                    392:        }
                    393:        
                    394:        if (use_array) {
                    395:                int i = 1;
                    396:                zval ***newargs;
                    397:                zval **array;
                    398: 
                    399:                z_format = args[format_offset];
                    400:                array = args[1 + format_offset];
                    401:                
                    402:                SEPARATE_ZVAL(array);
                    403:                convert_to_array_ex(array);
                    404:                
                    405:                argc = 1 + zend_hash_num_elements(Z_ARRVAL_PP(array));
                    406:                newargs = (zval ***)safe_emalloc(argc, sizeof(zval *), 0);
                    407:                newargs[0] = z_format;
                    408:                
                    409:                for (zend_hash_internal_pointer_reset(Z_ARRVAL_PP(array));
                    410:                         zend_hash_get_current_data(Z_ARRVAL_PP(array), (void **)&newargs[i++]) == SUCCESS;
                    411:                         zend_hash_move_forward(Z_ARRVAL_PP(array)));
                    412: 
                    413:                efree(args);
                    414:                args = newargs;
                    415:                format_offset = 0;
                    416:        }
                    417:        
                    418:        convert_to_string_ex(args[format_offset]);
                    419:        format = Z_STRVAL_PP(args[format_offset]);
                    420:        result = emalloc(size);
                    421: 
                    422:        currarg = 1;
                    423: 
                    424:        while (inpos<Z_STRLEN_PP(args[format_offset])) {
                    425:                int expprec = 0, multiuse = 0;
                    426:                zval *tmp;
                    427: 
                    428:                PRINTF_DEBUG(("sprintf: format[%d]='%c'\n", inpos, format[inpos]));
                    429:                PRINTF_DEBUG(("sprintf: outpos=%d\n", outpos));
                    430:                if (format[inpos] != '%') {
                    431:                        php_sprintf_appendchar(&result, &outpos, &size, format[inpos++] TSRMLS_CC);
                    432:                } else if (format[inpos + 1] == '%') {
                    433:                        php_sprintf_appendchar(&result, &outpos, &size, '%' TSRMLS_CC);
                    434:                        inpos += 2;
                    435:                } else {
                    436:                        /* starting a new format specifier, reset variables */
                    437:                        alignment = ALIGN_RIGHT;
                    438:                        adjusting = 0;
                    439:                        padding = ' ';
                    440:                        always_sign = 0;
                    441:                        inpos++;                        /* skip the '%' */
                    442: 
                    443:                        PRINTF_DEBUG(("sprintf: first looking at '%c', inpos=%d\n",
                    444:                                                  format[inpos], inpos));
                    445:                        if (isascii((int)format[inpos]) && !isalpha((int)format[inpos])) {
                    446:                                /* first look for argnum */
                    447:                                temppos = inpos;
                    448:                                while (isdigit((int)format[temppos])) temppos++;
                    449:                                if (format[temppos] == '$') {
                    450:                                        argnum = php_sprintf_getnumber(format, &inpos);
                    451: 
                    452:                                        if (argnum <= 0) {
                    453:                                                efree(result);
                    454:                                                efree(args);
                    455:                                                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Argument number must be greater than zero");
                    456:                                                return NULL;
                    457:                                        }
                    458: 
                    459:                                        multiuse = 1;
                    460:                                        inpos++;  /* skip the '$' */
                    461:                                } else {
                    462:                                        argnum = currarg++;
                    463:                                }
                    464: 
                    465:                                argnum += format_offset;
                    466: 
                    467:                                /* after argnum comes modifiers */
                    468:                                PRINTF_DEBUG(("sprintf: looking for modifiers\n"
                    469:                                                          "sprintf: now looking at '%c', inpos=%d\n",
                    470:                                                          format[inpos], inpos));
                    471:                                for (;; inpos++) {
                    472:                                        if (format[inpos] == ' ' || format[inpos] == '0') {
                    473:                                                padding = format[inpos];
                    474:                                        } else if (format[inpos] == '-') {
                    475:                                                alignment = ALIGN_LEFT;
                    476:                                                /* space padding, the default */
                    477:                                        } else if (format[inpos] == '+') {
                    478:                                                always_sign = 1;
                    479:                                        } else if (format[inpos] == '\'') {
                    480:                                                padding = format[++inpos];
                    481:                                        } else {
                    482:                                                PRINTF_DEBUG(("sprintf: end of modifiers\n"));
                    483:                                                break;
                    484:                                        }
                    485:                                }
                    486:                                PRINTF_DEBUG(("sprintf: padding='%c'\n", padding));
                    487:                                PRINTF_DEBUG(("sprintf: alignment=%s\n",
                    488:                                                          (alignment == ALIGN_LEFT) ? "left" : "right"));
                    489: 
                    490: 
                    491:                                /* after modifiers comes width */
                    492:                                if (isdigit((int)format[inpos])) {
                    493:                                        PRINTF_DEBUG(("sprintf: getting width\n"));
                    494:                                        if ((width = php_sprintf_getnumber(format, &inpos)) < 0) {
                    495:                                                efree(result);
                    496:                                                efree(args);
                    497:                                                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Width must be greater than zero and less than %d", INT_MAX);
                    498:                                                return NULL;
                    499:                                        }
                    500:                                        adjusting |= ADJ_WIDTH;
                    501:                                } else {
                    502:                                        width = 0;
                    503:                                }
                    504:                                PRINTF_DEBUG(("sprintf: width=%d\n", width));
                    505: 
                    506:                                /* after width and argnum comes precision */
                    507:                                if (format[inpos] == '.') {
                    508:                                        inpos++;
                    509:                                        PRINTF_DEBUG(("sprintf: getting precision\n"));
                    510:                                        if (isdigit((int)format[inpos])) {
                    511:                                                if ((precision = php_sprintf_getnumber(format, &inpos)) < 0) {
                    512:                                                        efree(result);
                    513:                                                        efree(args);
                    514:                                                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Precision must be greater than zero and less than %d", INT_MAX);
                    515:                                                        return NULL;
                    516:                                                }
                    517:                                                adjusting |= ADJ_PRECISION;
                    518:                                                expprec = 1;
                    519:                                        } else {
                    520:                                                precision = 0;
                    521:                                        }
                    522:                                } else {
                    523:                                        precision = 0;
                    524:                                }
                    525:                                PRINTF_DEBUG(("sprintf: precision=%d\n", precision));
                    526:                        } else {
                    527:                                width = precision = 0;
                    528:                                argnum = currarg++ + format_offset;
                    529:                        }
                    530: 
                    531:                        if (argnum >= argc) {
                    532:                                efree(result);
                    533:                                efree(args);
                    534:                                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Too few arguments");
                    535:                                return NULL;
                    536:                        }
                    537: 
                    538:                        if (format[inpos] == 'l') {
                    539:                                inpos++;
                    540:                        }
                    541:                        PRINTF_DEBUG(("sprintf: format character='%c'\n", format[inpos]));
                    542:                        /* now we expect to find a type specifier */
                    543:                        if (multiuse) {
                    544:                                MAKE_STD_ZVAL(tmp);
                    545:                                *tmp = **(args[argnum]);
                    546:                                INIT_PZVAL(tmp);
                    547:                                zval_copy_ctor(tmp);
                    548:                        } else {
                    549:                                SEPARATE_ZVAL(args[argnum]);
                    550:                                tmp = *(args[argnum]);
                    551:                        }
                    552: 
                    553:                        switch (format[inpos]) {
                    554:                                case 's': {
                    555:                                        zval *var, var_copy;
                    556:                                        int use_copy;
                    557: 
                    558:                                        zend_make_printable_zval(tmp, &var_copy, &use_copy);
                    559:                                        if (use_copy) {
                    560:                                                var = &var_copy;
                    561:                                        } else {
                    562:                                                var = tmp;
                    563:                                        }
                    564:                                        php_sprintf_appendstring(&result, &outpos, &size,
                    565:                                                                                         Z_STRVAL_P(var),
                    566:                                                                                         width, precision, padding,
                    567:                                                                                         alignment,
                    568:                                                                                         Z_STRLEN_P(var),
                    569:                                                                                         0, expprec, 0);
                    570:                                        if (use_copy) {
                    571:                                                zval_dtor(&var_copy);
                    572:                                        }
                    573:                                        break;
                    574:                                }
                    575: 
                    576:                                case 'd':
                    577:                                        convert_to_long(tmp);
                    578:                                        php_sprintf_appendint(&result, &outpos, &size,
                    579:                                                                                  Z_LVAL_P(tmp),
                    580:                                                                                  width, padding, alignment,
                    581:                                                                                  always_sign);
                    582:                                        break;
                    583: 
                    584:                                case 'u':
                    585:                                        convert_to_long(tmp);
                    586:                                        php_sprintf_appenduint(&result, &outpos, &size,
                    587:                                                                                  Z_LVAL_P(tmp),
                    588:                                                                                  width, padding, alignment);
                    589:                                        break;
                    590: 
                    591:                                case 'g':
                    592:                                case 'G':
                    593:                                case 'e':
                    594:                                case 'E':
                    595:                                case 'f':
                    596:                                case 'F':
                    597:                                        convert_to_double(tmp);
                    598:                                        php_sprintf_appenddouble(&result, &outpos, &size,
                    599:                                                                                         Z_DVAL_P(tmp),
                    600:                                                                                         width, padding, alignment,
                    601:                                                                                         precision, adjusting,
                    602:                                                                                         format[inpos], always_sign
                    603:                                                                                         TSRMLS_CC);
                    604:                                        break;
                    605:                                        
                    606:                                case 'c':
                    607:                                        convert_to_long(tmp);
                    608:                                        php_sprintf_appendchar(&result, &outpos, &size,
                    609:                                                                                (char) Z_LVAL_P(tmp) TSRMLS_CC);
                    610:                                        break;
                    611: 
                    612:                                case 'o':
                    613:                                        convert_to_long(tmp);
                    614:                                        php_sprintf_append2n(&result, &outpos, &size,
                    615:                                                                                 Z_LVAL_P(tmp),
                    616:                                                                                 width, padding, alignment, 3,
                    617:                                                                                 hexchars, expprec);
                    618:                                        break;
                    619: 
                    620:                                case 'x':
                    621:                                        convert_to_long(tmp);
                    622:                                        php_sprintf_append2n(&result, &outpos, &size,
                    623:                                                                                 Z_LVAL_P(tmp),
                    624:                                                                                 width, padding, alignment, 4,
                    625:                                                                                 hexchars, expprec);
                    626:                                        break;
                    627: 
                    628:                                case 'X':
                    629:                                        convert_to_long(tmp);
                    630:                                        php_sprintf_append2n(&result, &outpos, &size,
                    631:                                                                                 Z_LVAL_P(tmp),
                    632:                                                                                 width, padding, alignment, 4,
                    633:                                                                                 HEXCHARS, expprec);
                    634:                                        break;
                    635: 
                    636:                                case 'b':
                    637:                                        convert_to_long(tmp);
                    638:                                        php_sprintf_append2n(&result, &outpos, &size,
                    639:                                                                                 Z_LVAL_P(tmp),
                    640:                                                                                 width, padding, alignment, 1,
                    641:                                                                                 hexchars, expprec);
                    642:                                        break;
                    643: 
                    644:                                case '%':
                    645:                                        php_sprintf_appendchar(&result, &outpos, &size, '%' TSRMLS_CC);
                    646: 
                    647:                                        break;
                    648:                                default:
                    649:                                        break;
                    650:                        }
                    651:                        if (multiuse) {
                    652:                                zval_ptr_dtor(&tmp);
                    653:                        }
                    654:                        inpos++;
                    655:                }
                    656:        }
                    657:        
                    658:        efree(args);
                    659:        
                    660:        /* possibly, we have to make sure we have room for the terminating null? */
                    661:        result[outpos]=0;
                    662:        *len = outpos;  
                    663:        return result;
                    664: }
                    665: /* }}} */
                    666: 
                    667: /* {{{ proto string sprintf(string format [, mixed arg1 [, mixed ...]])
                    668:    Return a formatted string */
                    669: PHP_FUNCTION(user_sprintf)
                    670: {
                    671:        char *result;
                    672:        int len;
                    673:        
                    674:        if ((result=php_formatted_print(ht, &len, 0, 0 TSRMLS_CC))==NULL) {
                    675:                RETURN_FALSE;
                    676:        }
                    677:        RETVAL_STRINGL(result, len, 0);
                    678: }
                    679: /* }}} */
                    680: 
                    681: /* {{{ proto string vsprintf(string format, array args)
                    682:    Return a formatted string */
                    683: PHP_FUNCTION(vsprintf)
                    684: {
                    685:        char *result;
                    686:        int len;
                    687:        
                    688:        if ((result=php_formatted_print(ht, &len, 1, 0 TSRMLS_CC))==NULL) {
                    689:                RETURN_FALSE;
                    690:        }
                    691:        RETVAL_STRINGL(result, len, 0);
                    692: }
                    693: /* }}} */
                    694: 
                    695: /* {{{ proto int printf(string format [, mixed arg1 [, mixed ...]])
                    696:    Output a formatted string */
                    697: PHP_FUNCTION(user_printf)
                    698: {
                    699:        char *result;
                    700:        int len, rlen;
                    701:        
                    702:        if ((result=php_formatted_print(ht, &len, 0, 0 TSRMLS_CC))==NULL) {
                    703:                RETURN_FALSE;
                    704:        }
                    705:        rlen = PHPWRITE(result, len);
                    706:        efree(result);
                    707:        RETURN_LONG(rlen);
                    708: }
                    709: /* }}} */
                    710: 
                    711: /* {{{ proto int vprintf(string format, array args)
                    712:    Output a formatted string */
                    713: PHP_FUNCTION(vprintf)
                    714: {
                    715:        char *result;
                    716:        int len, rlen;
                    717:        
                    718:        if ((result=php_formatted_print(ht, &len, 1, 0 TSRMLS_CC))==NULL) {
                    719:                RETURN_FALSE;
                    720:        }
                    721:        rlen = PHPWRITE(result, len);
                    722:        efree(result);
                    723:        RETURN_LONG(rlen);
                    724: }
                    725: /* }}} */
                    726: 
                    727: /* {{{ proto int fprintf(resource stream, string format [, mixed arg1 [, mixed ...]])
                    728:    Output a formatted string into a stream */
                    729: PHP_FUNCTION(fprintf)
                    730: {
                    731:        php_stream *stream;
                    732:        zval *arg1;
                    733:        char *result;
                    734:        int len;
                    735:        
                    736:        if (ZEND_NUM_ARGS() < 2) {
                    737:                WRONG_PARAM_COUNT;
                    738:        }
                    739:        
                    740:        if (zend_parse_parameters(1 TSRMLS_CC, "r", &arg1) == FAILURE) {
                    741:                RETURN_FALSE;
                    742:        }
                    743:        
                    744:        php_stream_from_zval(stream, &arg1);
                    745: 
                    746:        if ((result=php_formatted_print(ht, &len, 0, 1 TSRMLS_CC))==NULL) {
                    747:                RETURN_FALSE;
                    748:        }
                    749: 
                    750:        php_stream_write(stream, result, len);
                    751: 
                    752:        efree(result);
                    753: 
                    754:        RETURN_LONG(len);
                    755: }
                    756: /* }}} */
                    757: 
                    758: /* {{{ proto int vfprintf(resource stream, string format, array args)
                    759:    Output a formatted string into a stream */
                    760: PHP_FUNCTION(vfprintf)
                    761: {
                    762:        php_stream *stream;
                    763:        zval *arg1;
                    764:        char *result;
                    765:        int len;
                    766:        
                    767:        if (ZEND_NUM_ARGS() != 3) {
                    768:                WRONG_PARAM_COUNT;
                    769:        }
                    770:        
                    771:        if (zend_parse_parameters(1 TSRMLS_CC, "r", &arg1) == FAILURE) {
                    772:                RETURN_FALSE;
                    773:        }
                    774:        
                    775:        php_stream_from_zval(stream, &arg1);
                    776: 
                    777:        if ((result=php_formatted_print(ht, &len, 1, 1 TSRMLS_CC))==NULL) {
                    778:                RETURN_FALSE;
                    779:        }
                    780: 
                    781:        php_stream_write(stream, result, len);
                    782: 
                    783:        efree(result);
                    784: 
                    785:        RETURN_LONG(len);
                    786: }
                    787: /* }}} */
                    788: 
                    789: /*
                    790:  * Local variables:
                    791:  * tab-width: 4
                    792:  * c-basic-offset: 4
                    793:  * End:
                    794:  * vim600: sw=4 ts=4 fdm=marker
                    795:  * vim<600: sw=4 ts=4
                    796:  */

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