From b38282c3fdceff0c9de33ba72f740cb70548d295 Mon Sep 17 00:00:00 2001 From: Sara Golemon Date: Mon, 29 Oct 2007 17:09:57 +0000 Subject: [PATCH] Backport +/* vararg specifiers from PHP6 --- Zend/zend_API.c | 67 ++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 66 insertions(+), 1 deletion(-) diff --git a/Zend/zend_API.c b/Zend/zend_API.c index 2bc48cd3d09..f8ad2f3f273 100644 --- a/Zend/zend_API.c +++ b/Zend/zend_API.c @@ -639,10 +639,12 @@ static int zend_parse_va_args(int num_args, char *type_spec, va_list *va, int fl int c, i; int min_num_args = -1; int max_num_args = 0; + int post_varargs = 0; zval **arg; void **p; int arg_count; int quiet = flags & ZEND_PARSE_PARAMS_QUIET; + zend_bool have_varargs = 0; for (spec_walk = type_spec; *spec_walk; spec_walk++) { c = *spec_walk; @@ -666,6 +668,29 @@ static int zend_parse_va_args(int num_args, char *type_spec, va_list *va, int fl /* Pass */ break; + case '*': + case '+': + if (have_varargs) { + if (!quiet) { + zend_function *active_function = EG(function_state_ptr)->function; + char *class_name = active_function->common.scope ? active_function->common.scope->name : ""; + zend_error(E_WARNING, "%s%s%s(): only one varargs specifier (* or +) is permitted", + class_name, + class_name[0] ? "::" : "", + get_active_function_name(TSRMLS_C)); + } + return FAILURE; + } + + have_varargs = 1; + /* we expect at least one parameter in varargs */ + if (c == '+') { + max_num_args++; + } + /* mark the beginning of varargs */ + post_varargs = max_num_args; + break; + default: if (!quiet) { zend_function *active_function = EG(function_state_ptr)->function; @@ -683,7 +708,14 @@ static int zend_parse_va_args(int num_args, char *type_spec, va_list *va, int fl min_num_args = max_num_args; } - if (num_args < min_num_args || num_args > max_num_args) { + if (have_varargs) { + /* calculate how many required args are at the end of the specifier list */ + post_varargs = max_num_args - post_varargs; + max_num_args = -1; + } + + + if (num_args < min_num_args || (num_args > max_num_args && max_num_args > 0)) { if (!quiet) { zend_function *active_function = EG(function_state_ptr)->function; char *class_name = active_function->common.scope ? active_function->common.scope->name : ""; @@ -714,6 +746,39 @@ static int zend_parse_va_args(int num_args, char *type_spec, va_list *va, int fl if (*type_spec == '|') { type_spec++; } + + if (*type_spec == '*' || *type_spec == '+') { + int num_varargs = num_args + 1 - post_varargs; + + /* eat up the passed in storage even if it won't be filled in with varargs */ + zval ****varargs = (zval ****)va_arg(*va, zval ****); + int *n_varargs = (int *) va_arg(*va, int *); + type_spec++; + + if (num_varargs > 0) { + int iv = 0; + zval **p = (zval **) (EG(argument_stack).top_element - 2 - (arg_count - i)); + + *n_varargs = num_varargs; + + /* allocate space for array and store args */ + *varargs = safe_emalloc(num_varargs, sizeof(zval **), 0); + while (num_varargs-- > 0) { + (*varargs)[iv++] = p++; + } + + /* adjust how many args we have left and restart loop */ + num_args = num_args + 1 - iv; + i += iv; + continue; + } else { + *varargs = NULL; + *n_varargs = 0; + } + } + + arg = (zval **) (EG(argument_stack).top_element - 2 - (arg_count-i)); + if (zend_parse_arg(i+1, arg, va, &type_spec, quiet TSRMLS_CC) == FAILURE) { return FAILURE; }