summaryrefslogtreecommitdiff
path: root/ext/standard/formatted_print.c
diff options
context:
space:
mode:
Diffstat (limited to 'ext/standard/formatted_print.c')
-rw-r--r--ext/standard/formatted_print.c321
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
- */