summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSara Golemon <pollita@php.net>2007-10-29 17:09:57 +0000
committerSara Golemon <pollita@php.net>2007-10-29 17:09:57 +0000
commitb38282c3fdceff0c9de33ba72f740cb70548d295 (patch)
treef0328405068d0a446224214a24184068d7d87549
parent19bf724c48d0d8cdfc1b53a82b307f6c89b2d03d (diff)
downloadphp-git-b38282c3fdceff0c9de33ba72f740cb70548d295.tar.gz
Backport +/* vararg specifiers from PHP6
-rw-r--r--Zend/zend_API.c67
1 files changed, 66 insertions, 1 deletions
diff --git a/Zend/zend_API.c b/Zend/zend_API.c
index 2bc48cd3d0..f8ad2f3f27 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;
}