summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSVN Migration <svn@php.net>2000-12-02 08:14:58 +0000
committerSVN Migration <svn@php.net>2000-12-02 08:14:58 +0000
commitdad882cd33b686ba5b5dd97915c3e827abcc2ea6 (patch)
treeb07b918b82cfc2db60c05c574ce527ecf600adaf
parentc277e3f98dab989279d2f6ea72068e0bdc884ac5 (diff)
downloadphp-git-php-4.0.4RC3.tar.gz
This commit was manufactured by cvs2svn to create tag 'php_4_0_4RC3'.php-4.0.4RC3
-rw-r--r--TSRM/TSRM.h120
-rw-r--r--TSRM/configure.in33
-rw-r--r--Zend/acconfig.h72
-rw-r--r--Zend/configure.in45
-rw-r--r--Zend/zend_API.h426
-rw-r--r--Zend/zend_builtin_functions.c1013
-rw-r--r--Zend/zend_compile.c2351
-rw-r--r--Zend/zend_execute.h213
-rw-r--r--Zend/zend_execute_API.c708
-rw-r--r--Zend/zend_hash.c1278
-rw-r--r--Zend/zend_language_parser.y725
-rw-r--r--Zend/zend_modules.h85
-rw-r--r--Zend/zend_operators.c1753
13 files changed, 8822 insertions, 0 deletions
diff --git a/TSRM/TSRM.h b/TSRM/TSRM.h
new file mode 100644
index 0000000000..e060cd238b
--- /dev/null
+++ b/TSRM/TSRM.h
@@ -0,0 +1,120 @@
+/*
+ +----------------------------------------------------------------------+
+ | Thread Safe Resource Manager |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1999, 2000, Andi Gutmans, Sascha Schumann, Zeev Suraski|
+ | This source file is subject to the TSRM license, that is bundled |
+ | with this package in the file LICENSE |
+ +----------------------------------------------------------------------+
+ | Authors: Zeev Suraski <zeev@zend.com> |
+ +----------------------------------------------------------------------+
+*/
+
+#ifndef TSRM_H
+#define TSRM_H
+
+#ifdef HAVE_CONFIG_H
+# undef PACKAGE
+# undef VERSION
+# include "tsrm_config.h"
+# undef PACKAGE
+# undef VERSION
+#endif
+
+/* Only compile multi-threading functions if we're in ZTS mode */
+#ifdef ZTS
+
+#ifdef WIN32
+# define TSRM_WIN32
+#endif
+
+#ifdef TSRM_WIN32
+# include <windows.h>
+#elif defined(GNUPTH)
+# include <pth.h>
+#elif defined(PTHREADS)
+# include <pthread.h>
+#endif
+
+typedef int ts_rsrc_id;
+
+#ifdef TSRM_WIN32
+# ifdef TSRM_EXPORTS
+# define TSRM_API __declspec(dllexport)
+# else
+# define TSRM_API __declspec(dllimport)
+# endif
+#else
+# define TSRM_API
+#endif
+
+
+/* Define THREAD_T and MUTEX_T */
+#ifdef TSRM_WIN32
+# define THREAD_T DWORD
+# define MUTEX_T CRITICAL_SECTION *
+#elif defined(GNUPTH)
+# define THREAD_T pth_t
+# define MUTEX_T pth_mutex_t *
+#elif defined(PTHREADS)
+# define THREAD_T pthread_t
+# define MUTEX_T pthread_mutex_t *
+#elif defined(NSAPI)
+# define THREAD_T SYS_THREAD
+# define MUTEX_T CRITICAL
+#elif defined(PI3WEB)
+# define THREAD_T PIThread *
+# define MUTEX_T PISync *
+#endif
+
+typedef void (*ts_allocate_ctor)(void *);
+typedef void (*ts_allocate_dtor)(void *);
+
+#define THREAD_HASH_OF(thr,ts) (unsigned long)thr%(unsigned long)ts
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* startup/shutdown */
+TSRM_API int tsrm_startup(int expected_threads, int expected_resources, int debug_level, char *debug_filename);
+TSRM_API void tsrm_shutdown(void);
+
+/* allocates a new thread-safe-resource id */
+TSRM_API ts_rsrc_id ts_allocate_id(size_t size, ts_allocate_ctor ctor, ts_allocate_dtor dtor);
+
+/* fetches the requested resource for the current thread */
+TSRM_API void *ts_resource_ex(ts_rsrc_id id, THREAD_T *th_id);
+#define ts_resource(id) ts_resource_ex(id, NULL)
+
+/* frees all resources allocated for the current thread */
+TSRM_API void ts_free_thread(void);
+
+/* deallocates all occurrences of a given id */
+TSRM_API void ts_free_id(ts_rsrc_id id);
+
+
+/* Debug support */
+#define TSRM_ERROR_LEVEL_ERROR 1
+#define TSRM_ERROR_LEVEL_CORE 2
+#define TSRM_ERROR_LEVEL_INFO 3
+TSRM_API int tsrm_error(int level, const char *format, ...);
+TSRM_API void tsrm_error_set(int level, char *debug_filename);
+
+/* utility functions */
+TSRM_API THREAD_T tsrm_thread_id(void);
+TSRM_API MUTEX_T tsrm_mutex_alloc(void);
+TSRM_API void tsrm_mutex_free(MUTEX_T mutexp);
+TSRM_API int tsrm_mutex_lock(MUTEX_T mutexp);
+TSRM_API int tsrm_mutex_unlock(MUTEX_T mutexp);
+
+TSRM_API void *tsrm_set_new_thread_begin_handler(void (*new_thread_begin_handler)(THREAD_T thread_id));
+TSRM_API void *tsrm_set_new_thread_end_handler(void (*new_thread_end_handler)(THREAD_T thread_id));
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* ZTS */
+
+#endif /* TSRM_H */
diff --git a/TSRM/configure.in b/TSRM/configure.in
new file mode 100644
index 0000000000..da5cb2953c
--- /dev/null
+++ b/TSRM/configure.in
@@ -0,0 +1,33 @@
+dnl $Id$
+dnl
+dnl Minimalistic configure.in for TSRM.
+dnl
+
+AC_INIT(TSRM.c)
+AM_INIT_AUTOMAKE(TSRM, 1.0)
+AM_CONFIG_HEADER(tsrm_config.h)
+
+sinclude(tsrm.m4)
+
+TSRM_BASIC_CHECKS
+TSRM_THREADS_CHECKS
+
+AM_PROG_LIBTOOL
+if test "$enable_debug" != "yes"; then
+ AM_SET_LIBTOOL_VARIABLE([--silent])
+fi
+
+dnl TSRM_PTHREAD
+
+AC_CHECK_HEADERS(
+utime.h \
+dirent.h \
+stdarg.h \
+alloca.h \
+unistd.h \
+limits.h
+)
+
+AC_DEFINE(ZTS,1,[ ])
+
+AC_OUTPUT(Makefile)
diff --git a/Zend/acconfig.h b/Zend/acconfig.h
new file mode 100644
index 0000000000..01397626a0
--- /dev/null
+++ b/Zend/acconfig.h
@@ -0,0 +1,72 @@
+#define ZEND_API
+#define ZEND_DLEXPORT
+
+@TOP@
+
+/* these are defined by automake */
+#undef PACKAGE
+#undef VERSION
+
+#undef uint
+#undef ulong
+
+/* Define if you want to enable memory limit support */
+#define MEMORY_LIMIT 0
+
+@BOTTOM@
+
+#ifdef HAVE_STDLIB_H
+# include <stdlib.h>
+#endif
+
+#ifdef HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+
+#ifdef HAVE_STRING_H
+# include <string.h>
+#else
+# include <strings.h>
+#endif
+
+#if ZEND_BROKEN_SPRINTF
+int zend_sprintf(char *buffer, const char *format, ...);
+#else
+# define zend_sprintf sprintf
+#endif
+
+#include <math.h>
+
+#ifdef HAVE_ISNAN
+#define zend_isnan(a) isnan(a)
+#elif defined(NAN)
+#define zend_isnan(a) (((a)==NAN)?1:0)
+#else
+#define zend_isnan(a) 0
+#endif
+
+#ifdef HAVE_ISINF
+#define zend_isinf(a) isinf(a)
+#elif defined(INFINITY)
+/* Might not work, but is required by ISO C99 */
+#define zend_isinf(a) (((a)==INFINITY)?1:0)
+#else
+#define zend_isinf(a) 0
+#endif
+
+#ifdef HAVE_FINITE
+#define zend_finite(a) finite(a)
+#elif defined(HAVE_ISFINITE) || defined(isfinite)
+#define zend_finite(a) isfinite(a)
+#elif defined(fpclassify)
+#define zend_finite(a) ((fpclassify((a))!=FP_INFINITE&&fpclassify((a))!=FP_NAN)?1:0)
+#else
+#define zend_finite(a) (zend_isnan(a) ? 0 : zend_isinf(a) ? 0 : 1)
+#endif
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ */
diff --git a/Zend/configure.in b/Zend/configure.in
new file mode 100644
index 0000000000..50ead57d93
--- /dev/null
+++ b/Zend/configure.in
@@ -0,0 +1,45 @@
+dnl $Id$
+dnl Process this file with autoconf to produce a configure script.
+
+AC_INIT(zend.c)
+AM_INIT_AUTOMAKE(zend, 0.80A)
+AM_CONFIG_HEADER(zend_config.h)
+AM_SANITY_CHECK
+AM_MAINTAINER_MODE
+AC_PROG_CC
+AM_PROG_LEX
+AM_PROG_CC_STDC
+ZEND_VERSION=$VERSION
+
+dnl We want this one before the checks, so the checks can modify CFLAGS.
+test -z "$CFLAGS" && auto_cflags=1
+
+sinclude(Zend.m4)
+
+LIBZEND_BASIC_CHECKS
+
+AM_PROG_LIBTOOL
+if test "$enable_debug" != "yes"; then
+ AM_SET_LIBTOOL_VARIABLE([--silent])
+fi
+
+dnl
+dnl Check for /usr/pkg/{lib,include} which is where NetBSD puts binary
+dnl and source packages. This should be harmless on other OSs.
+dnl
+if test -d /usr/pkg/include -a -d /usr/pkg/lib ; then
+ CFLAGS="$CFLAGS -I/usr/pkg/include"
+ LDFLAGS="$LDFLAGS -L/usr/pkg/lib"
+fi
+
+LIBZEND_ENABLE_DEBUG
+LIBZEND_OTHER_CHECKS
+
+EXTRA_LIBS="$LIBS"
+LIBS=""
+AC_SUBST(EXTRA_LIBS)
+AC_OUTPUT(Makefile)
+
+# Local Variables:
+# tab-width: 4
+# End:
diff --git a/Zend/zend_API.h b/Zend/zend_API.h
new file mode 100644
index 0000000000..8125193fcd
--- /dev/null
+++ b/Zend/zend_API.h
@@ -0,0 +1,426 @@
+/*
+ +----------------------------------------------------------------------+
+ | Zend Engine |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1998-2000 Zend Technologies Ltd. (http://www.zend.com) |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 0.92 of the Zend license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available at through the world-wide-web at |
+ | http://www.zend.com/license/0_92.txt. |
+ | If you did not receive a copy of the Zend license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@zend.com so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Andi Gutmans <andi@zend.com> |
+ | Zeev Suraski <zeev@zend.com> |
+ +----------------------------------------------------------------------+
+*/
+
+
+#ifndef ZEND_API_H
+#define ZEND_API_H
+
+#include "modules.h"
+#include "zend_list.h"
+#include "zend_fast_cache.h"
+#include "zend_operators.h"
+#include "zend_variables.h"
+#include "zend_execute.h"
+
+#define ZEND_FN(name) zend_if_##name
+#define ZEND_NAMED_FUNCTION(name) void name(INTERNAL_FUNCTION_PARAMETERS)
+#define ZEND_FUNCTION(name) ZEND_NAMED_FUNCTION(ZEND_FN(name))
+
+#define ZEND_NAMED_FE(zend_name, name, arg_types) { #zend_name, name, arg_types },
+#define ZEND_FE(name, arg_types) ZEND_NAMED_FE(name, ZEND_FN(name), arg_types)
+#define ZEND_FALIAS(name, alias, arg_types) ZEND_NAMED_FE(name, ZEND_FN(alias), arg_types)
+
+#define ZEND_MINIT(module) zend_minit_##module
+#define ZEND_MSHUTDOWN(module) zend_mshutdown_##module
+#define ZEND_RINIT(module) zend_rinit_##module
+#define ZEND_RSHUTDOWN(module) zend_rshutdown_##module
+#define ZEND_MINFO(module) zend_info_##module
+#define ZEND_GINIT(module) zend_ginit_##module
+#define ZEND_GSHUTDOWN(module) zend_gshutdown_##module
+
+#define ZEND_MINIT_FUNCTION(module) int ZEND_MINIT(module)(INIT_FUNC_ARGS)
+#define ZEND_MSHUTDOWN_FUNCTION(module) int ZEND_MSHUTDOWN(module)(SHUTDOWN_FUNC_ARGS)
+#define ZEND_RINIT_FUNCTION(module) int ZEND_RINIT(module)(INIT_FUNC_ARGS)
+#define ZEND_RSHUTDOWN_FUNCTION(module) int ZEND_RSHUTDOWN(module)(SHUTDOWN_FUNC_ARGS)
+#define ZEND_MINFO_FUNCTION(module) void ZEND_MINFO(module)(ZEND_MODULE_INFO_FUNC_ARGS)
+#define ZEND_GINIT_FUNCTION(module) int ZEND_GINIT(module)(GINIT_FUNC_ARGS)
+#define ZEND_GSHUTDOWN_FUNCTION(module) int ZEND_GSHUTDOWN(module)(void)
+
+#define ZEND_GET_MODULE(name) \
+ ZEND_DLEXPORT zend_module_entry *get_module(void) { return &name##_module_entry; }
+
+#define ZEND_BEGIN_MODULE_GLOBALS(module_name) \
+ typedef struct _zend_##module_name##_globals {
+#define ZEND_END_MODULE_GLOBALS(module_name) \
+ } zend_##module_name##_globals;
+
+#ifdef ZTS
+
+#define ZEND_DECLARE_MODULE_GLOBALS(module_name) \
+ static ts_rsrc_id module_name##_globals_id;
+#define ZEND_INIT_MODULE_GLOBALS(module_name, globals_ctor, globals_dtor) \
+ module_name##_globals_id = ts_allocate_id(sizeof(zend_##module_name##_globals), (ts_allocate_ctor) globals_ctor, (ts_allocate_dtor) globals_dtor);
+
+#else
+
+#define ZEND_DECLARE_MODULE_GLOBALS(module_name) \
+ static zend_##module_name##_globals module_name##_globals;
+#define ZEND_INIT_MODULE_GLOBALS(module_name, globals_ctor, globals_dtor) \
+ globals_ctor(&module_name##_globals);
+
+#endif
+
+
+
+#define INIT_CLASS_ENTRY(class_container, class_name, functions) \
+ { \
+ class_container.name = strdup(class_name); \
+ class_container.name_length = sizeof(class_name)-1; \
+ class_container.builtin_functions = functions; \
+ class_container.handle_function_call = NULL; \
+ class_container.handle_property_get = NULL; \
+ class_container.handle_property_set = NULL; \
+ }
+
+#define INIT_OVERLOADED_CLASS_ENTRY(class_container, class_name, functions, handle_fcall, handle_propget, handle_propset) \
+ { \
+ class_container.name = strdup(class_name); \
+ class_container.name_length = sizeof(class_name)-1; \
+ class_container.builtin_functions = functions; \
+ class_container.handle_function_call = handle_fcall; \
+ class_container.handle_property_get = handle_propget; \
+ class_container.handle_property_set = handle_propset; \
+ }
+
+
+
+int zend_next_free_module(void);
+
+ZEND_API int zend_get_parameters(int ht, int param_count, ...);
+ZEND_API int zend_get_parameters_array(int ht, int param_count, zval **argument_array);
+ZEND_API int zend_get_parameters_ex(int param_count, ...);
+ZEND_API int zend_get_parameters_array_ex(int param_count, zval ***argument_array);
+
+ZEND_API int ParameterPassedByReference(int ht, uint n);
+
+int zend_register_functions(zend_function_entry *functions, HashTable *function_table, int type);
+void zend_unregister_functions(zend_function_entry *functions, int count, HashTable *function_table);
+ZEND_API int zend_register_module(zend_module_entry *module_entry);
+
+ZEND_API zend_class_entry *zend_register_internal_class(zend_class_entry *class_entry);
+ZEND_API zend_class_entry *zend_register_internal_class_ex(zend_class_entry *class_entry, zend_class_entry *parent_ce, char *parent_name);
+
+ZEND_API zend_module_entry *zend_get_module(int module_number);
+ZEND_API int zend_disable_function(char *function_name, uint function_name_length);
+
+ZEND_API void wrong_param_count(void);
+
+#define getThis() (this_ptr)
+
+#define WRONG_PARAM_COUNT ZEND_WRONG_PARAM_COUNT()
+#define WRONG_PARAM_COUNT_WITH_RETVAL(ret) ZEND_WRONG_PARAM_COUNT_WITH_RETVAL(ret)
+#define ARG_COUNT(dummy) (ht)
+#define ZEND_NUM_ARGS() (ht)
+#define ZEND_WRONG_PARAM_COUNT() { wrong_param_count(); return; }
+#define ZEND_WRONG_PARAM_COUNT_WITH_RETVAL(ret) { wrong_param_count(); return ret; }
+
+#ifndef ZEND_WIN32
+#define DLEXPORT
+#endif
+
+ZEND_API int zend_startup_module(zend_module_entry *module);
+
+#define array_init(arg) _array_init((arg) ZEND_FILE_LINE_CC)
+#define object_init(arg) _object_init((arg) ZEND_FILE_LINE_CC)
+#define object_init_ex(arg, ce) _object_init_ex((arg), (ce) ZEND_FILE_LINE_CC)
+ZEND_API int _array_init(zval *arg ZEND_FILE_LINE_DC);
+ZEND_API int _object_init(zval *arg ZEND_FILE_LINE_DC);
+ZEND_API int _object_init_ex(zval *arg, zend_class_entry *ce ZEND_FILE_LINE_DC);
+
+/* no longer supported */
+ZEND_API int add_assoc_function(zval *arg, char *key,void (*function_ptr)(INTERNAL_FUNCTION_PARAMETERS));
+
+ZEND_API int add_assoc_long(zval *arg, char *key, long n);
+ZEND_API int add_assoc_unset(zval *arg, char *key);
+ZEND_API int add_assoc_bool(zval *arg, char *key, int b);
+ZEND_API int add_assoc_resource(zval *arg, char *key, int r);
+ZEND_API int add_assoc_double(zval *arg, char *key, double d);
+ZEND_API int add_assoc_string(zval *arg, char *key, char *str, int duplicate);
+ZEND_API int add_assoc_stringl(zval *arg, char *key, char *str, uint length, int duplicate);
+
+ZEND_API int add_index_long(zval *arg, uint idx, long n);
+ZEND_API int add_index_unset(zval *arg, uint idx);
+ZEND_API int add_index_bool(zval *arg, uint idx, int b);
+ZEND_API int add_index_resource(zval *arg, uint idx, int r);
+ZEND_API int add_index_double(zval *arg, uint idx, double d);
+ZEND_API int add_index_string(zval *arg, uint idx, char *str, int duplicate);
+ZEND_API int add_index_stringl(zval *arg, uint idx, char *str, uint length, int duplicate);
+
+ZEND_API int add_next_index_long(zval *arg, long n);
+ZEND_API int add_next_index_unset(zval *arg);
+ZEND_API int add_next_index_bool(zval *arg, int b);
+ZEND_API int add_next_index_resource(zval *arg, int r);
+ZEND_API int add_next_index_double(zval *arg, double d);
+ZEND_API int add_next_index_string(zval *arg, char *str, int duplicate);
+ZEND_API int add_next_index_stringl(zval *arg, char *str, uint length, int duplicate);
+
+ZEND_API int add_get_index_long(zval *arg, uint idx, long l, void **dest);
+ZEND_API int add_get_index_double(zval *arg, uint idx, double d, void **dest);
+ZEND_API int add_get_assoc_string(zval *arg, char *key, char *str, void **dest, int duplicate);
+ZEND_API int add_get_assoc_stringl(zval *arg, char *key, char *str, uint length, void **dest, int duplicate);
+ZEND_API int add_get_index_string(zval *arg, uint idx, char *str, void **dest, int duplicate);
+ZEND_API int add_get_index_stringl(zval *arg, uint idx, char *str, uint length, void **dest, int duplicate);
+
+ZEND_API int call_user_function(HashTable *function_table, zval *object, zval *function_name, zval *retval_ptr, int param_count, zval *params[]);
+ZEND_API int call_user_function_ex(HashTable *function_table, zval *object, zval *function_name, zval **retval_ptr_ptr, int param_count, zval **params[], int no_separation, HashTable *symbol_table);
+
+ZEND_API int add_property_long(zval *arg, char *key, long l);
+ZEND_API int add_property_unset(zval *arg, char *key);
+ZEND_API int add_property_bool(zval *arg, char *key, int b);
+ZEND_API int add_property_resource(zval *arg, char *key, long r);
+ZEND_API int add_property_double(zval *arg, char *key, double d);
+ZEND_API int add_property_string(zval *arg, char *key, char *str, int duplicate);
+ZEND_API int add_property_stringl(zval *arg, char *key, char *str, uint length, int duplicate);
+
+ZEND_API int zend_set_hash_symbol(zval *symbol, char *name, int name_length,
+ int is_ref, int num_symbol_tables, ...);
+
+#define add_method(arg,key,method) add_assoc_function((arg),(key),(method))
+
+#define ZVAL_RESOURCE(z,l) { \
+ (z)->type = IS_RESOURCE; \
+ (z)->value.lval = l; \
+ }
+#define ZVAL_BOOL(z,b) { \
+ (z)->type = IS_BOOL; \
+ (z)->value.lval = b; \
+ }
+#define ZVAL_NULL(z) { \
+ (z)->type = IS_NULL; \
+ }
+#define ZVAL_LONG(z,l) { \
+ (z)->type = IS_LONG; \
+ (z)->value.lval = l; \
+ }
+#define ZVAL_DOUBLE(z,d) { \
+ (z)->type = IS_DOUBLE; \
+ (z)->value.dval = d; \
+ }
+#define ZVAL_STRING(z,s,duplicate) { \
+ char *__s=(s); \
+ (z)->value.str.len = strlen(__s); \
+ (z)->value.str.val = (duplicate?estrndup(__s,(z)->value.str.len):__s); \
+ (z)->type = IS_STRING; \
+ }
+#define ZVAL_STRINGL(z,s,l,duplicate) { \
+ char *__s=(s); int __l=l; \
+ (z)->value.str.len = __l; \
+ (z)->value.str.val = (duplicate?estrndup(__s,__l):__s); \
+ (z)->type = IS_STRING; \
+ }
+
+#define ZVAL_EMPTY_STRING(z) { \
+ (z)->value.str.len = 0; \
+ (z)->value.str.val = empty_string; \
+ (z)->type = IS_STRING; \
+ }
+
+#define ZVAL_FALSE { (z)->value.lval = 0; (z)->type = IS_BOOL; }
+#define ZVAL_TRUE { (z)->value.lval = 1; (z)->type = IS_BOOL; }
+
+#define RETVAL_RESOURCE(l) { \
+ return_value->type = IS_RESOURCE;\
+ return_value->value.lval = l; \
+ }
+#define RETVAL_BOOL(b) { \
+ return_value->type = IS_BOOL; \
+ return_value->value.lval = b; \
+ }
+#define RETVAL_NULL() { \
+ return_value->type = IS_NULL; \
+ }
+#define RETVAL_LONG(l) { \
+ return_value->type = IS_LONG; \
+ return_value->value.lval = l; \
+ }
+#define RETVAL_DOUBLE(d) { \
+ return_value->type = IS_DOUBLE; \
+ return_value->value.dval = d; \
+ }
+#define RETVAL_STRING(s,duplicate) { \
+ char *__s=(s); \
+ return_value->value.str.len = strlen(__s); \
+ return_value->value.str.val = (duplicate?estrndup(__s,return_value->value.str.len):__s); \
+ return_value->type = IS_STRING; \
+ }
+#define RETVAL_STRINGL(s,l,duplicate) { \
+ char *__s=(s); int __l=l; \
+ return_value->value.str.len = __l; \
+ return_value->value.str.val = (duplicate?estrndup(__s,__l):__s); \
+ return_value->type = IS_STRING; \
+ }
+
+#define RETVAL_EMPTY_STRING() { \
+ return_value->value.str.len = 0; \
+ return_value->value.str.val = empty_string; \
+ return_value->type = IS_STRING; \
+ }
+
+#define RETVAL_FALSE { return_value->value.lval = 0; return_value->type = IS_BOOL; }
+#define RETVAL_TRUE { return_value->value.lval = 1; return_value->type = IS_BOOL; }
+
+#define RETURN_RESOURCE(l) { \
+ return_value->type = IS_RESOURCE;\
+ return_value->value.lval = l; \
+ return; \
+ }
+
+#define RETURN_BOOL(b) { \
+ return_value->type = IS_BOOL; \
+ return_value->value.lval = b; \
+ return; \
+ }
+
+#define RETURN_NULL() { \
+ return_value->type = IS_NULL; \
+ return; \
+ }
+
+#define RETURN_LONG(l) { \
+ return_value->type = IS_LONG; \
+ return_value->value.lval = l; \
+ return; \
+ }
+#define RETURN_DOUBLE(d) { \
+ return_value->type = IS_DOUBLE; \
+ return_value->value.dval = d; \
+ return; \
+ }
+#define RETURN_STRING(s,duplicate) { \
+ char *__s=(s); \
+ return_value->value.str.len = strlen(__s); \
+ return_value->value.str.val = (duplicate?estrndup(__s,return_value->value.str.len):__s); \
+ return_value->type = IS_STRING; \
+ return; \
+ }
+#define RETURN_STRINGL(s,l,duplicate) { \
+ char *__s=(s); int __l=l; \
+ return_value->value.str.len = __l; \
+ return_value->value.str.val = (duplicate?estrndup(__s,__l):__s); \
+ return_value->type = IS_STRING; \
+ return; \
+ }
+
+#define RETURN_EMPTY_STRING() { \
+ return_value->value.str.len = 0; \
+ return_value->value.str.val = empty_string; \
+ return_value->type = IS_STRING; \
+ return; \
+ }
+
+#define RETURN_FALSE { RETVAL_FALSE; return; }
+#define RETURN_TRUE { RETVAL_TRUE; return; }
+
+#define SET_VAR_STRING(n,v) { \
+ { \
+ zval *var; \
+ char *str=(v); /* prevent 'v' from being evaluated more than once */ \
+ \
+ ALLOC_ZVAL(var); \
+ var->value.str.val = (str); \
+ var->value.str.len = strlen((str)); \
+ var->type = IS_STRING; \
+ ZEND_SET_GLOBAL_VAR(n, var); \
+ } \
+ }
+
+#define SET_VAR_STRINGL(n,v,l) { \
+ { \
+ zval *var; \
+ \
+ ALLOC_ZVAL(var); \
+ var->value.str.val = (v); \
+ var->value.str.len = (l); \
+ var->type = IS_STRING; \
+ ZEND_SET_GLOBAL_VAR(n, var); \
+ } \
+ }
+
+#define SET_VAR_LONG(n,v) { \
+ { \
+ zval *var; \
+ \
+ ALLOC_ZVAL(var); \
+ var->value.lval = (v); \
+ var->type = IS_LONG; \
+ ZEND_SET_GLOBAL_VAR(n, var); \
+ } \
+ }
+
+#define SET_VAR_DOUBLE(n,v) { \
+ { \
+ zval *var; \
+ \
+ ALLOC_ZVAL(var); \
+ var->value.dval = (v); \
+ var->type = IS_DOUBLE; \
+ ZEND_SET_GLOBAL_VAR(n, var); \
+ } \
+ }
+
+
+#define ZEND_SET_SYMBOL(symtable, name, var) \
+ { \
+ char *_name = (name); \
+ \
+ ZEND_SET_SYMBOL_WITH_LENGTH(symtable, _name, strlen(_name)+1, var, 1, 0); \
+ }
+
+#define ZEND_SET_SYMBOL_WITH_LENGTH(symtable, name, name_length, var, _refcount, _is_ref) \
+ { \
+ zval **orig_var; \
+ \
+ if (zend_hash_find(symtable, (name), (name_length), (void **) &orig_var)==SUCCESS \
+ && PZVAL_IS_REF(*orig_var)) { \
+ (var)->refcount = (*orig_var)->refcount; \
+ (var)->is_ref = 1; \
+ \
+ if (_refcount) { \
+ (var)->refcount += _refcount-1; \
+ } \
+ zval_dtor(*orig_var); \
+ **orig_var = *(var); \
+ FREE_ZVAL(var); \
+ } else { \
+ (var)->is_ref = _is_ref; \
+ if (_refcount) { \
+ (var)->refcount = _refcount; \
+ } \
+ zend_hash_update(symtable, (name), (name_length), &(var), sizeof(zval *), NULL); \
+ } \
+ }
+
+
+#define ZEND_SET_GLOBAL_VAR(name, var) \
+ ZEND_SET_SYMBOL(&EG(symbol_table), name, var)
+
+#define ZEND_SET_GLOBAL_VAR_WITH_LENGTH(name, name_length, var, _refcount, _is_ref) \
+ ZEND_SET_SYMBOL_WITH_LENGTH(&EG(symbol_table), name, name_length, var, _refcount, _is_ref)
+
+#define HASH_OF(p) ((p)->type==IS_ARRAY ? (p)->value.ht : (((p)->type==IS_OBJECT ? (p)->value.obj.properties : NULL)))
+#define ZVAL_IS_NULL(z) ((z)->type==IS_NULL)
+
+#endif /* ZEND_API_H */
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ */
diff --git a/Zend/zend_builtin_functions.c b/Zend/zend_builtin_functions.c
new file mode 100644
index 0000000000..e693fab1e0
--- /dev/null
+++ b/Zend/zend_builtin_functions.c
@@ -0,0 +1,1013 @@
+/*
+ +----------------------------------------------------------------------+
+ | Zend Engine |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1998-2000 Zend Technologies Ltd. (http://www.zend.com) |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 0.92 of the Zend license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available at through the world-wide-web at |
+ | http://www.zend.com/license/0_92.txt. |
+ | If you did not receive a copy of the Zend license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@zend.com so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Andi Gutmans <andi@zend.com> |
+ | Zeev Suraski <zeev@zend.com> |
+ +----------------------------------------------------------------------+
+*/
+
+
+#include "zend.h"
+#include "zend_API.h"
+#include "zend_builtin_functions.h"
+#include "zend_constants.h"
+
+#undef ZEND_TEST_EXCEPTIONS
+
+static ZEND_FUNCTION(zend_version);
+static ZEND_FUNCTION(func_num_args);
+static ZEND_FUNCTION(func_get_arg);
+static ZEND_FUNCTION(func_get_args);
+static ZEND_FUNCTION(strlen);
+static ZEND_FUNCTION(strcmp);
+static ZEND_FUNCTION(strncmp);
+static ZEND_FUNCTION(strcasecmp);
+static ZEND_FUNCTION(strncasecmp);
+static ZEND_FUNCTION(each);
+static ZEND_FUNCTION(error_reporting);
+static ZEND_FUNCTION(define);
+static ZEND_FUNCTION(defined);
+static ZEND_FUNCTION(get_class);
+static ZEND_FUNCTION(get_parent_class);
+static ZEND_FUNCTION(method_exists);
+static ZEND_FUNCTION(class_exists);
+static ZEND_FUNCTION(function_exists);
+static ZEND_FUNCTION(leak);
+#ifdef ZEND_TEST_EXCEPTIONS
+static ZEND_FUNCTION(crash);
+#endif
+static ZEND_FUNCTION(get_included_files);
+static ZEND_FUNCTION(is_subclass_of);
+static ZEND_FUNCTION(get_class_vars);
+static ZEND_FUNCTION(get_object_vars);
+static ZEND_FUNCTION(get_class_methods);
+static ZEND_FUNCTION(trigger_error);
+static ZEND_FUNCTION(set_error_handler);
+static ZEND_FUNCTION(restore_error_handler);
+static ZEND_FUNCTION(get_declared_classes);
+static ZEND_FUNCTION(get_defined_functions);
+static ZEND_FUNCTION(get_defined_vars);
+static ZEND_FUNCTION(create_function);
+static ZEND_FUNCTION(get_resource_type);
+#if ZEND_DEBUG
+static ZEND_FUNCTION(zend_test_func);
+#endif
+
+unsigned char first_arg_force_ref[] = { 1, BYREF_FORCE };
+unsigned char first_arg_allow_ref[] = { 1, BYREF_ALLOW };
+unsigned char second_arg_force_ref[] = { 2, BYREF_NONE, BYREF_FORCE };
+unsigned char second_arg_allow_ref[] = { 2, BYREF_NONE, BYREF_ALLOW };
+
+static zend_function_entry builtin_functions[] = {
+ ZEND_FE(zend_version, NULL)
+ ZEND_FE(func_num_args, NULL)
+ ZEND_FE(func_get_arg, NULL)
+ ZEND_FE(func_get_args, NULL)
+ ZEND_FE(strlen, NULL)
+ ZEND_FE(strcmp, NULL)
+ ZEND_FE(strncmp, NULL)
+ ZEND_FE(strcasecmp, NULL)
+ ZEND_FE(strncasecmp, NULL)
+ ZEND_FE(each, first_arg_force_ref)
+ ZEND_FE(error_reporting, NULL)
+ ZEND_FE(define, NULL)
+ ZEND_FE(defined, NULL)
+ ZEND_FE(get_class, NULL)
+ ZEND_FE(get_parent_class, NULL)
+ ZEND_FE(method_exists, NULL)
+ ZEND_FE(class_exists, NULL)
+ ZEND_FE(function_exists, NULL)
+ ZEND_FE(leak, NULL)
+#ifdef ZEND_TEST_EXCEPTIONS
+ ZEND_FE(crash, NULL)
+#endif
+ ZEND_FE(get_included_files, NULL)
+ ZEND_FALIAS(get_required_files, get_included_files, NULL)
+ ZEND_FE(is_subclass_of, NULL)
+ ZEND_FE(get_class_vars, NULL)
+ ZEND_FE(get_object_vars, NULL)
+ ZEND_FE(get_class_methods, NULL)
+ ZEND_FE(trigger_error, NULL)
+ ZEND_FALIAS(user_error, trigger_error, NULL)
+ ZEND_FE(set_error_handler, NULL)
+ ZEND_FE(restore_error_handler, NULL)
+ ZEND_FE(get_declared_classes, NULL)
+ ZEND_FE(get_defined_functions, NULL)
+ ZEND_FE(get_defined_vars, NULL)
+ ZEND_FE(create_function, NULL)
+ ZEND_FE(get_resource_type, NULL)
+#if ZEND_DEBUG
+ ZEND_FE(zend_test_func, NULL)
+#endif
+ { NULL, NULL, NULL }
+};
+
+
+int zend_startup_builtin_functions()
+{
+ return zend_register_functions(builtin_functions, NULL, MODULE_PERSISTENT);
+}
+
+
+ZEND_FUNCTION(zend_version)
+{
+ RETURN_STRINGL(ZEND_VERSION, sizeof(ZEND_VERSION)-1, 1);
+}
+
+
+ZEND_FUNCTION(func_num_args)
+{
+ void **p;
+ int arg_count;
+
+ p = EG(argument_stack).top_element-1-1;
+ arg_count = (ulong) *p; /* this is the amount of arguments passed to func_num_args(); */
+ p -= 1+arg_count;
+ if (*p) {
+ zend_error(E_ERROR, "func_num_args(): Can't be used as a function parameter");
+ }
+ --p;
+ if (p>=EG(argument_stack).elements) {
+ RETURN_LONG((ulong) *p);
+ } else {
+ zend_error(E_WARNING, "func_num_args(): Called from the global scope - no function context");
+ RETURN_LONG(-1);
+ }
+}
+
+
+ZEND_FUNCTION(func_get_arg)
+{
+ void **p;
+ int arg_count;
+ zval **z_requested_offset;
+ zval *arg;
+ long requested_offset;
+
+ if (ZEND_NUM_ARGS()!=1 || zend_get_parameters_ex(1, &z_requested_offset)==FAILURE) {
+ RETURN_FALSE;
+ }
+ convert_to_long_ex(z_requested_offset);
+ requested_offset = (*z_requested_offset)->value.lval;
+
+ p = EG(argument_stack).top_element-1-1;
+ arg_count = (ulong) *p; /* this is the amount of arguments passed to func_get_arg(); */
+ p -= 1+arg_count;
+ if (*p) {
+ zend_error(E_ERROR, "func_get_arg(): Can't be used as a function parameter");
+ }
+ --p;
+ if (p<EG(argument_stack).elements) {
+ zend_error(E_WARNING, "func_get_arg(): Called from the global scope - no function context");
+ RETURN_FALSE;
+ }
+ arg_count = (ulong) *p;
+
+ if (requested_offset>=arg_count) {
+ zend_error(E_WARNING, "func_get_arg(): Argument %d not passed to function", requested_offset);
+ RETURN_FALSE;
+ }
+
+ arg = *(p-(arg_count-requested_offset));
+ *return_value = *arg;
+ zval_copy_ctor(return_value);
+}
+
+
+ZEND_FUNCTION(func_get_args)
+{
+ void **p;
+ int arg_count;
+ int i;
+
+ p = EG(argument_stack).top_element-1-1;
+ arg_count = (ulong) *p; /* this is the amount of arguments passed to func_get_args(); */
+ p -= 1+arg_count;
+ if (*p) {
+ zend_error(E_ERROR, "func_get_args(): Can't be used as a function parameter");
+ }
+ --p;
+
+ if (p<EG(argument_stack).elements) {
+ zend_error(E_WARNING, "func_get_args(): Called from the global scope - no function context");
+ RETURN_FALSE;
+ }
+ arg_count = (ulong) *p;
+
+
+ array_init(return_value);
+ for (i=0; i<arg_count; i++) {
+ zval *element;
+
+ ALLOC_ZVAL(element);
+ *element = **((zval **) (p-(arg_count-i)));
+ zval_copy_ctor(element);
+ INIT_PZVAL(element);
+ zend_hash_next_index_insert(return_value->value.ht, &element, sizeof(zval *), NULL);
+ }
+}
+
+
+/* {{{ proto int strlen(string str)
+ Get string length */
+ZEND_FUNCTION(strlen)
+{
+ zval **str;
+
+ if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &str) == FAILURE) {
+ ZEND_WRONG_PARAM_COUNT();
+ }
+ convert_to_string_ex(str);
+ RETVAL_LONG((*str)->value.str.len);
+}
+/* }}} */
+
+/* {{{ proto int strcmp(string str1, string str2)
+ Binary safe string comparison */
+ZEND_FUNCTION(strcmp)
+{
+ zval **s1, **s2;
+
+ if (ZEND_NUM_ARGS() != 2 || zend_get_parameters_ex(2, &s1, &s2) == FAILURE) {
+ ZEND_WRONG_PARAM_COUNT();
+ }
+ convert_to_string_ex(s1);
+ convert_to_string_ex(s2);
+ RETURN_LONG(zend_binary_zval_strcmp(*s1,*s2));
+}
+/* }}} */
+
+/* {{{ proto int strncmp(string str1, string str2, int len)
+ Binary safe string comparison */
+ZEND_FUNCTION(strncmp)
+{
+ zval **s1, **s2, **s3;
+
+ if (ZEND_NUM_ARGS() != 3 || zend_get_parameters_ex(3, &s1, &s2, &s3) == FAILURE) {
+ ZEND_WRONG_PARAM_COUNT();
+ }
+ convert_to_string_ex(s1);
+ convert_to_string_ex(s2);
+ convert_to_long_ex(s3);
+ RETURN_LONG(zend_binary_zval_strncmp(*s1,*s2,*s3));
+}
+/* }}} */
+
+/* {{{ proto int strcasecmp(string str1, string str2)
+ Binary safe case-insensitive string comparison */
+ZEND_FUNCTION(strcasecmp)
+{
+ zval **s1, **s2;
+
+ if (ZEND_NUM_ARGS()!=2 || zend_get_parameters_ex(2, &s1, &s2) == FAILURE) {
+ ZEND_WRONG_PARAM_COUNT();
+ }
+ convert_to_string_ex(s1);
+ convert_to_string_ex(s2);
+ RETURN_LONG(zend_binary_zval_strcasecmp(*s1, *s2));
+}
+/* }}} */
+
+/* {{{ proto int strncasecmp(string str1, string str2, int len)
+ Binary safe string comparison */
+ZEND_FUNCTION(strncasecmp)
+{
+ zval **s1, **s2, **s3;
+
+ if (ZEND_NUM_ARGS() != 3 || zend_get_parameters_ex(3, &s1, &s2, &s3) == FAILURE) {
+ ZEND_WRONG_PARAM_COUNT();
+ }
+ convert_to_string_ex(s1);
+ convert_to_string_ex(s2);
+ convert_to_long_ex(s3);
+ RETURN_LONG(zend_binary_zval_strncasecmp(*s1,*s2,*s3));
+}
+/* }}} */
+
+ZEND_FUNCTION(each)
+{
+ zval **array,*entry,**entry_ptr, *tmp;
+ char *string_key;
+ ulong num_key;
+ zval **inserted_pointer;
+ HashTable *target_hash;
+
+ if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &array) == FAILURE) {
+ ZEND_WRONG_PARAM_COUNT();
+ }
+ target_hash = HASH_OF(*array);
+ if (!target_hash) {
+ zend_error(E_WARNING,"Variable passed to each() is not an array or object");
+ return;
+ }
+ if (zend_hash_get_current_data(target_hash, (void **) &entry_ptr)==FAILURE) {
+ RETURN_FALSE;
+ }
+ array_init(return_value);
+ entry = *entry_ptr;
+
+ /* add value elements */
+ if (entry->is_ref) {
+ ALLOC_ZVAL(tmp);
+ *tmp = *entry;
+ zval_copy_ctor(tmp);
+ tmp->is_ref=0;
+ tmp->refcount=0;
+ entry=tmp;
+ }
+ zend_hash_index_update(return_value->value.ht, 1, &entry, sizeof(zval *), NULL);
+ entry->refcount++;
+ zend_hash_update(return_value->value.ht, "value", sizeof("value"), &entry, sizeof(zval *), NULL);
+ entry->refcount++;
+
+ /* add the key elements */
+ switch (zend_hash_get_current_key(target_hash, &string_key, &num_key)) {
+ case HASH_KEY_IS_STRING:
+ add_get_index_string(return_value,0,string_key,(void **) &inserted_pointer,0);
+ break;
+ case HASH_KEY_IS_LONG:
+ add_get_index_long(return_value,0,num_key, (void **) &inserted_pointer);
+ break;
+ }
+ zend_hash_update(return_value->value.ht, "key", sizeof("key"), inserted_pointer, sizeof(zval *), NULL);
+ (*inserted_pointer)->refcount++;
+ zend_hash_move_forward(target_hash);
+}
+
+ZEND_FUNCTION(error_reporting)
+{
+ zval **arg;
+ int old_error_reporting;
+
+ old_error_reporting = EG(error_reporting);
+ switch (ZEND_NUM_ARGS()) {
+ case 0:
+ break;
+ case 1:
+ if (zend_get_parameters_ex(1,&arg) == FAILURE) {
+ RETURN_FALSE;
+ }
+ convert_to_long_ex(arg);
+ EG(error_reporting)=(*arg)->value.lval;
+ break;
+ default:
+ ZEND_WRONG_PARAM_COUNT();
+ break;
+ }
+
+ RETVAL_LONG(old_error_reporting);
+}
+
+ZEND_FUNCTION(define)
+{
+ zval **var, **val, **non_cs;
+ int case_sensitive;
+ zend_constant c;
+
+ switch(ZEND_NUM_ARGS()) {
+ case 2:
+ if (zend_get_parameters_ex(2, &var, &val)==FAILURE) {
+ RETURN_FALSE;
+ }
+ case_sensitive = CONST_CS;
+ break;
+ case 3:
+ if (zend_get_parameters_ex(3, &var, &val, &non_cs)==FAILURE) {
+ RETURN_FALSE;
+ }
+ convert_to_long_ex(non_cs);
+ if ((*non_cs)->value.lval) {
+ case_sensitive = 0;
+ } else {
+ case_sensitive = CONST_CS;
+ }
+ break;
+ default:
+ ZEND_WRONG_PARAM_COUNT();
+ break;
+ }
+
+ switch((*val)->type) {
+ case IS_LONG:
+ case IS_DOUBLE:
+ case IS_STRING:
+ case IS_BOOL:
+ case IS_RESOURCE:
+ case IS_NULL:
+ break;
+ default:
+ zend_error(E_WARNING,"Constants may only evaluate to scalar values");
+ RETURN_FALSE;
+ break;
+ }
+ convert_to_string_ex(var);
+
+ c.value = **val;
+ zval_copy_ctor(&c.value);
+ c.flags = case_sensitive; /* non persistent */
+ c.name = zend_strndup((*var)->value.str.val, (*var)->value.str.len);
+ c.name_len = (*var)->value.str.len+1;
+ if(zend_register_constant(&c ELS_CC) == SUCCESS) {
+ RETURN_TRUE;
+ } else {
+ RETURN_FALSE;
+ }
+}
+
+
+ZEND_FUNCTION(defined)
+{
+ zval **var;
+ zval c;
+
+ if (ZEND_NUM_ARGS()!=1 || zend_get_parameters_ex(1, &var)==FAILURE) {
+ ZEND_WRONG_PARAM_COUNT();
+ }
+
+ convert_to_string_ex(var);
+ if (zend_get_constant((*var)->value.str.val, (*var)->value.str.len, &c)) {
+ zval_dtor(&c);
+ RETURN_LONG(1);
+ } else {
+ RETURN_LONG(0);
+ }
+}
+
+/* {{{ proto string get_class(object object)
+ Retrieves the class name */
+ZEND_FUNCTION(get_class)
+{
+ zval **arg;
+
+ if (ZEND_NUM_ARGS()!=1 || zend_get_parameters_ex(1, &arg)==FAILURE) {
+ ZEND_WRONG_PARAM_COUNT();
+ }
+ if ((*arg)->type != IS_OBJECT) {
+ RETURN_FALSE;
+ }
+ RETURN_STRINGL((*arg)->value.obj.ce->name, (*arg)->value.obj.ce->name_length, 1);
+}
+/* }}} */
+
+/* {{{ proto string get_parent_class(object object)
+ Retrieves the parent class name */
+ZEND_FUNCTION(get_parent_class)
+{
+ zval **arg;
+
+ if (ZEND_NUM_ARGS()!=1 || zend_get_parameters_ex(1, &arg)==FAILURE) {
+ ZEND_WRONG_PARAM_COUNT();
+ }
+ if (((*arg)->type != IS_OBJECT) || !(*arg)->value.obj.ce->parent) {
+ RETURN_FALSE;
+ }
+ RETURN_STRINGL((*arg)->value.obj.ce->parent->name, (*arg)->value.obj.ce->parent->name_length, 1);
+}
+/* }}} */
+
+/* {{{ proto bool is_subclass_of(object object, string class_name)
+ Returns true if the object has this class as one of its parents */
+ZEND_FUNCTION(is_subclass_of)
+{
+ zval **obj, **class_name;
+ char *lcname;
+ zend_class_entry *parent_ce = NULL;
+
+ if (ZEND_NUM_ARGS() != 2 || zend_get_parameters_ex(2, &obj, &class_name)==FAILURE) {
+ ZEND_WRONG_PARAM_COUNT();
+ }
+
+ if ((*obj)->type != IS_OBJECT) {
+ RETURN_FALSE;
+ }
+
+ convert_to_string_ex(class_name);
+ lcname = estrndup((*class_name)->value.str.val, (*class_name)->value.str.len);
+ zend_str_tolower(lcname, (*class_name)->value.str.len);
+
+ for (parent_ce = (*obj)->value.obj.ce->parent; parent_ce != NULL; parent_ce = parent_ce->parent) {
+ if (!strcmp(parent_ce->name, lcname)) {
+ efree(lcname);
+ RETURN_TRUE;
+ }
+ }
+ efree(lcname);
+ RETURN_FALSE;
+}
+/* }}} */
+
+/* {{{ proto array get_class_vars(string class_name)
+ Returns an array of default properties of the class */
+ZEND_FUNCTION(get_class_vars)
+{
+ zval **class_name;
+ char *lcname;
+ zend_class_entry *ce;
+ zval *tmp;
+ CLS_FETCH();
+
+ if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &class_name)==FAILURE) {
+ ZEND_WRONG_PARAM_COUNT();
+ }
+
+ convert_to_string_ex(class_name);
+ lcname = estrndup((*class_name)->value.str.val, (*class_name)->value.str.len);
+ zend_str_tolower(lcname, (*class_name)->value.str.len);
+
+ if (zend_hash_find(CG(class_table), lcname, (*class_name)->value.str.len+1, (void **)&ce)==FAILURE) {
+ efree(lcname);
+ RETURN_FALSE;
+ } else {
+ efree(lcname);
+ array_init(return_value);
+ if (!ce->constants_updated) {
+ zend_hash_apply_with_argument(&ce->default_properties, (int (*)(void *,void *)) zval_update_constant, (void *) 1);
+ ce->constants_updated = 1;
+ }
+ zend_hash_copy(return_value->value.ht, &ce->default_properties, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *));
+ }
+}
+/* }}} */
+
+/* {{{ proto array get_object_vars(object obj)
+ Returns an array of object properties */
+ZEND_FUNCTION(get_object_vars)
+{
+ zval **obj;
+ zval *tmp;
+
+ if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &obj) == FAILURE) {
+ ZEND_WRONG_PARAM_COUNT();
+ }
+
+ if ((*obj)->type != IS_OBJECT) {
+ RETURN_FALSE;
+ }
+
+ array_init(return_value);
+ zend_hash_copy(return_value->value.ht, (*obj)->value.obj.properties,
+ (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *));
+}
+/* }}} */
+
+/* {{{ proto array get_class_methods(string class_name)
+ Returns an array of class methods' names */
+ZEND_FUNCTION(get_class_methods)
+{
+ zval **class_name;
+ zval *method_name;
+ char *lcname;
+ zend_class_entry *ce;
+ char *string_key;
+ ulong num_key;
+ int key_type;
+ CLS_FETCH();
+
+ if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &class_name)==FAILURE) {
+ ZEND_WRONG_PARAM_COUNT();
+ }
+
+ convert_to_string_ex(class_name);
+ lcname = estrndup((*class_name)->value.str.val, (*class_name)->value.str.len);
+ zend_str_tolower(lcname, (*class_name)->value.str.len);
+
+ if (zend_hash_find(CG(class_table), lcname, (*class_name)->value.str.len+1, (void **)&ce)==FAILURE) {
+ efree(lcname);
+ RETURN_NULL();
+ } else {
+ efree(lcname);
+ array_init(return_value);
+ zend_hash_internal_pointer_reset(&ce->function_table);
+ while ((key_type = zend_hash_get_current_key(&ce->function_table, &string_key, &num_key)) != HASH_KEY_NON_EXISTANT) {
+ if (key_type == HASH_KEY_IS_STRING) {
+ MAKE_STD_ZVAL(method_name);
+ ZVAL_STRING(method_name, string_key, 1);
+ zend_hash_next_index_insert(return_value->value.ht, &method_name, sizeof(zval *), NULL);
+ }
+ zend_hash_move_forward(&ce->function_table);
+ }
+ }
+}
+/* }}} */
+
+/* {{{ proto bool method_exists(object object, string method)
+ Checks if the class method exists */
+ZEND_FUNCTION(method_exists)
+{
+ zval **klass, **method_name;
+ char *lcname;
+
+ if (ZEND_NUM_ARGS()!=2 || zend_get_parameters_ex(2, &klass, &method_name)==FAILURE) {
+ ZEND_WRONG_PARAM_COUNT();
+ }
+ if ((*klass)->type != IS_OBJECT) {
+ RETURN_FALSE;
+ }
+ convert_to_string_ex(method_name);
+ lcname = estrndup((*method_name)->value.str.val, (*method_name)->value.str.len);
+ zend_str_tolower(lcname, (*method_name)->value.str.len);
+ if(zend_hash_exists(&(*klass)->value.obj.ce->function_table, lcname, (*method_name)->value.str.len+1)) {
+ efree(lcname);
+ RETURN_TRUE;
+ } else {
+ efree(lcname);
+ RETURN_FALSE;
+ }
+}
+/* }}} */
+
+/* {{{ proto bool class_exists(string classname)
+ Checks if the class exists */
+ZEND_FUNCTION(class_exists)
+{
+ zval **class_name;
+ char *lcname;
+ CLS_FETCH();
+
+ if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &class_name)==FAILURE) {
+ ZEND_WRONG_PARAM_COUNT();
+ }
+ convert_to_string_ex(class_name);
+ lcname = estrndup((*class_name)->value.str.val, (*class_name)->value.str.len);
+ zend_str_tolower(lcname, (*class_name)->value.str.len);
+ if (zend_hash_exists(CG(class_table), lcname, (*class_name)->value.str.len+1)) {
+ efree(lcname);
+ RETURN_TRUE;
+ } else {
+ efree(lcname);
+ RETURN_FALSE;
+ }
+}
+/* }}} */
+
+/* {{{ proto bool function_exists(string function_name)
+ Checks if the function exists */
+ZEND_FUNCTION(function_exists)
+{
+ zval **function_name;
+ char *lcname;
+ int retval;
+
+ if (ZEND_NUM_ARGS()!=1 || zend_get_parameters_ex(1, &function_name)==FAILURE) {
+ ZEND_WRONG_PARAM_COUNT();
+ }
+ convert_to_string_ex(function_name);
+ lcname = estrndup((*function_name)->value.str.val, (*function_name)->value.str.len);
+ zend_str_tolower(lcname, (*function_name)->value.str.len);
+
+ retval = zend_hash_exists(EG(function_table), lcname, (*function_name)->value.str.len+1);
+ efree(lcname);
+
+ RETURN_BOOL(retval);
+}
+/* }}} */
+
+
+ZEND_FUNCTION(leak)
+{
+ int leakbytes=3;
+ zval **leak;
+
+ if (ZEND_NUM_ARGS()>=1) {
+ if (zend_get_parameters_ex(1, &leak)==SUCCESS) {
+ convert_to_long_ex(leak);
+ leakbytes = (*leak)->value.lval;
+ }
+ }
+
+ emalloc(leakbytes);
+}
+
+
+#ifdef ZEND_TEST_EXCEPTIONS
+ZEND_FUNCTION(crash)
+{
+ char *nowhere=NULL;
+
+ memcpy(nowhere, "something", sizeof("something"));
+}
+#endif
+
+
+static int copy_import_use_file(zend_file_handle *fh, zval *array)
+{
+ if (fh->filename) {
+ char *extension_start;
+
+ extension_start = strstr(fh->filename, zend_uv.import_use_extension);
+ if (extension_start) {
+ *extension_start = 0;
+ if (fh->opened_path) {
+ add_assoc_string(array, fh->filename, fh->opened_path, 1);
+ } else {
+ add_assoc_stringl(array, fh->filename, "N/A", sizeof("N/A")-1, 1);
+ }
+ *extension_start = zend_uv.import_use_extension[0];
+ }
+ }
+ return 0;
+}
+
+
+/* {{{ proto array get_included_files(void)
+ Returns an array with the file names that were include_once()'d */
+ZEND_FUNCTION(get_included_files)
+{
+ char *entry;
+ if (ZEND_NUM_ARGS() != 0) {
+ ZEND_WRONG_PARAM_COUNT();
+ }
+
+ array_init(return_value);
+ zend_hash_internal_pointer_reset(&EG(included_files));
+ while(zend_hash_get_current_key(&EG(included_files), &entry,NULL) == HASH_KEY_IS_STRING) {
+ add_next_index_string(return_value,entry,0);
+ zend_hash_move_forward(&EG(included_files));
+ }
+
+ /* zend_hash_apply_with_argument(&EG(included_files), (apply_func_arg_t) copy_import_use_file, return_value); */
+}
+/* }}} */
+
+
+/* {{{ proto void trigger_error(string messsage [, int error_type])
+ Generates a user-level error/warning/notice message */
+ZEND_FUNCTION(trigger_error)
+{
+ int error_type = E_USER_NOTICE;
+ zval **z_error_type, **z_error_message;
+
+ switch(ZEND_NUM_ARGS()) {
+ case 1:
+ if (zend_get_parameters_ex(1, &z_error_message)==FAILURE) {
+ ZEND_WRONG_PARAM_COUNT();
+ }
+ break;
+ case 2:
+ if (zend_get_parameters_ex(2, &z_error_message, &z_error_type)==FAILURE) {
+ ZEND_WRONG_PARAM_COUNT();
+ }
+ convert_to_long_ex(z_error_type);
+ error_type = (*z_error_type)->value.lval;
+ switch (error_type) {
+ case E_USER_ERROR:
+ case E_USER_WARNING:
+ case E_USER_NOTICE:
+ break;
+ default:
+ zend_error(E_WARNING, "Invalid error type specified");
+ RETURN_FALSE;
+ break;
+ }
+ break;
+ default:
+ ZEND_WRONG_PARAM_COUNT();
+ }
+ convert_to_string_ex(z_error_message);
+ zend_error(error_type, "%s", (*z_error_message)->value.str.val);
+ RETURN_TRUE;
+}
+/* }}} */
+
+
+/* {{{ proto string set_error_handler(string error_handler)
+ Sets a user-defined error handler function. Returns the previously defined error handler, or false on error */
+ZEND_FUNCTION(set_error_handler)
+{
+ zval **error_handler;
+ zend_bool had_orig_error_handler=0;
+
+ if (ZEND_NUM_ARGS()!=1 || zend_get_parameters_ex(1, &error_handler)==FAILURE) {
+ ZEND_WRONG_PARAM_COUNT();
+ }
+
+ convert_to_string_ex(error_handler);
+ if (EG(user_error_handler)) {
+ had_orig_error_handler = 1;
+ *return_value = *EG(user_error_handler);
+ zval_copy_ctor(return_value);
+ zend_ptr_stack_push(&EG(user_error_handlers), EG(user_error_handler));
+ }
+ ALLOC_ZVAL(EG(user_error_handler));
+
+ if (Z_STRLEN_PP(error_handler)==0) { /* unset user-defined handler */
+ FREE_ZVAL(EG(user_error_handler));
+ EG(user_error_handler) = NULL;
+ RETURN_TRUE;
+ }
+
+ *EG(user_error_handler) = **error_handler;
+ zval_copy_ctor(EG(user_error_handler));
+
+ if (!had_orig_error_handler) {
+ RETURN_NULL();
+ }
+}
+/* }}} */
+
+
+
+/* {{{ proto void restore_error_handler(void)
+ Restores the previously defined error handler function */
+ZEND_FUNCTION(restore_error_handler)
+{
+ if (EG(user_error_handler)) {
+ zval_ptr_dtor(&EG(user_error_handler));
+ }
+ if (zend_ptr_stack_num_elements(&EG(user_error_handlers))==0) {
+ EG(user_error_handler) = NULL;
+ } else {
+ EG(user_error_handler) = zend_ptr_stack_pop(&EG(user_error_handlers));
+ }
+ RETURN_TRUE;
+}
+
+
+static int copy_class_name(zend_class_entry *ce, int num_args, va_list args, zend_hash_key *hash_key)
+{
+ zval *array = va_arg(args, zval *);
+
+ if (hash_key->nKeyLength==0 || hash_key->arKey[0]!=0) {
+ add_next_index_stringl(array, ce->name, ce->name_length, 1);
+ }
+ return 0;
+}
+
+/* {{{ proto array get_declared_classes(void)
+ Returns an array of all declared classes. */
+ZEND_FUNCTION(get_declared_classes)
+{
+ CLS_FETCH();
+
+ if (ZEND_NUM_ARGS() != 0) {
+ ZEND_WRONG_PARAM_COUNT();
+ }
+
+ array_init(return_value);
+ zend_hash_apply_with_arguments(CG(class_table), (apply_func_args_t)copy_class_name, 1, return_value);
+}
+/* }}} */
+
+static int copy_function_name(zend_function *func, int num_args, va_list args, zend_hash_key *hash_key)
+{
+ zval *internal_ar = va_arg(args, zval *),
+ *user_ar = va_arg(args, zval *);
+
+ if (hash_key->nKeyLength == 0 || hash_key->arKey[0] == 0) {
+ return 0;
+ }
+
+ if (func->type == ZEND_INTERNAL_FUNCTION) {
+ add_next_index_stringl(internal_ar, hash_key->arKey, hash_key->nKeyLength, 1);
+ } else if (func->type == ZEND_USER_FUNCTION) {
+ add_next_index_stringl(user_ar, hash_key->arKey, hash_key->nKeyLength, 1);
+ }
+
+ return 0;
+}
+
+/* {{{ proto array get_defined_functions(void)
+ Returns an array of all defined functions */
+ZEND_FUNCTION(get_defined_functions)
+{
+ zval *internal;
+ zval *user;
+
+ if (ZEND_NUM_ARGS() != 0) {
+ ZEND_WRONG_PARAM_COUNT();
+ }
+
+ MAKE_STD_ZVAL(internal);
+ MAKE_STD_ZVAL(user);
+
+ array_init(internal);
+ array_init(user);
+ array_init(return_value);
+
+ zend_hash_apply_with_arguments(EG(function_table), (apply_func_args_t)copy_function_name, 2, internal, user);
+
+ if (zend_hash_add(return_value->value.ht, "internal", sizeof("internal"), (void **)&internal, sizeof(zval *), NULL) == FAILURE) {
+ zend_error(E_WARNING, "Cannot add internal functions to return value from get_defined_functions()");
+ RETURN_FALSE;
+ }
+
+ if (zend_hash_add(return_value->value.ht, "user", sizeof("user"), (void **)&user, sizeof(zval *), NULL) == FAILURE) {
+ zend_error(E_WARNING, "Cannot add user functions to return value from get_defined_functions()");
+ RETURN_FALSE;
+ }
+}
+/* }}} */
+
+/* {{{ proto array get_defined_vars(void)
+ Returns an associative array of names and values of all currently defined variable names (variables in the current scope) */
+ZEND_FUNCTION(get_defined_vars)
+{
+ zval *tmp;
+
+ array_init(return_value);
+
+ zend_hash_copy(return_value->value.ht, EG(active_symbol_table),
+ (copy_ctor_func_t)zval_add_ref, &tmp, sizeof(zval *));
+}
+/* }}} */
+
+#define LAMBDA_TEMP_FUNCNAME "__lambda_func"
+
+/* {{{ proto string create_function(string args, string code)
+ Creates an anonymous function, and returns its name (funny, eh?) */
+ZEND_FUNCTION(create_function)
+{
+ char *eval_code, *function_name;
+ int eval_code_length, function_name_length;
+ zval **z_function_args, **z_function_code;
+ int retval;
+ char *eval_name;
+ CLS_FETCH();
+
+ if (ZEND_NUM_ARGS()!=2 || zend_get_parameters_ex(2, &z_function_args, &z_function_code)==FAILURE) {
+ ZEND_WRONG_PARAM_COUNT();
+ }
+
+ convert_to_string_ex(z_function_args);
+ convert_to_string_ex(z_function_code);
+
+ eval_code_length = sizeof("function " LAMBDA_TEMP_FUNCNAME)
+ +Z_STRLEN_PP(z_function_args)
+ +2 /* for the args parentheses */
+ +2 /* for the curly braces */
+ +Z_STRLEN_PP(z_function_code);
+
+ eval_code = (char *) emalloc(eval_code_length);
+ sprintf(eval_code, "function " LAMBDA_TEMP_FUNCNAME "(%s){%s}", Z_STRVAL_PP(z_function_args), Z_STRVAL_PP(z_function_code));
+
+ eval_name = zend_make_compiled_string_description("runtime-created function");
+ retval = zend_eval_string(eval_code, NULL, eval_name CLS_CC ELS_CC);
+ efree(eval_code);
+ efree(eval_name);
+
+ if (retval==SUCCESS) {
+ zend_function *func;
+
+ if (zend_hash_find(EG(function_table), LAMBDA_TEMP_FUNCNAME, sizeof(LAMBDA_TEMP_FUNCNAME), (void **) &func)==FAILURE) {
+ zend_error(E_ERROR, "Unexpected inconsistency in create_function()");
+ RETURN_FALSE;
+ }
+ function_add_ref(func);
+
+ function_name = (char *) emalloc(sizeof("0lambda_")+MAX_LENGTH_OF_LONG);
+
+ do {
+ sprintf(function_name, "%clambda_%d", 0, ++EG(lambda_count));
+ function_name_length = strlen(function_name+1)+1;
+ } while (zend_hash_add(EG(function_table), function_name, function_name_length+1, func, sizeof(zend_function), NULL)==FAILURE);
+ zend_hash_del(EG(function_table), LAMBDA_TEMP_FUNCNAME, sizeof(LAMBDA_TEMP_FUNCNAME));
+ RETURN_STRINGL(function_name, function_name_length, 0);
+ } else {
+ RETURN_FALSE;
+ }
+}
+/* }}} */
+
+
+#if ZEND_DEBUG
+ZEND_FUNCTION(zend_test_func)
+{
+ zval *arg1, *arg2;
+
+ zend_get_parameters(ht, 2, &arg1, &arg2);
+}
+#endif
+
+
+ZEND_FUNCTION(get_resource_type)
+{
+ char *resource_type;
+ zval **z_resource_type;
+
+ if (ZEND_NUM_ARGS()!=1 || zend_get_parameters_ex(1, &z_resource_type)==FAILURE) {
+ ZEND_WRONG_PARAM_COUNT();
+ }
+
+ if (Z_TYPE_PP(z_resource_type) != IS_RESOURCE) {
+ zend_error(E_WARNING, "Supplied argument is not a valid resource handle");
+ RETURN_FALSE;
+ }
+
+ resource_type = zend_rsrc_list_get_rsrc_type(Z_LVAL_PP(z_resource_type));
+ if (resource_type) {
+ RETURN_STRING(resource_type, 1);
+ } else {
+ RETURN_STRING("Unknown", 1);
+ }
+}
diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c
new file mode 100644
index 0000000000..c975e5c88a
--- /dev/null
+++ b/Zend/zend_compile.c
@@ -0,0 +1,2351 @@
+/*
+ +----------------------------------------------------------------------+
+ | Zend Engine |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1998-2000 Zend Technologies Ltd. (http://www.zend.com) |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 0.92 of the Zend license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available at through the world-wide-web at |
+ | http://www.zend.com/license/0_92.txt. |
+ | If you did not receive a copy of the Zend license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@zend.com so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Andi Gutmans <andi@zend.com> |
+ | Zeev Suraski <zeev@zend.com> |
+ +----------------------------------------------------------------------+
+*/
+
+
+#include "zend_language_parser.h"
+#include "zend.h"
+#include "zend_compile.h"
+#include "zend_llist.h"
+#include "zend_API.h"
+#include "zend_fast_cache.h"
+
+
+ZEND_API zend_op_array *(*zend_compile_file)(zend_file_handle *file_handle, int type CLS_DC);
+
+
+#ifndef ZTS
+ZEND_API zend_compiler_globals compiler_globals;
+ZEND_API zend_executor_globals executor_globals;
+#endif
+
+static void free_filename(void *p)
+{
+ efree(*((char **) p));
+}
+
+
+static void build_runtime_defined_function_key(zval *result, zval *name, zend_op *opline CLS_DC)
+{
+ char lineno_buf[32];
+ uint lineno_len;
+ char *filename;
+
+ lineno_len = zend_sprintf(lineno_buf, "%d", opline->lineno);
+ if (CG(active_op_array)->filename) {
+ filename = CG(active_op_array)->filename;
+ } else {
+ filename = "-";
+ }
+
+ /* NULL, name length, filename length, line number length */
+ result->value.str.len = 1+name->value.str.len+strlen(filename)+lineno_len+1;
+ result->value.str.val = (char *) emalloc(result->value.str.len); /* Extra null byte is calculated a line before */
+ sprintf(result->value.str.val, "%c%s%s%s", '\0', name->value.str.val, filename, lineno_buf);
+ result->type = IS_STRING;
+ result->refcount = 1;
+}
+
+
+static void init_compiler_declarables(CLS_D ELS_DC)
+{
+ CG(declarables).ticks.type = IS_LONG;
+ CG(declarables).ticks.value.lval = 0;
+}
+
+
+void init_compiler(CLS_D ELS_DC)
+{
+ zend_stack_init(&CG(bp_stack));
+ zend_stack_init(&CG(function_call_stack));
+ zend_stack_init(&CG(switch_cond_stack));
+ zend_stack_init(&CG(foreach_copy_stack));
+ zend_stack_init(&CG(object_stack));
+ zend_stack_init(&CG(declare_stack));
+ CG(active_class_entry) = NULL;
+ zend_llist_init(&CG(list_llist), sizeof(list_llist_element), NULL, 0);
+ zend_llist_init(&CG(dimension_llist), sizeof(int), NULL, 0);
+ zend_hash_init(&CG(filenames_table), 5, NULL, (dtor_func_t) free_filename, 0);
+ CG(handle_op_arrays) = 1;
+ CG(in_compilation) = 0;
+ zend_init_rsrc_list(ELS_C);
+ CG(unclean_shutdown) = 0;
+ zend_llist_init(&CG(open_files), sizeof(zend_file_handle), (void (*)(void *)) zend_file_handle_dtor, 0);
+ init_compiler_declarables(CLS_C ELS_CC);
+}
+
+
+void shutdown_compiler(CLS_D)
+{
+ zend_stack_destroy(&CG(bp_stack));
+ zend_stack_destroy(&CG(function_call_stack));
+ zend_stack_destroy(&CG(switch_cond_stack));
+ zend_stack_destroy(&CG(foreach_copy_stack));
+ zend_stack_destroy(&CG(object_stack));
+ zend_stack_destroy(&CG(declare_stack));
+ zend_hash_destroy(&CG(filenames_table));
+ zend_llist_destroy(&CG(open_files));
+}
+
+
+ZEND_API char *zend_set_compiled_filename(char *new_compiled_filename)
+{
+ char **pp, *p;
+ int length = strlen(new_compiled_filename);
+ CLS_FETCH();
+
+ if (zend_hash_find(&CG(filenames_table), new_compiled_filename, length+1, (void **) &pp)==SUCCESS) {
+ CG(compiled_filename) = *pp;
+ return *pp;
+ }
+ p = estrndup(new_compiled_filename, length);
+ zend_hash_update(&CG(filenames_table), new_compiled_filename, length+1, &p, sizeof(char *), (void **) &pp);
+ CG(compiled_filename) = p;
+ return p;
+}
+
+
+ZEND_API void zend_restore_compiled_filename(char *original_compiled_filename)
+{
+ CLS_FETCH();
+
+ CG(compiled_filename) = original_compiled_filename;
+}
+
+
+ZEND_API char *zend_get_compiled_filename(CLS_D)
+{
+ return CG(compiled_filename);
+}
+
+
+ZEND_API int zend_get_compiled_lineno(CLS_D)
+{
+ return CG(zend_lineno);
+}
+
+
+ZEND_API zend_bool zend_is_compiling()
+{
+ CLS_FETCH();
+
+ return CG(in_compilation);
+}
+
+
+static zend_uint get_temporary_variable(zend_op_array *op_array)
+{
+ return (op_array->T)++;
+}
+
+
+void zend_do_binary_op(int op, znode *result, znode *op1, znode *op2 CLS_DC)
+{
+ zend_op *opline = get_next_op(CG(active_op_array) CLS_CC);
+
+ opline->opcode = op;
+ opline->result.op_type = IS_TMP_VAR;
+ opline->result.u.var = get_temporary_variable(CG(active_op_array));
+ opline->op1 = *op1;
+ opline->op2 = *op2;
+ *result = opline->result;
+}
+
+
+void zend_do_unary_op(int op, znode *result, znode *op1 CLS_DC)
+{
+ zend_op *opline = get_next_op(CG(active_op_array) CLS_CC);
+
+ opline->opcode = op;
+ opline->result.op_type = IS_TMP_VAR;
+ opline->result.u.var = get_temporary_variable(CG(active_op_array));
+ opline->op1 = *op1;
+ *result = opline->result;
+ SET_UNUSED(opline->op2);
+}
+
+
+void zend_do_binary_assign_op(int op, znode *result, znode *op1, znode *op2 CLS_DC)
+{
+ zend_op *opline = get_next_op(CG(active_op_array) CLS_CC);
+
+ opline->opcode = op;
+ opline->result.op_type = IS_VAR;
+ opline->result.u.EA.type = 0;
+ opline->result.u.var = get_temporary_variable(CG(active_op_array));
+ opline->op1 = *op1;
+ opline->op2 = *op2;
+ *result = opline->result;
+}
+
+
+
+void zend_do_fetch_globals(znode *varname CLS_DC)
+{
+ if (!CG(active_op_array)->uses_globals
+ && varname->op_type == IS_CONST
+ && varname->u.constant.type == IS_STRING
+ && varname->u.constant.value.str.len == (sizeof("GLOBALS")-1)
+ && !memcmp(varname->u.constant.value.str.val, "GLOBALS", sizeof("GLOBALS")-1)) {
+ CG(active_op_array)->uses_globals = 1;
+ }
+}
+
+void fetch_simple_variable_ex(znode *result, znode *varname, int bp, int op CLS_DC)
+{
+ zend_op opline;
+ zend_op *opline_ptr;
+ zend_llist *fetch_list_ptr;
+
+ if (bp) {
+ opline_ptr = &opline;
+ init_op(opline_ptr CLS_CC);
+ } else {
+ opline_ptr = get_next_op(CG(active_op_array) CLS_CC);
+ }
+
+ opline_ptr->opcode = op;
+ opline_ptr->result.op_type = IS_VAR;
+ opline_ptr->result.u.EA.type = 0;
+ opline_ptr->result.u.var = get_temporary_variable(CG(active_op_array));
+ opline_ptr->op1 = *varname;
+ *result = opline_ptr->result;
+ SET_UNUSED(opline_ptr->op2);
+ opline_ptr->op2.u.fetch_type = ZEND_FETCH_LOCAL;
+
+ if (bp) {
+ zend_stack_top(&CG(bp_stack), (void **) &fetch_list_ptr);
+ zend_llist_add_element(fetch_list_ptr, opline_ptr);
+ }
+}
+
+void fetch_simple_variable(znode *result, znode *varname, int bp CLS_DC)
+{
+ /* the default mode must be Write, since fetch_simple_variable() is used to define function arguments */
+ fetch_simple_variable_ex(result, varname, bp, ZEND_FETCH_W CLS_CC);
+}
+
+
+void fetch_array_begin(znode *result, znode *varname, znode *first_dim CLS_DC)
+{
+ fetch_simple_variable(result, varname, 1 CLS_CC);
+
+ fetch_array_dim(result, result, first_dim CLS_CC);
+}
+
+
+void fetch_array_dim(znode *result, znode *parent, znode *dim CLS_DC)
+{
+ zend_op opline;
+ zend_llist *fetch_list_ptr;
+
+ init_op(&opline CLS_CC);
+ opline.opcode = ZEND_FETCH_DIM_W; /* the backpatching routine assumes W */
+ opline.result.op_type = IS_VAR;
+ opline.result.u.EA.type = 0;
+ opline.result.u.var = get_temporary_variable(CG(active_op_array));
+ opline.op1 = *parent;
+ opline.op2 = *dim;
+ opline.extended_value = ZEND_FETCH_STANDARD;
+ *result = opline.result;
+
+ zend_stack_top(&CG(bp_stack), (void **) &fetch_list_ptr);
+ zend_llist_add_element(fetch_list_ptr, &opline);
+}
+
+
+void fetch_string_offset(znode *result, znode *parent, znode *offset CLS_DC)
+{
+ fetch_array_dim(result, parent, offset CLS_CC);
+}
+
+
+void zend_do_print(znode *result, znode *arg CLS_DC)
+{
+ zend_op *opline = get_next_op(CG(active_op_array) CLS_CC);
+
+ opline->result.op_type = IS_TMP_VAR;
+ opline->result.u.var = get_temporary_variable(CG(active_op_array));
+ opline->opcode = ZEND_PRINT;
+ opline->op1 = *arg;
+ SET_UNUSED(opline->op2);
+ *result = opline->result;
+}
+
+
+void zend_do_echo(znode *arg CLS_DC)
+{
+ zend_op *opline = get_next_op(CG(active_op_array) CLS_CC);
+
+ opline->opcode = ZEND_ECHO;
+ opline->op1 = *arg;
+ SET_UNUSED(opline->op2);
+}
+
+
+void zend_do_assign(znode *result, znode *variable, znode *value CLS_DC)
+{
+ zend_op *opline = get_next_op(CG(active_op_array) CLS_CC);
+
+ opline->opcode = ZEND_ASSIGN;
+ opline->result.op_type = IS_VAR;
+ opline->result.u.EA.type = 0;
+ opline->result.u.var = get_temporary_variable(CG(active_op_array));
+ opline->op1 = *variable;
+ opline->op2 = *value;
+ *result = opline->result;
+}
+
+
+void zend_do_assign_ref(znode *result, znode *lvar, znode *rvar CLS_DC)
+{
+ zend_op *opline = get_next_op(CG(active_op_array) CLS_CC);
+
+ opline->opcode = ZEND_ASSIGN_REF;
+ if (result) {
+ opline->result.op_type = IS_VAR;
+ opline->result.u.EA.type = 0;
+ opline->result.u.var = get_temporary_variable(CG(active_op_array));
+ *result = opline->result;
+ } else {
+ /* SET_UNUSED(opline->result); */
+ opline->result.u.EA.type |= EXT_TYPE_UNUSED;
+ }
+ opline->op1 = *lvar;
+ opline->op2 = *rvar;
+}
+
+
+static inline void do_begin_loop(CLS_D)
+{
+ zend_brk_cont_element *brk_cont_element;
+ int parent;
+
+ parent = CG(active_op_array)->current_brk_cont;
+ CG(active_op_array)->current_brk_cont = CG(active_op_array)->last_brk_cont;
+ brk_cont_element = get_next_brk_cont_element(CG(active_op_array));
+ brk_cont_element->parent = parent;
+}
+
+
+static inline void do_end_loop(int cont_addr CLS_DC)
+{
+ CG(active_op_array)->brk_cont_array[CG(active_op_array)->current_brk_cont].cont = cont_addr;
+ CG(active_op_array)->brk_cont_array[CG(active_op_array)->current_brk_cont].brk = get_next_op_number(CG(active_op_array));
+ CG(active_op_array)->current_brk_cont = CG(active_op_array)->brk_cont_array[CG(active_op_array)->current_brk_cont].parent;
+}
+
+
+void zend_do_while_cond(znode *expr, znode *close_bracket_token CLS_DC)
+{
+ int while_cond_op_number = get_next_op_number(CG(active_op_array));
+ zend_op *opline = get_next_op(CG(active_op_array) CLS_CC);
+
+ opline->opcode = ZEND_JMPZ;
+ opline->op1 = *expr;
+ close_bracket_token->u.opline_num = while_cond_op_number;
+ SET_UNUSED(opline->op2);
+
+ do_begin_loop(CLS_C);
+ INC_BPC(CG(active_op_array));
+}
+
+
+void zend_do_while_end(znode *while_token, znode *close_bracket_token CLS_DC)
+{
+ zend_op *opline = get_next_op(CG(active_op_array) CLS_CC);
+
+ /* add unconditional jump */
+ opline->opcode = ZEND_JMP;
+ opline->op1.u.opline_num = while_token->u.opline_num;
+ SET_UNUSED(opline->op1);
+ SET_UNUSED(opline->op2);
+
+ /* update while's conditional jmp */
+ CG(active_op_array)->opcodes[close_bracket_token->u.opline_num].op2.u.opline_num = get_next_op_number(CG(active_op_array));
+
+ do_end_loop(while_token->u.opline_num CLS_CC);
+
+ DEC_BPC(CG(active_op_array));
+}
+
+
+void zend_do_for_cond(znode *expr, znode *second_semicolon_token CLS_DC)
+{
+ int for_cond_op_number = get_next_op_number(CG(active_op_array));
+ zend_op *opline = get_next_op(CG(active_op_array) CLS_CC);
+
+ opline->opcode = ZEND_JMPZNZ;
+ opline->op1 = *expr; /* the conditional expression */
+ second_semicolon_token->u.opline_num = for_cond_op_number;
+ SET_UNUSED(opline->op2);
+}
+
+
+void zend_do_for_before_statement(znode *cond_start, znode *second_semicolon_token CLS_DC)
+{
+ zend_op *opline = get_next_op(CG(active_op_array) CLS_CC);
+
+ opline->opcode = ZEND_JMP;
+ opline->op1.u.opline_num = cond_start->u.opline_num;
+ CG(active_op_array)->opcodes[second_semicolon_token->u.opline_num].extended_value = get_next_op_number(CG(active_op_array));
+ SET_UNUSED(opline->op1);
+ SET_UNUSED(opline->op2);
+
+ do_begin_loop(CLS_C);
+
+ INC_BPC(CG(active_op_array));
+}
+
+
+void zend_do_for_end(znode *second_semicolon_token CLS_DC)
+{
+ zend_op *opline = get_next_op(CG(active_op_array) CLS_CC);
+
+ opline->opcode = ZEND_JMP;
+ opline->op1.u.opline_num = second_semicolon_token->u.opline_num+1;
+ CG(active_op_array)->opcodes[second_semicolon_token->u.opline_num].op2.u.opline_num = get_next_op_number(CG(active_op_array));
+ SET_UNUSED(opline->op1);
+ SET_UNUSED(opline->op2);
+
+ do_end_loop(second_semicolon_token->u.opline_num+1 CLS_CC);
+
+ DEC_BPC(CG(active_op_array));
+}
+
+
+void zend_do_pre_incdec(znode *result, znode *op1, int op CLS_DC)
+{
+ zend_op *opline = get_next_op(CG(active_op_array) CLS_CC);
+
+ opline->opcode = op;
+ opline->result.op_type = IS_VAR;
+ opline->result.u.EA.type = 0;
+ opline->result.u.var = get_temporary_variable(CG(active_op_array));
+ opline->op1 = *op1;
+ *result = opline->result;
+ SET_UNUSED(opline->op2);
+}
+
+
+void zend_do_post_incdec(znode *result, znode *op1, int op CLS_DC)
+{
+ zend_op *opline = get_next_op(CG(active_op_array) CLS_CC);
+
+ opline->opcode = op;
+ opline->result.op_type = IS_TMP_VAR;
+ opline->result.u.var = get_temporary_variable(CG(active_op_array));
+ opline->op1 = *op1;
+ *result = opline->result;
+ SET_UNUSED(opline->op2);
+}
+
+
+void zend_do_if_cond(znode *cond, znode *closing_bracket_token CLS_DC)
+{
+ int if_cond_op_number = get_next_op_number(CG(active_op_array));
+ zend_op *opline = get_next_op(CG(active_op_array) CLS_CC);
+
+ opline->opcode = ZEND_JMPZ;
+ opline->op1 = *cond;
+ closing_bracket_token->u.opline_num = if_cond_op_number;
+ SET_UNUSED(opline->op2);
+ INC_BPC(CG(active_op_array));
+}
+
+
+void zend_do_if_after_statement(znode *closing_bracket_token, unsigned char initialize CLS_DC)
+{
+ int if_end_op_number = get_next_op_number(CG(active_op_array));
+ zend_op *opline = get_next_op(CG(active_op_array) CLS_CC);
+ zend_llist *jmp_list_ptr;
+
+ opline->opcode = ZEND_JMP;
+ /* save for backpatching */
+ if (initialize) {
+ zend_llist jmp_list;
+
+ zend_llist_init(&jmp_list, sizeof(int), NULL, 0);
+ zend_stack_push(&CG(bp_stack), (void *) &jmp_list, sizeof(zend_llist));
+ }
+ zend_stack_top(&CG(bp_stack), (void **) &jmp_list_ptr);
+ zend_llist_add_element(jmp_list_ptr, &if_end_op_number);
+
+ CG(active_op_array)->opcodes[closing_bracket_token->u.opline_num].op2.u.opline_num = if_end_op_number+1;
+ SET_UNUSED(opline->op1);
+ SET_UNUSED(opline->op2);
+}
+
+
+void zend_do_if_end(CLS_D)
+{
+ int next_op_number = get_next_op_number(CG(active_op_array));
+ zend_llist *jmp_list_ptr;
+ zend_llist_element *le;
+
+ zend_stack_top(&CG(bp_stack), (void **) &jmp_list_ptr);
+ for (le=jmp_list_ptr->head; le; le = le->next) {
+ CG(active_op_array)->opcodes[*((int *) le->data)].op1.u.opline_num = next_op_number;
+ }
+ zend_llist_destroy(jmp_list_ptr);
+ zend_stack_del_top(&CG(bp_stack));
+ DEC_BPC(CG(active_op_array));
+}
+
+
+void zend_do_begin_variable_parse(CLS_D)
+{
+ zend_llist fetch_list;
+
+ zend_llist_init(&fetch_list, sizeof(zend_op), NULL, 0);
+ zend_stack_push(&CG(bp_stack), (void *) &fetch_list, sizeof(zend_llist));
+}
+
+
+void zend_do_end_variable_parse(int type, int arg_offset CLS_DC)
+{
+ zend_llist *fetch_list_ptr;
+ zend_llist_element *le;
+ zend_op *opline, *opline_ptr;
+
+ zend_stack_top(&CG(bp_stack), (void **) &fetch_list_ptr);
+
+ le = fetch_list_ptr->head;
+
+ while (le) {
+ opline_ptr = (zend_op *)le->data;
+ opline = get_next_op(CG(active_op_array) CLS_CC);
+ memcpy(opline, opline_ptr, sizeof(zend_op));
+ switch (type) {
+ case BP_VAR_R:
+ if (opline->opcode == ZEND_FETCH_DIM_W && opline->op2.op_type == IS_UNUSED) {
+ zend_error(E_COMPILE_ERROR, "Cannot use [] for reading");
+ }
+ opline->opcode -= 3;
+ break;
+ case BP_VAR_W:
+ break;
+ case BP_VAR_RW:
+ opline->opcode += 3;
+ break;
+ case BP_VAR_IS:
+ opline->opcode += 6; /* 3+3 */
+ break;
+ case BP_VAR_FUNC_ARG:
+ opline->opcode += 9; /* 3+3+3 */
+ opline->extended_value = arg_offset;
+ break;
+ case BP_VAR_UNSET:
+ opline->opcode += 12; /* 3+3+3+3 */
+ break;
+ }
+ le = le->next;
+ }
+ zend_llist_destroy(fetch_list_ptr);
+ zend_stack_del_top(&CG(bp_stack));
+}
+
+
+static zend_bool is_method_call(CLS_D)
+{
+ zend_llist *fetch_list_ptr;
+ zend_llist_element *cur;
+ zend_op *cur_opline;
+
+ zend_stack_top(&CG(bp_stack), (void **) &fetch_list_ptr);
+
+ cur = fetch_list_ptr->head;
+ /* There is always at least one node in the list */
+ while (cur->next) {
+ cur = cur->next;
+ }
+ cur_opline = (zend_op *)cur->data;
+ if (cur_opline->opcode == ZEND_FETCH_OBJ_W) {
+ return 1;
+ }
+ return 0;
+}
+
+
+void zend_do_init_string(znode *result CLS_DC)
+{
+ zend_op *opline = get_next_op(CG(active_op_array) CLS_CC);
+
+ opline->opcode = ZEND_INIT_STRING;
+ opline->result.op_type = IS_TMP_VAR;
+ opline->result.u.var = get_temporary_variable(CG(active_op_array));
+ *result = opline->result;
+ SET_UNUSED(opline->op1);
+ SET_UNUSED(opline->op2);
+}
+
+
+void zend_do_add_char(znode *result, znode *op1, znode *op2 CLS_DC)
+{
+ zend_op *opline = get_next_op(CG(active_op_array) CLS_CC);
+
+ opline->opcode = ZEND_ADD_CHAR;
+ opline->op1 = *op1;
+ opline->op2 = *op2;
+ opline->op2.op_type = IS_CONST;
+ opline->result = opline->op1;
+ *result = opline->result;
+}
+
+
+void zend_do_add_string(znode *result, znode *op1, znode *op2 CLS_DC)
+{
+ zend_op *opline = get_next_op(CG(active_op_array) CLS_CC);
+
+ opline->opcode = ZEND_ADD_STRING;
+ opline->op1 = *op1;
+ opline->op2 = *op2;
+ opline->op2.op_type = IS_CONST;
+ opline->result = opline->op1;
+ *result = opline->result;
+}
+
+
+void zend_do_add_variable(znode *result, znode *op1, znode *op2 CLS_DC)
+{
+ zend_op *opline;
+
+ if (op1->op_type == IS_CONST) {
+ opline = get_next_op(CG(active_op_array) CLS_CC);
+ opline->opcode = ZEND_INIT_STRING;
+ opline->result.op_type = IS_TMP_VAR;
+ opline->result.u.var = get_temporary_variable(CG(active_op_array));
+ *result = opline->result;
+ SET_UNUSED(opline->op1);
+ SET_UNUSED(opline->op2);
+
+ if (op1->u.constant.value.str.len>0) {
+ opline = get_next_op(CG(active_op_array) CLS_CC);
+ opline->opcode = ZEND_ADD_STRING;
+ opline->result = *result;
+ opline->op1 = *result;
+ opline->op2 = *op1;
+ opline->result = opline->op1;
+ } else {
+ zval_dtor(&op1->u.constant);
+ }
+ } else {
+ *result = *op1;
+ }
+
+ opline = get_next_op(CG(active_op_array) CLS_CC);
+ opline->opcode = ZEND_ADD_VAR;
+ opline->result = *result;
+ opline->op1 = *result;
+ opline->op2 = *op2;
+ *result = opline->result;
+}
+
+
+void zend_do_free(znode *op1 CLS_DC)
+{
+ if (op1->op_type==IS_TMP_VAR) {
+ zend_op *opline = get_next_op(CG(active_op_array) CLS_CC);
+
+ opline->opcode = ZEND_FREE;
+ opline->op1 = *op1;
+ SET_UNUSED(opline->op2);
+ } else if (op1->op_type==IS_VAR) {
+ zend_op *opline = &CG(active_op_array)->opcodes[CG(active_op_array)->last-1];
+
+ if (opline->opcode == ZEND_END_SILENCE) {
+ opline--;
+ }
+ if (opline->result.op_type == op1->op_type
+ && opline->result.u.var == op1->u.var) {
+ opline->result.u.EA.type |= EXT_TYPE_UNUSED;
+ } else {
+ while (opline>CG(active_op_array)->opcodes) {
+ /* This should be an object instantiation
+ * Find JMP_NO_CTOR, mark the preceding ASSIGN and the
+ * proceeding INIT_FCALL_BY_NAME as unused
+ */
+ if (opline->opcode == ZEND_JMP_NO_CTOR) {
+ (opline-1)->result.u.EA.type |= EXT_TYPE_UNUSED;
+ (opline+1)->op1.u.EA.type |= EXT_TYPE_UNUSED;
+ break;
+ } else if (opline->opcode == ZEND_FETCH_DIM_R
+ && opline->op1.op_type == IS_VAR
+ && opline->op1.u.var == op1->u.var) {
+ /* This should the end of a list() construct
+ * Mark its result as unused
+ */
+ opline->extended_value = ZEND_FETCH_STANDARD;
+ break;
+ } else if (opline->result.op_type==IS_VAR
+ && opline->result.u.var == op1->u.var) {
+ break;
+ }
+ opline--;
+ }
+ }
+ }
+}
+
+
+void zend_do_begin_function_declaration(znode *function_token, znode *function_name, int is_method, int return_reference CLS_DC)
+{
+ zend_op_array op_array;
+ char *name = function_name->u.constant.value.str.val;
+ int name_len = function_name->u.constant.value.str.len;
+ int function_begin_line = function_token->u.opline_num;
+
+ function_token->u.op_array = CG(active_op_array);
+ zend_str_tolower(name, name_len);
+
+ init_op_array(&op_array, ZEND_USER_FUNCTION, INITIAL_OP_ARRAY_SIZE CLS_CC);
+
+ op_array.function_name = name;
+ op_array.arg_types = NULL;
+ op_array.return_reference = return_reference;
+
+ if (is_method) {
+ zend_hash_update(&CG(active_class_entry)->function_table, name, name_len+1, &op_array, sizeof(zend_op_array), (void **) &CG(active_op_array));
+ } else {
+ zend_op *opline = get_next_op(CG(active_op_array) CLS_CC);
+
+ opline->opcode = ZEND_DECLARE_FUNCTION_OR_CLASS;
+ opline->op1.op_type = IS_CONST;
+ build_runtime_defined_function_key(&opline->op1.u.constant, &function_name->u.constant, opline CLS_CC);
+ opline->op2.op_type = IS_CONST;
+ opline->op2.u.constant.type = IS_STRING;
+ opline->op2.u.constant.value.str.val = estrndup(name, name_len);
+ opline->op2.u.constant.value.str.len = name_len;
+ opline->op2.u.constant.refcount = 1;
+ opline->extended_value = ZEND_DECLARE_FUNCTION;
+ zend_hash_update(CG(function_table), opline->op1.u.constant.value.str.val, opline->op1.u.constant.value.str.len, &op_array, sizeof(zend_op_array), (void **) &CG(active_op_array));
+ }
+
+ if (CG(extended_info)) {
+ zend_op *opline = get_next_op(CG(active_op_array) CLS_CC);
+
+ opline->opcode = ZEND_EXT_NOP;
+ opline->lineno = function_begin_line;
+ SET_UNUSED(opline->op1);
+ SET_UNUSED(opline->op2);
+ }
+
+ {
+ /* Push a seperator to the switch and foreach stacks */
+ zend_switch_entry switch_entry;
+
+ switch_entry.cond.op_type = IS_UNUSED;
+ switch_entry.default_case = 0;
+ switch_entry.control_var = 0;
+
+ zend_stack_push(&CG(switch_cond_stack), (void *) &switch_entry, sizeof(switch_entry));
+
+ zend_stack_push(&CG(foreach_copy_stack), (void *) &switch_entry.cond, sizeof(znode));
+ }
+}
+
+
+void zend_do_end_function_declaration(znode *function_token CLS_DC)
+{
+ zend_do_extended_info(CLS_C);
+ zend_do_return(NULL, 0 CLS_CC);
+ pass_two(CG(active_op_array));
+ CG(active_op_array) = function_token->u.op_array;
+
+ /* Pop the switch and foreach seperators */
+ zend_stack_del_top(&CG(switch_cond_stack));
+ zend_stack_del_top(&CG(foreach_copy_stack));
+}
+
+
+void zend_do_receive_arg(int op, znode *var, znode *offset, znode *initialization, unsigned char pass_type CLS_DC)
+{
+ zend_op *opline = get_next_op(CG(active_op_array) CLS_CC);
+
+ opline->opcode = op;
+ opline->result = *var;
+ opline->op1 = *offset;
+ if ((op == ZEND_RECV_INIT)) {
+ opline->op2 = *initialization;
+ } else {
+ SET_UNUSED(opline->op2);
+ }
+ if (!CG(active_op_array)->arg_types) {
+ if (pass_type==BYREF_FORCE) {
+ int i;
+
+ CG(active_op_array)->arg_types = (unsigned char *) emalloc(sizeof(unsigned char)*(offset->u.constant.value.lval+1));
+ for (i=1; i<offset->u.constant.value.lval; i++) {
+ CG(active_op_array)->arg_types[i] = BYREF_NONE;
+ }
+ CG(active_op_array)->arg_types[0]=(unsigned char) offset->u.constant.value.lval;
+ CG(active_op_array)->arg_types[offset->u.constant.value.lval] = pass_type;
+ }
+ } else {
+ CG(active_op_array)->arg_types = (unsigned char *) erealloc(CG(active_op_array)->arg_types, sizeof(unsigned char)*(offset->u.constant.value.lval+1));
+ CG(active_op_array)->arg_types[0]=(unsigned char) offset->u.constant.value.lval;
+ CG(active_op_array)->arg_types[offset->u.constant.value.lval] = pass_type;
+ }
+}
+
+
+int zend_do_begin_function_call(znode *function_name CLS_DC)
+{
+ zend_function *function;
+
+ zend_str_tolower(function_name->u.constant.value.str.val, function_name->u.constant.value.str.len);
+ if (zend_hash_find(CG(function_table), function_name->u.constant.value.str.val,function_name->u.constant.value.str.len+1, (void **) &function)==FAILURE) {
+ znode tmp = *function_name;
+
+ zval_copy_ctor(&tmp.u.constant);
+ zend_do_begin_dynamic_function_call(&tmp CLS_CC);
+ return 1; /* Dynamic */
+ }
+
+ switch (function->type) {
+ case ZEND_USER_FUNCTION: {
+ zend_op_array *op_array = (zend_op_array *) function;
+
+ zend_stack_push(&CG(function_call_stack), (void *) &op_array, sizeof(zend_function *));
+ }
+ break;
+ case ZEND_INTERNAL_FUNCTION: {
+ zend_internal_function *internal_function = (zend_internal_function *) function;
+
+ zend_stack_push(&CG(function_call_stack), (void *) &internal_function, sizeof(zend_function *));
+ }
+ break;
+ }
+ zend_do_extended_fcall_begin(CLS_C);
+ return 0;
+}
+
+
+void zend_do_begin_dynamic_function_call(znode *function_name CLS_DC)
+{
+ unsigned char *ptr = NULL;
+ int last_op_number;
+ zend_op *last_op;
+
+ if (function_name->op_type != IS_CONST && is_method_call(CLS_C)) {
+ zend_do_end_variable_parse(BP_VAR_W, 0 CLS_CC);
+ last_op_number = get_next_op_number(CG(active_op_array))-1;
+ last_op = &CG(active_op_array)->opcodes[last_op_number];
+ last_op->opcode = ZEND_INIT_FCALL_BY_NAME;
+ last_op->extended_value = ZEND_MEMBER_FUNC_CALL;
+ } else {
+ zend_op *opline;
+
+ if (function_name->op_type != IS_CONST) {
+ zend_do_end_variable_parse(BP_VAR_R, 0 CLS_CC);
+ }
+
+ opline = get_next_op(CG(active_op_array) CLS_CC);
+ opline->opcode = ZEND_INIT_FCALL_BY_NAME;
+ opline->op2 = *function_name;
+ opline->extended_value = 0;
+ SET_UNUSED(opline->op1);
+ }
+ zend_stack_push(&CG(function_call_stack), (void *) &ptr, sizeof(zend_function *));
+ zend_do_extended_fcall_begin(CLS_C);
+}
+
+
+void zend_do_begin_class_member_function_call(znode *class_name, znode *function_name CLS_DC)
+{
+ unsigned char *ptr = NULL;
+ zend_op *opline = get_next_op(CG(active_op_array) CLS_CC);
+
+ opline->opcode = ZEND_INIT_FCALL_BY_NAME;
+ zend_str_tolower(class_name->u.constant.value.str.val, class_name->u.constant.value.str.len);
+ if ((class_name->u.constant.value.str.len == sizeof("parent")-1)
+ && !memcmp(class_name->u.constant.value.str.val, "parent", sizeof("parent")-1)) {
+ if (!CG(active_class_entry) || !CG(active_class_entry)->parent) {
+ zend_error(E_COMPILE_ERROR, "No parent class available in this context");
+ }
+ efree(class_name->u.constant.value.str.val);
+ class_name->u.constant.value.str.len = CG(active_class_entry)->parent->name_length;
+ class_name->u.constant.value.str.val = estrndup(CG(active_class_entry)->parent->name, class_name->u.constant.value.str.len);
+ }
+ opline->op1 = *class_name;
+ opline->op2 = *function_name;
+ opline->extended_value = ZEND_MEMBER_FUNC_CALL;
+ zval_copy_ctor(&opline->op2.u.constant);
+ zend_stack_push(&CG(function_call_stack), (void *) &ptr, sizeof(zend_function *));
+}
+
+
+void zend_do_end_function_call(znode *function_name, znode *result, znode *argument_list, int is_method, int is_dynamic_fcall CLS_DC)
+{
+ zend_op *opline = get_next_op(CG(active_op_array) CLS_CC);
+
+ if (function_name->op_type==IS_CONST && !is_method && !is_dynamic_fcall) {
+ opline->opcode = ZEND_DO_FCALL;
+ } else {
+ opline->opcode = ZEND_DO_FCALL_BY_NAME;
+ }
+ opline->op1 = *function_name;
+ opline->result.u.var = get_temporary_variable(CG(active_op_array));
+ opline->result.op_type = IS_VAR;
+ *result = opline->result;
+ SET_UNUSED(opline->op2);
+ opline->op2.u.constant.value.lval = is_method;
+ zend_stack_del_top(&CG(function_call_stack));
+ opline->extended_value = argument_list->u.constant.value.lval;
+}
+
+
+void zend_do_pass_param(znode *param, int op, int offset CLS_DC)
+{
+ zend_op *opline;
+ unsigned char *arg_types;
+ int original_op=op;
+ zend_function **function_ptr_ptr, *function_ptr;
+ int send_by_reference;
+
+
+ zend_stack_top(&CG(function_call_stack), (void **) &function_ptr_ptr);
+ function_ptr = *function_ptr_ptr;
+
+ if (original_op==ZEND_SEND_REF
+ && !CG(allow_call_time_pass_reference)) {
+ zend_error(E_COMPILE_WARNING,
+ "Call-time pass-by-reference has been deprecated - argument passed by value; "
+ "If you would like to pass it by reference, modify the declaration of %s(). "
+ "If you would like to enable call-time pass-by-reference, you can set "
+ "allow_call_time_pass_reference to true in your INI file. "
+ "However, future versions may not support this any longer. ",
+ (function_ptr?function_ptr->common.function_name:"[runtime function name]"),
+ offset+1);
+ }
+
+ if (function_ptr) {
+ arg_types = function_ptr->common.arg_types;
+ } else {
+ arg_types = NULL;
+ }
+
+ send_by_reference = ARG_SHOULD_BE_SENT_BY_REF(offset, 1, arg_types)?ZEND_ARG_SEND_BY_REF:0;
+
+ if (op == ZEND_SEND_VAL && param->op_type == IS_VAR) {
+ op = ZEND_SEND_VAR_NO_REF;
+ }
+
+ if (op!=ZEND_SEND_VAR_NO_REF && send_by_reference == ZEND_ARG_SEND_BY_REF) {
+ /* change to passing by reference */
+ switch (param->op_type) {
+ case IS_VAR:
+ op = ZEND_SEND_REF;
+ break;
+ default:
+ zend_error(E_COMPILE_ERROR, "Only variables can be passed by reference");
+ break;
+ }
+ }
+
+ if (original_op == ZEND_SEND_VAR) {
+ switch(op) {
+ case ZEND_SEND_VAR_NO_REF:
+ zend_do_end_variable_parse(BP_VAR_R, 0 CLS_CC);
+ break;
+ case ZEND_SEND_VAR:
+ if (function_ptr) {
+ zend_do_end_variable_parse(BP_VAR_R, 0 CLS_CC);
+ } else {
+ zend_do_end_variable_parse(BP_VAR_FUNC_ARG, offset CLS_CC);
+ }
+ break;
+ case ZEND_SEND_REF:
+ zend_do_end_variable_parse(BP_VAR_W, 0 CLS_CC);
+ break;
+ }
+ }
+
+ opline = get_next_op(CG(active_op_array) CLS_CC);
+
+ if (op == ZEND_SEND_VAR_NO_REF) {
+ if (function_ptr) {
+ opline->extended_value = ZEND_ARG_COMPILE_TIME_BOUND | send_by_reference;
+ } else {
+ opline->extended_value = 0;
+ }
+ } else {
+ if (function_ptr) {
+ opline->extended_value = ZEND_DO_FCALL;
+ } else {
+ opline->extended_value = ZEND_DO_FCALL_BY_NAME;
+ }
+ }
+ opline->opcode = op;
+ opline->op1 = *param;
+ opline->op2.u.opline_num = offset;
+ SET_UNUSED(opline->op2);
+}
+
+
+static int generate_free_switch_expr(zend_switch_entry *switch_entry CLS_DC)
+{
+ zend_op *opline;
+
+ if (switch_entry->cond.op_type!=IS_VAR && switch_entry->cond.op_type!=IS_TMP_VAR) {
+ return 1;
+ }
+
+ opline = get_next_op(CG(active_op_array) CLS_CC);
+
+ opline->opcode = ZEND_SWITCH_FREE;
+ opline->op1 = switch_entry->cond;
+ SET_UNUSED(opline->op2);
+ opline->extended_value = 0;
+ return 0;
+}
+
+static int generate_free_foreach_copy(znode *foreach_copy CLS_DC)
+{
+ zend_op *opline;
+
+ if (foreach_copy->op_type!=IS_VAR && foreach_copy->op_type!=IS_TMP_VAR) {
+ return 1;
+ }
+
+ opline = get_next_op(CG(active_op_array) CLS_CC);
+
+ opline->opcode = ZEND_SWITCH_FREE;
+ opline->op1 = *foreach_copy;
+ SET_UNUSED(opline->op2);
+ opline->extended_value = 1;
+ return 0;
+}
+
+void zend_do_return(znode *expr, int do_end_vparse CLS_DC)
+{
+ zend_op *opline;
+
+ if (do_end_vparse) {
+ if (CG(active_op_array)->return_reference) {
+ zend_do_end_variable_parse(BP_VAR_W, 0 CLS_CC);
+ } else {
+ zend_do_end_variable_parse(BP_VAR_R, 0 CLS_CC);
+ }
+ }
+#ifdef ZTS
+ zend_stack_apply_with_argument(&CG(switch_cond_stack), ZEND_STACK_APPLY_TOPDOWN, (int (*)(void *element, void *)) generate_free_switch_expr CLS_CC);
+ zend_stack_apply_with_argument(&CG(foreach_copy_stack), ZEND_STACK_APPLY_TOPDOWN, (int (*)(void *element, void *)) generate_free_foreach_copy CLS_CC);
+#else
+ zend_stack_apply(&CG(switch_cond_stack), ZEND_STACK_APPLY_TOPDOWN, (int (*)(void *element)) generate_free_switch_expr);
+ zend_stack_apply(&CG(foreach_copy_stack), ZEND_STACK_APPLY_TOPDOWN, (int (*)(void *element)) generate_free_foreach_copy);
+#endif
+
+ opline = get_next_op(CG(active_op_array) CLS_CC);
+
+ opline->opcode = ZEND_RETURN;
+
+ if (expr) {
+ opline->op1 = *expr;
+ } else {
+ opline->op1.op_type = IS_CONST;
+ INIT_ZVAL(opline->op1.u.constant);
+ }
+ SET_UNUSED(opline->op2);
+}
+
+
+ZEND_API void function_add_ref(zend_function *function)
+{
+ if (function->type == ZEND_USER_FUNCTION) {
+ zend_op_array *op_array = &function->op_array;
+
+ (*op_array->refcount)++;
+ if (op_array->static_variables) {
+ HashTable *static_variables = op_array->static_variables;
+ zval *tmp_zval;
+
+ ALLOC_HASHTABLE(op_array->static_variables);
+ zend_hash_init(op_array->static_variables, 2, NULL, ZVAL_PTR_DTOR, 0);
+ zend_hash_copy(op_array->static_variables, static_variables, (copy_ctor_func_t) zval_add_ref, (void *) &tmp_zval, sizeof(zval *));
+ }
+ }
+}
+
+
+static void do_inherit_parent_constructor(zend_class_entry *ce)
+{
+ if (ce->parent
+ && !zend_hash_exists(&ce->function_table, ce->name, ce->name_length+1)) {
+ zend_function *function;
+
+ if (zend_hash_find(&ce->parent->function_table, ce->parent->name, ce->parent->name_length+1, (void **) &function)==SUCCESS) {
+ /* inherit parent's constructor */
+ zend_hash_update(&ce->function_table, ce->name, ce->name_length+1, function, sizeof(zend_function), NULL);
+ function_add_ref(function);
+ }
+ }
+}
+
+void zend_do_inheritance(zend_class_entry *ce, zend_class_entry *parent_ce)
+{
+ zend_function tmp_zend_function;
+ zval *tmp;
+
+ /* Perform inheritance */
+ zend_hash_merge(&ce->default_properties, &parent_ce->default_properties, (void (*)(void *)) zval_add_ref, (void *) &tmp, sizeof(zval *), 0);
+ zend_hash_merge(&ce->function_table, &parent_ce->function_table, (void (*)(void *)) function_add_ref, &tmp_zend_function, sizeof(zend_function), 0);
+ ce->parent = parent_ce;
+ do_inherit_parent_constructor(ce);
+}
+
+
+ZEND_API int do_bind_function_or_class(zend_op *opline, HashTable *function_table, HashTable *class_table, int compile_time)
+{
+ switch (opline->extended_value) {
+ case ZEND_DECLARE_FUNCTION: {
+ zend_function *function;
+
+ zend_hash_find(function_table, opline->op1.u.constant.value.str.val, opline->op1.u.constant.value.str.len, (void *) &function);
+ if (zend_hash_add(function_table, opline->op2.u.constant.value.str.val, opline->op2.u.constant.value.str.len+1, function, sizeof(zend_function), NULL)==FAILURE) {
+ if (!compile_time) {
+ zend_error(E_ERROR, "Cannot redeclare %s()", opline->op2.u.constant.value.str.val);
+ }
+ return FAILURE;
+ } else {
+ (*function->op_array.refcount)++;
+ function->op_array.static_variables = NULL; /* NULL out the unbound function */
+ return SUCCESS;
+ }
+ }
+ break;
+ case ZEND_DECLARE_CLASS: {
+ zend_class_entry *ce;
+
+ if (zend_hash_find(class_table, opline->op1.u.constant.value.str.val, opline->op1.u.constant.value.str.len, (void **) &ce)==FAILURE) {
+ zend_error(E_ERROR, "Internal Zend error - Missing class information for %s", opline->op1.u.constant.value.str.val);
+ return FAILURE;
+ }
+ (*ce->refcount)++;
+ if (zend_hash_add(class_table, opline->op2.u.constant.value.str.val, opline->op2.u.constant.value.str.len+1, ce, sizeof(zend_class_entry), NULL)==FAILURE) {
+ (*ce->refcount)--;
+ if (!compile_time) {
+ zend_error(E_ERROR, "Cannot redeclare class %s", opline->op2.u.constant.value.str.val);
+ }
+ return FAILURE;
+ } else {
+ return SUCCESS;
+ }
+ }
+ break;
+ case ZEND_DECLARE_INHERITED_CLASS: {
+ zend_class_entry *ce, *parent_ce;
+ int parent_name_length;
+ char *class_name, *parent_name;
+ int found_ce;
+
+
+ found_ce = zend_hash_find(class_table, opline->op1.u.constant.value.str.val, opline->op1.u.constant.value.str.len, (void **) &ce);
+
+ /* Restore base class / derived class names */
+ class_name = strchr(opline->op2.u.constant.value.str.val, ':');
+ if (!class_name) {
+ zend_error(E_CORE_ERROR, "Invalid runtime class entry");
+ }
+ class_name++;
+
+ if (found_ce==FAILURE) {
+ zend_error(E_ERROR, "Cannot redeclare class %s", class_name);
+ return FAILURE;
+ }
+
+ (*ce->refcount)++;
+
+ /* Obtain parent class */
+ parent_name_length = class_name - opline->op2.u.constant.value.str.val - 1;
+ parent_name = estrndup(opline->op2.u.constant.value.str.val, parent_name_length);
+ if (zend_hash_find(class_table, parent_name, parent_name_length+1, (void **) &parent_ce)==FAILURE) {
+ if (!compile_time) {
+ zend_error(E_ERROR, "Class %s: Cannot inherit from undefined class %s", class_name, parent_name);
+ }
+ (*ce->refcount)--;
+ efree(parent_name);
+ return FAILURE;
+ }
+ efree(parent_name);
+
+ zend_do_inheritance(ce, parent_ce);
+
+ /* Register the derived class */
+ if (zend_hash_add(class_table, class_name, strlen(class_name)+1, ce, sizeof(zend_class_entry), NULL)==FAILURE) {
+ if (!compile_time) {
+ zend_error(E_ERROR, "Cannot redeclare class %s", opline->op2.u.constant.value.str.val);
+ }
+ (*ce->refcount)--;
+ zend_hash_destroy(&ce->function_table);
+ zend_hash_destroy(&ce->default_properties);
+ return FAILURE;
+ }
+ return SUCCESS;
+ }
+ break;
+ }
+ return FAILURE;
+}
+
+
+void zend_do_early_binding(CLS_D)
+{
+ zend_op *opline = &CG(active_op_array)->opcodes[CG(active_op_array)->last-1];
+ HashTable *table;
+
+ if (do_bind_function_or_class(opline, CG(function_table), CG(class_table), 1)==FAILURE) {
+ return;
+ }
+ switch (opline->extended_value) {
+ case ZEND_DECLARE_FUNCTION:
+ table = CG(function_table);
+ break;
+ case ZEND_DECLARE_CLASS:
+ table = CG(class_table);
+ break;
+ default:
+ zend_error(E_COMPILE_ERROR, "Invalid binding type");
+ return;
+ }
+ zend_hash_del(table, opline->op1.u.constant.value.str.val, opline->op1.u.constant.value.str.len);
+ zval_dtor(&opline->op1.u.constant);
+ zval_dtor(&opline->op2.u.constant);
+ opline->opcode = ZEND_NOP;
+ memset(&opline->op1, 0, sizeof(znode));
+ memset(&opline->op2, 0, sizeof(znode));
+ SET_UNUSED(opline->op1);
+ SET_UNUSED(opline->op2);
+}
+
+
+void zend_do_boolean_or_begin(znode *expr1, znode *op_token CLS_DC)
+{
+ int next_op_number = get_next_op_number(CG(active_op_array));
+ zend_op *opline = get_next_op(CG(active_op_array) CLS_CC);
+
+ opline->opcode = ZEND_JMPNZ_EX;
+ if (expr1->op_type == IS_TMP_VAR) {
+ opline->result = *expr1;
+ } else {
+ opline->result.u.var = get_temporary_variable(CG(active_op_array));
+ opline->result.op_type = IS_TMP_VAR;
+ }
+ opline->op1 = *expr1;
+ SET_UNUSED(opline->op2);
+
+ op_token->u.opline_num = next_op_number;
+
+ *expr1 = opline->result;
+}
+
+
+void zend_do_boolean_or_end(znode *result, znode *expr1, znode *expr2, znode *op_token CLS_DC)
+{
+ zend_op *opline = get_next_op(CG(active_op_array) CLS_CC);
+
+ *result = *expr1; /* we saved the original result in expr1 */
+ opline->opcode = ZEND_BOOL;
+ opline->result = *result;
+ opline->op1 = *expr2;
+ SET_UNUSED(opline->op2);
+
+ CG(active_op_array)->opcodes[op_token->u.opline_num].op2.u.opline_num = get_next_op_number(CG(active_op_array));
+}
+
+
+void zend_do_boolean_and_begin(znode *expr1, znode *op_token CLS_DC)
+{
+ int next_op_number = get_next_op_number(CG(active_op_array));
+ zend_op *opline = get_next_op(CG(active_op_array) CLS_CC);
+
+ opline->opcode = ZEND_JMPZ_EX;
+ if (expr1->op_type == IS_TMP_VAR) {
+ opline->result = *expr1;
+ } else {
+ opline->result.u.var = get_temporary_variable(CG(active_op_array));
+ opline->result.op_type = IS_TMP_VAR;
+ }
+ opline->op1 = *expr1;
+ SET_UNUSED(opline->op2);
+
+ op_token->u.opline_num = next_op_number;
+
+ *expr1 = opline->result;
+}
+
+
+void zend_do_boolean_and_end(znode *result, znode *expr1, znode *expr2, znode *op_token CLS_DC)
+{
+ zend_op *opline = get_next_op(CG(active_op_array) CLS_CC);
+
+ *result = *expr1; /* we saved the original result in expr1 */
+ opline->opcode = ZEND_BOOL;
+ opline->result = *result;
+ opline->op1 = *expr2;
+ SET_UNUSED(opline->op2);
+
+ CG(active_op_array)->opcodes[op_token->u.opline_num].op2.u.opline_num = get_next_op_number(CG(active_op_array));
+}
+
+
+void zend_do_do_while_begin(CLS_D)
+{
+ do_begin_loop(CLS_C);
+ INC_BPC(CG(active_op_array));
+}
+
+
+void zend_do_do_while_end(znode *do_token, znode *expr_open_bracket, znode *expr CLS_DC)
+{
+ zend_op *opline = get_next_op(CG(active_op_array) CLS_CC);
+
+ opline->opcode = ZEND_JMPNZ;
+ opline->op1 = *expr;
+ opline->op2.u.opline_num = do_token->u.opline_num;
+ SET_UNUSED(opline->op2);
+
+ do_end_loop(expr_open_bracket->u.opline_num CLS_CC);
+
+ DEC_BPC(CG(active_op_array));
+}
+
+
+void zend_do_brk_cont(int op, znode *expr CLS_DC)
+{
+ zend_op *opline = get_next_op(CG(active_op_array) CLS_CC);
+
+ opline->opcode = op;
+ opline->op1.u.opline_num = CG(active_op_array)->current_brk_cont;
+ SET_UNUSED(opline->op1);
+ if (expr) {
+ opline->op2 = *expr;
+ } else {
+ opline->op2.u.constant.type = IS_LONG;
+ opline->op2.u.constant.value.lval = 1;
+ INIT_PZVAL(&opline->op2.u.constant);
+ opline->op2.op_type = IS_CONST;
+ }
+}
+
+
+void zend_do_switch_cond(znode *cond CLS_DC)
+{
+ zend_switch_entry switch_entry;
+ zend_op *opline;
+
+ /* Initialize the conditional value */
+ opline = get_next_op(CG(active_op_array) CLS_CC);
+ opline->opcode = ZEND_BOOL;
+ opline->result.u.var = get_temporary_variable(CG(active_op_array));
+ opline->result.op_type = IS_TMP_VAR;
+ opline->op1.op_type = IS_CONST;
+ opline->op1.u.constant.type = IS_BOOL;
+ opline->op1.u.constant.value.lval = 0;
+ INIT_PZVAL(&opline->op1.u.constant);
+ SET_UNUSED(opline->op2);
+
+ switch_entry.cond = *cond;
+ switch_entry.default_case = -1;
+ switch_entry.control_var = opline->result.u.var;
+ zend_stack_push(&CG(switch_cond_stack), (void *) &switch_entry, sizeof(switch_entry));
+
+ do_begin_loop(CLS_C);
+
+ INC_BPC(CG(active_op_array));
+}
+
+
+
+void zend_do_switch_end(znode *case_list CLS_DC)
+{
+ zend_op *opline;
+ zend_switch_entry *switch_entry_ptr;
+
+ zend_stack_top(&CG(switch_cond_stack), (void **) &switch_entry_ptr);
+
+ if (case_list->op_type != IS_UNUSED) { /* non-empty switch */
+ int next_op_number = get_next_op_number(CG(active_op_array));
+
+ CG(active_op_array)->opcodes[case_list->u.opline_num].op1.u.opline_num = next_op_number;
+ }
+
+ /* add code to jmp to default case */
+ if (switch_entry_ptr->default_case != -1) {
+ opline = get_next_op(CG(active_op_array) CLS_CC);
+ opline->opcode = ZEND_JMPZ;
+ opline->op1.op_type = IS_TMP_VAR;
+ opline->op1.u.var = switch_entry_ptr->control_var;
+ opline->op2.u.opline_num = switch_entry_ptr->default_case;
+ SET_UNUSED(opline->op2);
+ }
+
+
+ /* remember break/continue loop information */
+ CG(active_op_array)->brk_cont_array[CG(active_op_array)->current_brk_cont].cont = CG(active_op_array)->brk_cont_array[CG(active_op_array)->current_brk_cont].brk = get_next_op_number(CG(active_op_array));
+ CG(active_op_array)->current_brk_cont = CG(active_op_array)->brk_cont_array[CG(active_op_array)->current_brk_cont].parent;
+
+ if (switch_entry_ptr->cond.op_type==IS_VAR || switch_entry_ptr->cond.op_type==IS_TMP_VAR) {
+ /* emit free for the switch condition*/
+ opline = get_next_op(CG(active_op_array) CLS_CC);
+ opline->opcode = ZEND_SWITCH_FREE;
+ opline->op1 = switch_entry_ptr->cond;
+ SET_UNUSED(opline->op2);
+ }
+ if (switch_entry_ptr->cond.op_type == IS_CONST) {
+ zval_dtor(&switch_entry_ptr->cond.u.constant);
+ }
+
+ zend_stack_del_top(&CG(switch_cond_stack));
+
+ DEC_BPC(CG(active_op_array));
+}
+
+
+void zend_do_case_before_statement(znode *case_list, znode *case_token, znode *case_expr CLS_DC)
+{
+ zend_op *opline = get_next_op(CG(active_op_array) CLS_CC);
+ int next_op_number;
+ zend_switch_entry *switch_entry_ptr;
+ znode result;
+
+ zend_stack_top(&CG(switch_cond_stack), (void **) &switch_entry_ptr);
+
+ opline->opcode = ZEND_CASE;
+ opline->result.u.var = switch_entry_ptr->control_var;
+ opline->result.op_type = IS_TMP_VAR;
+ opline->op1 = switch_entry_ptr->cond;
+ opline->op2 = *case_expr;
+ if (opline->op1.op_type == IS_CONST) {
+ zval_copy_ctor(&opline->op1.u.constant);
+ }
+ result = opline->result;
+
+ next_op_number = get_next_op_number(CG(active_op_array));
+ opline = get_next_op(CG(active_op_array) CLS_CC);
+ opline->opcode = ZEND_JMPZ;
+ opline->op1 = result;
+ SET_UNUSED(opline->op2);
+ case_token->u.opline_num = next_op_number;
+
+ if (case_list->op_type==IS_UNUSED) {
+ return;
+ }
+ next_op_number = get_next_op_number(CG(active_op_array));
+ CG(active_op_array)->opcodes[case_list->u.opline_num].op1.u.opline_num = next_op_number;
+}
+
+
+void zend_do_case_after_statement(znode *result, znode *case_token CLS_DC)
+{
+ int next_op_number = get_next_op_number(CG(active_op_array));
+ zend_op *opline = get_next_op(CG(active_op_array) CLS_CC);
+
+ opline->opcode = ZEND_JMP;
+ SET_UNUSED(opline->op1);
+ SET_UNUSED(opline->op2);
+ result->u.opline_num = next_op_number;
+
+ switch (CG(active_op_array)->opcodes[case_token->u.opline_num].opcode) {
+ case ZEND_JMP:
+ CG(active_op_array)->opcodes[case_token->u.opline_num].op1.u.opline_num = get_next_op_number(CG(active_op_array));
+ break;
+ case ZEND_JMPZ:
+ CG(active_op_array)->opcodes[case_token->u.opline_num].op2.u.opline_num = get_next_op_number(CG(active_op_array));
+ break;
+ }
+}
+
+
+
+void zend_do_default_before_statement(znode *case_list, znode *default_token CLS_DC)
+{
+ int next_op_number = get_next_op_number(CG(active_op_array));
+ zend_op *opline = get_next_op(CG(active_op_array) CLS_CC);
+ zend_switch_entry *switch_entry_ptr;
+
+ zend_stack_top(&CG(switch_cond_stack), (void **) &switch_entry_ptr);
+
+ opline->opcode = ZEND_JMP;
+ SET_UNUSED(opline->op1);
+ SET_UNUSED(opline->op2);
+ default_token->u.opline_num = next_op_number;
+
+ next_op_number = get_next_op_number(CG(active_op_array));
+ opline = get_next_op(CG(active_op_array) CLS_CC);
+ opline->opcode = ZEND_BOOL;
+ opline->result.u.var = switch_entry_ptr->control_var;
+ opline->result.op_type = IS_TMP_VAR;
+ opline->op1.op_type = IS_CONST;
+ opline->op1.u.constant.type = IS_BOOL;
+ opline->op1.u.constant.value.lval = 1;
+ INIT_PZVAL(&opline->op1.u.constant);
+ SET_UNUSED(opline->op2);
+ switch_entry_ptr->default_case = next_op_number;
+
+ if (case_list->op_type==IS_UNUSED) {
+ return;
+ }
+ next_op_number = get_next_op_number(CG(active_op_array));
+ CG(active_op_array)->opcodes[case_list->u.opline_num].op1.u.opline_num = next_op_number;
+}
+
+
+void zend_do_begin_class_declaration(znode *class_name, znode *parent_class_name CLS_DC)
+{
+ zend_op *opline = get_next_op(CG(active_op_array) CLS_CC);
+ int runtime_inheritance = 0;
+
+ if (CG(active_class_entry)) {
+ zend_error(E_COMPILE_ERROR, "Class declarations may not be nested");
+ return;
+ }
+ CG(class_entry).type = ZEND_USER_CLASS;
+ CG(class_entry).name = class_name->u.constant.value.str.val;
+ CG(class_entry).name_length = class_name->u.constant.value.str.len;
+ CG(class_entry).refcount = (int *) emalloc(sizeof(int));
+ *CG(class_entry).refcount = 1;
+ CG(class_entry).constants_updated = 0;
+
+ zend_str_tolower(CG(class_entry).name, CG(class_entry).name_length);
+
+ zend_hash_init(&CG(class_entry).function_table, 10, NULL, ZEND_FUNCTION_DTOR, 0);
+ zend_hash_init(&CG(class_entry).default_properties, 10, NULL, ZVAL_PTR_DTOR, 0);
+
+ /* code for inheritance from parent class */
+ if (parent_class_name) {
+ zend_class_entry *parent_class;
+ zend_function tmp_zend_function;
+ zval *tmp;
+
+ zend_str_tolower(parent_class_name->u.constant.value.str.val, parent_class_name->u.constant.value.str.len);
+
+ if (zend_hash_find(CG(class_table), parent_class_name->u.constant.value.str.val, parent_class_name->u.constant.value.str.len+1, (void **) &parent_class)==SUCCESS) {
+ /* copy functions */
+ zend_hash_copy(&CG(class_entry).function_table, &parent_class->function_table, (copy_ctor_func_t) function_add_ref, &tmp_zend_function, sizeof(zend_function));
+
+ /* copy default properties */
+ zend_hash_copy(&CG(class_entry).default_properties, &parent_class->default_properties, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *));
+
+ CG(class_entry).parent = parent_class;
+
+ zval_dtor(&parent_class_name->u.constant);
+ } else {
+ runtime_inheritance = 1;
+ CG(class_entry).parent = NULL;
+ }
+ } else {
+ CG(class_entry).parent = NULL;
+ }
+
+ CG(class_entry).handle_function_call = NULL;
+ CG(class_entry).handle_property_set = NULL;
+ CG(class_entry).handle_property_get = NULL;
+
+ opline->opcode = ZEND_DECLARE_FUNCTION_OR_CLASS;
+ opline->op1.op_type = IS_CONST;
+ build_runtime_defined_function_key(&opline->op1.u.constant, &class_name->u.constant, opline CLS_CC);
+ opline->op2.op_type = IS_CONST;
+ opline->op2.u.constant.type = IS_STRING;
+ opline->op2.u.constant.refcount = 1;
+ if (runtime_inheritance) {
+ char *full_class_name;
+
+ opline->op2.u.constant.value.str.len = parent_class_name->u.constant.value.str.len+1+CG(class_entry).name_length;
+ full_class_name = opline->op2.u.constant.value.str.val = (char *) emalloc(opline->op2.u.constant.value.str.len+1);
+
+ memcpy(full_class_name, parent_class_name->u.constant.value.str.val, parent_class_name->u.constant.value.str.len);
+ full_class_name += parent_class_name->u.constant.value.str.len;
+ full_class_name[0] = ':';
+ full_class_name++;
+ memcpy(full_class_name, CG(class_entry).name, CG(class_entry).name_length);
+ zval_dtor(&parent_class_name->u.constant);
+ full_class_name += CG(class_entry).name_length;
+ full_class_name[0] = 0;
+ opline->extended_value = ZEND_DECLARE_INHERITED_CLASS;
+ } else {
+ opline->op2.u.constant.value.str.val = estrndup(CG(class_entry).name, CG(class_entry).name_length);
+ opline->op2.u.constant.value.str.len = CG(class_entry).name_length;
+ opline->extended_value = ZEND_DECLARE_CLASS;
+ }
+
+ zend_hash_update(CG(class_table), opline->op1.u.constant.value.str.val, opline->op1.u.constant.value.str.len, &CG(class_entry), sizeof(zend_class_entry), (void **) &CG(active_class_entry));
+}
+
+
+void zend_do_end_class_declaration(CLS_D)
+{
+ do_inherit_parent_constructor(CG(active_class_entry));
+ CG(active_class_entry) = NULL;
+}
+
+
+void zend_do_declare_property(znode *var_name, znode *value CLS_DC)
+{
+ if (value) {
+ zval *property;
+
+ ALLOC_ZVAL(property);
+
+ *property = value->u.constant;
+ zend_hash_update(&CG(active_class_entry)->default_properties, var_name->u.constant.value.str.val, var_name->u.constant.value.str.len+1, &property, sizeof(zval *), NULL);
+ }
+ FREE_PNODE(var_name);
+}
+
+
+void zend_do_fetch_property(znode *result, znode *object, znode *property CLS_DC)
+{
+ zend_op opline;
+ zend_llist *fetch_list_ptr;
+
+ init_op(&opline CLS_CC);
+ opline.opcode = ZEND_FETCH_OBJ_W; /* the backpatching routine assumes W */
+ opline.result.op_type = IS_VAR;
+ opline.result.u.EA.type = 0;
+ opline.result.u.var = get_temporary_variable(CG(active_op_array));
+ opline.op1 = *object;
+ opline.op2 = *property;
+ *result = opline.result;
+
+ zend_stack_top(&CG(bp_stack), (void **) &fetch_list_ptr);
+ zend_llist_add_element(fetch_list_ptr, &opline);
+}
+
+
+void zend_do_push_object(znode *object CLS_DC)
+{
+ zend_stack_push(&CG(object_stack), object, sizeof(znode));
+}
+
+
+void zend_do_pop_object(znode *object CLS_DC)
+{
+ znode *tmp;
+
+ zend_stack_top(&CG(object_stack), (void **) &tmp);
+ *object = *tmp;
+ zend_stack_del_top(&CG(object_stack));
+}
+
+
+void zend_do_begin_new_object(znode *new_token, znode *class_name CLS_DC)
+{
+ zend_op *opline = get_next_op(CG(active_op_array) CLS_CC);
+ unsigned char *ptr = NULL;
+
+ opline->opcode = ZEND_NEW;
+ opline->result.op_type = IS_VAR;
+ opline->result.u.var = get_temporary_variable(CG(active_op_array));
+ opline->op1 = *class_name;
+ SET_UNUSED(opline->op2);
+
+ new_token->u.opline_num = get_next_op_number(CG(active_op_array));
+ opline = get_next_op(CG(active_op_array) CLS_CC);
+ opline->opcode = ZEND_JMP_NO_CTOR;
+ opline->op1 = (opline-1)->result;
+ SET_UNUSED(opline->op2);
+
+ if (class_name->op_type == IS_CONST) {
+ zval_copy_ctor(&class_name->u.constant);
+ }
+ opline = get_next_op(CG(active_op_array) CLS_CC);
+ opline->opcode = ZEND_INIT_FCALL_BY_NAME;
+ opline->op1 = (opline-2)->result;
+ opline->op2 = *class_name;
+ opline->extended_value = ZEND_MEMBER_FUNC_CALL | ZEND_CTOR_CALL;
+ zend_stack_push(&CG(function_call_stack), (void *) &ptr, sizeof(unsigned char *));
+}
+
+
+void zend_do_end_new_object(znode *result, znode *class_name, znode *new_token, znode *argument_list CLS_DC)
+{
+ znode ctor_result;
+
+ if (class_name->op_type == IS_CONST) {
+ zval_copy_ctor(&class_name->u.constant);
+ }
+ zend_do_end_function_call(class_name, &ctor_result, argument_list, 1, 0 CLS_CC);
+ zend_do_free(&ctor_result CLS_CC);
+
+ CG(active_op_array)->opcodes[new_token->u.opline_num].op2.u.opline_num = get_next_op_number(CG(active_op_array));
+ *result = CG(active_op_array)->opcodes[new_token->u.opline_num].op1;
+}
+
+
+void zend_do_fetch_constant(znode *result, znode *constant_name, int mode CLS_DC)
+{
+ switch (mode) {
+ case ZEND_CT:
+ *result = *constant_name;
+ result->u.constant.type = IS_CONSTANT;
+ break;
+ case ZEND_RT: {
+ zend_op *opline = get_next_op(CG(active_op_array) CLS_CC);
+
+ opline->opcode = ZEND_FETCH_CONSTANT;
+ opline->result.op_type = IS_TMP_VAR;
+ opline->result.u.var = get_temporary_variable(CG(active_op_array));
+ opline->op1 = *constant_name;
+ *result = opline->result;
+ SET_UNUSED(opline->op2);
+ }
+ break;
+ }
+}
+
+
+void zend_do_shell_exec(znode *result, znode *cmd CLS_DC)
+{
+ zend_op *opline = get_next_op(CG(active_op_array) CLS_CC);
+
+ switch (cmd->op_type) {
+ case IS_TMP_VAR:
+ opline->opcode = ZEND_SEND_VAL;
+ break;
+ default:
+ opline->opcode = ZEND_SEND_VAR;
+ break;
+ }
+ opline->op1 = *cmd;
+ opline->op2.u.opline_num = 0;
+ opline->extended_value = ZEND_DO_FCALL;
+ SET_UNUSED(opline->op2);
+
+ opline = get_next_op(CG(active_op_array) CLS_CC);
+ opline->opcode = ZEND_DO_FCALL;
+ opline->result.u.var = get_temporary_variable(CG(active_op_array));
+ opline->result.op_type = IS_VAR;
+ opline->op1.u.constant.value.str.val = estrndup("shell_exec",sizeof("shell_exec")-1);
+ opline->op1.u.constant.value.str.len = sizeof("shell_exec")-1;
+ INIT_PZVAL(&opline->op1.u.constant);
+ opline->op1.u.constant.type = IS_STRING;
+ opline->op1.op_type = IS_CONST;
+ opline->extended_value = 1;
+ SET_UNUSED(opline->op2);
+ *result = opline->result;
+}
+
+
+
+void zend_do_init_array(znode *result, znode *expr, znode *offset, int is_ref CLS_DC)
+{
+ zend_op *opline = get_next_op(CG(active_op_array) CLS_CC);
+
+ opline->opcode = ZEND_INIT_ARRAY;
+ opline->result.u.var = get_temporary_variable(CG(active_op_array));
+ opline->result.op_type = IS_TMP_VAR;
+ *result = opline->result;
+ if (expr) {
+ opline->op1 = *expr;
+ if (offset) {
+ opline->op2 = *offset;
+ } else {
+ SET_UNUSED(opline->op2);
+ }
+ } else {
+ SET_UNUSED(opline->op1);
+ SET_UNUSED(opline->op2);
+ }
+ opline->extended_value = is_ref;
+}
+
+
+void zend_do_add_array_element(znode *result, znode *expr, znode *offset, int is_ref CLS_DC)
+{
+ zend_op *opline = get_next_op(CG(active_op_array) CLS_CC);
+
+ opline->opcode = ZEND_ADD_ARRAY_ELEMENT;
+ opline->result = *result;
+ opline->op1 = *expr;
+ if (offset) {
+ opline->op2 = *offset;
+ } else {
+ SET_UNUSED(opline->op2);
+ }
+ opline->extended_value = is_ref;
+}
+
+
+
+void zend_do_add_static_array_element(znode *result, znode *offset, znode *expr)
+{
+ zval *element;
+
+ ALLOC_ZVAL(element);
+ *element = expr->u.constant;
+ if (offset) {
+ switch (offset->u.constant.type) {
+ case IS_STRING:
+ zend_hash_update(result->u.constant.value.ht, offset->u.constant.value.str.val, offset->u.constant.value.str.len+1, &element, sizeof(zval *), NULL);
+ zval_dtor(&offset->u.constant);
+ break;
+ case IS_LONG:
+ zend_hash_index_update(result->u.constant.value.ht, offset->u.constant.value.lval, &element, sizeof(zval *), NULL);
+ break;
+ }
+ } else {
+ zend_hash_next_index_insert(result->u.constant.value.ht, &element, sizeof(zval *), NULL);
+ }
+}
+
+
+void zend_do_add_list_element(znode *element CLS_DC)
+{
+ list_llist_element lle;
+
+ if (element) {
+ lle.var = *element;
+ zend_llist_copy(&lle.dimensions, &CG(dimension_llist));
+ zend_llist_prepend_element(&CG(list_llist), &lle);
+ }
+ (*((int *)CG(dimension_llist).tail->data))++;
+}
+
+
+void zend_do_new_list_begin(CLS_D)
+{
+ int current_dimension = 0;
+ zend_llist_add_element(&CG(dimension_llist), &current_dimension);
+}
+
+
+void zend_do_new_list_end(CLS_D)
+{
+ zend_llist_remove_tail(&CG(dimension_llist));
+ (*((int *)CG(dimension_llist).tail->data))++;
+}
+
+
+void zend_do_list_init(CLS_D)
+{
+ zend_llist_init(&CG(list_llist), sizeof(list_llist_element), NULL, 0);
+ zend_llist_init(&CG(dimension_llist), sizeof(int), NULL, 0);
+ zend_do_new_list_begin(CLS_C);
+}
+
+
+void zend_do_list_end(znode *result, znode *expr CLS_DC)
+{
+ zend_llist_element *le;
+ zend_llist_element *dimension;
+ zend_op *opline;
+ znode last_container;
+
+ le = CG(list_llist).head;
+ while (le) {
+ zend_llist *tmp_dimension_llist = &((list_llist_element *)le->data)->dimensions;
+ dimension = tmp_dimension_llist->head;
+ while (dimension) {
+ opline = get_next_op(CG(active_op_array) CLS_CC);
+ if (dimension == tmp_dimension_llist->head) { /* first */
+ last_container = *expr;
+ switch(expr->op_type) {
+ case IS_VAR:
+ opline->opcode = ZEND_FETCH_DIM_R;
+ break;
+ case IS_TMP_VAR:
+ opline->opcode = ZEND_FETCH_DIM_TMP_VAR;
+ break;
+ case IS_CONST: /* fetch_dim_tmp_var will handle this bogus fetch */
+ zval_copy_ctor(&expr->u.constant);
+ opline->opcode = ZEND_FETCH_DIM_TMP_VAR;
+ break;
+ }
+ } else {
+ opline->opcode = ZEND_FETCH_DIM_R;
+ }
+ opline->result.op_type = IS_VAR;
+ opline->result.u.EA.type = 0;
+ opline->result.u.var = get_temporary_variable(CG(active_op_array));
+ opline->op1 = last_container;
+ opline->op2.op_type = IS_CONST;
+ opline->op2.u.constant.type = IS_LONG;
+ opline->op2.u.constant.value.lval = *((int *) dimension->data);
+ INIT_PZVAL(&opline->op2.u.constant);
+ opline->extended_value = ZEND_FETCH_ADD_LOCK;
+ last_container = opline->result;
+ dimension = dimension->next;
+ }
+ ((list_llist_element *) le->data)->value = last_container;
+ zend_llist_destroy(&((list_llist_element *) le->data)->dimensions);
+ zend_do_end_variable_parse(BP_VAR_W, 0 CLS_CC);
+ zend_do_assign(result, &((list_llist_element *) le->data)->var, &((list_llist_element *) le->data)->value CLS_CC);
+ CG(active_op_array)->opcodes[CG(active_op_array)->last-1].result.u.EA.type |= EXT_TYPE_UNUSED;
+ le = le->next;
+ }
+ zend_llist_destroy(&CG(dimension_llist));
+ zend_llist_destroy(&CG(list_llist));
+ *result = *expr;
+}
+
+
+void zend_do_fetch_global_or_static_variable(znode *varname, znode *static_assignment, int fetch_type CLS_DC)
+{
+ zend_op *opline = get_next_op(CG(active_op_array) CLS_CC);
+ znode lval;
+ znode result;
+
+ if (fetch_type==ZEND_FETCH_STATIC && static_assignment) {
+ zval *tmp;
+
+ ALLOC_ZVAL(tmp);
+ convert_to_string(&varname->u.constant);
+ *tmp = static_assignment->u.constant;
+ if (!CG(active_op_array)->static_variables) {
+ ALLOC_HASHTABLE(CG(active_op_array)->static_variables);
+ zend_hash_init(CG(active_op_array)->static_variables, 2, NULL, ZVAL_PTR_DTOR, 0);
+ }
+ zend_hash_update(CG(active_op_array)->static_variables, varname->u.constant.value.str.val, varname->u.constant.value.str.len+1, &tmp, sizeof(zval *), NULL);
+ }
+
+
+ opline->opcode = ZEND_FETCH_W; /* the default mode must be Write, since fetch_simple_variable() is used to define function arguments */
+ opline->result.op_type = IS_VAR;
+ opline->result.u.EA.type = 0;
+ opline->result.u.var = get_temporary_variable(CG(active_op_array));
+ opline->op1 = *varname;
+ SET_UNUSED(opline->op2);
+ opline->op2.u.fetch_type = fetch_type;
+ result = opline->result;
+
+ if (varname->op_type == IS_CONST) {
+ zval_copy_ctor(&varname->u.constant);
+ }
+ fetch_simple_variable(&lval, varname, 0 CLS_CC); /* Relies on the fact that the default fetch is BP_VAR_W */
+
+ zend_do_assign_ref(NULL, &lval, &result CLS_CC);
+ CG(active_op_array)->opcodes[CG(active_op_array)->last-1].result.u.EA.type |= EXT_TYPE_UNUSED;
+}
+
+
+void zend_do_cast(znode *result, znode *expr, int type CLS_DC)
+{
+ zend_op *opline = get_next_op(CG(active_op_array) CLS_CC);
+
+ opline->opcode = ZEND_CAST;
+ opline->result.op_type = IS_TMP_VAR;
+ opline->result.u.var = get_temporary_variable(CG(active_op_array));
+ opline->op1 = *expr;
+ SET_UNUSED(opline->op2);
+ opline->extended_value = type;
+ *result = opline->result;
+}
+
+
+void zend_do_include_or_eval(int type, znode *result, znode *op1 CLS_DC)
+{
+ zend_do_extended_fcall_begin(CLS_C);
+ {
+ zend_op *opline = get_next_op(CG(active_op_array) CLS_CC);
+
+ opline->opcode = ZEND_INCLUDE_OR_EVAL;
+ opline->result.op_type = IS_VAR;
+ opline->result.u.var = get_temporary_variable(CG(active_op_array));
+ opline->op1 = *op1;
+ SET_UNUSED(opline->op2);
+ opline->op2.u.constant.value.lval = type;
+ *result = opline->result;
+ if (type==ZEND_REQUIRE) {
+ opline->result.u.EA.type |= EXT_TYPE_UNUSED;
+ }
+ }
+ zend_do_extended_fcall_end(CLS_C);
+}
+
+
+void zend_do_indirect_references(znode *result, znode *num_references, znode *variable CLS_DC)
+{
+ int i;
+
+ zend_do_end_variable_parse(BP_VAR_R, 0 CLS_CC);
+ for (i=1; i<num_references->u.constant.value.lval; i++) {
+ fetch_simple_variable_ex(result, variable, 0, ZEND_FETCH_R CLS_CC);
+ *variable = *result;
+ }
+ zend_do_begin_variable_parse(CLS_C);
+ fetch_simple_variable(result, variable, 1 CLS_CC);
+}
+
+
+void zend_do_unset(znode *variable CLS_DC)
+{
+ zend_op *last_op;
+
+ last_op = &CG(active_op_array)->opcodes[get_next_op_number(CG(active_op_array))-1];
+
+ switch (last_op->opcode) {
+ case ZEND_FETCH_UNSET:
+ last_op->opcode = ZEND_UNSET_VAR;
+ break;
+ case ZEND_FETCH_DIM_UNSET:
+ case ZEND_FETCH_OBJ_UNSET:
+ last_op->opcode = ZEND_UNSET_DIM_OBJ;
+ break;
+
+ }
+}
+
+
+void zend_do_isset_or_isempty(int type, znode *result, znode *variable CLS_DC)
+{
+ zend_op *opline;
+
+ zend_do_end_variable_parse(BP_VAR_IS, 0 CLS_CC);
+ opline = get_next_op(CG(active_op_array) CLS_CC);
+
+ opline->opcode = ZEND_ISSET_ISEMPTY;
+ opline->result.op_type = IS_TMP_VAR;
+ opline->result.u.var = get_temporary_variable(CG(active_op_array));
+ opline->op1 = *variable;
+ opline->op2.u.constant.value.lval = type;
+ SET_UNUSED(opline->op2);
+ *result = opline->result;
+}
+
+
+void zend_do_foreach_begin(znode *foreach_token, znode *array, znode *open_brackets_token, znode *as_token, int variable CLS_DC)
+{
+ zend_op *opline = get_next_op(CG(active_op_array) CLS_CC);
+
+ /* Preform array reset */
+ opline->opcode = ZEND_FE_RESET;
+ opline->result.op_type = IS_VAR;
+ opline->result.u.var = get_temporary_variable(CG(active_op_array));
+ opline->op1 = *array;
+ SET_UNUSED(opline->op2);
+ if (variable) {
+ opline->extended_value = 1;
+ } else {
+ opline->extended_value = 0;
+ }
+ *open_brackets_token = opline->result;
+
+ zend_stack_push(&CG(foreach_copy_stack), (void *) &opline->result, sizeof(znode));
+
+ /* save the location of the beginning of the loop (array fetching) */
+ foreach_token->u.opline_num = get_next_op_number(CG(active_op_array));
+
+ opline = get_next_op(CG(active_op_array) CLS_CC);
+ opline->opcode = ZEND_FE_FETCH;
+ opline->result.op_type = IS_TMP_VAR;
+ opline->result.u.var = get_temporary_variable(CG(active_op_array));
+ opline->op1 = *open_brackets_token;
+ SET_UNUSED(opline->op2);
+ *as_token = opline->result;
+}
+
+
+void zend_do_foreach_cont(znode *value, znode *key, znode *as_token CLS_DC)
+{
+ zend_op *opline = get_next_op(CG(active_op_array) CLS_CC);
+ znode result_value, result_key, dummy;
+
+ if (key->op_type != IS_UNUSED) {
+ znode *tmp;
+
+ /* switch between the key and value... */
+ tmp = key;
+ key = value;
+ value = tmp;
+ }
+
+ opline->opcode = ZEND_FETCH_DIM_TMP_VAR;
+ opline->result.op_type = IS_VAR;
+ opline->result.u.EA.type = 0;
+ opline->result.u.opline_num = get_temporary_variable(CG(active_op_array));
+ opline->op1 = *as_token;
+ opline->op2.op_type = IS_CONST;
+ opline->op2.u.constant.type = IS_LONG;
+ opline->op2.u.constant.value.lval = 0;
+ opline->extended_value = ZEND_FETCH_STANDARD; /* ignored in fetch_dim_tmp_var, but what the hell. */
+ result_value = opline->result;
+
+ if (key->op_type != IS_UNUSED) {
+ opline = get_next_op(CG(active_op_array) CLS_CC);
+ opline->opcode = ZEND_FETCH_DIM_TMP_VAR;
+ opline->result.op_type = IS_VAR;
+ opline->result.u.EA.type = 0;
+ opline->result.u.opline_num = get_temporary_variable(CG(active_op_array));
+ opline->op1 = *as_token;
+ opline->op2.op_type = IS_CONST;
+ opline->op2.u.constant.type = IS_LONG;
+ opline->op2.u.constant.value.lval = 1;
+ opline->extended_value = ZEND_FETCH_STANDARD; /* ignored in fetch_dim_tmp_var, but what the hell. */
+ result_key = opline->result;
+ }
+
+ zend_do_assign(&dummy, value, &result_value CLS_CC);
+ CG(active_op_array)->opcodes[CG(active_op_array)->last-1].result.u.EA.type |= EXT_TYPE_UNUSED;
+ if (key->op_type != IS_UNUSED) {
+ zend_do_assign(&dummy, key, &result_key CLS_CC);
+ CG(active_op_array)->opcodes[CG(active_op_array)->last-1].result.u.EA.type |= EXT_TYPE_UNUSED;
+ }
+ zend_do_free(as_token CLS_CC);
+
+ do_begin_loop(CLS_C);
+ INC_BPC(CG(active_op_array));
+}
+
+
+void zend_do_foreach_end(znode *foreach_token, znode *open_brackets_token CLS_DC)
+{
+ zend_op *opline = get_next_op(CG(active_op_array) CLS_CC);
+
+ opline->opcode = ZEND_JMP;
+ opline->op1.u.opline_num = foreach_token->u.opline_num;
+ SET_UNUSED(opline->op1);
+ SET_UNUSED(opline->op2);
+
+ CG(active_op_array)->opcodes[foreach_token->u.opline_num].op2.u.opline_num = get_next_op_number(CG(active_op_array));
+
+ do_end_loop(foreach_token->u.opline_num CLS_CC);
+
+ generate_free_foreach_copy(open_brackets_token CLS_CC);
+
+ zend_stack_del_top(&CG(foreach_copy_stack));
+
+ DEC_BPC(CG(active_op_array));
+}
+
+
+void zend_do_declare_begin(CLS_D)
+{
+ zend_stack_push(&CG(declare_stack), &CG(declarables), sizeof(zend_declarables));
+}
+
+
+void zend_do_declare_stmt(znode *var, znode *val CLS_DC)
+{
+ convert_to_string(&var->u.constant);
+
+ if (!zend_binary_strcasecmp(var->u.constant.value.str.val, var->u.constant.value.str.len, "ticks", sizeof("ticks")-1)) {
+ convert_to_long(&val->u.constant);
+ CG(declarables).ticks = val->u.constant;
+ }
+ zval_dtor(&var->u.constant);
+}
+
+
+void zend_do_declare_end(CLS_D)
+{
+ zend_declarables *declarables;
+
+ zend_stack_top(&CG(declare_stack), (void **) &declarables);
+ CG(declarables) = *declarables;
+}
+
+
+void zend_do_end_heredoc(CLS_D)
+{
+ int opline_num = get_next_op_number(CG(active_op_array))-1;
+ zend_op *opline = &CG(active_op_array)->opcodes[opline_num];
+
+ if (opline->opcode != ZEND_ADD_STRING) {
+ return;
+ }
+
+ opline->op2.u.constant.value.str.val[(opline->op2.u.constant.value.str.len--)-1] = 0;
+ if (opline->op2.u.constant.value.str.len>0) {
+ if (opline->op2.u.constant.value.str.val[opline->op2.u.constant.value.str.len-1]=='\r') {
+ opline->op2.u.constant.value.str.val[(opline->op2.u.constant.value.str.len--)-1] = 0;
+ }
+ }
+}
+
+
+void zend_do_exit(znode *result, znode *message CLS_DC)
+{
+ zend_op *opline = get_next_op(CG(active_op_array) CLS_CC);
+
+ opline->opcode = ZEND_EXIT;
+ opline->op1 = *message;
+ SET_UNUSED(opline->op2);
+
+ result->op_type = IS_CONST;
+ result->u.constant.type = IS_BOOL;
+ result->u.constant.value.lval = 1;
+}
+
+
+void zend_do_begin_silence(znode *strudel_token CLS_DC)
+{
+ zend_op *opline = get_next_op(CG(active_op_array) CLS_CC);
+
+ opline->opcode = ZEND_BEGIN_SILENCE;
+ opline->result.op_type = IS_TMP_VAR;
+ opline->result.u.var = get_temporary_variable(CG(active_op_array));
+ SET_UNUSED(opline->op1);
+ SET_UNUSED(opline->op2);
+ *strudel_token = opline->result;
+}
+
+
+void zend_do_end_silence(znode *strudel_token CLS_DC)
+{
+ zend_op *opline = get_next_op(CG(active_op_array) CLS_CC);
+
+ opline->opcode = ZEND_END_SILENCE;
+ opline->op1 = *strudel_token;
+ SET_UNUSED(opline->op2);
+}
+
+
+void zend_do_begin_qm_op(znode *cond, znode *qm_token CLS_DC)
+{
+ int jmpz_op_number = get_next_op_number(CG(active_op_array));
+ zend_op *opline;
+
+ opline = get_next_op(CG(active_op_array) CLS_CC);
+
+ opline->opcode = ZEND_JMPZ;
+ opline->op1 = *cond;
+ SET_UNUSED(opline->op2);
+ opline->op2.u.opline_num = jmpz_op_number;
+ *qm_token = opline->op2;
+
+ INC_BPC(CG(active_op_array));
+}
+
+
+void zend_do_qm_true(znode *true_value, znode *qm_token, znode *colon_token CLS_DC)
+{
+ zend_op *opline = get_next_op(CG(active_op_array) CLS_CC);
+
+ CG(active_op_array)->opcodes[qm_token->u.opline_num].op2.u.opline_num = get_next_op_number(CG(active_op_array))+1; /* jmp over the ZEND_JMP */
+
+ opline->opcode = ZEND_QM_ASSIGN;
+ opline->result.op_type = IS_TMP_VAR;
+ opline->result.u.var = get_temporary_variable(CG(active_op_array));
+ opline->op1 = *true_value;
+ SET_UNUSED(opline->op2);
+
+ *qm_token = opline->result;
+ colon_token->u.opline_num = get_next_op_number(CG(active_op_array));
+
+ opline = get_next_op(CG(active_op_array) CLS_CC);
+ opline->opcode = ZEND_JMP;
+ SET_UNUSED(opline->op1);
+ SET_UNUSED(opline->op2);
+}
+
+
+void zend_do_qm_false(znode *result, znode *false_value, znode *qm_token, znode *colon_token CLS_DC)
+{
+ zend_op *opline = get_next_op(CG(active_op_array) CLS_CC);
+
+ opline->opcode = ZEND_QM_ASSIGN;
+ opline->result = *qm_token;
+ opline->op1 = *false_value;
+ SET_UNUSED(opline->op2);
+
+ CG(active_op_array)->opcodes[colon_token->u.opline_num].op1.u.opline_num = get_next_op_number(CG(active_op_array));
+
+ *result = opline->result;
+
+ DEC_BPC(CG(active_op_array));
+}
+
+
+void zend_do_extended_info(CLS_D)
+{
+ zend_op *opline;
+
+ if (!CG(extended_info)) {
+ return;
+ }
+
+ opline = get_next_op(CG(active_op_array) CLS_CC);
+
+ opline->opcode = ZEND_EXT_STMT;
+ SET_UNUSED(opline->op1);
+ SET_UNUSED(opline->op2);
+}
+
+
+void zend_do_extended_fcall_begin(CLS_D)
+{
+ zend_op *opline;
+
+ if (!CG(extended_info)) {
+ return;
+ }
+
+ opline = get_next_op(CG(active_op_array) CLS_CC);
+
+ opline->opcode = ZEND_EXT_FCALL_BEGIN;
+ SET_UNUSED(opline->op1);
+ SET_UNUSED(opline->op2);
+}
+
+
+void zend_do_extended_fcall_end(CLS_D)
+{
+ zend_op *opline;
+
+ if (!CG(extended_info)) {
+ return;
+ }
+
+ opline = get_next_op(CG(active_op_array) CLS_CC);
+
+ opline->opcode = ZEND_EXT_FCALL_END;
+ SET_UNUSED(opline->op1);
+ SET_UNUSED(opline->op2);
+}
+
+void zend_do_ticks(CLS_D)
+{
+ if (CG(declarables).ticks.value.lval) {
+ zend_op *opline = get_next_op(CG(active_op_array) CLS_CC);
+
+ opline->opcode = ZEND_TICKS;
+ opline->op1.u.constant = CG(declarables).ticks;
+ opline->op1.op_type = IS_CONST;
+ SET_UNUSED(opline->op2);
+ }
+}
+
+
+int zendlex(znode *zendlval CLS_DC)
+{
+ int retval;
+
+ zendlval->u.constant.type = IS_LONG;
+ retval = lex_scan(&zendlval->u.constant CLS_CC);
+ switch(retval) {
+ case T_COMMENT:
+ case T_OPEN_TAG:
+ case T_WHITESPACE:
+ retval = zendlex(zendlval CLS_CC);
+ break;
+ case T_CLOSE_TAG:
+ retval = ';'; /* implicit ; */
+ break;
+ case T_OPEN_TAG_WITH_ECHO:
+ retval = T_ECHO;
+ break;
+ case T_END_HEREDOC:
+ efree(zendlval->u.constant.value.str.val);
+ break;
+ }
+
+ INIT_PZVAL(&zendlval->u.constant);
+ zendlval->op_type = IS_CONST;
+ return retval;
+}
diff --git a/Zend/zend_execute.h b/Zend/zend_execute.h
new file mode 100644
index 0000000000..68ca747b76
--- /dev/null
+++ b/Zend/zend_execute.h
@@ -0,0 +1,213 @@
+/*
+ +----------------------------------------------------------------------+
+ | Zend Engine |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1998-2000 Zend Technologies Ltd. (http://www.zend.com) |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 0.92 of the Zend license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available at through the world-wide-web at |
+ | http://www.zend.com/license/0_92.txt. |
+ | If you did not receive a copy of the Zend license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@zend.com so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Andi Gutmans <andi@zend.com> |
+ | Zeev Suraski <zeev@zend.com> |
+ +----------------------------------------------------------------------+
+*/
+
+
+#ifndef ZEND_EXECUTE_H
+#define ZEND_EXECUTE_H
+
+#include "zend_compile.h"
+#include "zend_hash.h"
+#include "zend_variables.h"
+#include "zend_execute_locks.h"
+
+typedef union _temp_variable {
+ zval tmp_var;
+ struct {
+ zval **ptr_ptr;
+ zval *ptr;
+ } var;
+ struct {
+ zval tmp_var; /* a dummy */
+
+ union {
+ struct {
+ zval *str;
+ int offset;
+ } str_offset;
+ zend_property_reference overloaded_element;
+ } data;
+
+ unsigned char type;
+ } EA;
+} temp_variable;
+
+
+ZEND_API extern void (*zend_execute)(zend_op_array *op_array ELS_DC);
+
+void init_executor(CLS_D ELS_DC);
+void shutdown_executor(ELS_D);
+void execute(zend_op_array *op_array ELS_DC);
+ZEND_API int zend_is_true(zval *op);
+static inline void safe_free_zval_ptr(zval *p)
+{
+ ELS_FETCH();
+
+ if (p!=EG(uninitialized_zval_ptr)) {
+ FREE_ZVAL(p);
+ }
+}
+
+ZEND_API int zend_eval_string(char *str, zval *retval_ptr, char *string_name CLS_DC ELS_DC);
+static inline int i_zend_is_true(zval *op)
+{
+ int result;
+
+ switch (op->type) {
+ case IS_NULL:
+ result = 0;
+ break;
+ case IS_LONG:
+ case IS_BOOL:
+ case IS_RESOURCE:
+ result = (op->value.lval?1:0);
+ break;
+ case IS_DOUBLE:
+ result = (op->value.dval ? 1 : 0);
+ break;
+ case IS_STRING:
+ if (op->value.str.len == 0
+ || (op->value.str.len==1 && op->value.str.val[0]=='0')) {
+ result = 0;
+ } else {
+ result = 1;
+ }
+ break;
+ case IS_ARRAY:
+ result = (zend_hash_num_elements(op->value.ht)?1:0);
+ break;
+ case IS_OBJECT:
+ result = (zend_hash_num_elements(op->value.obj.properties)?1:0);
+ break;
+ default:
+ result = 0;
+ break;
+ }
+ return result;
+}
+
+ZEND_API int zval_update_constant(zval **pp, void *arg);
+
+/* dedicated Zend executor functions - do not use! */
+static inline void zend_ptr_stack_clear_multiple(ELS_D)
+{
+ void **p = EG(argument_stack).top_element-2;
+ int delete_count = (ulong) *p;
+
+ EG(argument_stack).top -= (delete_count+2);
+ while (--delete_count>=0) {
+ zval_ptr_dtor((zval **) --p);
+ }
+ EG(argument_stack).top_element = p;
+}
+
+static inline int zend_ptr_stack_get_arg(int requested_arg, void **data ELS_DC)
+{
+ void **p = EG(argument_stack).top_element-2;
+ int arg_count = (ulong) *p;
+
+ if (requested_arg>arg_count) {
+ return FAILURE;
+ }
+ *data = (p-arg_count+requested_arg-1);
+ return SUCCESS;
+}
+
+#if SUPPORT_INTERACTIVE
+void execute_new_code(CLS_D);
+#endif
+
+
+/* services */
+ZEND_API char *get_active_function_name(void);
+ZEND_API char *zend_get_executed_filename(ELS_D);
+ZEND_API uint zend_get_executed_lineno(ELS_D);
+ZEND_API zend_bool zend_is_executing(void);
+
+void zend_set_timeout(long seconds);
+void zend_unset_timeout(void);
+ZEND_API void zend_timeout(int dummy);
+
+#ifdef ZEND_WIN32
+void zend_init_timeout_thread();
+void zend_shutdown_timeout_thread();
+#define WM_REGISTER_ZEND_TIMEOUT (WM_USER+1)
+#define WM_UNREGISTER_ZEND_TIMEOUT (WM_USER+2)
+#endif
+
+#define zendi_zval_copy_ctor(p) zval_copy_ctor(&(p))
+#define zendi_zval_dtor(p) zval_dtor(&(p))
+
+#define active_opline (*EG(opline_ptr))
+
+static inline void zend_assign_to_variable_reference(znode *result, zval **variable_ptr_ptr, zval **value_ptr_ptr, temp_variable *Ts ELS_DC)
+{
+ zval *variable_ptr;
+ zval *value_ptr;
+
+ if (!value_ptr_ptr || !variable_ptr_ptr) {
+ zend_error(E_ERROR, "Cannot create references to/from string offsets nor overloaded objects");
+ return;
+ }
+
+ variable_ptr = *variable_ptr_ptr;
+ value_ptr = *value_ptr_ptr;
+
+ if (variable_ptr == EG(error_zval_ptr) || value_ptr==EG(error_zval_ptr)) {
+ variable_ptr_ptr = &EG(uninitialized_zval_ptr);
+/* } else if (variable_ptr==&EG(uninitialized_zval) || variable_ptr!=value_ptr) { */
+ } else if (variable_ptr_ptr != value_ptr_ptr) {
+ variable_ptr->refcount--;
+ if (variable_ptr->refcount==0) {
+ zendi_zval_dtor(*variable_ptr);
+ FREE_ZVAL(variable_ptr);
+ }
+
+ if (!PZVAL_IS_REF(value_ptr)) {
+ /* break it away */
+ value_ptr->refcount--;
+ if (value_ptr->refcount>0) {
+ ALLOC_ZVAL(*value_ptr_ptr);
+ **value_ptr_ptr = *value_ptr;
+ value_ptr = *value_ptr_ptr;
+ zendi_zval_copy_ctor(*value_ptr);
+ }
+ value_ptr->refcount = 1;
+ value_ptr->is_ref = 1;
+ }
+
+ *variable_ptr_ptr = value_ptr;
+ value_ptr->refcount++;
+ } else {
+ if (variable_ptr->refcount>1) { /* we need to break away */
+ SEPARATE_ZVAL(variable_ptr_ptr);
+ }
+ (*variable_ptr_ptr)->is_ref = 1;
+ }
+
+ if (result && !(result->u.EA.type & EXT_TYPE_UNUSED)) {
+ Ts[result->u.var].var.ptr_ptr = variable_ptr_ptr;
+ SELECTIVE_PZVAL_LOCK(*variable_ptr_ptr, result);
+ AI_USE_PTR(Ts[result->u.var].var);
+ }
+}
+
+#define IS_OVERLOADED_OBJECT 1
+#define IS_STRING_OFFSET 2
+
+#endif /* ZEND_EXECUTE_H */
diff --git a/Zend/zend_execute_API.c b/Zend/zend_execute_API.c
new file mode 100644
index 0000000000..9834499195
--- /dev/null
+++ b/Zend/zend_execute_API.c
@@ -0,0 +1,708 @@
+/*
+ +----------------------------------------------------------------------+
+ | Zend Engine |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1998-2000 Zend Technologies Ltd. (http://www.zend.com) |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 0.92 of the Zend license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available at through the world-wide-web at |
+ | http://www.zend.com/license/0_92.txt. |
+ | If you did not receive a copy of the Zend license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@zend.com so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Andi Gutmans <andi@zend.com> |
+ | Zeev Suraski <zeev@zend.com> |
+ +----------------------------------------------------------------------+
+*/
+
+
+#include <stdio.h>
+#include <signal.h>
+
+#include "zend.h"
+#include "zend_compile.h"
+#include "zend_execute.h"
+#include "zend_API.h"
+#include "zend_ptr_stack.h"
+#include "zend_constants.h"
+#include "zend_extensions.h"
+#include "zend_execute_locks.h"
+#if HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+
+
+ZEND_API void (*zend_execute)(zend_op_array *op_array ELS_DC);
+
+#ifdef ZEND_WIN32
+#include <process.h>
+/* true global */
+static WNDCLASS wc;
+static HWND timeout_window;
+static HANDLE timeout_thread_event;
+static DWORD timeout_thread_id;
+static int timeout_thread_initialized=0;
+#endif
+
+
+#if ZEND_DEBUG
+static void (*original_sigsegv_handler)(int);
+static void zend_handle_sigsegv(int dummy)
+{
+ fflush(stdout);
+ fflush(stderr);
+ if (original_sigsegv_handler==zend_handle_sigsegv) {
+ signal(SIGSEGV, original_sigsegv_handler);
+ } else {
+ signal(SIGSEGV, SIG_DFL);
+ }
+ {
+ ELS_FETCH();
+
+ fprintf(stderr, "SIGSEGV caught on opcode %d on opline %d of %s() at %s:%d\n\n",
+ active_opline->opcode,
+ active_opline-EG(active_op_array)->opcodes,
+ get_active_function_name(),
+ zend_get_executed_filename(ELS_C),
+ zend_get_executed_lineno(ELS_C));
+ }
+ if (original_sigsegv_handler!=zend_handle_sigsegv) {
+ original_sigsegv_handler(dummy);
+ }
+}
+#endif
+
+
+static void zend_extension_activator(zend_extension *extension)
+{
+ if (extension->activate) {
+ extension->activate();
+ }
+}
+
+
+static void zend_extension_deactivator(zend_extension *extension)
+{
+ if (extension->deactivate) {
+ extension->deactivate();
+ }
+}
+
+
+static int is_not_internal_function(zend_function *function)
+{
+ return(function->type != ZEND_INTERNAL_FUNCTION);
+}
+
+
+static int is_not_internal_class(zend_class_entry *ce)
+{
+ return(ce->type != ZEND_INTERNAL_CLASS);
+}
+
+
+void init_executor(CLS_D ELS_DC)
+{
+ INIT_ZVAL(EG(uninitialized_zval));
+ INIT_ZVAL(EG(error_zval));
+ EG(uninitialized_zval_ptr)=&EG(uninitialized_zval);
+ EG(error_zval_ptr)=&EG(error_zval);
+ zend_ptr_stack_init(&EG(arg_types_stack));
+/* destroys stack frame, therefore makes core dumps worthless */
+#if 0&&ZEND_DEBUG
+ original_sigsegv_handler = signal(SIGSEGV, zend_handle_sigsegv);
+#endif
+ EG(return_value_ptr_ptr) = &EG(global_return_value_ptr);
+ EG(global_return_value_ptr) = NULL;
+
+ EG(symtable_cache_ptr) = EG(symtable_cache)-1;
+ EG(symtable_cache_limit)=EG(symtable_cache)+SYMTABLE_CACHE_SIZE-1;
+ EG(no_extensions)=0;
+
+ EG(function_table) = CG(function_table);
+ EG(class_table) = CG(class_table);
+
+ EG(in_execution) = 0;
+
+ zend_ptr_stack_init(&EG(argument_stack));
+
+ zend_hash_init(&EG(symbol_table), 50, NULL, ZVAL_PTR_DTOR, 0);
+ EG(active_symbol_table) = &EG(symbol_table);
+
+ zend_llist_apply(&zend_extensions, (void (*)(void *)) zend_extension_activator);
+ EG(opline_ptr) = NULL;
+ EG(garbage_ptr) = 0;
+
+ zend_hash_init(&EG(included_files), 5, NULL, NULL, 0);
+
+ EG(ticks_count) = 0;
+
+ EG(user_error_handler) = NULL;
+
+ zend_ptr_stack_init(&EG(user_error_handlers));
+
+ EG(orig_error_reporting) = EG(error_reporting);
+
+#ifdef ZEND_WIN32
+ EG(timed_out) = 0;
+#endif
+}
+
+
+void shutdown_executor(ELS_D)
+{
+ zend_ptr_stack_destroy(&EG(arg_types_stack));
+
+ while (EG(symtable_cache_ptr)>=EG(symtable_cache)) {
+ zend_hash_destroy(*EG(symtable_cache_ptr));
+ efree(*EG(symtable_cache_ptr));
+ EG(symtable_cache_ptr)--;
+ }
+ zend_llist_apply(&zend_extensions, (void (*)(void *)) zend_extension_deactivator);
+
+ zend_hash_destroy(&EG(symbol_table));
+
+ while (EG(garbage_ptr)--) {
+ if (EG(garbage)[EG(garbage_ptr)]->refcount==1) {
+ zval_ptr_dtor(&EG(garbage)[EG(garbage_ptr)]);
+ }
+ }
+
+ zend_ptr_stack_destroy(&EG(argument_stack));
+
+ /* Destroy all op arrays */
+ zend_hash_apply(EG(function_table), (int (*)(void *)) is_not_internal_function);
+ zend_hash_apply(EG(class_table), (int (*)(void *)) is_not_internal_class);
+
+ zend_destroy_rsrc_list(ELS_C); /* must be destroyed after the main symbol table and
+ * op arrays are destroyed.
+ */
+
+ clean_non_persistent_constants();
+#if ZEND_DEBUG
+ signal(SIGSEGV, original_sigsegv_handler);
+#endif
+
+ zend_hash_destroy(&EG(included_files));
+
+ if (EG(user_error_handler)) {
+ zval_dtor(EG(user_error_handler));
+ FREE_ZVAL(EG(user_error_handler));
+ }
+
+ zend_ptr_stack_clean(&EG(user_error_handlers), ZVAL_DESTRUCTOR, 1);
+ zend_ptr_stack_destroy(&EG(user_error_handlers));
+
+ EG(error_reporting) = EG(orig_error_reporting);
+}
+
+
+ZEND_API char *get_active_function_name()
+{
+ ELS_FETCH();
+
+ switch(EG(function_state_ptr)->function->type) {
+ case ZEND_USER_FUNCTION: {
+ char *function_name = ((zend_op_array *) EG(function_state_ptr)->function)->function_name;
+
+ if (function_name) {
+ return function_name;
+ } else {
+ return "main";
+ }
+ }
+ break;
+ case ZEND_INTERNAL_FUNCTION:
+ return ((zend_internal_function *) EG(function_state_ptr)->function)->function_name;
+ break;
+ default:
+ return NULL;
+ }
+}
+
+
+ZEND_API char *zend_get_executed_filename(ELS_D)
+{
+ if (EG(active_op_array)) {
+ return EG(active_op_array)->filename;
+ } else {
+ return "[no active file]";
+ }
+}
+
+
+ZEND_API uint zend_get_executed_lineno(ELS_D)
+{
+ if (EG(opline_ptr)) {
+ return active_opline->lineno;
+ } else {
+ return 0;
+ }
+}
+
+
+ZEND_API zend_bool zend_is_executing()
+{
+ ELS_FETCH();
+
+ return EG(in_execution);
+}
+
+
+ZEND_API void _zval_ptr_dtor(zval **zval_ptr ZEND_FILE_LINE_DC)
+{
+#if DEBUG_ZEND>=2
+ printf("Reducing refcount for %x (%x): %d->%d\n", *zval_ptr, zval_ptr, (*zval_ptr)->refcount, (*zval_ptr)->refcount-1);
+#endif
+ (*zval_ptr)->refcount--;
+ if ((*zval_ptr)->refcount==0) {
+ zval_dtor(*zval_ptr);
+ safe_free_zval_ptr(*zval_ptr);
+ } else if (((*zval_ptr)->refcount == 1) && ((*zval_ptr)->type != IS_OBJECT)) {
+ (*zval_ptr)->is_ref = 0;
+ }
+}
+
+
+ZEND_API int zend_is_true(zval *op)
+{
+ return i_zend_is_true(op);
+}
+
+
+ZEND_API int zval_update_constant(zval **pp, void *arg)
+{
+ zval *p = *pp;
+ zend_bool inline_change = (zend_bool) (unsigned long) arg;
+
+ if (p->type == IS_CONSTANT) {
+ zval c;
+ int refcount;
+
+ SEPARATE_ZVAL(pp);
+ p = *pp;
+
+ refcount = p->refcount;
+
+ if (!zend_get_constant(p->value.str.val, p->value.str.len, &c)) {
+ zend_error(E_NOTICE, "Use of undefined constant %s - assumed '%s'",
+ p->value.str.val,
+ p->value.str.val);
+ p->type = IS_STRING;
+ if (!inline_change) {
+ zval_copy_ctor(p);
+ }
+ } else {
+ if (inline_change) {
+ STR_FREE(p->value.str.val);
+ }
+ *p = c;
+ }
+ INIT_PZVAL(p);
+ p->refcount = refcount;
+ } else if (p->type == IS_CONSTANT_ARRAY) {
+ SEPARATE_ZVAL(pp);
+ p = *pp;
+ p->type = IS_ARRAY;
+ zend_hash_apply_with_argument(p->value.ht, (int (*)(void *,void *)) zval_update_constant, (void *) 1);
+ }
+ return 0;
+}
+
+
+int call_user_function(HashTable *function_table, zval *object, zval *function_name, zval *retval_ptr, int param_count, zval *params[])
+{
+ zval ***params_array = (zval ***) emalloc(sizeof(zval **)*param_count);
+ int i;
+ int ex_retval;
+ zval *local_retval_ptr;
+
+ for (i=0; i<param_count; i++) {
+ params_array[i] = &params[i];
+ }
+ ex_retval = call_user_function_ex(function_table, object, function_name, &local_retval_ptr, param_count, params_array, 1, NULL);
+ if (local_retval_ptr) {
+ COPY_PZVAL_TO_ZVAL(*retval_ptr, local_retval_ptr);
+ } else {
+ INIT_ZVAL(*retval_ptr);
+ }
+ efree(params_array);
+ return ex_retval;
+}
+
+
+int call_user_function_ex(HashTable *function_table, zval *object, zval *function_name, zval **retval_ptr_ptr, int param_count, zval **params[], int no_separation, HashTable *symbol_table)
+{
+ int i;
+ zval **original_return_value;
+ HashTable *calling_symbol_table;
+ zend_function_state function_state;
+ zend_function_state *original_function_state_ptr;
+ zend_op_array *original_op_array;
+ zend_op **original_opline_ptr;
+ ELS_FETCH();
+
+ *retval_ptr_ptr = NULL;
+
+ if (function_name->type==IS_ARRAY) { /* assume array($obj, $name) couple */
+ zval **tmp_object_ptr, **tmp_real_function_name;
+
+ if (zend_hash_index_find(function_name->value.ht, 0, (void **) &tmp_object_ptr)==FAILURE) {
+ return FAILURE;
+ }
+ if (zend_hash_index_find(function_name->value.ht, 1, (void **) &tmp_real_function_name)==FAILURE) {
+ return FAILURE;
+ }
+ function_name = *tmp_real_function_name;
+ SEPARATE_ZVAL_IF_NOT_REF(tmp_object_ptr);
+ object = *tmp_object_ptr;
+ object->is_ref = 1;
+ }
+
+ if (object) {
+ if (object->type != IS_OBJECT) {
+ return FAILURE;
+ }
+ function_table = &object->value.obj.ce->function_table;
+ }
+
+ if (function_name->type!=IS_STRING) {
+ return FAILURE;
+ }
+
+ original_function_state_ptr = EG(function_state_ptr);
+ zend_str_tolower(function_name->value.str.val, function_name->value.str.len);
+ if (zend_hash_find(function_table, function_name->value.str.val, function_name->value.str.len+1, (void **) &function_state.function)==FAILURE) {
+ return FAILURE;
+ }
+
+ for (i=0; i<param_count; i++) {
+ zval *param;
+
+ if (function_state.function->common.arg_types
+ && i<function_state.function->common.arg_types[0]
+ && function_state.function->common.arg_types[i+1]==BYREF_FORCE
+ && !PZVAL_IS_REF(*params[i])) {
+ if ((*params[i])->refcount>1) {
+ zval *new_zval;
+
+ if (no_separation) {
+ return FAILURE;
+ }
+ ALLOC_ZVAL(new_zval);
+ *new_zval = **params[i];
+ zval_copy_ctor(new_zval);
+ new_zval->refcount = 1;
+ (*params[i])->refcount--;
+ *params[i] = new_zval;
+ }
+ (*params[i])->refcount++;
+ (*params[i])->is_ref = 1;
+ param = *params[i];
+ } else if (*params[i] != &EG(uninitialized_zval)) {
+ (*params[i])->refcount++;
+ param = *params[i];
+ } else {
+ ALLOC_ZVAL(param);
+ *param = **(params[i]);
+ INIT_PZVAL(param);
+ }
+ zend_ptr_stack_push(&EG(argument_stack), param);
+ }
+
+ zend_ptr_stack_n_push(&EG(argument_stack), 2, (void *) (long) param_count, NULL);
+
+ if (function_state.function->type == ZEND_USER_FUNCTION) {
+ calling_symbol_table = EG(active_symbol_table);
+ if (symbol_table) {
+ EG(active_symbol_table) = symbol_table;
+ } else {
+ ALLOC_HASHTABLE(EG(active_symbol_table));
+ zend_hash_init(EG(active_symbol_table), 0, NULL, ZVAL_PTR_DTOR, 0);
+ }
+ if (object) {
+ zval *dummy, **this_ptr;
+
+ ALLOC_ZVAL(dummy);
+ INIT_ZVAL(*dummy);
+
+ zend_hash_update(EG(active_symbol_table), "this", sizeof("this"), &dummy, sizeof(zval *), (void **) &this_ptr);
+ zend_assign_to_variable_reference(NULL, this_ptr, &object, NULL ELS_CC);
+ }
+ original_return_value = EG(return_value_ptr_ptr);
+ original_op_array = EG(active_op_array);
+ EG(return_value_ptr_ptr) = retval_ptr_ptr;
+ EG(active_op_array) = (zend_op_array *) function_state.function;
+ original_opline_ptr = EG(opline_ptr);
+ zend_execute(EG(active_op_array) ELS_CC);
+ if (!symbol_table) {
+ zend_hash_destroy(EG(active_symbol_table));
+ FREE_HASHTABLE(EG(active_symbol_table));
+ }
+ EG(active_symbol_table) = calling_symbol_table;
+ EG(active_op_array) = original_op_array;
+ EG(return_value_ptr_ptr)=original_return_value;
+ EG(opline_ptr) = original_opline_ptr;
+ } else {
+ ALLOC_INIT_ZVAL(*retval_ptr_ptr);
+ ((zend_internal_function *) function_state.function)->handler(param_count, *retval_ptr_ptr, object, 1 ELS_CC);
+ INIT_PZVAL(*retval_ptr_ptr);
+ }
+ zend_ptr_stack_clear_multiple(ELS_C);
+ EG(function_state_ptr) = original_function_state_ptr;
+
+ return SUCCESS;
+}
+
+
+ZEND_API int zend_eval_string(char *str, zval *retval_ptr, char *string_name CLS_DC ELS_DC)
+{
+ zval pv;
+ zend_op_array *new_op_array;
+ zend_op_array *original_active_op_array = EG(active_op_array);
+ zend_function_state *original_function_state_ptr = EG(function_state_ptr);
+ int original_handle_op_arrays;
+ int retval;
+
+ if (retval_ptr) {
+ pv.value.str.len = strlen(str)+sizeof("return ;")-1;
+ pv.value.str.val = emalloc(pv.value.str.len+1);
+ strcpy(pv.value.str.val, "return ");
+ strcat(pv.value.str.val, str);
+ strcat(pv.value.str.val, " ;");
+ } else {
+ pv.value.str.len = strlen(str);
+ pv.value.str.val = estrndup(str, pv.value.str.len);
+ }
+ pv.type = IS_STRING;
+
+ /*printf("Evaluating '%s'\n", pv.value.str.val);*/
+
+ original_handle_op_arrays = CG(handle_op_arrays);
+ CG(handle_op_arrays) = 0;
+ new_op_array = compile_string(&pv, string_name CLS_CC);
+ CG(handle_op_arrays) = original_handle_op_arrays;
+
+ if (new_op_array) {
+ zval *local_retval_ptr=NULL;
+ zval **original_return_value_ptr_ptr = EG(return_value_ptr_ptr);
+ zend_op **original_opline_ptr = EG(opline_ptr);
+
+ EG(return_value_ptr_ptr) = &local_retval_ptr;
+ EG(active_op_array) = new_op_array;
+ EG(no_extensions)=1;
+
+ zend_execute(new_op_array ELS_CC);
+
+ if (local_retval_ptr) {
+ if (retval_ptr) {
+ COPY_PZVAL_TO_ZVAL(*retval_ptr, local_retval_ptr);
+ } else {
+ zval_ptr_dtor(&local_retval_ptr);
+ }
+ } else {
+ if (retval_ptr) {
+ INIT_ZVAL(*retval_ptr);
+ }
+ }
+
+ EG(no_extensions)=0;
+ EG(opline_ptr) = original_opline_ptr;
+ EG(active_op_array) = original_active_op_array;
+ EG(function_state_ptr) = original_function_state_ptr;
+ destroy_op_array(new_op_array);
+ efree(new_op_array);
+ EG(return_value_ptr_ptr) = original_return_value_ptr_ptr;
+ retval = SUCCESS;
+ } else {
+ retval = FAILURE;
+ }
+ zval_dtor(&pv);
+ return retval;
+}
+
+
+
+#if SUPPORT_INTERACTIVE
+void execute_new_code(CLS_D)
+{
+ ELS_FETCH();
+
+ if (!EG(interactive)
+ || CG(active_op_array)->backpatch_count>0
+ || CG(active_op_array)->function_name
+ || CG(active_op_array)->type!=ZEND_USER_FUNCTION) {
+ return;
+ }
+ CG(active_op_array)->start_op_number = CG(active_op_array)->last_executed_op_number;
+ CG(active_op_array)->end_op_number = CG(active_op_array)->last;
+ EG(active_op_array) = CG(active_op_array);
+ zend_execute(CG(active_op_array) ELS_CC);
+ zval_ptr_dtor(EG(return_value_ptr_ptr));
+ CG(active_op_array)->start_op_number = CG(active_op_array)->last_executed_op_number;
+}
+#endif
+
+
+ZEND_API void zend_timeout(int dummy)
+{
+ ELS_FETCH();
+
+ /* is there any point in this? we're terminating the request anyway...
+ PLS_FETCH();
+
+ PG(connection_status) |= PHP_CONNECTION_TIMEOUT;
+ */
+ zend_error(E_ERROR, "Maximum execution time of %d second%s exceeded",
+ EG(timeout_seconds), EG(timeout_seconds) == 1 ? "" : "s");
+}
+
+
+#ifdef ZEND_WIN32
+static LRESULT CALLBACK zend_timeout_WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ switch (message) {
+ case WM_DESTROY:
+ PostQuitMessage(0);
+ break;
+ case WM_REGISTER_ZEND_TIMEOUT:
+ /* wParam is the thread id pointer, lParam is the timeout amount in seconds */
+ if (lParam==0) {
+ KillTimer(timeout_window, wParam);
+ } else {
+ SetTimer(timeout_window, wParam, lParam*1000, NULL);
+ }
+ break;
+ case WM_UNREGISTER_ZEND_TIMEOUT:
+ /* wParam is the thread id pointer */
+ KillTimer(timeout_window, wParam);
+ break;
+ case WM_TIMER: {
+#ifdef ZTS
+ zend_executor_globals *executor_globals;
+
+ executor_globals = ts_resource_ex(executor_globals_id, &wParam);
+ if (!executor_globals) {
+ /* Thread died before receiving its timeout? */
+ break;
+ }
+#endif
+ KillTimer(timeout_window, wParam);
+ EG(timed_out) = 1;
+ }
+ break;
+ default:
+ return DefWindowProc(hWnd,message,wParam,lParam);
+ }
+ return 0;
+}
+
+
+
+static unsigned __stdcall timeout_thread_proc(void *pArgs)
+{
+ MSG message;
+
+ wc.style=0;
+ wc.lpfnWndProc = zend_timeout_WndProc;
+ wc.cbClsExtra=0;
+ wc.cbWndExtra=0;
+ wc.hInstance=NULL;
+ wc.hIcon=NULL;
+ wc.hCursor=NULL;
+ wc.hbrBackground=(HBRUSH)(COLOR_BACKGROUND + 5);
+ wc.lpszMenuName=NULL;
+ wc.lpszClassName = "Zend Timeout Window";
+ if(!RegisterClass(&wc)) {
+ return -1;
+ }
+ timeout_window = CreateWindow(wc.lpszClassName, wc.lpszClassName, 0, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, NULL, NULL);
+ SetEvent(timeout_thread_event);
+ while (GetMessage(&message, NULL, 0, 0)) {
+ SendMessage(timeout_window, message.message, message.wParam, message.lParam);
+ if (message.message == WM_QUIT) {
+ break;
+ }
+ }
+ DestroyWindow(timeout_window);
+ UnregisterClass(wc.lpszClassName, NULL);
+ return 0;
+}
+
+
+void zend_init_timeout_thread()
+{
+ timeout_thread_event = CreateEvent(NULL, FALSE, FALSE, NULL);
+ _beginthreadex(NULL, 0, timeout_thread_proc, NULL, 0, &timeout_thread_id);
+ WaitForSingleObject(timeout_thread_event, INFINITE);
+}
+
+
+void zend_shutdown_timeout_thread()
+{
+ if (!timeout_thread_initialized) {
+ return;
+ }
+ PostThreadMessage(timeout_thread_id, WM_QUIT, 0, 0);
+}
+
+#endif
+
+/* This one doesn't exists on QNX */
+#ifndef SIGPROF
+#define SIGPROF 27
+#endif
+
+void zend_set_timeout(long seconds)
+{
+ ELS_FETCH();
+
+ EG(timeout_seconds) = seconds;
+#ifdef ZEND_WIN32
+ if (timeout_thread_initialized==0 && InterlockedIncrement(&timeout_thread_initialized)==1) {
+ /* We start up this process-wide thread here and not in zend_startup(), because if Zend
+ * is initialized inside a DllMain(), you're not supposed to start threads from it.
+ */
+ zend_init_timeout_thread();
+ }
+ PostThreadMessage(timeout_thread_id, WM_REGISTER_ZEND_TIMEOUT, (WPARAM) GetCurrentThreadId(), (LPARAM) seconds);
+#else
+# ifdef HAVE_SETITIMER
+ {
+ struct itimerval t_r; /* timeout requested */
+ sigset_t sigset;
+
+ t_r.it_value.tv_sec = seconds;
+ t_r.it_value.tv_usec = t_r.it_interval.tv_sec = t_r.it_interval.tv_usec = 0;
+
+ setitimer(ITIMER_PROF, &t_r, NULL);
+ signal(SIGPROF, zend_timeout);
+ sigemptyset(&sigset);
+ sigaddset(&sigset, SIGPROF);
+ sigprocmask(SIG_UNBLOCK,&sigset,NULL);
+ }
+# endif
+#endif
+}
+
+
+void zend_unset_timeout(void)
+{
+ ELS_FETCH();
+
+#ifdef ZEND_WIN32
+ PostThreadMessage(timeout_thread_id, WM_UNREGISTER_ZEND_TIMEOUT, (WPARAM) GetCurrentThreadId(), (LPARAM) 0);
+#else
+# ifdef HAVE_SETITIMER
+ {
+ struct itimerval no_timeout;
+
+ no_timeout.it_value.tv_sec = no_timeout.it_value.tv_usec = no_timeout.it_interval.tv_sec = no_timeout.it_interval.tv_usec = 0;
+
+ setitimer(ITIMER_PROF, &no_timeout, NULL);
+ }
+# endif
+#endif
+}
diff --git a/Zend/zend_hash.c b/Zend/zend_hash.c
new file mode 100644
index 0000000000..4d258b7759
--- /dev/null
+++ b/Zend/zend_hash.c
@@ -0,0 +1,1278 @@
+/*
+ +----------------------------------------------------------------------+
+ | Zend Engine |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1998-2000 Zend Technologies Ltd. (http://www.zend.com) |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 0.92 of the Zend license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available at through the world-wide-web at |
+ | http://www.zend.com/license/0_92.txt. |
+ | If you did not receive a copy of the Zend license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@zend.com so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Andi Gutmans <andi@zend.com> |
+ | Zeev Suraski <zeev@zend.com> |
+ +----------------------------------------------------------------------+
+*/
+
+
+#include "zend.h"
+
+#include <stdio.h>
+
+#ifdef HAVE_STDLIB_H
+# include <stdlib.h>
+#endif
+
+#ifdef HAVE_LIMITS_H
+# include <limits.h>
+#endif
+
+#define HANDLE_NUMERIC(key, length, func) { \
+ register char *tmp=key; \
+ \
+ if ((*tmp>='0' && *tmp<='9')) do { /* possibly a numeric index */ \
+ char *end=tmp+length-1; \
+ ulong idx; \
+ \
+ if (*tmp++=='0' && length>2) { /* don't accept numbers with leading zeros */ \
+ break; \
+ } \
+ while (tmp<end) { \
+ if (!(*tmp>='0' && *tmp<='9')) { \
+ break; \
+ } \
+ tmp++; \
+ } \
+ if (tmp==end && *tmp=='\0') { /* a numeric index */ \
+ idx = strtol(key, NULL, 10); \
+ if (idx!=LONG_MAX) { \
+ return func; \
+ } \
+ } \
+ } while(0); \
+}
+
+
+#define CONNECT_TO_BUCKET_DLLIST(element, list_head) \
+ (element)->pNext = (list_head); \
+ (element)->pLast = NULL; \
+ if ((element)->pNext) { \
+ (element)->pNext->pLast = (element); \
+ }
+
+#define CONNECT_TO_GLOBAL_DLLIST(element, ht) \
+ (element)->pListLast = (ht)->pListTail; \
+ (ht)->pListTail = (element); \
+ (element)->pListNext = NULL; \
+ if ((element)->pListLast != NULL) { \
+ (element)->pListLast->pListNext = (element); \
+ } \
+ if (!(ht)->pListHead) { \
+ (ht)->pListHead = (element); \
+ } \
+ if ((ht)->pInternalPointer == NULL) { \
+ (ht)->pInternalPointer = (element); \
+ }
+
+#if ZEND_DEBUG
+#define HT_OK 0
+#define HT_IS_DESTROYING 1
+#define HT_DESTROYED 2
+#define HT_CLEANING 3
+
+static void _zend_is_inconsistent(HashTable *ht, char *file, int line)
+{
+ if (ht->inconsistent==HT_OK) {
+ return;
+ }
+ switch (ht->inconsistent) {
+ case HT_IS_DESTROYING:
+ zend_output_debug_string(1, "%s(%d) : ht=0x%08x is being destroyed", file, line, ht);
+ break;
+ case HT_DESTROYED:
+ zend_output_debug_string(1, "%s(%d) : ht=0x%08x is already destroyed", file, line, ht);
+ break;
+ case HT_CLEANING:
+ zend_output_debug_string(1, "%s(%d) : ht=0x%08x is being cleaned", file, line, ht);
+ break;
+ }
+ zend_bailout();
+}
+#define IS_CONSISTENT(a) _zend_is_inconsistent(a,__FILE__,__LINE__);
+#define SET_INCONSISTENT(n) ht->inconsistent = n;
+#else
+#define IS_CONSISTENT(a)
+#define SET_INCONSISTENT(n)
+#endif
+
+#define HASH_APPLY_BEGIN(ht) \
+ if ((ht)->bApplyProtection) { \
+ if ((ht)->nApplyCount>=3) { \
+ zend_error(E_WARNING, "Nesting level too deep - recursive dependency?"); \
+ return; \
+ } \
+ (ht)->nApplyCount++; \
+ }
+
+#define HASH_APPLY_END(ht) \
+ (ht)->nApplyCount--;
+
+
+/* Generated on an Octa-ALPHA 300MHz CPU & 2.5GB RAM monster */
+static uint PrimeNumbers[] =
+ {5, 11, 19, 53, 107, 223, 463, 983, 1979, 3907, 7963, 16229, 32531, 65407, 130987, 262237, 524521, 1048793, 2097397, 4194103, 8388857, 16777447, 33554201, 67108961, 134217487, 268435697, 536870683, 1073741621, 2147483399};
+static uint nNumPrimeNumbers = sizeof(PrimeNumbers) / sizeof(uint);
+
+#define ZEND_HASH_IF_FULL_DO_RESIZE(ht) \
+ if ((ht)->nNumOfElements > (ht)->nTableSize) { \
+ zend_hash_do_resize(ht); \
+ }
+
+static int zend_hash_do_resize(HashTable *ht);
+
+
+ZEND_API ulong hashpjw(char *arKey, uint nKeyLength)
+{
+ ulong h = 0, g;
+ char *arEnd=arKey+nKeyLength;
+
+ while (arKey < arEnd) {
+ h = (h << 4) + *arKey++;
+ if ((g = (h & 0xF0000000))) {
+ h = h ^ (g >> 24);
+ h = h ^ g;
+ }
+ }
+ return h;
+}
+
+
+#define UPDATE_DATA(ht, p, pData, nDataSize) \
+ if (nDataSize == sizeof(void*)) { \
+ if (!(p)->pDataPtr) { \
+ pefree((p)->pData, (ht)->persistent); \
+ } \
+ (p)->pDataPtr = *(void **)pData; \
+ (p)->pData = &(p)->pDataPtr; \
+ } else { \
+ if ((p)->pDataPtr) { \
+ (p)->pData = (void *) pemalloc(nDataSize, (ht)->persistent); \
+ (p)->pDataPtr=NULL; \
+ } \
+ memcpy((p)->pData, pData, nDataSize); \
+ }
+
+#define INIT_DATA(ht, p, pData, nDataSize); \
+ if (nDataSize == sizeof(void*)) { \
+ (p)->pDataPtr = *(void **)pData; \
+ (p)->pData = &(p)->pDataPtr; \
+ } else { \
+ (p)->pData = (void *) pemalloc(nDataSize, (ht)->persistent); \
+ if (!(p)->pData) { \
+ pefree(p, (ht)->persistent); \
+ return FAILURE; \
+ } \
+ memcpy((p)->pData, pData, nDataSize); \
+ (p)->pDataPtr=NULL; \
+ }
+
+
+ZEND_API int zend_hash_init(HashTable *ht, uint nSize, hash_func_t pHashFunction, dtor_func_t pDestructor, int persistent)
+{
+ uint i;
+
+ SET_INCONSISTENT(HT_OK);
+
+ for (i = 0; i < nNumPrimeNumbers; i++) {
+ if (nSize <= PrimeNumbers[i]) {
+ nSize = PrimeNumbers[i];
+ ht->nHashSizeIndex = i;
+ break;
+ }
+ }
+ if (i == nNumPrimeNumbers) { /* This shouldn't really happen unless the ask for a ridiculous size */
+ nSize = PrimeNumbers[i - 1];
+ ht->nHashSizeIndex = i - 1;
+ }
+
+ /* Uses ecalloc() so that Bucket* == NULL */
+ ht->arBuckets = (Bucket **) pecalloc(nSize, sizeof(Bucket *), persistent);
+
+ if (!ht->arBuckets) {
+ return FAILURE;
+ }
+ if (pHashFunction == NULL) {
+ ht->pHashFunction = hashpjw;
+ } else {
+ ht->pHashFunction = pHashFunction;
+ }
+ ht->pDestructor = pDestructor;
+ ht->nTableSize = nSize;
+ ht->pListHead = NULL;
+ ht->pListTail = NULL;
+ ht->nNumOfElements = 0;
+ ht->nNextFreeElement = 0;
+ ht->pInternalPointer = NULL;
+ ht->persistent = persistent;
+ ht->nApplyCount = 0;
+ ht->bApplyProtection = 1;
+ return SUCCESS;
+}
+
+
+ZEND_API int zend_hash_init_ex(HashTable *ht, uint nSize, hash_func_t pHashFunction, dtor_func_t pDestructor, int persistent, zend_bool bApplyProtection)
+{
+ int retval = zend_hash_init(ht, nSize, pHashFunction, pDestructor, persistent);
+
+ ht->bApplyProtection = bApplyProtection;
+ return retval;
+}
+
+
+ZEND_API void zend_hash_set_apply_protection(HashTable *ht, zend_bool bApplyProtection)
+{
+ ht->bApplyProtection = bApplyProtection;
+}
+
+
+
+ZEND_API int zend_hash_add_or_update(HashTable *ht, char *arKey, uint nKeyLength, void *pData, uint nDataSize, void **pDest, int flag)
+{
+ ulong h;
+ uint nIndex;
+ Bucket *p;
+
+ IS_CONSISTENT(ht);
+
+ if (nKeyLength <= 0) {
+#if ZEND_DEBUG
+ ZEND_PUTS("zend_hash_update: Can't put in empty key\n");
+#endif
+ return FAILURE;
+ }
+
+ HANDLE_NUMERIC(arKey, nKeyLength, zend_hash_index_update_or_next_insert(ht, idx, pData, nDataSize, pDest, flag));
+
+ h = ht->pHashFunction(arKey, nKeyLength);
+ nIndex = h % ht->nTableSize;
+
+ p = ht->arBuckets[nIndex];
+ while (p != NULL) {
+ if ((p->h == h) && (p->nKeyLength == nKeyLength)) {
+ if (!memcmp(p->arKey, arKey, nKeyLength)) {
+ if (flag & HASH_ADD) {
+ return FAILURE;
+ }
+ HANDLE_BLOCK_INTERRUPTIONS();
+#if ZEND_DEBUG
+ if (p->pData == pData) {
+ ZEND_PUTS("Fatal error in zend_hash_update: p->pData == pData\n");
+ HANDLE_UNBLOCK_INTERRUPTIONS();
+ return FAILURE;
+ }
+#endif
+ if (ht->pDestructor) {
+ ht->pDestructor(p->pData);
+ }
+ UPDATE_DATA(ht, p, pData, nDataSize);
+ if (pDest) {
+ *pDest = p->pData;
+ }
+ HANDLE_UNBLOCK_INTERRUPTIONS();
+ return SUCCESS;
+ }
+ }
+ p = p->pNext;
+ }
+
+ p = (Bucket *) pemalloc(sizeof(Bucket)-1+nKeyLength, ht->persistent);
+ if (!p) {
+ return FAILURE;
+ }
+ memcpy(p->arKey, arKey, nKeyLength);
+ p->nKeyLength = nKeyLength;
+ INIT_DATA(ht, p, pData, nDataSize);
+ p->h = h;
+ CONNECT_TO_BUCKET_DLLIST(p, ht->arBuckets[nIndex]);
+ if (pDest) {
+ *pDest = p->pData;
+ }
+
+ HANDLE_BLOCK_INTERRUPTIONS();
+ CONNECT_TO_GLOBAL_DLLIST(p, ht);
+ ht->arBuckets[nIndex] = p;
+ HANDLE_UNBLOCK_INTERRUPTIONS();
+
+ ht->nNumOfElements++;
+ ZEND_HASH_IF_FULL_DO_RESIZE(ht); /* If the Hash table is full, resize it */
+ return SUCCESS;
+}
+
+ZEND_API int zend_hash_quick_add_or_update(HashTable *ht, char *arKey, uint nKeyLength, ulong h, void *pData, uint nDataSize, void **pDest, int flag)
+{
+ uint nIndex;
+ Bucket *p;
+
+ IS_CONSISTENT(ht);
+
+ if (nKeyLength <= 0) {
+#if ZEND_DEBUG
+ ZEND_PUTS("zend_hash_update: Can't put in empty key\n");
+#endif
+ return FAILURE;
+ }
+
+ nIndex = h % ht->nTableSize;
+
+ p = ht->arBuckets[nIndex];
+ while (p != NULL) {
+ if ((p->h == h) && (p->nKeyLength == nKeyLength)) {
+ if (!memcmp(p->arKey, arKey, nKeyLength)) {
+ if (flag & HASH_ADD) {
+ return FAILURE;
+ }
+ HANDLE_BLOCK_INTERRUPTIONS();
+#if ZEND_DEBUG
+ if (p->pData == pData) {
+ ZEND_PUTS("Fatal error in zend_hash_update: p->pData == pData\n");
+ HANDLE_UNBLOCK_INTERRUPTIONS();
+ return FAILURE;
+ }
+#endif
+ if (ht->pDestructor) {
+ ht->pDestructor(p->pData);
+ }
+ UPDATE_DATA(ht, p, pData, nDataSize);
+ if (pDest) {
+ *pDest = p->pData;
+ }
+ HANDLE_UNBLOCK_INTERRUPTIONS();
+ return SUCCESS;
+ }
+ }
+ p = p->pNext;
+ }
+
+ p = (Bucket *) pemalloc(sizeof(Bucket)-1+nKeyLength, ht->persistent);
+ if (!p) {
+ return FAILURE;
+ }
+
+ memcpy(p->arKey, arKey, nKeyLength);
+ p->nKeyLength = nKeyLength;
+ INIT_DATA(ht, p, pData, nDataSize);
+ p->h = h;
+
+ CONNECT_TO_BUCKET_DLLIST(p, ht->arBuckets[nIndex]);
+
+ if (pDest) {
+ *pDest = p->pData;
+ }
+
+ HANDLE_BLOCK_INTERRUPTIONS();
+ ht->arBuckets[nIndex] = p;
+ CONNECT_TO_GLOBAL_DLLIST(p, ht);
+ HANDLE_UNBLOCK_INTERRUPTIONS();
+
+ ht->nNumOfElements++;
+ ZEND_HASH_IF_FULL_DO_RESIZE(ht); /* If the Hash table is full, resize it */
+ return SUCCESS;
+}
+
+
+ZEND_API int zend_hash_index_update_or_next_insert(HashTable *ht, ulong h, void *pData, uint nDataSize, void **pDest, int flag)
+{
+ uint nIndex;
+ Bucket *p;
+
+ IS_CONSISTENT(ht);
+
+ if (flag & HASH_NEXT_INSERT) {
+ h = ht->nNextFreeElement;
+ }
+ nIndex = h % ht->nTableSize;
+
+ p = ht->arBuckets[nIndex];
+ while (p != NULL) {
+ if ((p->nKeyLength == 0) && (p->h == h)) {
+ if (flag & HASH_NEXT_INSERT || flag & HASH_ADD) {
+ return FAILURE;
+ }
+ HANDLE_BLOCK_INTERRUPTIONS();
+#if ZEND_DEBUG
+ if (p->pData == pData) {
+ ZEND_PUTS("Fatal error in zend_hash_index_update: p->pData == pData\n");
+ HANDLE_UNBLOCK_INTERRUPTIONS();
+ return FAILURE;
+ }
+#endif
+ if (ht->pDestructor) {
+ ht->pDestructor(p->pData);
+ }
+ UPDATE_DATA(ht, p, pData, nDataSize);
+ HANDLE_UNBLOCK_INTERRUPTIONS();
+ if (h >= ht->nNextFreeElement) {
+ ht->nNextFreeElement = h + 1;
+ }
+ if (pDest) {
+ *pDest = p->pData;
+ }
+ return SUCCESS;
+ }
+ p = p->pNext;
+ }
+ p = (Bucket *) pemalloc(sizeof(Bucket)-1, ht->persistent);
+ if (!p) {
+ return FAILURE;
+ }
+ p->nKeyLength = 0; /* Numeric indices are marked by making the nKeyLength == 0 */
+ p->h = h;
+ INIT_DATA(ht, p, pData, nDataSize);
+ if (pDest) {
+ *pDest = p->pData;
+ }
+
+ CONNECT_TO_BUCKET_DLLIST(p, ht->arBuckets[nIndex]);
+
+ HANDLE_BLOCK_INTERRUPTIONS();
+ ht->arBuckets[nIndex] = p;
+ CONNECT_TO_GLOBAL_DLLIST(p, ht);
+ HANDLE_UNBLOCK_INTERRUPTIONS();
+
+ if (h >= ht->nNextFreeElement) {
+ ht->nNextFreeElement = h + 1;
+ }
+ ht->nNumOfElements++;
+ ZEND_HASH_IF_FULL_DO_RESIZE(ht);
+ return SUCCESS;
+}
+
+
+static int zend_hash_do_resize(HashTable *ht)
+{
+ Bucket **t;
+
+ IS_CONSISTENT(ht);
+
+ if ((ht->nHashSizeIndex < nNumPrimeNumbers - 1)) { /* Let's double the table size */
+ t = (Bucket **) perealloc_recoverable(ht->arBuckets, PrimeNumbers[ht->nHashSizeIndex + 1] * sizeof(Bucket *), ht->persistent);
+ if (t) {
+ HANDLE_BLOCK_INTERRUPTIONS();
+ ht->arBuckets = t;
+ ht->nTableSize = PrimeNumbers[ht->nHashSizeIndex + 1];
+ ht->nHashSizeIndex++;
+ zend_hash_rehash(ht);
+ HANDLE_UNBLOCK_INTERRUPTIONS();
+ return SUCCESS;
+ }
+ return FAILURE;
+ }
+ return SUCCESS;
+}
+
+ZEND_API int zend_hash_rehash(HashTable *ht)
+{
+ Bucket *p;
+ uint nIndex;
+
+ IS_CONSISTENT(ht);
+
+ memset(ht->arBuckets, 0, PrimeNumbers[ht->nHashSizeIndex] * sizeof(Bucket *));
+ p = ht->pListHead;
+ while (p != NULL) {
+ nIndex = p->h % ht->nTableSize;
+ CONNECT_TO_BUCKET_DLLIST(p, ht->arBuckets[nIndex]);
+ ht->arBuckets[nIndex] = p;
+ p = p->pListNext;
+ }
+ return SUCCESS;
+}
+
+ZEND_API int zend_hash_del_key_or_index(HashTable *ht, char *arKey, uint nKeyLength, ulong h, int flag)
+{
+ uint nIndex;
+ Bucket *p;
+
+ IS_CONSISTENT(ht);
+
+ if (flag == HASH_DEL_KEY) {
+ HANDLE_NUMERIC(arKey, nKeyLength, zend_hash_del_key_or_index(ht, arKey, nKeyLength, idx, HASH_DEL_INDEX));
+ h = ht->pHashFunction(arKey, nKeyLength);
+ }
+ nIndex = h % ht->nTableSize;
+
+ p = ht->arBuckets[nIndex];
+ while (p != NULL) {
+ if ((p->h == h) && ((p->nKeyLength == 0) || /* Numeric index */
+ ((p->nKeyLength == nKeyLength) && (!memcmp(p->arKey, arKey, nKeyLength))))) {
+ HANDLE_BLOCK_INTERRUPTIONS();
+ if (p == ht->arBuckets[nIndex]) {
+ ht->arBuckets[nIndex] = p->pNext;
+ } else {
+ p->pLast->pNext = p->pNext;
+ }
+ if (p->pNext) {
+ p->pNext->pLast = p->pLast;
+ }
+ if (p->pListLast != NULL) {
+ p->pListLast->pListNext = p->pListNext;
+ } else {
+ /* Deleting the head of the list */
+ ht->pListHead = p->pListNext;
+ }
+ if (p->pListNext != NULL) {
+ p->pListNext->pListLast = p->pListLast;
+ } else {
+ ht->pListTail = p->pListLast;
+ }
+ if (ht->pInternalPointer == p) {
+ ht->pInternalPointer = p->pListNext;
+ }
+ if (ht->pDestructor) {
+ ht->pDestructor(p->pData);
+ }
+ if (!p->pDataPtr) {
+ pefree(p->pData, ht->persistent);
+ }
+ pefree(p, ht->persistent);
+ HANDLE_UNBLOCK_INTERRUPTIONS();
+ ht->nNumOfElements--;
+ return SUCCESS;
+ }
+ p = p->pNext;
+ }
+ return FAILURE;
+}
+
+
+ZEND_API void zend_hash_destroy(HashTable *ht)
+{
+ Bucket *p, *q;
+
+ IS_CONSISTENT(ht);
+
+ SET_INCONSISTENT(HT_IS_DESTROYING);
+
+ p = ht->pListHead;
+ while (p != NULL) {
+ q = p;
+ p = p->pListNext;
+ if (ht->pDestructor) {
+ ht->pDestructor(q->pData);
+ }
+ if (!q->pDataPtr && q->pData) {
+ pefree(q->pData, ht->persistent);
+ }
+ pefree(q, ht->persistent);
+ }
+ pefree(ht->arBuckets, ht->persistent);
+
+ SET_INCONSISTENT(HT_DESTROYED);
+}
+
+
+ZEND_API void zend_hash_clean(HashTable *ht)
+{
+ Bucket *p, *q;
+
+ IS_CONSISTENT(ht);
+
+ SET_INCONSISTENT(HT_CLEANING);
+
+ p = ht->pListHead;
+ while (p != NULL) {
+ q = p;
+ p = p->pListNext;
+ if (ht->pDestructor) {
+ ht->pDestructor(q->pData);
+ }
+ if (!q->pDataPtr && q->pData) {
+ pefree(q->pData, ht->persistent);
+ }
+ pefree(q, ht->persistent);
+ }
+ memset(ht->arBuckets, 0, ht->nTableSize*sizeof(Bucket *));
+ ht->pListHead = NULL;
+ ht->pListTail = NULL;
+ ht->nNumOfElements = 0;
+ ht->nNextFreeElement = 0;
+ ht->pInternalPointer = NULL;
+
+ SET_INCONSISTENT(HT_OK);
+}
+
+/* This function is used by the various apply() functions.
+ * It deletes the passed bucket, and returns the address of the
+ * next bucket. The hash *may* be altered during that time, the
+ * returned value will still be valid.
+ */
+static Bucket *zend_hash_apply_deleter(HashTable *ht, Bucket *p)
+{
+ Bucket *retval;
+
+ HANDLE_BLOCK_INTERRUPTIONS();
+
+ if (ht->pDestructor) {
+ ht->pDestructor(p->pData);
+ }
+ if (!p->pDataPtr) {
+ pefree(p->pData, ht->persistent);
+ }
+ retval = p->pListNext;
+
+ if (p->pLast) {
+ p->pLast->pNext = p->pNext;
+ } else {
+ uint nIndex;
+
+ nIndex = p->h % ht->nTableSize;
+ ht->arBuckets[nIndex] = p->pNext;
+ }
+ if (p->pNext) {
+ p->pNext->pLast = p->pLast;
+ } else {
+ /* Nothing to do as this list doesn't have a tail */
+ }
+
+ if (p->pListLast != NULL) {
+ p->pListLast->pListNext = p->pListNext;
+ } else {
+ /* Deleting the head of the list */
+ ht->pListHead = p->pListNext;
+ }
+ if (p->pListNext != NULL) {
+ p->pListNext->pListLast = p->pListLast;
+ } else {
+ ht->pListTail = p->pListLast;
+ }
+ if (ht->pInternalPointer == p) {
+ ht->pInternalPointer = p->pListNext;
+ }
+ pefree(p, ht->persistent);
+ HANDLE_UNBLOCK_INTERRUPTIONS();
+ ht->nNumOfElements--;
+
+ return retval;
+}
+
+
+ZEND_API void zend_hash_graceful_destroy(HashTable *ht)
+{
+ Bucket *p;
+
+ IS_CONSISTENT(ht);
+
+ p = ht->pListHead;
+ while (p != NULL) {
+ p = zend_hash_apply_deleter(ht, p);
+ }
+ pefree(ht->arBuckets, ht->persistent);
+
+ SET_INCONSISTENT(HT_DESTROYED);
+}
+
+/* This is used to selectively delete certain entries from a hashtable.
+ * destruct() receives the data and decides if the entry should be deleted
+ * or not
+ */
+
+
+ZEND_API void zend_hash_apply(HashTable *ht, apply_func_t apply_func)
+{
+ Bucket *p;
+
+ IS_CONSISTENT(ht);
+
+ HASH_APPLY_BEGIN(ht);
+ p = ht->pListHead;
+ while (p != NULL) {
+ if (apply_func(p->pData)) {
+ p = zend_hash_apply_deleter(ht, p);
+ } else {
+ p = p->pListNext;
+ }
+ }
+ HASH_APPLY_END(ht);
+}
+
+
+ZEND_API void zend_hash_apply_with_argument(HashTable *ht, apply_func_arg_t apply_func, void *argument)
+{
+ Bucket *p;
+
+ IS_CONSISTENT(ht);
+
+ HASH_APPLY_BEGIN(ht);
+ p = ht->pListHead;
+ while (p != NULL) {
+ if (apply_func(p->pData, argument)) {
+ p = zend_hash_apply_deleter(ht, p);
+ } else {
+ p = p->pListNext;
+ }
+ }
+ HASH_APPLY_END(ht);
+}
+
+
+ZEND_API void zend_hash_apply_with_arguments(HashTable *ht, int (*destruct)(void *, int, va_list, zend_hash_key *), int num_args, ...)
+{
+ Bucket *p;
+ va_list args;
+ zend_hash_key hash_key;
+
+ IS_CONSISTENT(ht);
+
+ HASH_APPLY_BEGIN(ht);
+
+ va_start(args, num_args);
+ p = ht->pListHead;
+ while (p != NULL) {
+ hash_key.arKey = p->arKey;
+ hash_key.nKeyLength = p->nKeyLength;
+ hash_key.h = p->h;
+ if (destruct(p->pData, num_args, args, &hash_key)) {
+ p = zend_hash_apply_deleter(ht, p);
+ } else {
+ p = p->pListNext;
+ }
+ }
+ va_end(args);
+
+ HASH_APPLY_END(ht);
+}
+
+
+
+ZEND_API void zend_hash_copy(HashTable *target, HashTable *source, copy_ctor_func_t pCopyConstructor, void *tmp, uint size)
+{
+ Bucket *p;
+ void *new_entry;
+
+ IS_CONSISTENT(source);
+ IS_CONSISTENT(target);
+
+ p = source->pListHead;
+ while (p) {
+ if (p->nKeyLength) {
+ zend_hash_update(target, p->arKey, p->nKeyLength, p->pData, size, &new_entry);
+ } else {
+ zend_hash_index_update(target, p->h, p->pData, size, &new_entry);
+ }
+ if (pCopyConstructor) {
+ pCopyConstructor(new_entry);
+ }
+ p = p->pListNext;
+ }
+ target->pInternalPointer = target->pListHead;
+}
+
+
+ZEND_API void zend_hash_merge(HashTable *target, HashTable *source, copy_ctor_func_t pCopyConstructor, void *tmp, uint size, int overwrite)
+{
+ Bucket *p;
+ void *t;
+ int mode = (overwrite?HASH_UPDATE:HASH_ADD);
+
+ IS_CONSISTENT(source);
+ IS_CONSISTENT(target);
+
+ p = source->pListHead;
+ while (p) {
+ if (p->nKeyLength>0) {
+ if (zend_hash_add_or_update(target, p->arKey, p->nKeyLength, p->pData, size, &t, mode)==SUCCESS && pCopyConstructor) {
+ pCopyConstructor(t);
+ }
+ } else {
+ if ((mode==HASH_UPDATE || !zend_hash_index_exists(target, p->h)) && zend_hash_index_update(target, p->h, p->pData, size, &t)==SUCCESS && pCopyConstructor) {
+ pCopyConstructor(t);
+ }
+ }
+ p = p->pListNext;
+ }
+ target->pInternalPointer = target->pListHead;
+}
+
+
+ZEND_API void zend_hash_merge_ex(HashTable *target, HashTable *source, copy_ctor_func_t pCopyConstructor, uint size, zend_bool (*pReplaceOrig)(void *orig, void *p_new))
+{
+ Bucket *p;
+ void *t;
+ void *pOrig;
+
+ IS_CONSISTENT(source);
+ IS_CONSISTENT(target);
+
+ p = source->pListHead;
+ while (p) {
+ if (p->nKeyLength>0) {
+ if (zend_hash_find(target, p->arKey, p->nKeyLength, &pOrig)==FAILURE
+ || pReplaceOrig(pOrig, p->pData)) {
+ if (zend_hash_update(target, p->arKey, p->nKeyLength, p->pData, size, &t)==SUCCESS && pCopyConstructor) {
+ pCopyConstructor(t);
+ }
+ }
+ } else {
+ if (zend_hash_index_find(target, p->h, &pOrig)==FAILURE
+ || pReplaceOrig(pOrig, p->pData)) {
+ if (zend_hash_index_update(target, p->h, p->pData, size, &t)==SUCCESS && pCopyConstructor) {
+ pCopyConstructor(t);
+ }
+ }
+ }
+ p = p->pListNext;
+ }
+ target->pInternalPointer = target->pListHead;
+}
+
+
+ZEND_API ulong zend_get_hash_value(HashTable *ht, char *arKey, uint nKeyLength)
+{
+ IS_CONSISTENT(ht);
+
+ return ht->pHashFunction(arKey, nKeyLength);
+}
+
+
+/* Returns SUCCESS if found and FAILURE if not. The pointer to the
+ * data is returned in pData. The reason is that there's no reason
+ * someone using the hash table might not want to have NULL data
+ */
+ZEND_API int zend_hash_find(HashTable *ht, char *arKey, uint nKeyLength, void **pData)
+{
+ ulong h;
+ uint nIndex;
+ Bucket *p;
+
+ IS_CONSISTENT(ht);
+
+ HANDLE_NUMERIC(arKey, nKeyLength, zend_hash_index_find(ht, idx, pData));
+
+ h = ht->pHashFunction(arKey, nKeyLength);
+ nIndex = h % ht->nTableSize;
+
+ p = ht->arBuckets[nIndex];
+ while (p != NULL) {
+ if ((p->h == h) && (p->nKeyLength == nKeyLength)) {
+ if (!memcmp(p->arKey, arKey, nKeyLength)) {
+ *pData = p->pData;
+ return SUCCESS;
+ }
+ }
+ p = p->pNext;
+ }
+ return FAILURE;
+}
+
+
+ZEND_API int zend_hash_quick_find(HashTable *ht, char *arKey, uint nKeyLength, ulong h, void **pData)
+{
+ uint nIndex;
+ Bucket *p;
+
+ IS_CONSISTENT(ht);
+
+ nIndex = h % ht->nTableSize;
+
+ p = ht->arBuckets[nIndex];
+ while (p != NULL) {
+ if ((p->h == h) && (p->nKeyLength == nKeyLength)) {
+ if (!memcmp(p->arKey, arKey, nKeyLength)) {
+ *pData = p->pData;
+ return SUCCESS;
+ }
+ }
+ p = p->pNext;
+ }
+ return FAILURE;
+}
+
+
+ZEND_API int zend_hash_exists(HashTable *ht, char *arKey, uint nKeyLength)
+{
+ ulong h;
+ uint nIndex;
+ Bucket *p;
+
+ IS_CONSISTENT(ht);
+
+ HANDLE_NUMERIC(arKey, nKeyLength, zend_hash_index_exists(ht, idx));
+
+ h = ht->pHashFunction(arKey, nKeyLength);
+ nIndex = h % ht->nTableSize;
+
+ p = ht->arBuckets[nIndex];
+ while (p != NULL) {
+ if ((p->h == h) && (p->nKeyLength == nKeyLength)) {
+ if (!memcmp(p->arKey, arKey, nKeyLength)) {
+ return 1;
+ }
+ }
+ p = p->pNext;
+ }
+ return 0;
+}
+
+
+ZEND_API int zend_hash_index_find(HashTable *ht, ulong h, void **pData)
+{
+ uint nIndex;
+ Bucket *p;
+
+ IS_CONSISTENT(ht);
+
+ nIndex = h % ht->nTableSize;
+
+ p = ht->arBuckets[nIndex];
+ while (p != NULL) {
+ if ((p->h == h) && (p->nKeyLength == 0)) {
+ *pData = p->pData;
+ return SUCCESS;
+ }
+ p = p->pNext;
+ }
+ return FAILURE;
+}
+
+
+ZEND_API int zend_hash_index_exists(HashTable *ht, ulong h)
+{
+ uint nIndex;
+ Bucket *p;
+
+ IS_CONSISTENT(ht);
+
+ nIndex = h % ht->nTableSize;
+
+ p = ht->arBuckets[nIndex];
+ while (p != NULL) {
+ if ((p->h == h) && (p->nKeyLength == 0)) {
+ return 1;
+ }
+ p = p->pNext;
+ }
+ return 0;
+}
+
+
+ZEND_API int zend_hash_num_elements(HashTable *ht)
+{
+ IS_CONSISTENT(ht);
+
+ return ht->nNumOfElements;
+}
+
+
+ZEND_API void zend_hash_internal_pointer_reset_ex(HashTable *ht, HashPosition *pos)
+{
+ IS_CONSISTENT(ht);
+
+ if (pos)
+ *pos = ht->pListHead;
+ else
+ ht->pInternalPointer = ht->pListHead;
+}
+
+
+/* This function will be extremely optimized by remembering
+ * the end of the list
+ */
+ZEND_API void zend_hash_internal_pointer_end_ex(HashTable *ht, HashPosition *pos)
+{
+ IS_CONSISTENT(ht);
+
+ if (pos)
+ *pos = ht->pListTail;
+ else
+ ht->pInternalPointer = ht->pListTail;
+}
+
+
+ZEND_API int zend_hash_move_forward_ex(HashTable *ht, HashPosition *pos)
+{
+ HashPosition *current = pos ? pos : &ht->pInternalPointer;
+
+ IS_CONSISTENT(ht);
+
+ if (*current) {
+ *current = (*current)->pListNext;
+ return SUCCESS;
+ } else
+ return FAILURE;
+}
+
+ZEND_API int zend_hash_move_backwards_ex(HashTable *ht, HashPosition *pos)
+{
+ HashPosition *current = pos ? pos : &ht->pInternalPointer;
+
+ IS_CONSISTENT(ht);
+
+ if (*current) {
+ *current = (*current)->pListLast;
+ return SUCCESS;
+ } else
+ return FAILURE;
+}
+
+
+/* This function should be made binary safe */
+ZEND_API int zend_hash_get_current_key_ex(HashTable *ht, char **str_index, ulong *str_length, ulong *num_index, HashPosition *pos)
+{
+ Bucket *p;
+
+ p = pos ? (*pos) : ht->pInternalPointer;
+
+ IS_CONSISTENT(ht);
+
+ if (p) {
+ if (p->nKeyLength) {
+ *str_index = (char *) pemalloc(p->nKeyLength, ht->persistent);
+ memcpy(*str_index, p->arKey, p->nKeyLength);
+ if (str_length) {
+ *str_length = p->nKeyLength;
+ }
+ return HASH_KEY_IS_STRING;
+ } else {
+ *num_index = p->h;
+ return HASH_KEY_IS_LONG;
+ }
+ }
+ return HASH_KEY_NON_EXISTANT;
+}
+
+
+ZEND_API int zend_hash_get_current_key_type_ex(HashTable *ht, HashPosition *pos)
+{
+ Bucket *p;
+
+ p = pos ? (*pos) : ht->pInternalPointer;
+
+ IS_CONSISTENT(ht);
+
+ if (p) {
+ if (p->nKeyLength) {
+ return HASH_KEY_IS_STRING;
+ } else {
+ return HASH_KEY_IS_LONG;
+ }
+ }
+ return HASH_KEY_NON_EXISTANT;
+}
+
+
+ZEND_API int zend_hash_get_current_data_ex(HashTable *ht, void **pData, HashPosition *pos)
+{
+ Bucket *p;
+
+ p = pos ? (*pos) : ht->pInternalPointer;
+
+ IS_CONSISTENT(ht);
+
+ if (p) {
+ *pData = p->pData;
+ return SUCCESS;
+ } else {
+ return FAILURE;
+ }
+}
+
+
+ZEND_API int zend_hash_sort(HashTable *ht, sort_func_t sort_func,
+ compare_func_t compar, int renumber)
+{
+ Bucket **arTmp;
+ Bucket *p;
+ int i, j;
+
+ IS_CONSISTENT(ht);
+
+ if (ht->nNumOfElements <= 1) { /* Doesn't require sorting */
+ return SUCCESS;
+ }
+ arTmp = (Bucket **) pemalloc(ht->nNumOfElements * sizeof(Bucket *), ht->persistent);
+ if (!arTmp) {
+ return FAILURE;
+ }
+ p = ht->pListHead;
+ i = 0;
+ while (p) {
+ arTmp[i] = p;
+ p = p->pListNext;
+ i++;
+ }
+
+ (*sort_func)((void *) arTmp, i, sizeof(Bucket *), compar);
+
+ HANDLE_BLOCK_INTERRUPTIONS();
+ ht->pListHead = arTmp[0];
+ ht->pListTail = NULL;
+ ht->pInternalPointer = ht->pListHead;
+
+ for (j = 0; j < i; j++) {
+ if (ht->pListTail) {
+ ht->pListTail->pListNext = arTmp[j];
+ }
+ arTmp[j]->pListLast = ht->pListTail;
+ arTmp[j]->pListNext = NULL;
+ ht->pListTail = arTmp[j];
+ }
+ pefree(arTmp, ht->persistent);
+ HANDLE_UNBLOCK_INTERRUPTIONS();
+
+ if (renumber) {
+ p = ht->pListHead;
+ i=0;
+ while (p != NULL) {
+ p->nKeyLength = 0;
+ p->h = i++;
+ p = p->pListNext;
+ }
+ ht->nNextFreeElement = i;
+ zend_hash_rehash(ht);
+ }
+ return SUCCESS;
+}
+
+
+ZEND_API int zend_hash_compare(HashTable *ht1, HashTable *ht2, compare_func_t compar, zend_bool ordered)
+{
+ Bucket *p1, *p2;
+ int result;
+ void *pData2;
+
+ IS_CONSISTENT(ht1);
+ IS_CONSISTENT(ht2);
+
+ result = ht1->nNumOfElements - ht2->nNumOfElements;
+ if (result!=0) {
+ return result;
+ }
+
+ p1 = ht1->pListHead;
+ if (ordered) {
+ p2 = ht2->pListHead;
+ }
+
+ while (p1) {
+ if (ordered && !p2) {
+ return 1; /* That's not supposed to happen */
+ }
+ if (ordered) {
+ if (p1->nKeyLength==0 && p2->nKeyLength==0) { /* numeric indices */
+ result = p1->h - p2->h;
+ if (result!=0) {
+ return result;
+ }
+ } else { /* string indices */
+ result = p1->nKeyLength - p2->nKeyLength;
+ if (result!=0) {
+ return result;
+ }
+ result = memcmp(p1->arKey, p2->arKey, p1->nKeyLength);
+ if (result!=0) {
+ return result;
+ }
+ }
+ pData2 = p2->pData;
+ } else {
+ if (p1->nKeyLength==0) { /* numeric index */
+ if (zend_hash_index_find(ht2, p1->h, &pData2)==FAILURE) {
+ return 1;
+ }
+ } else { /* string index */
+ if (zend_hash_find(ht2, p1->arKey, p1->nKeyLength, &pData2)==FAILURE) {
+ return 1;
+ }
+ }
+ }
+ result = compar(p1->pData, pData2);
+ if (result!=0) {
+ return result;
+ }
+ p1 = p1->pListNext;
+ if (ordered) {
+ p2 = p2->pListNext;
+ }
+ }
+
+ return 0;
+}
+
+
+ZEND_API int zend_hash_minmax(HashTable *ht, int (*compar) (const void *, const void *), int flag, void **pData)
+{
+ Bucket *p,*res;
+
+ IS_CONSISTENT(ht);
+
+ if (ht->nNumOfElements == 0 ) {
+ *pData=NULL;
+ return FAILURE;
+ }
+
+ res = p = ht->pListHead;
+ while ((p = p->pListNext)) {
+ if (flag) {
+ if (compar(&res,&p) < 0) { /* max */
+ res = p;
+ }
+ } else {
+ if (compar(&res,&p) > 0) { /* min */
+ res = p;
+ }
+ }
+ }
+ *pData = res->pData;
+ return SUCCESS;
+}
+
+ZEND_API ulong zend_hash_next_free_element(HashTable *ht)
+{
+ IS_CONSISTENT(ht);
+
+ return ht->nNextFreeElement;
+
+}
+
+#if ZEND_DEBUG
+void zend_hash_display_pListTail(HashTable *ht)
+{
+ Bucket *p;
+
+ p = ht->pListTail;
+ while (p != NULL) {
+ zend_output_debug_string(0, "pListTail has key %s\n", p->arKey);
+ p = p->pListLast;
+ }
+}
+
+void zend_hash_display(HashTable *ht)
+{
+ Bucket *p;
+ uint i;
+
+ for (i = 0; i < ht->nTableSize; i++) {
+ p = ht->arBuckets[i];
+ while (p != NULL) {
+ zend_output_debug_string(0, "%s <==> 0x%X\n", p->arKey, p->h);
+ p = p->pNext;
+ }
+ }
+
+ p = ht->pListTail;
+ while (p != NULL) {
+ zend_output_debug_string(0, "%s <==> 0x%X\n", p->arKey, p->h);
+ p = p->pListLast;
+ }
+}
+#endif
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ */
diff --git a/Zend/zend_language_parser.y b/Zend/zend_language_parser.y
new file mode 100644
index 0000000000..a84b57cd59
--- /dev/null
+++ b/Zend/zend_language_parser.y
@@ -0,0 +1,725 @@
+%{
+/*
+ +----------------------------------------------------------------------+
+ | Zend Engine |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1998-2000 Zend Technologies Ltd. (http://www.zend.com) |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 0.92 of the Zend license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available at through the world-wide-web at |
+ | http://www.zend.com/license/0_92.txt. |
+ | If you did not receive a copy of the Zend license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@zend.com so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Andi Gutmans <andi@zend.com> |
+ | Zeev Suraski <zeev@zend.com> |
+ +----------------------------------------------------------------------+
+*/
+
+/*
+ * LALR shift/reduce conflicts and how they are resolved:
+ *
+ * - 2 shift/reduce conflicts due to the dangeling elseif/else ambiguity. Solved by shift.
+ * - 1 shift/reduce conflict due to arrays within encapsulated strings. Solved by shift.
+ * - 1 shift/reduce conflict due to objects within encapsulated strings. Solved by shift.
+ *
+ */
+
+
+#include "zend_compile.h"
+#include "zend.h"
+#include "zend_list.h"
+#include "zend_globals.h"
+#include "zend_API.h"
+
+#define YYERROR_VERBOSE
+#define YYSTYPE znode
+#ifdef ZTS
+# define YYPARSE_PARAM compiler_globals
+# define YYLEX_PARAM compiler_globals
+#endif
+
+
+%}
+
+%pure_parser
+%expect 4
+
+%left T_INCLUDE T_INCLUDE_ONCE T_EVAL T_REQUIRE T_REQUIRE_ONCE
+%left ','
+%left T_LOGICAL_OR
+%left T_LOGICAL_XOR
+%left T_LOGICAL_AND
+%right T_PRINT
+%left '=' T_PLUS_EQUAL T_MINUS_EQUAL T_MUL_EQUAL T_DIV_EQUAL T_CONCAT_EQUAL T_MOD_EQUAL T_AND_EQUAL T_OR_EQUAL T_XOR_EQUAL T_SL_EQUAL T_SR_EQUAL
+%left '?' ':'
+%left T_BOOLEAN_OR
+%left T_BOOLEAN_AND
+%left '|'
+%left '^'
+%left '&'
+%nonassoc T_IS_EQUAL T_IS_NOT_EQUAL T_IS_IDENTICAL T_IS_NOT_IDENTICAL
+%nonassoc '<' T_IS_SMALLER_OR_EQUAL '>' T_IS_GREATER_OR_EQUAL
+%left T_SL T_SR
+%left '+' '-' '.'
+%left '*' '/' '%'
+%right '!' '~' T_INC T_DEC T_INT_CAST T_DOUBLE_CAST T_STRING_CAST T_ARRAY_CAST T_OBJECT_CAST T_BOOL_CAST T_UNSET_CAST '@'
+%right '['
+%nonassoc T_NEW
+%token T_EXIT
+%token T_IF
+%left T_ELSEIF
+%left T_ELSE
+%left T_ENDIF
+%token T_LNUMBER
+%token T_DNUMBER
+%token T_STRING
+%token T_STRING_VARNAME
+%token T_VARIABLE
+%token T_NUM_STRING
+%token T_INLINE_HTML
+%token T_CHARACTER
+%token T_BAD_CHARACTER
+%token T_ENCAPSED_AND_WHITESPACE
+%token T_CONSTANT_ENCAPSED_STRING
+%token T_ECHO
+%token T_DO
+%token T_WHILE
+%token T_ENDWHILE
+%token T_FOR
+%token T_ENDFOR
+%token T_FOREACH
+%token T_ENDFOREACH
+%token T_DECLARE
+%token T_ENDDECLARE
+%token T_AS
+%token T_SWITCH
+%token T_ENDSWITCH
+%token T_CASE
+%token T_DEFAULT
+%token T_BREAK
+%token T_CONTINUE
+%token T_OLD_FUNCTION
+%token T_FUNCTION
+%token T_CONST
+%token T_RETURN
+%token T_USE
+%token T_GLOBAL
+%token T_STATIC
+%token T_VAR
+%token T_UNSET
+%token T_ISSET
+%token T_EMPTY
+%token T_CLASS
+%token T_EXTENDS
+%token T_OBJECT_OPERATOR
+%token T_DOUBLE_ARROW
+%token T_LIST
+%token T_ARRAY
+%token T_LINE
+%token T_FILE
+%token T_COMMENT
+%token T_ML_COMMENT
+%token T_OPEN_TAG
+%token T_OPEN_TAG_WITH_ECHO
+%token T_CLOSE_TAG
+%token T_WHITESPACE
+%token T_START_HEREDOC
+%token T_END_HEREDOC
+%token T_DOLLAR_OPEN_CURLY_BRACES
+%token T_CURLY_OPEN
+%token T_PAAMAYIM_NEKUDOTAYIM
+
+%% /* Rules */
+
+start:
+ top_statement_list
+;
+
+top_statement_list:
+ top_statement_list { zend_do_extended_info(CLS_C); } top_statement { HANDLE_INTERACTIVE(); }
+ | /* empty */
+;
+
+
+top_statement:
+ statement
+ | declaration_statement { zend_do_early_binding(CLS_C); }
+;
+
+
+inner_statement_list:
+ inner_statement_list { zend_do_extended_info(CLS_C); } inner_statement { HANDLE_INTERACTIVE(); }
+ | /* empty */
+;
+
+
+inner_statement:
+ statement
+ | declaration_statement
+;
+
+
+statement:
+ unticked_statement { zend_do_ticks(CLS_C); }
+;
+
+
+unticked_statement:
+ '{' inner_statement_list '}'
+ | T_IF '(' expr ')' { zend_do_if_cond(&$3, &$4 CLS_CC); } statement { zend_do_if_after_statement(&$4, 1 CLS_CC); } elseif_list else_single { zend_do_if_end(CLS_C); }
+ | T_IF '(' expr ')' ':' { zend_do_if_cond(&$3, &$4 CLS_CC); } inner_statement_list { zend_do_if_after_statement(&$4, 1 CLS_CC); } new_elseif_list new_else_single T_ENDIF ';' { zend_do_if_end(CLS_C); }
+ | T_WHILE '(' { $1.u.opline_num = get_next_op_number(CG(active_op_array)); } expr ')' { zend_do_while_cond(&$4, &$5 CLS_CC); } while_statement { zend_do_while_end(&$1, &$5 CLS_CC); }
+ | T_DO { $1.u.opline_num = get_next_op_number(CG(active_op_array)); zend_do_do_while_begin(CLS_C); } statement T_WHILE '(' { $5.u.opline_num = get_next_op_number(CG(active_op_array)); } expr ')' ';' { zend_do_do_while_end(&$1, &$5, &$7 CLS_CC); }
+ | T_FOR
+ '('
+ for_expr
+ ';' { zend_do_free(&$3 CLS_CC); $4.u.opline_num = get_next_op_number(CG(active_op_array)); }
+ for_expr
+ ';' { zend_do_extended_info(CLS_C); zend_do_for_cond(&$6, &$7 CLS_CC); }
+ for_expr
+ ')' { zend_do_free(&$9 CLS_CC); zend_do_for_before_statement(&$4, &$7 CLS_CC); }
+ for_statement { zend_do_for_end(&$7 CLS_CC); }
+ | T_SWITCH '(' expr ')' { zend_do_switch_cond(&$3 CLS_CC); } switch_case_list { zend_do_switch_end(&$6 CLS_CC); }
+ | T_BREAK ';' { zend_do_brk_cont(ZEND_BRK, NULL CLS_CC); }
+ | T_BREAK expr ';' { zend_do_brk_cont(ZEND_BRK, &$2 CLS_CC); }
+ | T_CONTINUE ';' { zend_do_brk_cont(ZEND_CONT, NULL CLS_CC); }
+ | T_CONTINUE expr ';' { zend_do_brk_cont(ZEND_CONT, &$2 CLS_CC); }
+ | T_RETURN ';' { zend_do_return(NULL, 0 CLS_CC); }
+ | T_RETURN expr_without_variable ';' { zend_do_return(&$2, 0 CLS_CC); }
+ | T_RETURN cvar ';' { zend_do_return(&$2, 1 CLS_CC); }
+ | T_GLOBAL global_var_list ';'
+ | T_STATIC static_var_list ';'
+ | T_ECHO echo_expr_list ';'
+ | T_INLINE_HTML { zend_do_echo(&$1 CLS_CC); }
+ | expr ';' { zend_do_free(&$1 CLS_CC); }
+ | T_USE use_filename ';' { zend_error(E_COMPILE_ERROR,"use: Not yet supported. Please use include_once() or require_once()"); zval_dtor(&$2.u.constant); }
+ | T_UNSET '(' unset_variables ')' ';'
+ | T_FOREACH '(' w_cvar T_AS { zend_do_foreach_begin(&$1, &$3, &$2, &$4, 1 CLS_CC); } w_cvar foreach_optional_arg ')' { zend_do_foreach_cont(&$6, &$7, &$4 CLS_CC); } foreach_statement { zend_do_foreach_end(&$1, &$2 CLS_CC); }
+ | T_FOREACH '(' expr_without_variable T_AS { zend_do_foreach_begin(&$1, &$3, &$2, &$4, 0 CLS_CC); } w_cvar foreach_optional_arg ')' { zend_do_foreach_cont(&$6, &$7, &$4 CLS_CC); } foreach_statement { zend_do_foreach_end(&$1, &$2 CLS_CC); }
+ | T_DECLARE { zend_do_declare_begin(CLS_C); } '(' declare_list ')' declare_statement { zend_do_declare_end(CLS_C); }
+ | ';' /* empty statement */
+;
+
+unset_variables:
+ unset_variable
+ | unset_variables ',' unset_variable
+;
+
+unset_variable:
+ cvar { zend_do_end_variable_parse(BP_VAR_UNSET, 0 CLS_CC); zend_do_unset(&$1 CLS_CC); }
+;
+
+use_filename:
+ T_CONSTANT_ENCAPSED_STRING { $$ = $1; }
+ | '(' T_CONSTANT_ENCAPSED_STRING ')' { $$ = $2; }
+;
+
+
+declaration_statement:
+ unticked_declaration_statement { zend_do_ticks(CLS_C); }
+;
+
+
+unticked_declaration_statement:
+ T_FUNCTION { $1.u.opline_num = CG(zend_lineno); } is_reference T_STRING { zend_do_begin_function_declaration(&$1, &$4, 0, $3.op_type CLS_CC); }
+ '(' parameter_list ')' '{' inner_statement_list '}' { zend_do_end_function_declaration(&$1 CLS_CC); }
+ | T_OLD_FUNCTION { $1.u.opline_num = CG(zend_lineno); } is_reference T_STRING { zend_do_begin_function_declaration(&$1, &$4, 0, $3.op_type CLS_CC); }
+ parameter_list '(' inner_statement_list ')' ';' { zend_do_end_function_declaration(&$1 CLS_CC); }
+ | T_CLASS T_STRING { zend_do_begin_class_declaration(&$2, NULL CLS_CC); } '{' class_statement_list '}' { zend_do_end_class_declaration(CLS_C); }
+ | T_CLASS T_STRING T_EXTENDS T_STRING { zend_do_begin_class_declaration(&$2, &$4 CLS_CC); } '{' class_statement_list '}' { zend_do_end_class_declaration(CLS_C); }
+;
+
+
+foreach_optional_arg:
+ /* empty */ { $$.op_type = IS_UNUSED; }
+ | T_DOUBLE_ARROW w_cvar { $$ = $2; }
+;
+
+
+for_statement:
+ statement
+ | ':' inner_statement_list T_ENDFOR ';'
+;
+
+
+foreach_statement:
+ statement
+ | ':' inner_statement_list T_ENDFOREACH ';'
+;
+
+
+declare_statement:
+ statement
+ | ':' inner_statement_list T_ENDDECLARE ';'
+;
+
+
+declare_list:
+ T_STRING '=' static_scalar { zend_do_declare_stmt(&$1, &$3 CLS_CC); }
+ | declare_list ',' T_STRING '=' static_scalar { zend_do_declare_stmt(&$3, &$5 CLS_CC); }
+;
+
+
+switch_case_list:
+ '{' case_list '}' { $$ = $2; }
+ | '{' ';' case_list '}' { $$ = $3; }
+ | ':' case_list T_ENDSWITCH ';' { $$ = $2; }
+ | ':' ';' case_list T_ENDSWITCH ';' { $$ = $3; }
+;
+
+
+case_list:
+ /* empty */ { $$.op_type = IS_UNUSED; }
+ | case_list T_CASE expr case_separator { zend_do_extended_info(CLS_C); zend_do_case_before_statement(&$1, &$2, &$3 CLS_CC); } inner_statement_list { zend_do_case_after_statement(&$$, &$2 CLS_CC); $$.op_type = IS_CONST }
+ | case_list T_DEFAULT case_separator { zend_do_extended_info(CLS_C); zend_do_default_before_statement(&$1, &$2 CLS_CC); } inner_statement_list { zend_do_case_after_statement(&$$, &$2 CLS_CC); $$.op_type = IS_CONST; }
+;
+
+
+case_separator:
+ ':'
+ | ';'
+;
+
+
+while_statement:
+ statement
+ | ':' inner_statement_list T_ENDWHILE ';'
+;
+
+
+
+elseif_list:
+ /* empty */
+ | elseif_list T_ELSEIF '(' expr ')' { zend_do_if_cond(&$4, &$5 CLS_CC); } statement { zend_do_if_after_statement(&$5, 0 CLS_CC); }
+;
+
+
+new_elseif_list:
+ /* empty */
+ | new_elseif_list T_ELSEIF '(' expr ')' ':' { zend_do_if_cond(&$4, &$5 CLS_CC); } inner_statement_list { zend_do_if_after_statement(&$5, 0 CLS_CC); }
+;
+
+
+else_single:
+ /* empty */
+ | T_ELSE statement
+;
+
+
+new_else_single:
+ /* empty */
+ | T_ELSE ':' inner_statement_list
+;
+
+
+parameter_list:
+ non_empty_parameter_list
+ | /* empty */
+;
+
+
+non_empty_parameter_list:
+ T_VARIABLE { znode tmp; fetch_simple_variable(&tmp, &$1, 0 CLS_CC); $$.op_type = IS_CONST; $$.u.constant.value.lval=1; $$.u.constant.type=IS_LONG; INIT_PZVAL(&$$.u.constant); zend_do_receive_arg(ZEND_RECV, &tmp, &$$, NULL, BYREF_NONE CLS_CC); }
+ | '&' T_VARIABLE { znode tmp; fetch_simple_variable(&tmp, &$2, 0 CLS_CC); $$.op_type = IS_CONST; $$.u.constant.value.lval=1; $$.u.constant.type=IS_LONG; INIT_PZVAL(&$$.u.constant); zend_do_receive_arg(ZEND_RECV, &tmp, &$$, NULL, BYREF_FORCE CLS_CC); }
+ | T_CONST T_VARIABLE { znode tmp; fetch_simple_variable(&tmp, &$2, 0 CLS_CC); $$.op_type = IS_CONST; $$.u.constant.value.lval=1; $$.u.constant.type=IS_LONG; INIT_PZVAL(&$$.u.constant); zend_do_receive_arg(ZEND_RECV, &tmp, &$$, NULL, BYREF_NONE CLS_CC); }
+ | T_VARIABLE '=' static_scalar { znode tmp; fetch_simple_variable(&tmp, &$1, 0 CLS_CC); $$.op_type = IS_CONST; $$.u.constant.value.lval=1; $$.u.constant.type=IS_LONG; INIT_PZVAL(&$$.u.constant); zend_do_receive_arg(ZEND_RECV_INIT, &tmp, &$$, &$3, BYREF_NONE CLS_CC); }
+ | non_empty_parameter_list ',' T_VARIABLE { znode tmp; fetch_simple_variable(&tmp, &$3, 0 CLS_CC); $$=$1; $$.u.constant.value.lval++; zend_do_receive_arg(ZEND_RECV, &tmp, &$$, NULL, BYREF_NONE CLS_CC); }
+ | non_empty_parameter_list ',' '&' T_VARIABLE { znode tmp; fetch_simple_variable(&tmp, &$4, 0 CLS_CC); $$=$1; $$.u.constant.value.lval++; zend_do_receive_arg(ZEND_RECV, &tmp, &$$, NULL, BYREF_FORCE CLS_CC); }
+ | non_empty_parameter_list ',' T_CONST T_VARIABLE { znode tmp; fetch_simple_variable(&tmp, &$4, 0 CLS_CC); $$=$1; $$.u.constant.value.lval++; zend_do_receive_arg(ZEND_RECV, &tmp, &$$, NULL, BYREF_NONE CLS_CC); }
+ | non_empty_parameter_list ',' T_VARIABLE '=' static_scalar { znode tmp; fetch_simple_variable(&tmp, &$3, 0 CLS_CC); $$=$1; $$.u.constant.value.lval++; zend_do_receive_arg(ZEND_RECV_INIT, &tmp, &$$, &$5, BYREF_NONE CLS_CC); }
+;
+
+
+function_call_parameter_list:
+ non_empty_function_call_parameter_list { $$ = $1; }
+ | /* empty */ { $$.u.constant.value.lval = 0; }
+;
+
+
+non_empty_function_call_parameter_list:
+ expr_without_variable { $$.u.constant.value.lval = 1; zend_do_pass_param(&$1, ZEND_SEND_VAL, $$.u.constant.value.lval CLS_CC); }
+ | cvar { $$.u.constant.value.lval = 1; zend_do_pass_param(&$1, ZEND_SEND_VAR, $$.u.constant.value.lval CLS_CC); }
+ | '&' w_cvar { $$.u.constant.value.lval = 1; zend_do_pass_param(&$2, ZEND_SEND_REF, $$.u.constant.value.lval CLS_CC); }
+ | non_empty_function_call_parameter_list ',' expr_without_variable { $$.u.constant.value.lval=$1.u.constant.value.lval+1; zend_do_pass_param(&$3, ZEND_SEND_VAL, $$.u.constant.value.lval CLS_CC); }
+ | non_empty_function_call_parameter_list ',' cvar { $$.u.constant.value.lval=$1.u.constant.value.lval+1; zend_do_pass_param(&$3, ZEND_SEND_VAR, $$.u.constant.value.lval CLS_CC); }
+ | non_empty_function_call_parameter_list ',' '&' w_cvar { $$.u.constant.value.lval=$1.u.constant.value.lval+1; zend_do_pass_param(&$4, ZEND_SEND_REF, $$.u.constant.value.lval CLS_CC); }
+;
+
+global_var_list:
+ global_var_list ',' global_var { zend_do_fetch_global_or_static_variable(&$3, NULL, ZEND_FETCH_GLOBAL CLS_CC); }
+ | global_var { zend_do_fetch_global_or_static_variable(&$1, NULL, ZEND_FETCH_GLOBAL CLS_CC); }
+;
+
+
+global_var:
+ T_VARIABLE { $$ = $1; }
+ | '$' r_cvar { $$ = $2; }
+ | '$' '{' expr '}' { $$ = $3; }
+;
+
+
+static_var_list:
+ static_var_list ',' T_VARIABLE { zend_do_fetch_global_or_static_variable(&$3, NULL, ZEND_FETCH_STATIC CLS_CC); }
+ | static_var_list ',' T_VARIABLE '=' static_scalar { zend_do_fetch_global_or_static_variable(&$3, &$5, ZEND_FETCH_STATIC CLS_CC); }
+ | T_VARIABLE { zend_do_fetch_global_or_static_variable(&$1, NULL, ZEND_FETCH_STATIC CLS_CC); }
+ | T_VARIABLE '=' static_scalar { zend_do_fetch_global_or_static_variable(&$1, &$3, ZEND_FETCH_STATIC CLS_CC); }
+
+;
+
+
+class_statement_list:
+ class_statement_list class_statement
+ | /* empty */
+;
+
+
+class_statement:
+ T_VAR class_variable_decleration ';'
+ | T_FUNCTION { $1.u.opline_num = CG(zend_lineno); } is_reference T_STRING { zend_do_begin_function_declaration(&$1, &$4, 1, $3.op_type CLS_CC); } '('
+ parameter_list ')' '{' inner_statement_list '}' { zend_do_end_function_declaration(&$1 CLS_CC); }
+ | T_OLD_FUNCTION { $1.u.opline_num = CG(zend_lineno); } is_reference T_STRING { zend_do_begin_function_declaration(&$1, &$4, 1, $3.op_type CLS_CC); }
+ parameter_list '(' inner_statement_list ')' ';' { zend_do_end_function_declaration(&$1 CLS_CC); }
+
+;
+
+is_reference:
+ /* empty */ { $$.op_type = ZEND_RETURN_VAL; }
+ | '&' { $$.op_type = ZEND_RETURN_REF; }
+
+class_variable_decleration:
+ class_variable_decleration ',' T_VARIABLE { zend_do_declare_property(&$3, NULL CLS_CC); }
+ | class_variable_decleration ',' T_VARIABLE '=' static_scalar { zend_do_declare_property(&$3, &$5 CLS_CC); }
+ | T_VARIABLE { zend_do_declare_property(&$1, NULL CLS_CC); }
+ | T_VARIABLE '=' static_scalar { zend_do_declare_property(&$1, &$3 CLS_CC); }
+;
+
+
+echo_expr_list:
+ | echo_expr_list ',' expr { zend_do_echo(&$3 CLS_CC); }
+ | expr { zend_do_echo(&$1 CLS_CC); }
+;
+
+
+for_expr:
+ /* empty */ { $$.op_type = IS_CONST; $$.u.constant.type = IS_BOOL; $$.u.constant.value.lval = 1; }
+ | non_empty_for_expr { $$ = $1; }
+;
+
+non_empty_for_expr:
+ non_empty_for_expr ',' { zend_do_free(&$1 CLS_CC); } expr { $$ = $4; }
+ | expr { $$ = $1; }
+;
+
+
+expr_without_variable:
+ T_LIST '(' { zend_do_list_init(CLS_C); } assignment_list ')' '=' expr { zend_do_list_end(&$$, &$7 CLS_CC); }
+ | cvar '=' expr { zend_do_end_variable_parse(BP_VAR_W, 0 CLS_CC); zend_do_assign(&$$, &$1, &$3 CLS_CC); }
+ | cvar '=' '&' w_cvar { zend_do_end_variable_parse(BP_VAR_W, 0 CLS_CC); zend_do_assign_ref(&$$, &$1, &$4 CLS_CC); }
+ | cvar '=' '&' function_call { zend_do_end_variable_parse(BP_VAR_W, 0 CLS_CC); zend_do_assign_ref(&$$, &$1, &$4 CLS_CC); }
+ | T_NEW class_name { zend_do_extended_fcall_begin(CLS_C); zend_do_begin_new_object(&$1, &$2 CLS_CC); } ctor_arguments { zend_do_end_new_object(&$$, &$2, &$1, &$4 CLS_CC); zend_do_extended_fcall_end(CLS_C);}
+ | cvar T_PLUS_EQUAL expr { zend_do_end_variable_parse(BP_VAR_RW, 0 CLS_CC); zend_do_binary_assign_op(ZEND_ASSIGN_ADD, &$$, &$1, &$3 CLS_CC); }
+ | cvar T_MINUS_EQUAL expr { zend_do_end_variable_parse(BP_VAR_RW, 0 CLS_CC); zend_do_binary_assign_op(ZEND_ASSIGN_SUB, &$$, &$1, &$3 CLS_CC); }
+ | cvar T_MUL_EQUAL expr { zend_do_end_variable_parse(BP_VAR_RW, 0 CLS_CC); zend_do_binary_assign_op(ZEND_ASSIGN_MUL, &$$, &$1, &$3 CLS_CC); }
+ | cvar T_DIV_EQUAL expr { zend_do_end_variable_parse(BP_VAR_RW, 0 CLS_CC); zend_do_binary_assign_op(ZEND_ASSIGN_DIV, &$$, &$1, &$3 CLS_CC); }
+ | cvar T_CONCAT_EQUAL expr { zend_do_end_variable_parse(BP_VAR_RW, 0 CLS_CC); zend_do_binary_assign_op(ZEND_ASSIGN_CONCAT, &$$, &$1, &$3 CLS_CC); }
+ | cvar T_MOD_EQUAL expr { zend_do_end_variable_parse(BP_VAR_RW, 0 CLS_CC); zend_do_binary_assign_op(ZEND_ASSIGN_MOD, &$$, &$1, &$3 CLS_CC); }
+ | cvar T_AND_EQUAL expr { zend_do_end_variable_parse(BP_VAR_RW, 0 CLS_CC); zend_do_binary_assign_op(ZEND_ASSIGN_BW_AND, &$$, &$1, &$3 CLS_CC); }
+ | cvar T_OR_EQUAL expr { zend_do_end_variable_parse(BP_VAR_RW, 0 CLS_CC); zend_do_binary_assign_op(ZEND_ASSIGN_BW_OR, &$$, &$1, &$3 CLS_CC); }
+ | cvar T_XOR_EQUAL expr { zend_do_end_variable_parse(BP_VAR_RW, 0 CLS_CC); zend_do_binary_assign_op(ZEND_ASSIGN_BW_XOR, &$$, &$1, &$3 CLS_CC); }
+ | cvar T_SL_EQUAL expr { zend_do_end_variable_parse(BP_VAR_RW, 0 CLS_CC); zend_do_binary_assign_op(ZEND_ASSIGN_SL, &$$, &$1, &$3 CLS_CC); }
+ | cvar T_SR_EQUAL expr { zend_do_end_variable_parse(BP_VAR_RW, 0 CLS_CC); zend_do_binary_assign_op(ZEND_ASSIGN_SR, &$$, &$1, &$3 CLS_CC); }
+ | rw_cvar T_INC { zend_do_post_incdec(&$$, &$1, ZEND_POST_INC CLS_CC); }
+ | T_INC rw_cvar { zend_do_pre_incdec(&$$, &$2, ZEND_PRE_INC CLS_CC); }
+ | rw_cvar T_DEC { zend_do_post_incdec(&$$, &$1, ZEND_POST_DEC CLS_CC); }
+ | T_DEC rw_cvar { zend_do_pre_incdec(&$$, &$2, ZEND_PRE_DEC CLS_CC); }
+ | expr T_BOOLEAN_OR { zend_do_boolean_or_begin(&$1, &$2 CLS_CC); } expr { zend_do_boolean_or_end(&$$, &$1, &$4, &$2 CLS_CC); }
+ | expr T_BOOLEAN_AND { zend_do_boolean_and_begin(&$1, &$2 CLS_CC); } expr { zend_do_boolean_and_end(&$$, &$1, &$4, &$2 CLS_CC); }
+ | expr T_LOGICAL_OR { zend_do_boolean_or_begin(&$1, &$2 CLS_CC); } expr { zend_do_boolean_or_end(&$$, &$1, &$4, &$2 CLS_CC); }
+ | expr T_LOGICAL_AND { zend_do_boolean_and_begin(&$1, &$2 CLS_CC); } expr { zend_do_boolean_and_end(&$$, &$1, &$4, &$2 CLS_CC); }
+ | expr T_LOGICAL_XOR expr { zend_do_binary_op(ZEND_BOOL_XOR, &$$, &$1, &$3 CLS_CC); }
+ | expr '|' expr { zend_do_binary_op(ZEND_BW_OR, &$$, &$1, &$3 CLS_CC); }
+ | expr '&' expr { zend_do_binary_op(ZEND_BW_AND, &$$, &$1, &$3 CLS_CC); }
+ | expr '^' expr { zend_do_binary_op(ZEND_BW_XOR, &$$, &$1, &$3 CLS_CC); }
+ | expr '.' expr { zend_do_binary_op(ZEND_CONCAT,&$$,&$1,&$3 CLS_CC); }
+ | expr '+' expr { zend_do_binary_op(ZEND_ADD,&$$,&$1,&$3 CLS_CC); }
+ | expr '-' expr { zend_do_binary_op(ZEND_SUB,&$$,&$1,&$3 CLS_CC); }
+ | expr '*' expr { zend_do_binary_op(ZEND_MUL,&$$,&$1,&$3 CLS_CC); }
+ | expr '/' expr { zend_do_binary_op(ZEND_DIV,&$$,&$1,&$3 CLS_CC); }
+ | expr '%' expr { zend_do_binary_op(ZEND_MOD,&$$,&$1,&$3 CLS_CC); }
+ | expr T_SL expr { zend_do_binary_op(ZEND_SL, &$$, &$1, &$3 CLS_CC); }
+ | expr T_SR expr { zend_do_binary_op(ZEND_SR, &$$, &$1, &$3 CLS_CC); }
+ | '+' expr { $1.u.constant.value.lval=0; $1.u.constant.type=IS_LONG; $1.op_type = IS_CONST; INIT_PZVAL(&$1.u.constant); zend_do_binary_op(ZEND_ADD, &$$, &$1, &$2 CLS_CC); }
+ | '-' expr { $1.u.constant.value.lval=0; $1.u.constant.type=IS_LONG; $1.op_type = IS_CONST; INIT_PZVAL(&$1.u.constant); zend_do_binary_op(ZEND_SUB, &$$, &$1, &$2 CLS_CC); }
+ | '!' expr { zend_do_unary_op(ZEND_BOOL_NOT, &$$, &$2 CLS_CC); }
+ | '~' expr { zend_do_unary_op(ZEND_BW_NOT, &$$, &$2 CLS_CC); }
+ | expr T_IS_IDENTICAL expr { zend_do_binary_op(ZEND_IS_IDENTICAL, &$$, &$1, &$3 CLS_CC); }
+ | expr T_IS_NOT_IDENTICAL expr { zend_do_binary_op(ZEND_IS_NOT_IDENTICAL, &$$, &$1, &$3 CLS_CC); }
+ | expr T_IS_EQUAL expr { zend_do_binary_op(ZEND_IS_EQUAL, &$$, &$1, &$3 CLS_CC); }
+ | expr T_IS_NOT_EQUAL expr { zend_do_binary_op(ZEND_IS_NOT_EQUAL, &$$, &$1, &$3 CLS_CC); }
+ | expr '<' expr { zend_do_binary_op(ZEND_IS_SMALLER, &$$, &$1, &$3 CLS_CC); }
+ | expr T_IS_SMALLER_OR_EQUAL expr { zend_do_binary_op(ZEND_IS_SMALLER_OR_EQUAL, &$$, &$1, &$3 CLS_CC); }
+ | expr '>' expr { zend_do_binary_op(ZEND_IS_SMALLER, &$$, &$3, &$1 CLS_CC); }
+ | expr T_IS_GREATER_OR_EQUAL expr { zend_do_binary_op(ZEND_IS_SMALLER_OR_EQUAL, &$$, &$3, &$1 CLS_CC); }
+ | '(' expr ')' { $$ = $2; }
+ | expr '?' { zend_do_begin_qm_op(&$1, &$2 CLS_CC); }
+ expr ':' { zend_do_qm_true(&$4, &$2, &$5 CLS_CC); }
+ expr { zend_do_qm_false(&$$, &$7, &$2, &$5 CLS_CC); }
+ | function_call { $$ = $1; }
+ | internal_functions_in_yacc { $$ = $1; }
+ | T_INT_CAST expr { zend_do_cast(&$$, &$2, IS_LONG CLS_CC); }
+ | T_DOUBLE_CAST expr { zend_do_cast(&$$, &$2, IS_DOUBLE CLS_CC); }
+ | T_STRING_CAST expr { zend_do_cast(&$$, &$2, IS_STRING CLS_CC); }
+ | T_ARRAY_CAST expr { zend_do_cast(&$$, &$2, IS_ARRAY CLS_CC); }
+ | T_OBJECT_CAST expr { zend_do_cast(&$$, &$2, IS_OBJECT CLS_CC); }
+ | T_BOOL_CAST expr { zend_do_cast(&$$, &$2, IS_BOOL CLS_CC); }
+ | T_UNSET_CAST expr { zend_do_cast(&$$, &$2, IS_NULL CLS_CC); }
+ | T_EXIT exit_expr { zend_do_exit(&$$, &$2 CLS_CC); }
+ | '@' { zend_do_begin_silence(&$1 CLS_CC); } expr { zend_do_end_silence(&$1 CLS_CC); $$ = $3; }
+ | scalar { $$ = $1; }
+ | T_ARRAY '(' array_pair_list ')' { $$ = $3; }
+ | '`' encaps_list '`' { zend_do_shell_exec(&$$, &$2 CLS_CC); }
+ | T_PRINT expr { zend_do_print(&$$, &$2 CLS_CC); }
+;
+
+function_call:
+ T_STRING '(' { $2.u.opline_num = zend_do_begin_function_call(&$1 CLS_CC); }
+ function_call_parameter_list
+ ')' { zend_do_end_function_call(&$1, &$$, &$4, 0, $2.u.opline_num CLS_CC); zend_do_extended_fcall_end(CLS_C); }
+ | cvar '(' { zend_do_begin_dynamic_function_call(&$1 CLS_CC); }
+ function_call_parameter_list
+ ')' { zend_do_end_function_call(&$1, &$$, &$4, 0, 1 CLS_CC); zend_do_extended_fcall_end(CLS_C);}
+ | T_STRING T_PAAMAYIM_NEKUDOTAYIM T_STRING '(' { zend_do_extended_fcall_begin(CLS_C); zend_do_begin_class_member_function_call(&$1, &$3 CLS_CC); }
+ function_call_parameter_list
+ ')' { zend_do_end_function_call(&$3, &$$, &$6, 1, 1 CLS_CC); zend_do_extended_fcall_end(CLS_C);}
+;
+
+
+exit_expr:
+ /* empty */ { memset(&$$, 0, sizeof(znode)); $$.op_type = IS_UNUSED; }
+ | '(' ')' { memset(&$$, 0, sizeof(znode)); $$.op_type = IS_UNUSED; }
+ | '(' expr ')' { $$ = $2; }
+;
+
+
+ctor_arguments:
+ /* empty */ { $$.u.constant.value.lval=0; }
+ | '(' function_call_parameter_list ')' { $$ = $2; }
+;
+
+
+class_name:
+ T_STRING { $$ = $1; }
+ | r_cvar { $$ = $1; }
+;
+
+
+
+common_scalar:
+ T_LNUMBER { $$ = $1; }
+ | T_DNUMBER { $$ = $1; }
+ | T_CONSTANT_ENCAPSED_STRING { $$ = $1; }
+ | T_LINE { $$ = $1; }
+ | T_FILE { $$ = $1; }
+;
+
+
+static_scalar: /* compile-time evaluated scalars */
+ common_scalar { $$ = $1; }
+ | T_STRING { zend_do_fetch_constant(&$$, &$1, ZEND_CT CLS_CC); }
+ | '+' static_scalar { $$ = $1; }
+ | '-' static_scalar { zval minus_one; minus_one.type = IS_LONG; minus_one.value.lval = -1; mul_function(&$2.u.constant, &$2.u.constant, &minus_one); $$ = $2; }
+ | T_ARRAY '(' static_array_pair_list ')' { $$ = $3; $$.u.constant.type = IS_CONSTANT_ARRAY; }
+;
+
+
+scalar:
+ T_STRING { zend_do_fetch_constant(&$$, &$1, ZEND_RT CLS_CC); }
+ | T_STRING_VARNAME { $$ = $1; }
+ | common_scalar { $$ = $1; }
+ | '"' encaps_list '"' { $$ = $2; }
+ | '\'' encaps_list '\'' { $$ = $2; }
+ | T_START_HEREDOC encaps_list T_END_HEREDOC { $$ = $2; zend_do_end_heredoc(CLS_C); }
+;
+
+
+static_array_pair_list:
+ /* empty */ { $$.op_type = IS_CONST; INIT_PZVAL(&$$.u.constant); array_init(&$$.u.constant); }
+ | non_empty_static_array_pair_list possible_comma { $$ = $1; }
+;
+
+possible_comma:
+ /* empty */
+ | ','
+;
+
+non_empty_static_array_pair_list:
+ non_empty_static_array_pair_list ',' static_scalar T_DOUBLE_ARROW static_scalar { zend_do_add_static_array_element(&$$, &$3, &$5); }
+ | non_empty_static_array_pair_list ',' static_scalar { zend_do_add_static_array_element(&$$, NULL, &$3); }
+ | static_scalar T_DOUBLE_ARROW static_scalar { $$.op_type = IS_CONST; INIT_PZVAL(&$$.u.constant); array_init(&$$.u.constant); zend_do_add_static_array_element(&$$, &$1, &$3); }
+ | static_scalar { $$.op_type = IS_CONST; INIT_PZVAL(&$$.u.constant); array_init(&$$.u.constant); zend_do_add_static_array_element(&$$, NULL, &$1); }
+;
+
+expr:
+ r_cvar { $$ = $1; }
+ | expr_without_variable { $$ = $1; }
+;
+
+/*
+w_expr:
+ w_cvar { $$ = $1; }
+ | expr_without_variable { $$ = $1; }
+;
+*/
+
+
+r_cvar:
+ cvar { zend_do_end_variable_parse(BP_VAR_R, 0 CLS_CC); $$ = $1; }
+;
+
+
+w_cvar:
+ cvar { zend_do_end_variable_parse(BP_VAR_W, 0 CLS_CC); $$ = $1; }
+;
+
+
+rw_cvar:
+ cvar { zend_do_end_variable_parse(BP_VAR_RW, 0 CLS_CC); $$ = $1; }
+;
+
+
+cvar:
+ cvar_without_objects { $$ = $1; }
+ | cvar_without_objects T_OBJECT_OPERATOR { zend_do_push_object(&$1 CLS_CC); } ref_list { $$ = $4; }
+;
+
+
+cvar_without_objects:
+ reference_variable { $$ = $1; }
+ | simple_indirect_reference reference_variable { zend_do_indirect_references(&$$, &$1, &$2 CLS_CC); }
+;
+
+
+reference_variable:
+ reference_variable '[' dim_offset ']' { fetch_array_dim(&$$, &$1, &$3 CLS_CC); }
+ | reference_variable '{' expr '}' { fetch_string_offset(&$$, &$1, &$3 CLS_CC); }
+ | compound_variable { zend_do_fetch_globals(&$1 CLS_CC); zend_do_begin_variable_parse(CLS_C); fetch_simple_variable(&$$, &$1, 1 CLS_CC); }
+;
+
+
+compound_variable:
+ T_VARIABLE { $$ = $1; }
+ | '$' '{' expr '}' { $$ = $3; }
+;
+
+dim_offset:
+ /* empty */ { $$.op_type = IS_UNUSED; }
+ | expr { $$ = $1; }
+;
+
+ref_list:
+ object_property { $$ = $1; }
+ | ref_list T_OBJECT_OPERATOR { zend_do_push_object(&$1 CLS_CC); } object_property { $$ = $4; }
+;
+
+object_property:
+ object_dim_list { $$ = $1; }
+ | cvar_without_objects { zend_do_end_variable_parse(BP_VAR_R, 0 CLS_CC); } { znode tmp_znode; zend_do_pop_object(&tmp_znode CLS_CC); zend_do_fetch_property(&$$, &tmp_znode, &$1 CLS_CC);}
+;
+
+object_dim_list:
+ object_dim_list '[' dim_offset ']' { fetch_array_dim(&$$, &$1, &$3 CLS_CC); }
+ | object_dim_list '{' expr '}' { fetch_string_offset(&$$, &$1, &$3 CLS_CC); }
+ | variable_name { znode tmp_znode; zend_do_pop_object(&tmp_znode CLS_CC); zend_do_fetch_property(&$$, &tmp_znode, &$1 CLS_CC);}
+;
+
+variable_name:
+ T_STRING { $$ = $1; }
+ | '{' expr '}' { $$ = $2; }
+;
+
+
+simple_indirect_reference:
+ '$' { $$.u.constant.value.lval = 1; }
+ | simple_indirect_reference '$' { $$.u.constant.value.lval++; }
+;
+
+assignment_list:
+ assignment_list ',' assignment_list_element
+ | assignment_list_element
+;
+
+
+assignment_list_element:
+ cvar { zend_do_add_list_element(&$1 CLS_CC); }
+ | T_LIST '(' { zend_do_new_list_begin(CLS_C); } assignment_list ')' { zend_do_new_list_end(CLS_C); }
+ | /* empty */ { zend_do_add_list_element(NULL CLS_CC); }
+;
+
+
+array_pair_list:
+ /* empty */ { zend_do_init_array(&$$, NULL, NULL, 0 CLS_CC); }
+ | non_empty_array_pair_list possible_comma { $$ = $1; }
+;
+
+non_empty_array_pair_list:
+ non_empty_array_pair_list ',' expr T_DOUBLE_ARROW expr { zend_do_add_array_element(&$$, &$5, &$3, 0 CLS_CC); }
+ | non_empty_array_pair_list ',' expr { zend_do_add_array_element(&$$, &$3, NULL, 0 CLS_CC); }
+ | expr T_DOUBLE_ARROW expr { zend_do_init_array(&$$, &$3, &$1, 0 CLS_CC); }
+ | expr { zend_do_init_array(&$$, &$1, NULL, 0 CLS_CC); }
+ | non_empty_array_pair_list ',' expr T_DOUBLE_ARROW '&' w_cvar { zend_do_add_array_element(&$$, &$6, &$3, 1 CLS_CC); }
+ | non_empty_array_pair_list ',' '&' w_cvar { zend_do_add_array_element(&$$, &$4, NULL, 1 CLS_CC); }
+ | expr T_DOUBLE_ARROW '&' w_cvar { zend_do_init_array(&$$, &$4, &$1, 1 CLS_CC); }
+ | '&' w_cvar { zend_do_init_array(&$$, &$2, NULL, 1 CLS_CC); }
+;
+
+encaps_list:
+ encaps_list encaps_var { zend_do_end_variable_parse(BP_VAR_R, 0 CLS_CC); zend_do_add_variable(&$$, &$1, &$2 CLS_CC); }
+ | encaps_list T_STRING { zend_do_add_string(&$$, &$1, &$2 CLS_CC); }
+ | encaps_list T_NUM_STRING { zend_do_add_string(&$$, &$1, &$2 CLS_CC); }
+ | encaps_list T_ENCAPSED_AND_WHITESPACE { zend_do_add_string(&$$, &$1, &$2 CLS_CC); }
+ | encaps_list T_CHARACTER { zend_do_add_char(&$$, &$1, &$2 CLS_CC); }
+ | encaps_list T_BAD_CHARACTER { zend_do_add_string(&$$, &$1, &$2 CLS_CC); }
+ | encaps_list '[' { $2.u.constant.value.lval = (long) '['; zend_do_add_char(&$$, &$1, &$2 CLS_CC); }
+ | encaps_list ']' { $2.u.constant.value.lval = (long) ']'; zend_do_add_char(&$$, &$1, &$2 CLS_CC); }
+ | encaps_list '{' { $2.u.constant.value.lval = (long) '{'; zend_do_add_char(&$$, &$1, &$2 CLS_CC); }
+ | encaps_list '}' { $2.u.constant.value.lval = (long) '}'; zend_do_add_char(&$$, &$1, &$2 CLS_CC); }
+ | encaps_list T_OBJECT_OPERATOR { znode tmp; $2.u.constant.value.lval = (long) '-'; zend_do_add_char(&tmp, &$1, &$2 CLS_CC); $2.u.constant.value.lval = (long) '>'; zend_do_add_char(&$$, &tmp, &$2 CLS_CC); }
+ | /* empty */ { zend_do_init_string(&$$ CLS_CC); }
+
+;
+
+
+
+encaps_var:
+ T_VARIABLE { zend_do_fetch_globals(&$1 CLS_CC); zend_do_begin_variable_parse(CLS_C); fetch_simple_variable(&$$, &$1, 1 CLS_CC); }
+ | T_VARIABLE '[' { zend_do_begin_variable_parse(CLS_C); } encaps_var_offset ']' { zend_do_fetch_globals(&$1 CLS_CC); fetch_array_begin(&$$, &$1, &$4 CLS_CC); }
+ | T_VARIABLE T_OBJECT_OPERATOR T_STRING { zend_do_begin_variable_parse(CLS_C); fetch_simple_variable(&$2, &$1, 1 CLS_CC); zend_do_fetch_property(&$$, &$2, &$3 CLS_CC); }
+ | T_DOLLAR_OPEN_CURLY_BRACES expr '}' { zend_do_begin_variable_parse(CLS_C); fetch_simple_variable(&$$, &$2, 1 CLS_CC); }
+ | T_DOLLAR_OPEN_CURLY_BRACES T_STRING_VARNAME '[' expr ']' '}' { zend_do_begin_variable_parse(CLS_C); fetch_array_begin(&$$, &$2, &$4 CLS_CC); }
+ | T_CURLY_OPEN cvar '}' { $$ = $2; }
+;
+
+
+encaps_var_offset:
+ T_STRING { $$ = $1; }
+ | T_NUM_STRING { $$ = $1; }
+ | T_VARIABLE { fetch_simple_variable(&$$, &$1, 1 CLS_CC); }
+;
+
+
+internal_functions_in_yacc:
+ T_ISSET '(' cvar ')' { zend_do_isset_or_isempty(ZEND_ISSET, &$$, &$3 CLS_CC); }
+ | T_EMPTY '(' cvar ')' { zend_do_isset_or_isempty(ZEND_ISEMPTY, &$$, &$3 CLS_CC); }
+ | T_INCLUDE expr { zend_do_include_or_eval(ZEND_INCLUDE, &$$, &$2 CLS_CC); }
+ | T_INCLUDE_ONCE expr { zend_do_include_or_eval(ZEND_INCLUDE_ONCE, &$$, &$2 CLS_CC); }
+ | T_EVAL '(' expr ')' { zend_do_include_or_eval(ZEND_EVAL, &$$, &$3 CLS_CC); }
+ | T_REQUIRE expr { zend_do_include_or_eval(ZEND_REQUIRE, &$$, &$2 CLS_CC); }
+ | T_REQUIRE_ONCE expr { zend_do_include_or_eval(ZEND_REQUIRE_ONCE, &$$, &$2 CLS_CC); }
+;
+
+
+%%
+
diff --git a/Zend/zend_modules.h b/Zend/zend_modules.h
new file mode 100644
index 0000000000..0dd01306c8
--- /dev/null
+++ b/Zend/zend_modules.h
@@ -0,0 +1,85 @@
+/*
+ +----------------------------------------------------------------------+
+ | Zend Engine |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1998-2000 Zend Technologies Ltd. (http://www.zend.com) |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 0.92 of the Zend license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available at through the world-wide-web at |
+ | http://www.zend.com/license/0_92.txt. |
+ | If you did not receive a copy of the Zend license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@zend.com so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Andi Gutmans <andi@zend.com> |
+ | Zeev Suraski <zeev@zend.com> |
+ +----------------------------------------------------------------------+
+*/
+
+
+#ifndef MODULES_H
+#define MODULES_H
+
+#define INIT_FUNC_ARGS int type, int module_number ELS_DC
+#define INIT_FUNC_ARGS_PASSTHRU type, module_number ELS_CC
+#define SHUTDOWN_FUNC_ARGS int type, int module_number
+#define SHUTDOWN_FUNC_ARGS_PASSTHRU type, module_number
+#define ZEND_MODULE_INFO_FUNC_ARGS zend_module_entry *zend_module
+#define ZEND_MODULE_INFO_FUNC_ARGS_PASSTHRU zend_module
+#define GINIT_FUNC_ARGS void
+#define GINIT_FUNC_ARGS_PASSTHRU
+
+extern unsigned char first_arg_force_ref[];
+extern unsigned char first_arg_allow_ref[];
+extern unsigned char second_arg_force_ref[];
+extern unsigned char second_arg_allow_ref[];
+
+#include "zend.h"
+
+#define ZEND_MODULE_API_NO 20000809
+#ifdef ZTS
+#define USING_ZTS 1
+#else
+#define USING_ZTS 0
+#endif
+
+#define STANDARD_MODULE_PROPERTIES_EX 0, 0, 0, NULL, 0, ZEND_DEBUG, USING_ZTS, ZEND_MODULE_API_NO
+
+#define STANDARD_MODULE_PROPERTIES \
+ NULL, NULL, STANDARD_MODULE_PROPERTIES_EX
+
+#define MODULE_PERSISTENT 1
+#define MODULE_TEMPORARY 2
+
+typedef struct _zend_module_entry zend_module_entry;
+
+struct _zend_module_entry {
+ char *name;
+ zend_function_entry *functions;
+ int (*module_startup_func)(INIT_FUNC_ARGS);
+ int (*module_shutdown_func)(SHUTDOWN_FUNC_ARGS);
+ int (*request_startup_func)(INIT_FUNC_ARGS);
+ int (*request_shutdown_func)(SHUTDOWN_FUNC_ARGS);
+ void (*info_func)(ZEND_MODULE_INFO_FUNC_ARGS);
+ int (*global_startup_func)(void);
+ int (*global_shutdown_func)(void);
+ int globals_id;
+ int module_started;
+ unsigned char type;
+ void *handle;
+ int module_number;
+ unsigned char zend_debug;
+ unsigned char zts;
+ unsigned int zend_api;
+};
+
+
+extern ZEND_API HashTable module_registry;
+
+void module_destructor(zend_module_entry *module);
+int module_registry_cleanup(zend_module_entry *module);
+int module_registry_request_startup(zend_module_entry *module);
+
+#define ZEND_MODULE_DTOR (void (*)(void *)) module_destructor
+#endif
diff --git a/Zend/zend_operators.c b/Zend/zend_operators.c
new file mode 100644
index 0000000000..09734abac5
--- /dev/null
+++ b/Zend/zend_operators.c
@@ -0,0 +1,1753 @@
+/*
+ +----------------------------------------------------------------------+
+ | Zend Engine |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1998-2000 Zend Technologies Ltd. (http://www.zend.com) |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 0.92 of the Zend license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available at through the world-wide-web at |
+ | http://www.zend.com/license/0_92.txt. |
+ | If you did not receive a copy of the Zend license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@zend.com so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Andi Gutmans <andi@zend.com> |
+ | Zeev Suraski <zeev@zend.com> |
+ +----------------------------------------------------------------------+
+*/
+
+
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <ctype.h>
+#include <math.h>
+
+#include "zend.h"
+#include "zend_operators.h"
+#include "zend_variables.h"
+#include "zend_globals.h"
+#include "zend_list.h"
+#include "zend_fast_cache.h"
+
+#if 0&&WITH_BCMATH
+#include "ext/bcmath/number.h"
+#endif
+
+ZEND_API int zend_atoi(const char *str, int str_len)
+{
+ int retval;
+
+ if (!str_len) {
+ str_len = strlen(str);
+ }
+ retval = atoi(str);
+ if (str_len>0) {
+ switch (str[str_len-1]) {
+ case 'k':
+ case 'K':
+ retval *= 1024;
+ break;
+ case 'm':
+ case 'M':
+ retval *= 1048576;
+ break;
+ }
+ }
+ return retval;
+}
+
+
+ZEND_API double zend_string_to_double(const char *number, zend_uint length)
+{
+ double divisor = 10.0;
+ double result = 0.0;
+ double exponent;
+ const char *end = number+length;
+ const char *digit = number;
+
+ if (!length) {
+ return result;
+ }
+
+ while (digit < end) {
+ if ((*digit <= '9' && *digit >= '0')) {
+ result *= 10;
+ result += *digit - '0';
+ } else if (*digit == '.') {
+ digit++;
+ break;
+ } else if (toupper(*digit) == 'E') {
+ exponent = (double) atoi(digit+1);
+ result *= pow(10.0, exponent);
+ return result;
+ } else {
+ return result;
+ }
+ digit++;
+ }
+
+ while (digit < end) {
+ if ((*digit <= '9' && *digit >= '0')) {
+ result += (*digit - '0') / divisor;
+ divisor *= 10;
+ } else if (toupper(*digit) == 'E') {
+ exponent = (double) atoi(digit+1);
+ result *= pow(10.0, exponent);
+ return result;
+ } else {
+ return result;
+ }
+ digit++;
+ }
+ return result;
+}
+
+
+ZEND_API void convert_scalar_to_number(zval *op)
+{
+ char *strval;
+
+ if (op->type == IS_STRING) {
+ strval = op->value.str.val;
+ switch ((op->type=is_numeric_string(strval, op->value.str.len, &op->value.lval, &op->value.dval))) {
+ case IS_DOUBLE:
+ case IS_LONG:
+ break;
+#if 0&&WITH_BCMATH
+ case FLAG_IS_BC:
+ op->type = IS_DOUBLE; /* may have lost significant digits */
+ break;
+#endif
+ default:
+ op->value.lval = strtol(op->value.str.val, NULL, 10);
+ op->type = IS_LONG;
+ break;
+ }
+ STR_FREE(strval);
+ } else if (op->type==IS_BOOL || op->type==IS_RESOURCE) {
+ op->type = IS_LONG;
+ } else if (op->type==IS_NULL) {
+ op->type = IS_LONG;
+ op->value.lval = 0;
+ }
+}
+
+#define zendi_convert_scalar_to_number(op, holder, result) \
+ if (op==result) { \
+ convert_scalar_to_number(op); \
+ } else if ((op)->type == IS_STRING) { \
+ switch (((holder).type=is_numeric_string((op)->value.str.val, (op)->value.str.len, &(holder).value.lval, &(holder).value.dval))) { \
+ case IS_DOUBLE: \
+ case IS_LONG: \
+ break; \
+ case FLAG_IS_BC: \
+ (holder).type = IS_DOUBLE; /* may have lost significant digits */ \
+ break; \
+ default: \
+ (holder).value.lval = strtol((op)->value.str.val, NULL, 10); \
+ (holder).type = IS_LONG; \
+ break; \
+ } \
+ (op) = &(holder); \
+ } else if ((op)->type==IS_BOOL || (op)->type==IS_RESOURCE) { \
+ (holder).value.lval = (op)->value.lval; \
+ (holder).type = IS_LONG; \
+ (op) = &(holder); \
+ } else if ((op)->type==IS_NULL) { \
+ (holder).value.lval = 0; \
+ (holder).type = IS_LONG; \
+ (op) = &(holder); \
+ }
+
+
+
+#define zendi_convert_to_long(op, holder, result) \
+ if (op==result) { \
+ convert_to_long(op); \
+ } else if ((op)->type==IS_BOOL || (op)->type==IS_RESOURCE) { \
+ (holder).value.lval = (op)->value.lval; \
+ (holder).type = IS_LONG; \
+ (op) = &(holder); \
+ } else if ((op)->type != IS_LONG) { \
+ switch ((op)->type) { \
+ case IS_NULL: \
+ (holder).value.lval = 0; \
+ break; \
+ case IS_DOUBLE: \
+ (holder).value.lval = (long) (op)->value.dval; \
+ break; \
+ case IS_STRING: \
+ (holder).value.lval = strtol((op)->value.str.val, NULL, 10); \
+ break; \
+ case IS_ARRAY: \
+ (holder).value.lval = (zend_hash_num_elements((op)->value.ht)?1:0); \
+ break; \
+ case IS_OBJECT: \
+ (holder).value.lval = (zend_hash_num_elements((op)->value.obj.properties)?1:0); \
+ break; \
+ default: \
+ zend_error(E_WARNING, "Cannot convert to ordinal value"); \
+ (holder).value.lval = 0; \
+ break; \
+ } \
+ (holder).type = IS_LONG; \
+ (op) = &(holder); \
+ }
+
+
+#define zendi_convert_to_boolean(op, holder, result) \
+ if (op==result) { \
+ convert_to_boolean(op); \
+ } else if ((op)->type != IS_BOOL) { \
+ switch ((op)->type) { \
+ case IS_NULL: \
+ (holder).value.lval = 0; \
+ break; \
+ case IS_RESOURCE: \
+ case IS_LONG: \
+ (holder).value.lval = ((op)->value.lval ? 1 : 0); \
+ break; \
+ case IS_DOUBLE: \
+ (holder).value.lval = ((op)->value.dval ? 1 : 0); \
+ break; \
+ case IS_STRING: \
+ if ((op)->value.str.len == 0 \
+ || ((op)->value.str.len==1 && (op)->value.str.val[0]=='0')) { \
+ (holder).value.lval = 0; \
+ } else { \
+ (holder).value.lval = 1; \
+ } \
+ break; \
+ case IS_ARRAY: \
+ (holder).value.lval = (zend_hash_num_elements((op)->value.ht)?1:0); \
+ break; \
+ case IS_OBJECT: \
+ (holder).value.lval = (zend_hash_num_elements((op)->value.obj.properties)?1:0); \
+ break; \
+ default: \
+ (holder).value.lval = 0; \
+ break; \
+ } \
+ (holder).type = IS_BOOL; \
+ (op) = &(holder); \
+ }
+
+
+ZEND_API void convert_to_long(zval *op)
+{
+ convert_to_long_base(op, 10);
+}
+
+
+ZEND_API void convert_to_long_base(zval *op, int base)
+{
+ char *strval;
+ long tmp;
+
+ switch (op->type) {
+ case IS_NULL:
+ op->value.lval = 0;
+ break;
+ case IS_RESOURCE:
+ case IS_BOOL:
+ case IS_LONG:
+ break;
+ case IS_DOUBLE:
+ op->value.lval = (long) op->value.dval;
+ break;
+ case IS_STRING:
+ strval = op->value.str.val;
+ op->value.lval = strtol(strval, NULL, base);
+ STR_FREE(strval);
+ break;
+ case IS_ARRAY:
+ tmp = (zend_hash_num_elements(op->value.ht)?1:0);
+ zval_dtor(op);
+ op->value.lval = tmp;
+ break;
+ case IS_OBJECT:
+ tmp = (zend_hash_num_elements(op->value.obj.properties)?1:0);
+ zval_dtor(op);
+ op->value.lval = tmp;
+ break;
+ default:
+ zend_error(E_WARNING, "Cannot convert to ordinal value");
+ zval_dtor(op);
+ op->value.lval = 0;
+ break;
+ }
+
+ op->type = IS_LONG;
+}
+
+
+ZEND_API void convert_to_double(zval *op)
+{
+ char *strval;
+ double tmp;
+
+ switch (op->type) {
+ case IS_NULL:
+ op->value.dval = 0.0;
+ break;
+ case IS_RESOURCE:
+ case IS_BOOL:
+ case IS_LONG:
+ op->value.dval = (double) op->value.lval;
+ break;
+ case IS_DOUBLE:
+ break;
+ case IS_STRING:
+ strval = op->value.str.val;
+
+ op->value.dval = strtod(strval, NULL);
+ STR_FREE(strval);
+ break;
+ case IS_ARRAY:
+ tmp = (zend_hash_num_elements(op->value.ht)?1:0);
+ zval_dtor(op);
+ op->value.dval = tmp;
+ break;
+ case IS_OBJECT:
+ tmp = (zend_hash_num_elements(op->value.obj.properties)?1:0);
+ zval_dtor(op);
+ op->value.dval = tmp;
+ break;
+ default:
+ zend_error(E_WARNING, "Cannot convert to real value (type=%d)", op->type);
+ zval_dtor(op);
+ op->value.dval = 0;
+ break;
+ }
+ op->type = IS_DOUBLE;
+}
+
+
+ZEND_API void convert_to_null(zval *op)
+{
+ zval_dtor(op);
+ op->type = IS_NULL;
+}
+
+
+ZEND_API void convert_to_boolean(zval *op)
+{
+ char *strval;
+ int tmp;
+
+ switch (op->type) {
+ case IS_BOOL:
+ break;
+ case IS_NULL:
+ op->value.lval = 0;
+ break;
+ case IS_RESOURCE:
+ case IS_LONG:
+ op->value.lval = (op->value.lval ? 1 : 0);
+ break;
+ case IS_DOUBLE:
+ op->value.lval = (op->value.dval ? 1 : 0);
+ break;
+ case IS_STRING:
+ strval = op->value.str.val;
+
+ if (op->value.str.len == 0
+ || (op->value.str.len==1 && op->value.str.val[0]=='0')) {
+ op->value.lval = 0;
+ } else {
+ op->value.lval = 1;
+ }
+ STR_FREE(strval);
+ break;
+ case IS_ARRAY:
+ tmp = (zend_hash_num_elements(op->value.ht)?1:0);
+ zval_dtor(op);
+ op->value.lval = tmp;
+ break;
+ case IS_OBJECT:
+ tmp = (zend_hash_num_elements(op->value.obj.properties)?1:0);
+ zval_dtor(op);
+ op->value.lval = tmp;
+ break;
+ default:
+ zval_dtor(op);
+ op->value.lval = 0;
+ break;
+ }
+ op->type = IS_BOOL;
+}
+
+
+ZEND_API void _convert_to_string(zval *op ZEND_FILE_LINE_DC)
+{
+ long lval;
+ double dval;
+ ELS_FETCH();
+
+ switch (op->type) {
+ case IS_NULL:
+ op->value.str.val = empty_string;
+ op->value.str.len = 0;
+ break;
+ case IS_STRING:
+ break;
+ case IS_BOOL:
+ if (op->value.lval) {
+ op->value.str.val = estrndup_rel("1", 1);
+ op->value.str.len = 1;
+ } else {
+ op->value.str.val = empty_string;
+ op->value.str.len = 0;
+ }
+ break;
+ case IS_RESOURCE: {
+ long tmp = op->value.lval;
+ op->value.str.val = (char *) emalloc(sizeof("Resource id #")-1 + MAX_LENGTH_OF_LONG);
+ op->value.str.len = sprintf(op->value.str.val, "Resource id #%ld", tmp);
+ break;
+ }
+ case IS_LONG:
+ lval = op->value.lval;
+
+ op->value.str.val = (char *) emalloc_rel(MAX_LENGTH_OF_LONG + 1);
+ op->value.str.len = zend_sprintf(op->value.str.val, "%ld", lval); /* SAFE */
+ break;
+ case IS_DOUBLE: {
+ dval = op->value.dval;
+ op->value.str.val = (char *) emalloc_rel(MAX_LENGTH_OF_DOUBLE + EG(precision) + 1);
+ op->value.str.len = zend_sprintf(op->value.str.val, "%.*G", (int) EG(precision), dval); /* SAFE */
+ /* %G already handles removing trailing zeros from the fractional part, yay */
+ break;
+ }
+ case IS_ARRAY:
+ zval_dtor(op);
+ op->value.str.val = estrndup_rel("Array",sizeof("Array")-1);
+ op->value.str.len = sizeof("Array")-1;
+ break;
+ case IS_OBJECT:
+ zval_dtor(op);
+ op->value.str.val = estrndup_rel("Object",sizeof("Object")-1);
+ op->value.str.len = sizeof("Object")-1;
+ break;
+ default:
+ zval_dtor(op);
+ var_reset(op);
+ break;
+ }
+ op->type = IS_STRING;
+}
+
+
+static void convert_scalar_to_array(zval *op, int type)
+{
+ zval *entry;
+
+ ALLOC_ZVAL(entry);
+ *entry = *op;
+ INIT_PZVAL(entry);
+
+ switch (type) {
+ case IS_ARRAY:
+ ALLOC_HASHTABLE(op->value.ht);
+ zend_hash_init(op->value.ht, 0, NULL, ZVAL_PTR_DTOR, 0);
+ zend_hash_index_update(op->value.ht, 0, (void *) &entry, sizeof(zval *), NULL);
+ op->type = IS_ARRAY;
+ break;
+ case IS_OBJECT:
+ ALLOC_HASHTABLE(op->value.obj.properties);
+ zend_hash_init(op->value.obj.properties, 0, NULL, ZVAL_PTR_DTOR, 0);
+ zend_hash_update(op->value.obj.properties, "scalar", sizeof("scalar"), (void *) &entry, sizeof(zval *), NULL);
+ op->value.obj.ce = &zend_standard_class_def;
+ op->type = IS_OBJECT;
+ break;
+ }
+}
+
+
+ZEND_API void convert_to_array(zval *op)
+{
+ switch(op->type) {
+ case IS_ARRAY:
+ return;
+ break;
+ case IS_OBJECT:
+ op->type = IS_ARRAY;
+ op->value.ht = op->value.obj.properties;
+ return;
+ case IS_NULL:
+ ALLOC_HASHTABLE(op->value.ht);
+ zend_hash_init(op->value.ht, 0, NULL, ZVAL_PTR_DTOR, 0);
+ op->type = IS_ARRAY;
+ break;
+ default:
+ convert_scalar_to_array(op, IS_ARRAY);
+ break;
+ }
+}
+
+
+ZEND_API void convert_to_object(zval *op)
+{
+ switch(op->type) {
+ case IS_ARRAY:
+ op->type = IS_OBJECT;
+ op->value.obj.properties = op->value.ht;
+ op->value.obj.ce = &zend_standard_class_def;
+ return;
+ break;
+ case IS_OBJECT:
+ return;
+ case IS_NULL:
+ ALLOC_HASHTABLE(op->value.obj.properties);
+ zend_hash_init(op->value.obj.properties, 0, NULL, ZVAL_PTR_DTOR, 0);
+ op->value.obj.ce = &zend_standard_class_def;
+ op->type = IS_OBJECT;
+ break;
+ default:
+ convert_scalar_to_array(op, IS_OBJECT);
+ break;
+ }
+}
+
+ZEND_API void multi_convert_to_long_ex(int argc, ...)
+{
+ zval **arg;
+ va_list ap;
+
+ va_start(ap, argc);
+
+ while (argc--) {
+ arg = va_arg(ap, zval **);
+ convert_to_long_ex(arg);
+ }
+
+ va_end(ap);
+}
+
+ZEND_API void multi_convert_to_double_ex(int argc, ...)
+{
+ zval **arg;
+ va_list ap;
+
+ va_start(ap, argc);
+
+ while (argc--) {
+ arg = va_arg(ap, zval **);
+ convert_to_double_ex(arg);
+ }
+
+ va_end(ap);
+}
+
+ZEND_API void multi_convert_to_string_ex(int argc, ...)
+{
+ zval **arg;
+ va_list ap;
+
+ va_start(ap, argc);
+
+ while (argc--) {
+ arg = va_arg(ap, zval **);
+ convert_to_string_ex(arg);
+ }
+
+ va_end(ap);
+}
+
+ZEND_API int add_function(zval *result, zval *op1, zval *op2)
+{
+ zval op1_copy, op2_copy;
+
+ if (op1->type == IS_ARRAY && op2->type == IS_ARRAY) {
+ zval *tmp;
+
+ if ((result == op1) && (result == op2)) {
+ /* $a += $a */
+ return SUCCESS;
+ }
+ if (result != op1) {
+ /* $a += $b */
+ *result = *op1;
+ zval_copy_ctor(result);
+ }
+ zend_hash_merge(result->value.ht, op2->value.ht, (void (*)(void *pData)) zval_add_ref, (void *) &tmp, sizeof(zval *), 0);
+ return SUCCESS;
+ }
+ zendi_convert_scalar_to_number(op1, op1_copy, result);
+ zendi_convert_scalar_to_number(op2, op2_copy, result);
+
+
+ if (op1->type == IS_LONG && op2->type == IS_LONG) {
+ double dval = (double) op1->value.lval + (double) op2->value.lval;
+
+ if (dval > (double) LONG_MAX) {
+ result->value.dval = dval;
+ result->type = IS_DOUBLE;
+ } else {
+ result->value.lval = op1->value.lval + op2->value.lval;
+ result->type = IS_LONG;
+ }
+ return SUCCESS;
+ }
+ if ((op1->type == IS_DOUBLE && op2->type == IS_LONG)
+ || (op1->type == IS_LONG && op2->type == IS_DOUBLE)) {
+ result->value.dval = (op1->type == IS_LONG ?
+ (((double) op1->value.lval) + op2->value.dval) :
+ (op1->value.dval + ((double) op2->value.lval)));
+ result->type = IS_DOUBLE;
+ return SUCCESS;
+ }
+ if (op1->type == IS_DOUBLE && op2->type == IS_DOUBLE) {
+ result->type = IS_DOUBLE;
+ result->value.dval = op1->value.dval + op2->value.dval;
+ return SUCCESS;
+ }
+ zend_error(E_ERROR, "Unsupported operand types");
+ return FAILURE; /* unknown datatype */
+}
+
+
+ZEND_API int sub_function(zval *result, zval *op1, zval *op2)
+{
+ zval op1_copy, op2_copy;
+
+ zendi_convert_scalar_to_number(op1, op1_copy, result);
+ zendi_convert_scalar_to_number(op2, op2_copy, result);
+
+ if (op1->type == IS_LONG && op2->type == IS_LONG) {
+ double dval = (double) op1->value.lval - (double) op2->value.lval;
+
+ if (dval < (double) LONG_MIN) {
+ result->value.dval = dval;
+ result->type = IS_DOUBLE;
+ } else {
+ result->value.lval = op1->value.lval - op2->value.lval;
+ result->type = IS_LONG;
+ }
+ return SUCCESS;
+ }
+ if ((op1->type == IS_DOUBLE && op2->type == IS_LONG)
+ || (op1->type == IS_LONG && op2->type == IS_DOUBLE)) {
+ result->value.dval = (op1->type == IS_LONG ?
+ (((double) op1->value.lval) - op2->value.dval) :
+ (op1->value.dval - ((double) op2->value.lval)));
+ result->type = IS_DOUBLE;
+ return SUCCESS;
+ }
+ if (op1->type == IS_DOUBLE && op2->type == IS_DOUBLE) {
+ result->type = IS_DOUBLE;
+ result->value.dval = op1->value.dval - op2->value.dval;
+ return SUCCESS;
+ }
+ zend_error(E_ERROR, "Unsupported operand types");
+ return FAILURE; /* unknown datatype */
+}
+
+
+ZEND_API int mul_function(zval *result, zval *op1, zval *op2)
+{
+ zval op1_copy, op2_copy;
+
+ zendi_convert_scalar_to_number(op1, op1_copy, result);
+ zendi_convert_scalar_to_number(op2, op2_copy, result);
+
+ if (op1->type == IS_LONG && op2->type == IS_LONG) {
+ double dval = (double) op1->value.lval * (double) op2->value.lval;
+
+ if (dval > (double) LONG_MAX) {
+ result->value.dval = dval;
+ result->type = IS_DOUBLE;
+ } else {
+ result->value.lval = op1->value.lval * op2->value.lval;
+ result->type = IS_LONG;
+ }
+ return SUCCESS;
+ }
+ if ((op1->type == IS_DOUBLE && op2->type == IS_LONG)
+ || (op1->type == IS_LONG && op2->type == IS_DOUBLE)) {
+ result->value.dval = (op1->type == IS_LONG ?
+ (((double) op1->value.lval) * op2->value.dval) :
+ (op1->value.dval * ((double) op2->value.lval)));
+ result->type = IS_DOUBLE;
+ return SUCCESS;
+ }
+ if (op1->type == IS_DOUBLE && op2->type == IS_DOUBLE) {
+ result->type = IS_DOUBLE;
+ result->value.dval = op1->value.dval * op2->value.dval;
+ return SUCCESS;
+ }
+ zend_error(E_ERROR, "Unsupported operand types");
+ return FAILURE; /* unknown datatype */
+}
+
+ZEND_API int div_function(zval *result, zval *op1, zval *op2)
+{
+ zval op1_copy, op2_copy;
+
+ zendi_convert_scalar_to_number(op1, op1_copy, result);
+ zendi_convert_scalar_to_number(op2, op2_copy, result);
+
+ if ((op2->type == IS_LONG && op2->value.lval == 0) || (op2->type == IS_DOUBLE && op2->value.dval == 0.0)) {
+ zend_error(E_WARNING, "Division by zero");
+ var_reset(result);
+ return FAILURE; /* division by zero */
+ }
+ if (op1->type == IS_LONG && op2->type == IS_LONG) {
+ if (op1->value.lval % op2->value.lval == 0) { /* integer */
+ result->type = IS_LONG;
+ result->value.lval = op1->value.lval / op2->value.lval;
+ } else {
+ result->type = IS_DOUBLE;
+ result->value.dval = ((double) op1->value.lval) / op2->value.lval;
+ }
+ return SUCCESS;
+ }
+ if ((op1->type == IS_DOUBLE && op2->type == IS_LONG)
+ || (op1->type == IS_LONG && op2->type == IS_DOUBLE)) {
+ result->value.dval = (op1->type == IS_LONG ?
+ (((double) op1->value.lval) / op2->value.dval) :
+ (op1->value.dval / ((double) op2->value.lval)));
+ result->type = IS_DOUBLE;
+ return SUCCESS;
+ }
+ if (op1->type == IS_DOUBLE && op2->type == IS_DOUBLE) {
+ result->type = IS_DOUBLE;
+ result->value.dval = op1->value.dval / op2->value.dval;
+ return SUCCESS;
+ }
+ zend_error(E_ERROR, "Unsupported operand types");
+ return FAILURE; /* unknown datatype */
+}
+
+
+ZEND_API int mod_function(zval *result, zval *op1, zval *op2)
+{
+ zval op1_copy, op2_copy;
+
+ zendi_convert_to_long(op1, op1_copy, result);
+ zendi_convert_to_long(op2, op2_copy, result);
+
+ if (op2->value.lval == 0) {
+ var_reset(result);
+ return FAILURE; /* modulus by zero */
+ }
+
+ result->type = IS_LONG;
+ result->value.lval = op1->value.lval % op2->value.lval;
+ return SUCCESS;
+}
+
+
+ZEND_API int boolean_or_function(zval *result, zval *op1, zval *op2)
+{
+ zval op1_copy, op2_copy;
+
+ result->type = IS_BOOL;
+
+ zendi_convert_to_boolean(op1, op1_copy, result);
+ if (op1->value.lval) {
+ result->value.lval = 1;
+ return SUCCESS;
+ }
+ zendi_convert_to_boolean(op2, op2_copy, result);
+ if (op2->value.lval) {
+ result->value.lval = 1;
+ return SUCCESS;
+ }
+ result->value.lval = 0;
+ return SUCCESS;
+}
+
+
+ZEND_API int boolean_and_function(zval *result, zval *op1, zval *op2)
+{
+ zval op1_copy, op2_copy;
+
+ result->type = IS_BOOL;
+
+ zendi_convert_to_boolean(op1, op1_copy, result);
+ if (!op1->value.lval) {
+ result->value.lval = 0;
+ return SUCCESS;
+ }
+ zendi_convert_to_boolean(op2, op2_copy, result);
+ if (!op2->value.lval) {
+ result->value.lval = 0;
+ return SUCCESS;
+ }
+ result->value.lval = 1;
+ return SUCCESS;
+}
+
+
+ZEND_API int boolean_xor_function(zval *result, zval *op1, zval *op2)
+{
+ zval op1_copy, op2_copy;
+
+ result->type = IS_BOOL;
+
+ zendi_convert_to_boolean(op1, op1_copy, result);
+ zendi_convert_to_boolean(op2, op2_copy, result);
+ result->value.lval = op1->value.lval ^ op2->value.lval;
+ return SUCCESS;
+}
+
+
+ZEND_API int boolean_not_function(zval *result, zval *op1)
+{
+ zval op1_copy;
+
+ zendi_convert_to_boolean(op1, op1_copy, result);
+
+ result->type = IS_BOOL;
+ result->value.lval = !op1->value.lval;
+ return SUCCESS;
+}
+
+
+ZEND_API int bitwise_not_function(zval *result, zval *op1)
+{
+ zval op1_copy = *op1;
+
+ op1 = &op1_copy;
+
+ if (op1->type == IS_DOUBLE) {
+ op1->value.lval = (long) op1->value.dval;
+ op1->type = IS_LONG;
+ }
+ if (op1->type == IS_LONG) {
+ result->value.lval = ~op1->value.lval;
+ result->type = IS_LONG;
+ return SUCCESS;
+ }
+ if (op1->type == IS_STRING) {
+ int i;
+
+ result->type = IS_STRING;
+ result->value.str.val = estrndup(op1->value.str.val, op1->value.str.len);
+ result->value.str.len = op1->value.str.len;
+ for (i = 0; i < op1->value.str.len; i++) {
+ result->value.str.val[i] = ~op1->value.str.val[i];
+ }
+ return SUCCESS;
+ }
+ zend_error(E_ERROR, "Unsupported operand types");
+ return FAILURE; /* unknown datatype */
+}
+
+
+ZEND_API int bitwise_or_function(zval *result, zval *op1, zval *op2)
+{
+ zval op1_copy, op2_copy;
+
+ if (op1->type == IS_STRING && op2->type == IS_STRING) {
+ zval *longer, *shorter;
+ char *result_str;
+ int i, result_len;
+
+ if (op1->value.str.len >= op2->value.str.len) {
+ longer = op1;
+ shorter = op2;
+ } else {
+ longer = op2;
+ shorter = op1;
+ }
+
+ result->type = IS_STRING;
+ result_len = longer->value.str.len;
+ result_str = estrndup(longer->value.str.val, longer->value.str.len);
+ for (i = 0; i < shorter->value.str.len; i++) {
+ result_str[i] |= shorter->value.str.val[i];
+ }
+ if (result==op1) {
+ efree(result->value.str.val);
+ }
+ result->value.str.val = result_str;
+ result->value.str.len = result_len;
+ return SUCCESS;
+ }
+ zendi_convert_to_long(op1, op1_copy, result);
+ zendi_convert_to_long(op2, op2_copy, result);
+
+ result->type = IS_LONG;
+ result->value.lval = op1->value.lval | op2->value.lval;
+ return SUCCESS;
+}
+
+
+ZEND_API int bitwise_and_function(zval *result, zval *op1, zval *op2)
+{
+ zval op1_copy, op2_copy;
+
+ if (op1->type == IS_STRING && op2->type == IS_STRING) {
+ zval *longer, *shorter;
+ char *result_str;
+ int i, result_len;
+
+ if (op1->value.str.len >= op2->value.str.len) {
+ longer = op1;
+ shorter = op2;
+ } else {
+ longer = op2;
+ shorter = op1;
+ }
+
+ result->type = IS_STRING;
+ result_len = shorter->value.str.len;
+ result_str = estrndup(shorter->value.str.val, shorter->value.str.len);
+ for (i = 0; i < shorter->value.str.len; i++) {
+ result_str[i] &= longer->value.str.val[i];
+ }
+ if (result==op1) {
+ efree(result->value.str.val);
+ }
+ result->value.str.val = result_str;
+ result->value.str.len = result_len;
+ return SUCCESS;
+ }
+
+
+ zendi_convert_to_long(op1, op1_copy, result);
+ zendi_convert_to_long(op2, op2_copy, result);
+
+ result->type = IS_LONG;
+ result->value.lval = op1->value.lval & op2->value.lval;
+ return SUCCESS;
+}
+
+
+ZEND_API int bitwise_xor_function(zval *result, zval *op1, zval *op2)
+{
+ zval op1_copy, op2_copy;
+
+ if (op1->type == IS_STRING && op2->type == IS_STRING) {
+ zval *longer, *shorter;
+ char *result_str;
+ int i, result_len;
+
+ if (op1->value.str.len >= op2->value.str.len) {
+ longer = op1;
+ shorter = op2;
+ } else {
+ longer = op2;
+ shorter = op1;
+ }
+
+ result->type = IS_STRING;
+ result_len = shorter->value.str.len;
+ result_str = estrndup(shorter->value.str.val, shorter->value.str.len);
+ for (i = 0; i < shorter->value.str.len; i++) {
+ result_str[i] ^= longer->value.str.val[i];
+ }
+ if (result==op1) {
+ efree(result->value.str.val);
+ }
+ result->value.str.val = result_str;
+ result->value.str.len = result_len;
+ return SUCCESS;
+ }
+
+ zendi_convert_to_long(op1, op1_copy, result);
+ zendi_convert_to_long(op2, op2_copy, result);
+
+ result->type = IS_LONG;
+ result->value.lval = op1->value.lval ^ op2->value.lval;
+ return SUCCESS;
+}
+
+
+ZEND_API int shift_left_function(zval *result, zval *op1, zval *op2)
+{
+ zval op1_copy, op2_copy;
+
+ zendi_convert_to_long(op1, op1_copy, result);
+ zendi_convert_to_long(op2, op2_copy, result);
+ result->value.lval = op1->value.lval << op2->value.lval;
+ result->type = IS_LONG;
+ return SUCCESS;
+}
+
+
+ZEND_API int shift_right_function(zval *result, zval *op1, zval *op2)
+{
+ zval op1_copy, op2_copy;
+
+ zendi_convert_to_long(op1, op1_copy, result);
+ zendi_convert_to_long(op2, op2_copy, result);
+ result->value.lval = op1->value.lval >> op2->value.lval;
+ result->type = IS_LONG;
+ return SUCCESS;
+}
+
+
+
+/* must support result==op1 */
+ZEND_API int add_char_to_string(zval *result, zval *op1, zval *op2)
+{
+ result->value.str.len = op1->value.str.len + 1;
+ result->value.str.val = (char *) erealloc(op1->value.str.val, result->value.str.len+1);
+ result->value.str.val[result->value.str.len - 1] = (char) op2->value.lval;
+ result->value.str.val[result->value.str.len] = 0;
+ result->type = IS_STRING;
+ return SUCCESS;
+}
+
+
+/* must support result==op1 */
+ZEND_API int add_string_to_string(zval *result, zval *op1, zval *op2)
+{
+ int length = op1->value.str.len + op2->value.str.len;
+ result->value.str.val = (char *) erealloc(op1->value.str.val, length+1);
+ memcpy(result->value.str.val+op1->value.str.len, op2->value.str.val, op2->value.str.len);
+ result->value.str.val[length] = 0;
+ result->value.str.len = length;
+ result->type = IS_STRING;
+ return SUCCESS;
+}
+
+
+ZEND_API int concat_function(zval *result, zval *op1, zval *op2)
+{
+ zval op1_copy, op2_copy;
+ int use_copy1, use_copy2;
+
+
+ zend_make_printable_zval(op1, &op1_copy, &use_copy1);
+ zend_make_printable_zval(op2, &op2_copy, &use_copy2);
+
+ if (use_copy1) {
+ op1 = &op1_copy;
+ }
+ if (use_copy2) {
+ op2 = &op2_copy;
+ }
+ if (result==op1) { /* special case, perform operations on result */
+ uint res_len = op1->value.str.len + op2->value.str.len;
+
+ if (result->value.str.len == 0) { /* handle empty_string */
+ STR_FREE(result->value.str.val);
+ result->value.str.val = emalloc(res_len+1);
+ } else {
+ result->value.str.val = erealloc(result->value.str.val, res_len+1);
+ }
+ memcpy(result->value.str.val+result->value.str.len, op2->value.str.val, op2->value.str.len);
+ result->value.str.val[res_len]=0;
+ result->value.str.len = res_len;
+ } else {
+ result->value.str.len = op1->value.str.len + op2->value.str.len;
+ result->value.str.val = (char *) emalloc(result->value.str.len + 1);
+ memcpy(result->value.str.val, op1->value.str.val, op1->value.str.len);
+ memcpy(result->value.str.val+op1->value.str.len, op2->value.str.val,op2->value.str.len);
+ result->value.str.val[result->value.str.len] = 0;
+ result->type = IS_STRING;
+ }
+ if (use_copy1) {
+ zval_dtor(op1);
+ }
+ if (use_copy2) {
+ zval_dtor(op2);
+ }
+ return SUCCESS;
+}
+
+
+ZEND_API int string_compare_function(zval *result, zval *op1, zval *op2)
+{
+ zval op1_copy, op2_copy;
+ int use_copy1, use_copy2;
+
+ zend_make_printable_zval(op1, &op1_copy, &use_copy1);
+ zend_make_printable_zval(op2, &op2_copy, &use_copy2);
+
+ if (use_copy1) {
+ op1 = &op1_copy;
+ }
+ if (use_copy2) {
+ op2 = &op2_copy;
+ }
+
+ result->value.lval = zend_binary_zval_strcmp(op1, op2);
+ result->type = IS_LONG;
+
+ if (use_copy1) {
+ zval_dtor(op1);
+ }
+ if (use_copy2) {
+ zval_dtor(op2);
+ }
+ return SUCCESS;
+}
+
+ZEND_API int numeric_compare_function(zval *result, zval *op1, zval *op2)
+{
+ zval op1_copy, op2_copy;
+
+ op1_copy = *op1;
+ zval_copy_ctor(&op1_copy);
+
+ op2_copy = *op2;
+ zval_copy_ctor(&op2_copy);
+
+ convert_to_double(&op1_copy);
+ convert_to_double(&op2_copy);
+
+ result->value.lval = ZEND_NORMALIZE_BOOL(op1_copy.value.dval-op2_copy.value.dval);
+ result->type = IS_LONG;
+
+ return SUCCESS;
+}
+
+
+ZEND_API int compare_function(zval *result, zval *op1, zval *op2)
+{
+ zval op1_copy, op2_copy;
+
+ if ((op1->type == IS_NULL && op2->type == IS_STRING)
+ || (op2->type == IS_NULL && op1->type == IS_STRING)) {
+ if (op1->type == IS_NULL) {
+ result->type = IS_LONG;
+ result->value.lval = zend_binary_strcmp("", 0, op2->value.str.val, op2->value.str.len);
+ return SUCCESS;
+ } else {
+ result->type = IS_LONG;
+ result->value.lval = zend_binary_strcmp(op1->value.str.val, op1->value.str.len, "", 0);
+ return SUCCESS;
+ }
+ }
+
+ if (op1->type == IS_STRING && op2->type == IS_STRING) {
+ zendi_smart_strcmp(result, op1, op2);
+ return SUCCESS;
+ }
+
+ if (op1->type == IS_BOOL || op2->type == IS_BOOL
+ || op1->type == IS_NULL || op2->type == IS_NULL) {
+ zendi_convert_to_boolean(op1, op1_copy, result);
+ zendi_convert_to_boolean(op2, op2_copy, result);
+ result->type = IS_LONG;
+ result->value.lval = ZEND_NORMALIZE_BOOL(op1->value.lval-op2->value.lval);
+ return SUCCESS;
+ }
+
+ zendi_convert_scalar_to_number(op1, op1_copy, result);
+ zendi_convert_scalar_to_number(op2, op2_copy, result);
+
+ if (op1->type == IS_LONG && op2->type == IS_LONG) {
+ result->type = IS_LONG;
+ result->value.lval = ZEND_NORMALIZE_BOOL(op1->value.lval-op2->value.lval);
+ return SUCCESS;
+ }
+ if ((op1->type == IS_DOUBLE || op1->type == IS_LONG)
+ && (op2->type == IS_DOUBLE || op2->type == IS_LONG)) {
+ result->value.dval = (op1->type == IS_LONG ? (double) op1->value.lval : op1->value.dval) - (op2->type == IS_LONG ? (double) op2->value.lval : op2->value.dval);
+ result->value.lval = ZEND_NORMALIZE_BOOL(result->value.dval);
+ result->type = IS_LONG;
+ return SUCCESS;
+ }
+ if (op1->type==IS_ARRAY && op2->type==IS_ARRAY) {
+ zend_compare_arrays(result, op1, op2);
+ return SUCCESS;
+ }
+
+ if (op1->type==IS_OBJECT && op2->type==IS_OBJECT) {
+ zend_compare_objects(result, op1, op2);
+ return SUCCESS;
+ }
+
+ if (op1->type==IS_ARRAY) {
+ result->value.lval = 1;
+ result->type = IS_LONG;
+ return SUCCESS;
+ }
+ if (op2->type==IS_ARRAY) {
+ result->value.lval = -1;
+ result->type = IS_LONG;
+ return SUCCESS;
+ }
+ if (op1->type==IS_OBJECT) {
+ result->value.lval = 1;
+ result->type = IS_LONG;
+ return SUCCESS;
+ }
+ if (op2->type==IS_OBJECT) {
+ result->value.lval = -1;
+ result->type = IS_LONG;
+ return SUCCESS;
+ }
+
+ var_reset(result);
+ return FAILURE;
+}
+
+
+static int hash_zval_identical_function(const zval **z1, const zval **z2)
+{
+ zval result;
+
+ /* is_identical_function() returns 1 in case of identity and 0 in case
+ * of a difference;
+ * whereas this comparison function is expected to return 0 on identity,
+ * and non zero otherwise.
+ */
+ if (is_identical_function(&result, (zval *) *z1, (zval *) *z2)==FAILURE) {
+ return 1;
+ }
+ return !result.value.lval;
+}
+
+
+ZEND_API int is_identical_function(zval *result, zval *op1, zval *op2)
+{
+ result->type = IS_BOOL;
+ if (op1->type != op2->type) {
+ result->value.lval = 0;
+ return SUCCESS;
+ }
+ switch (op1->type) {
+ case IS_NULL:
+ result->value.lval = (op2->type==IS_NULL);
+ break;
+ case IS_BOOL:
+ case IS_LONG:
+ case IS_RESOURCE:
+ result->value.lval = (op1->value.lval == op2->value.lval);
+ break;
+ case IS_DOUBLE:
+ result->value.lval = (op1->value.dval == op2->value.dval);
+ break;
+ case IS_STRING:
+ if ((op1->value.str.len == op2->value.str.len)
+ && (!memcmp(op1->value.str.val, op2->value.str.val, op1->value.str.len))) {
+ result->value.lval = 1;
+ } else {
+ result->value.lval = 0;
+ }
+ break;
+ case IS_ARRAY:
+ if (zend_hash_compare(op1->value.ht, op2->value.ht, (compare_func_t) hash_zval_identical_function, 1)==0) {
+ result->value.lval = 1;
+ } else {
+ result->value.lval = 0;
+ }
+ break;
+ case IS_OBJECT:
+ if (op1->value.obj.ce != op2->value.obj.ce) {
+ result->value.lval = 0;
+ } else {
+ if (zend_hash_compare(op1->value.obj.properties, op2->value.obj.properties, (compare_func_t) hash_zval_identical_function, 1)==0) {
+ result->value.lval = 1;
+ } else {
+ result->value.lval = 0;
+ }
+ }
+ break;
+ default:
+ var_reset(result);
+ return FAILURE;
+ }
+ return SUCCESS;
+}
+
+
+ZEND_API int is_not_identical_function(zval *result, zval *op1, zval *op2)
+{
+ result->type = IS_BOOL;
+ if (is_identical_function( result, op1, op2 ) == FAILURE) {
+ return FAILURE;
+ }
+ result->value.lval = !result->value.lval;
+ return SUCCESS;
+}
+
+
+ZEND_API int is_equal_function(zval *result, zval *op1, zval *op2)
+{
+ if (compare_function(result, op1, op2) == FAILURE) {
+ return FAILURE;
+ }
+ convert_to_boolean(result);
+ if (result->value.lval == 0) {
+ result->value.lval = 1;
+ } else {
+ result->value.lval = 0;
+ }
+ return SUCCESS;
+}
+
+
+ZEND_API int is_not_equal_function(zval *result, zval *op1, zval *op2)
+{
+ if (compare_function(result, op1, op2) == FAILURE) {
+ return FAILURE;
+ }
+ convert_to_boolean(result);
+ if (result->value.lval) {
+ result->value.lval = 1;
+ } else {
+ result->value.lval = 0;
+ }
+ return SUCCESS;
+}
+
+
+ZEND_API int is_smaller_function(zval *result, zval *op1, zval *op2)
+{
+ if (compare_function(result, op1, op2) == FAILURE) {
+ return FAILURE;
+ }
+ if (result->type == IS_LONG) {
+ result->type = IS_BOOL;
+ if (result->value.lval < 0) {
+ result->value.lval = 1;
+ } else {
+ result->value.lval = 0;
+ }
+ return SUCCESS;
+ }
+ if (result->type == IS_DOUBLE) {
+ result->type = IS_BOOL;
+ if (result->value.dval < 0) {
+ result->value.lval = 1;
+ } else {
+ result->value.lval = 0;
+ }
+ return SUCCESS;
+ }
+ zend_error(E_ERROR, "Unsupported operand types");
+ return FAILURE;
+}
+
+
+ZEND_API int is_smaller_or_equal_function(zval *result, zval *op1, zval *op2)
+{
+ if (compare_function(result, op1, op2) == FAILURE) {
+ return FAILURE;
+ }
+ if (result->type == IS_LONG) {
+ result->type = IS_BOOL;
+ if (result->value.lval <= 0) {
+ result->value.lval = 1;
+ } else {
+ result->value.lval = 0;
+ }
+ return SUCCESS;
+ }
+ if (result->type == IS_DOUBLE) {
+ result->type = IS_BOOL;
+ if (result->value.dval <= 0) {
+ result->value.lval = 1;
+ } else {
+ result->value.lval = 0;
+ }
+ return SUCCESS;
+ }
+ zend_error(E_ERROR, "Unsupported operand types");
+ return FAILURE;
+}
+
+
+#define LOWER_CASE 1
+#define UPPER_CASE 2
+#define NUMERIC 3
+
+
+static void increment_string(zval *str)
+{
+ int carry=0;
+ int pos=str->value.str.len-1;
+ char *s=str->value.str.val;
+ char *t;
+ int last=0; /* Shut up the compiler warning */
+ int ch;
+
+ if (str->value.str.len == 0) {
+ STR_FREE(str->value.str.val);
+ str->value.str.val = estrndup("1", sizeof("1")-1);
+ str->value.str.len = 1;
+ return;
+ }
+
+ while(pos >= 0) {
+ ch = s[pos];
+ if (ch >= 'a' && ch <= 'z') {
+ if (ch == 'z') {
+ s[pos] = 'a';
+ carry=1;
+ } else {
+ s[pos]++;
+ carry=0;
+ }
+ last=LOWER_CASE;
+ } else if (ch >= 'A' && ch <= 'Z') {
+ if (ch == 'Z') {
+ s[pos] = 'A';
+ carry=1;
+ } else {
+ s[pos]++;
+ carry=0;
+ }
+ last=UPPER_CASE;
+ } else if (ch >= '0' && ch <= '9') {
+ if (ch == '9') {
+ s[pos] = '0';
+ carry=1;
+ } else {
+ s[pos]++;
+ carry=0;
+ }
+ last = NUMERIC;
+ } else {
+ carry=0;
+ break;
+ }
+ if (carry == 0) {
+ break;
+ }
+ pos--;
+ }
+
+ if (carry) {
+ t = (char *) emalloc(str->value.str.len+1+1);
+ memcpy(t+1,str->value.str.val, str->value.str.len);
+ str->value.str.len++;
+ t[str->value.str.len] = '\0';
+ switch (last) {
+ case NUMERIC:
+ t[0] = '1';
+ break;
+ case UPPER_CASE:
+ t[0] = 'A';
+ break;
+ case LOWER_CASE:
+ t[0] = 'a';
+ break;
+ }
+ STR_FREE(str->value.str.val);
+ str->value.str.val = t;
+ }
+}
+
+
+ZEND_API int increment_function(zval *op1)
+{
+ switch (op1->type) {
+ case IS_LONG:
+ op1->value.lval++;
+ break;
+ case IS_DOUBLE:
+ op1->value.dval = op1->value.dval + 1;
+ break;
+ case IS_NULL:
+ op1->value.lval = 1;
+ op1->type = IS_LONG;
+ break;
+ case IS_STRING: /* Perl style string increment */
+ increment_string(op1);
+ break;
+ default:
+ return FAILURE;
+ }
+ return SUCCESS;
+}
+
+
+ZEND_API int decrement_function(zval *op1)
+{
+ long lval;
+
+ switch (op1->type) {
+ case IS_LONG:
+ op1->value.lval--;
+ break;
+ case IS_DOUBLE:
+ op1->value.dval = op1->value.dval - 1;
+ break;
+ case IS_STRING: /* Like perl we only support string increment */
+ if (op1->value.str.len==0) { /* consider as 0 */
+ STR_FREE(op1->value.str.val);
+ op1->value.lval = -1;
+ op1->type = IS_LONG;
+ break;
+ } else if (is_numeric_string(op1->value.str.val, op1->value.str.len, &lval, NULL)==IS_LONG) { /* long */
+ STR_FREE(op1->value.str.val);
+ op1->value.lval = lval-1;
+ op1->type = IS_LONG;
+ break;
+ }
+ break;
+ default:
+ return FAILURE;
+ }
+
+ return SUCCESS;
+}
+
+
+ZEND_API int zval_is_true(zval *op)
+{
+ convert_to_boolean(op);
+ return (op->value.lval ? 1 : 0);
+}
+
+
+ZEND_API void zend_str_tolower(char *str, unsigned int length)
+{
+ register char *p=str, *end=p+length;
+
+ while (p<end) {
+ *p = tolower(*p);
+ p++;
+ }
+}
+
+
+ZEND_API int zend_binary_strcmp(char *s1, uint len1, char *s2, uint len2)
+{
+ int retval;
+
+ retval = memcmp(s1, s2, MIN(len1, len2));
+ if (!retval) {
+ return (len1 - len2);
+ } else {
+ return retval;
+ }
+}
+
+ZEND_API int zend_binary_strncmp(char *s1, uint len1, char *s2, uint len2, uint length)
+{
+ int retval;
+
+ retval = memcmp(s1, s2, MIN(length, MIN(len1, len2)));
+ if (!retval) {
+ return (MIN(length, len1) - MIN(length, len2));
+ } else {
+ return retval;
+ }
+}
+
+
+ZEND_API int zend_binary_strcasecmp(char *s1, uint len1, char *s2, uint len2)
+{
+ int len;
+ int c1,c2;
+
+ len = MIN(len1, len2);
+
+ while (len--) {
+ c1 = tolower(*s1++);
+ c2 = tolower(*s2++);
+ if (c1 != c2) {
+ return c1 - c2;
+ }
+ }
+
+ return len1 - len2;
+}
+
+
+ZEND_API int zend_binary_strncasecmp(char *s1, uint len1, char *s2, uint len2, uint length)
+{
+ int len;
+ int c1,c2;
+
+ len = MIN(length, MIN(len1, len2));
+
+ while (len--) {
+ c1 = tolower(*s1++);
+ c2 = tolower(*s2++);
+ if (c1 != c2) {
+ return c1 - c2;
+ }
+ }
+
+ return len1 - len2;
+}
+
+
+ZEND_API int zend_binary_zval_strcmp(zval *s1, zval *s2)
+{
+ return zend_binary_strcmp(s1->value.str.val, s1->value.str.len, s2->value.str.val, s2->value.str.len);
+}
+
+ZEND_API int zend_binary_zval_strncmp(zval *s1, zval *s2, zval *s3)
+{
+ return zend_binary_strncmp(s1->value.str.val, s1->value.str.len, s2->value.str.val, s2->value.str.len, s3->value.lval);
+}
+
+
+ZEND_API int zend_binary_zval_strcasecmp(zval *s1, zval *s2)
+{
+ return zend_binary_strcasecmp(s1->value.str.val, s1->value.str.len, s2->value.str.val, s2->value.str.len);
+}
+
+
+ZEND_API int zend_binary_zval_strncasecmp(zval *s1, zval *s2, zval *s3)
+{
+ return zend_binary_strncasecmp(s1->value.str.val, s1->value.str.len, s2->value.str.val, s2->value.str.len, s3->value.lval);
+}
+
+
+ZEND_API void zendi_smart_strcmp(zval *result, zval *s1, zval *s2)
+{
+ int ret1,ret2;
+ long lval1, lval2;
+ double dval1, dval2;
+
+ if ((ret1=is_numeric_string(s1->value.str.val, s1->value.str.len, &lval1, &dval1)) &&
+ (ret2=is_numeric_string(s2->value.str.val, s2->value.str.len, &lval2, &dval2))) {
+#if 0&&WITH_BCMATH
+ if ((ret1==FLAG_IS_BC) || (ret2==FLAG_IS_BC)) {
+ bc_num first, second;
+
+ /* use the BC math library to compare the numbers */
+ init_num(&first);
+ init_num(&second);
+ str2num(&first,s1->value.str.val,100); /* this scale should do */
+ str2num(&second,s2->value.str.val,100); /* ditto */
+ result->value.lval = bc_compare(first,second);
+ result->value.lval = ZEND_NORMALIZE_BOOL(result->value.lval);
+ result->type = IS_LONG;
+ free_num(&first);
+ free_num(&second);
+ } else
+#endif
+ if ((ret1==IS_DOUBLE) || (ret2==IS_DOUBLE)) {
+ if (ret1!=IS_DOUBLE) {
+ dval1 = strtod(s1->value.str.val, NULL);
+ } else if (ret2!=IS_DOUBLE) {
+ dval2 = strtod(s2->value.str.val, NULL);
+ }
+ result->value.dval = dval1 - dval2;
+ result->value.lval = ZEND_NORMALIZE_BOOL(result->value.dval);
+ result->type = IS_LONG;
+ } else { /* they both have to be long's */
+ result->value.lval = lval1 - lval2;
+ result->value.lval = ZEND_NORMALIZE_BOOL(result->value.lval);
+ result->type = IS_LONG;
+ }
+ } else {
+ result->value.lval = zend_binary_zval_strcmp(s1, s2);
+ result->value.lval = ZEND_NORMALIZE_BOOL(result->value.lval);
+ result->type = IS_LONG;
+ }
+ return;
+}
+
+
+static int hash_zval_compare_function(const zval **z1, const zval **z2)
+{
+ zval result;
+
+ if (compare_function(&result, (zval *) *z1, (zval *) *z2)==FAILURE) {
+ return 1;
+ }
+ return result.value.lval;
+}
+
+
+
+ZEND_API void zend_compare_symbol_tables(zval *result, HashTable *ht1, HashTable *ht2)
+{
+ result->type = IS_LONG;
+ result->value.lval = zend_hash_compare(ht1, ht2, (compare_func_t) hash_zval_compare_function, 0);
+}
+
+
+ZEND_API void zend_compare_arrays(zval *result, zval *a1, zval *a2)
+{
+ zend_compare_symbol_tables(result, a1->value.ht, a2->value.ht);
+}
+
+
+ZEND_API void zend_compare_objects(zval *result, zval *o1, zval *o2)
+{
+ if (o1->value.obj.ce != o2->value.obj.ce) {
+ result->value.lval = 1; /* Comparing objects of different types is pretty much meaningless */
+ result->type = IS_LONG;
+ return;
+ }
+ zend_compare_symbol_tables(result, o1->value.obj.properties, o2->value.obj.properties);
+}
+
+
+/* returns 0 for non-numeric string
+ * returns IS_DOUBLE for floating point string, and assigns the value to *dval (if it's not NULL)
+ * returns IS_LONG for integer strings, and assigns the value to *lval (if it's not NULL)
+ * returns FLAG_IS_BC if the number might lose accuracy when converted to a double
+ */
+
+#if 0
+
+static inline int is_numeric_string(char *str, int length, long *lval, double *dval)
+{
+ register char *p=str, *end=str+length;
+ unsigned char had_period=0,had_exponent=0;
+ char *end_ptr;
+
+ if (!length) {
+ return 0;
+ }
+ switch (*p) {
+ case '-':
+ case '+':
+ while (*++p==' '); /* ignore spaces after the sign */
+ break;
+ default:
+ break;
+ }
+ while (p<end) {
+ if (isdigit((int)(unsigned char)*p)) {
+ p++;
+ } else if (*p=='.') {
+ if (had_period) {
+ return 0;
+ } else {
+ had_period=1;
+ p++;
+ }
+ } else if (*p=='e' || *p=='E') {
+ p++;
+ if (is_numeric_string(p, length - (int) (p-str), NULL, NULL)==IS_LONG) { /* valid exponent */
+ had_exponent=1;
+ break;
+ } else {
+ return 0;
+ }
+ } else {
+ return 0;
+ }
+ }
+ errno=0;
+ if (had_period || had_exponent) { /* floating point number */
+ double local_dval;
+
+ local_dval = strtod(str, &end_ptr);
+ if (errno==ERANGE || end_ptr != str+length) { /* overflow or bad string */
+ return 0;
+ } else {
+ if (dval) {
+ *dval = local_dval;
+ }
+ return IS_DOUBLE;
+ }
+ } else {
+ long local_lval;
+
+ local_lval = strtol(str, &end_ptr, 10);
+ if (errno==ERANGE || end_ptr != str+length) { /* overflow or bad string */
+ return 0;
+ } else {
+ if (lval) {
+ *lval = local_lval;
+ }
+ return IS_LONG;
+ }
+ }
+}
+
+
+
+#endif