diff options
Diffstat (limited to 'ext/standard/formatted_print.c')
-rw-r--r-- | ext/standard/formatted_print.c | 321 |
1 files changed, 186 insertions, 135 deletions
diff --git a/ext/standard/formatted_print.c b/ext/standard/formatted_print.c index 857e55d770..ae1e529f1d 100644 --- a/ext/standard/formatted_print.c +++ b/ext/standard/formatted_print.c @@ -2,7 +2,7 @@ +----------------------------------------------------------------------+ | PHP Version 7 | +----------------------------------------------------------------------+ - | Copyright (c) 1997-2018 The PHP Group | + | Copyright (c) The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.01 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | @@ -57,7 +57,7 @@ static const char HEXCHARS[] = "0123456789ABCDEF"; inline static void php_sprintf_appendchar(zend_string **buffer, size_t *pos, char add) { - if (!*buffer || (*pos + 1) >= ZSTR_LEN(*buffer)) { + if ((*pos + 1) >= ZSTR_LEN(*buffer)) { PRINTF_DEBUG(("%s(): ereallocing buffer to %d bytes\n", get_active_function_name(), ZSTR_LEN(*buffer))); *buffer = zend_string_extend(*buffer, ZSTR_LEN(*buffer) << 1, 0); } @@ -66,6 +66,25 @@ php_sprintf_appendchar(zend_string **buffer, size_t *pos, char add) } /* }}} */ +/* php_spintf_appendchar() {{{ */ +inline static void +php_sprintf_appendchars(zend_string **buffer, size_t *pos, char *add, size_t len) +{ + if ((*pos + len) >= ZSTR_LEN(*buffer)) { + size_t nlen = ZSTR_LEN(*buffer); + + PRINTF_DEBUG(("%s(): ereallocing buffer to %d bytes\n", get_active_function_name(), ZSTR_LEN(*buffer))); + do { + nlen = nlen << 1; + } while ((*pos + len) >= nlen); + *buffer = zend_string_extend(*buffer, nlen, 0); + } + PRINTF_DEBUG(("sprintf: appending \"%s\", pos=\n", add, *pos)); + memcpy(ZSTR_VAL(*buffer) + (*pos), add, len); + *pos += len; +} +/* }}} */ + /* php_spintf_appendstring() {{{ */ inline static void php_sprintf_appendstring(zend_string **buffer, size_t *pos, char *add, @@ -90,7 +109,7 @@ php_sprintf_appendstring(zend_string **buffer, size_t *pos, char *add, req_size = *pos + m_width + 1; - if (!*buffer || req_size > ZSTR_LEN(*buffer)) { + if (req_size > ZSTR_LEN(*buffer)) { size_t size = ZSTR_LEN(*buffer); while (req_size > size) { if (size > ZEND_SIZE_MAX/2) { @@ -336,17 +355,18 @@ php_sprintf_append2n(zend_string **buffer, size_t *pos, zend_long number, /* php_spintf_getnumber() {{{ */ inline static int -php_sprintf_getnumber(char *buffer, size_t *pos) +php_sprintf_getnumber(char **buffer, size_t *len) { char *endptr; - register zend_long num = ZEND_STRTOL(&buffer[*pos], &endptr, 10); - register size_t i = 0; + register zend_long num = ZEND_STRTOL(*buffer, &endptr, 10); + register size_t i; if (endptr != NULL) { - i = (endptr - &buffer[*pos]); + i = (endptr - *buffer); + *len -= endptr - *buffer; + *buffer = endptr; } PRINTF_DEBUG(("sprintf_getnumber: number was %d bytes long\n", i)); - *pos += i; if (num >= INT_MAX || num < 0) { return -1; @@ -381,116 +401,90 @@ php_sprintf_getnumber(char *buffer, size_t *pos) * */ static zend_string * -php_formatted_print(zend_execute_data *execute_data, int use_array, int format_offset) +php_formatted_print(zval *z_format, zval *args, int argc) { - zval *newargs = NULL; - zval *args, *z_format; - int argc; - size_t size = 240, inpos = 0, outpos = 0, temppos; + size_t size = 240, outpos = 0; int alignment, currarg, adjusting, argnum, width, precision; - char *format, padding; + char *format, *temppos, padding; zend_string *result; int always_sign; size_t format_len; - ZEND_PARSE_PARAMETERS_START(1, -1) - Z_PARAM_VARIADIC('+', args, argc) - ZEND_PARSE_PARAMETERS_END_EX(return NULL); - - /* verify the number of args */ - if ((use_array && argc != (2 + format_offset)) - || (!use_array && argc < (1 + format_offset))) { - WRONG_PARAM_COUNT_WITH_RETVAL(NULL); - } - - convert_to_string_ex(&args[format_offset]); - if (use_array) { - int i = 1; - zval *zv; - zval *array; - - z_format = &args[format_offset]; - array = &args[1 + format_offset]; - if (Z_TYPE_P(array) != IS_ARRAY) { - convert_to_array(array); - } - - argc = 1 + zend_hash_num_elements(Z_ARRVAL_P(array)); - newargs = (zval *)safe_emalloc(argc, sizeof(zval), 0); - ZVAL_COPY_VALUE(&newargs[0], z_format); - - ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(array), zv) { - ZVAL_COPY_VALUE(&newargs[i], zv); - i++; - } ZEND_HASH_FOREACH_END(); - args = newargs; - format_offset = 0; - } - - format = Z_STRVAL(args[format_offset]); - format_len = Z_STRLEN(args[format_offset]); + convert_to_string_ex(z_format); + format = Z_STRVAL_P(z_format); + format_len = Z_STRLEN_P(z_format); result = zend_string_alloc(size, 0); - currarg = 1; + currarg = 0; - while (inpos < Z_STRLEN(args[format_offset])) { - int expprec = 0; + while (format_len) { + int expprec; zval *tmp; - PRINTF_DEBUG(("sprintf: format[%d]='%c'\n", inpos, format[inpos])); - PRINTF_DEBUG(("sprintf: outpos=%d\n", outpos)); - if (format[inpos] != '%') { - php_sprintf_appendchar(&result, &outpos, format[inpos++]); - } else if (format[inpos + 1] == '%') { + temppos = memchr(format, '%', format_len); + if (!temppos) { + php_sprintf_appendchars(&result, &outpos, format, format_len); + break; + } else if (temppos != format) { + php_sprintf_appendchars(&result, &outpos, format, temppos - format); + format_len -= temppos - format; + format = temppos; + } + format++; /* skip the '%' */ + format_len--; + + if (*format == '%') { php_sprintf_appendchar(&result, &outpos, '%'); - inpos += 2; + format++; + format_len--; } else { /* starting a new format specifier, reset variables */ alignment = ALIGN_RIGHT; adjusting = 0; padding = ' '; always_sign = 0; - inpos++; /* skip the '%' */ + expprec = 0; PRINTF_DEBUG(("sprintf: first looking at '%c', inpos=%d\n", - format[inpos], inpos)); - if (isascii((int)format[inpos]) && !isalpha((int)format[inpos])) { + *format, format - Z_STRVAL_P(z_format))); + if (isalpha((int)*format)) { + width = precision = 0; + argnum = currarg++; + } else { /* first look for argnum */ - temppos = inpos; - while (isdigit((int)format[temppos])) temppos++; - if (format[temppos] == '$') { - argnum = php_sprintf_getnumber(format, &inpos); + temppos = format; + while (isdigit((int)*temppos)) temppos++; + if (*temppos == '$') { + argnum = php_sprintf_getnumber(&format, &format_len); if (argnum <= 0) { - efree(result); - if (newargs) { - efree(newargs); - } + zend_string_efree(result); php_error_docref(NULL, E_WARNING, "Argument number must be greater than zero"); return NULL; } - - inpos++; /* skip the '$' */ + argnum--; + format++; /* skip the '$' */ + format_len--; } else { argnum = currarg++; } - argnum += format_offset; - /* after argnum comes modifiers */ PRINTF_DEBUG(("sprintf: looking for modifiers\n" "sprintf: now looking at '%c', inpos=%d\n", - format[inpos], inpos)); - for (;; inpos++) { - if (format[inpos] == ' ' || format[inpos] == '0') { - padding = format[inpos]; - } else if (format[inpos] == '-') { + *format, format - Z_STRVAL_P(z_format))); + for (;; format++, format_len--) { + if (*format == ' ' || *format == '0') { + padding = *format; + } else if (*format == '-') { alignment = ALIGN_LEFT; /* space padding, the default */ - } else if (format[inpos] == '+') { + } else if (*format == '+') { always_sign = 1; - } else if (format[inpos] == '\'' && inpos+1<format_len) { - padding = format[++inpos]; + } else if (*format == '\'' && format_len > 1) { + format++; + format_len--; + padding = *format; } else { PRINTF_DEBUG(("sprintf: end of modifiers\n")); break; @@ -502,13 +496,10 @@ php_formatted_print(zend_execute_data *execute_data, int use_array, int format_o /* after modifiers comes width */ - if (isdigit((int)format[inpos])) { + if (isdigit((int)*format)) { PRINTF_DEBUG(("sprintf: getting width\n")); - if ((width = php_sprintf_getnumber(format, &inpos)) < 0) { + if ((width = php_sprintf_getnumber(&format, &format_len)) < 0) { efree(result); - if (newargs) { - efree(newargs); - } php_error_docref(NULL, E_WARNING, "Width must be greater than zero and less than %d", INT_MAX); return NULL; } @@ -519,15 +510,13 @@ php_formatted_print(zend_execute_data *execute_data, int use_array, int format_o PRINTF_DEBUG(("sprintf: width=%d\n", width)); /* after width and argnum comes precision */ - if (format[inpos] == '.') { - inpos++; + if (*format == '.') { + format++; + format_len--; PRINTF_DEBUG(("sprintf: getting precision\n")); - if (isdigit((int)format[inpos])) { - if ((precision = php_sprintf_getnumber(format, &inpos)) < 0) { + if (isdigit((int)*format)) { + if ((precision = php_sprintf_getnumber(&format, &format_len)) < 0) { efree(result); - if (newargs) { - efree(newargs); - } php_error_docref(NULL, E_WARNING, "Precision must be greater than zero and less than %d", INT_MAX); return NULL; } @@ -540,27 +529,22 @@ php_formatted_print(zend_execute_data *execute_data, int use_array, int format_o precision = 0; } PRINTF_DEBUG(("sprintf: precision=%d\n", precision)); - } else { - width = precision = 0; - argnum = currarg++ + format_offset; } if (argnum >= argc) { efree(result); - if (newargs) { - efree(newargs); - } php_error_docref(NULL, E_WARNING, "Too few arguments"); return NULL; } - if (format[inpos] == 'l') { - inpos++; + if (*format == 'l') { + format++; + format_len--; } - PRINTF_DEBUG(("sprintf: format character='%c'\n", format[inpos])); + PRINTF_DEBUG(("sprintf: format character='%c'\n", *format)); /* now we expect to find a type specifier */ tmp = &args[argnum]; - switch (format[inpos]) { + switch (*format) { case 's': { zend_string *t; zend_string *str = zval_get_tmp_string(tmp, &t); @@ -597,7 +581,7 @@ php_formatted_print(zend_execute_data *execute_data, int use_array, int format_o zval_get_double(tmp), width, padding, alignment, precision, adjusting, - format[inpos], always_sign + *format, always_sign ); break; @@ -638,17 +622,22 @@ php_formatted_print(zend_execute_data *execute_data, int use_array, int format_o php_sprintf_appendchar(&result, &outpos, '%'); break; + + case '\0': + if (!format_len) { + goto exit; + } + break; + default: break; } - inpos++; + format++; + format_len--; } } - if (newargs) { - efree(newargs); - } - +exit: /* possibly, we have to make sure we have room for the terminating null? */ ZSTR_VAL(result)[outpos]=0; ZSTR_LEN(result) = outpos; @@ -656,13 +645,45 @@ php_formatted_print(zend_execute_data *execute_data, int use_array, int format_o } /* }}} */ +/* php_formatted_print_get_array() {{{ */ +static zval* +php_formatted_print_get_array(zval *array, int *argc) +{ + zval *args, *zv; + int n; + + if (Z_TYPE_P(array) != IS_ARRAY) { + convert_to_array(array); + } + + n = zend_hash_num_elements(Z_ARRVAL_P(array)); + args = (zval *)safe_emalloc(n, sizeof(zval), 0); + n = 0; + ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(array), zv) { + ZVAL_COPY_VALUE(&args[n], zv); + n++; + } ZEND_HASH_FOREACH_END(); + + *argc = n; + return args; +} +/* }}} */ + /* {{{ proto string sprintf(string format [, mixed arg1 [, mixed ...]]) Return a formatted string */ PHP_FUNCTION(user_sprintf) { zend_string *result; + zval *format, *args; + int argc; - if ((result=php_formatted_print(execute_data, 0, 0))==NULL) { + ZEND_PARSE_PARAMETERS_START(1, -1) + Z_PARAM_ZVAL(format) + Z_PARAM_VARIADIC('*', args, argc) + ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE); + + result = php_formatted_print(format, args, argc); + if (result == NULL) { RETURN_FALSE; } RETVAL_STR(result); @@ -674,8 +695,19 @@ PHP_FUNCTION(user_sprintf) PHP_FUNCTION(vsprintf) { zend_string *result; + zval *format, *array, *args; + int argc; + + ZEND_PARSE_PARAMETERS_START(2, 2) + Z_PARAM_ZVAL(format) + Z_PARAM_ZVAL(array) + ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE); - if ((result=php_formatted_print(execute_data, 1, 0))==NULL) { + args = php_formatted_print_get_array(array, &argc); + + result = php_formatted_print(format, args, argc); + efree(args); + if (result == NULL) { RETURN_FALSE; } RETVAL_STR(result); @@ -688,12 +720,20 @@ PHP_FUNCTION(user_printf) { zend_string *result; size_t rlen; + zval *format, *args; + int argc; + + ZEND_PARSE_PARAMETERS_START(1, -1) + Z_PARAM_ZVAL(format) + Z_PARAM_VARIADIC('*', args, argc) + ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE); - if ((result=php_formatted_print(execute_data, 0, 0))==NULL) { + result = php_formatted_print(format, args, argc); + if (result == NULL) { RETURN_FALSE; } rlen = PHPWRITE(ZSTR_VAL(result), ZSTR_LEN(result)); - zend_string_free(result); + zend_string_efree(result); RETURN_LONG(rlen); } /* }}} */ @@ -704,12 +744,23 @@ PHP_FUNCTION(vprintf) { zend_string *result; size_t rlen; + zval *format, *array, *args; + int argc; + + ZEND_PARSE_PARAMETERS_START(2, 2) + Z_PARAM_ZVAL(format) + Z_PARAM_ZVAL(array) + ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE); + + args = php_formatted_print_get_array(array, &argc); - if ((result=php_formatted_print(execute_data, 1, 0))==NULL) { + result = php_formatted_print(format, args, argc); + efree(args); + if (result == NULL) { RETURN_FALSE; } rlen = PHPWRITE(ZSTR_VAL(result), ZSTR_LEN(result)); - zend_string_free(result); + zend_string_efree(result); RETURN_LONG(rlen); } /* }}} */ @@ -719,28 +770,31 @@ PHP_FUNCTION(vprintf) PHP_FUNCTION(fprintf) { php_stream *stream; - zval *arg1; + zval *arg1, *format, *args; + int argc; zend_string *result; if (ZEND_NUM_ARGS() < 2) { WRONG_PARAM_COUNT; } - ZEND_PARSE_PARAMETERS_START(1, -1) + ZEND_PARSE_PARAMETERS_START(2, -1) Z_PARAM_RESOURCE(arg1) - /* php_formatted_print does its own zpp for extra args */ + Z_PARAM_ZVAL(format) + Z_PARAM_VARIADIC('*', args, argc) ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE); php_stream_from_zval(stream, arg1); - if ((result=php_formatted_print(execute_data, 0, 1))==NULL) { + result = php_formatted_print(format, args, argc); + if (result == NULL) { RETURN_FALSE; } php_stream_write(stream, ZSTR_VAL(result), ZSTR_LEN(result)); RETVAL_LONG(ZSTR_LEN(result)); - zend_string_free(result); + zend_string_efree(result); } /* }}} */ @@ -749,36 +803,33 @@ PHP_FUNCTION(fprintf) PHP_FUNCTION(vfprintf) { php_stream *stream; - zval *arg1; + zval *arg1, *format, *array, *args; + int argc; zend_string *result; if (ZEND_NUM_ARGS() != 3) { WRONG_PARAM_COUNT; } - ZEND_PARSE_PARAMETERS_START(1, -1) + ZEND_PARSE_PARAMETERS_START(3, 3) Z_PARAM_RESOURCE(arg1) - /* php_formatted_print does its own zpp for extra args */ + Z_PARAM_ZVAL(format) + Z_PARAM_ZVAL(array) ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE); php_stream_from_zval(stream, arg1); - if ((result=php_formatted_print(execute_data, 1, 1))==NULL) { + args = php_formatted_print_get_array(array, &argc); + + result = php_formatted_print(format, args, argc); + efree(args); + if (result == NULL) { RETURN_FALSE; } php_stream_write(stream, ZSTR_VAL(result), ZSTR_LEN(result)); RETVAL_LONG(ZSTR_LEN(result)); - zend_string_free(result); + zend_string_efree(result); } /* }}} */ - -/* - * Local variables: - * tab-width: 4 - * c-basic-offset: 4 - * End: - * vim600: sw=4 ts=4 fdm=marker - * vim<600: sw=4 ts=4 - */ |