mirror of https://github.com/swig/swig
2751 lines
88 KiB
C++
2751 lines
88 KiB
C++
/* -----------------------------------------------------------------------------
|
|
* This file is part of SWIG, which is licensed as a whole under version 3
|
|
* (or any later version) of the GNU General Public License. Some additional
|
|
* terms also apply to certain portions of SWIG. The full details of the SWIG
|
|
* license and copyrights can be found in the LICENSE and COPYRIGHT files
|
|
* included with the SWIG source code as distributed by the SWIG developers
|
|
* and at http://www.swig.org/legal.html.
|
|
*
|
|
* php.cxx
|
|
*
|
|
* PHP language module for SWIG.
|
|
* -----------------------------------------------------------------------------
|
|
*/
|
|
|
|
/* FIXME: PHP5 OO wrapping TODO list:
|
|
*
|
|
* Medium term:
|
|
*
|
|
* Handle default parameters on overloaded methods in PHP where possible.
|
|
* (Mostly done - just need to handle cases of overloaded methods with
|
|
* default parameters...)
|
|
* This is an optimisation - we could handle this case using a PHP
|
|
* default value, but currently we treat it as we would for a default
|
|
* value which is a compound C++ expression (i.e. as if we had a
|
|
* method with two overloaded forms instead of a single method with
|
|
* a default parameter value).
|
|
*
|
|
* Long term:
|
|
*
|
|
* Sort out locale-dependent behaviour of strtod() - it's harmless unless
|
|
* SWIG ever sets the locale and DOH/base.c calls atof, so we're probably
|
|
* OK currently at least.
|
|
*/
|
|
|
|
/*
|
|
* TODO: Replace remaining stderr messages with Swig_error or Swig_warning
|
|
* (may need to add more WARN_PHP_xxx codes...)
|
|
*/
|
|
|
|
char cvsroot_php_cxx[] = "$Id$";
|
|
|
|
#include "swigmod.h"
|
|
|
|
#include <ctype.h>
|
|
#include <errno.h>
|
|
|
|
static const char *usage = (char *) "\
|
|
PHP Options (available with -php)\n\
|
|
-cppext - cpp file extension (default to .cpp)\n\
|
|
-noproxy - Don't generate proxy classes.\n\
|
|
-prefix <prefix> - Prepend <prefix> to all class names in PHP wrappers\n\
|
|
\n";
|
|
|
|
/* The original class wrappers for PHP stored the pointer to the C++ class in
|
|
* the object property _cPtr. If we use the same name for the member variable
|
|
* which we put the pointer to the C++ class in, then the flat function
|
|
* wrappers will automatically pull it out without any changes being required.
|
|
* FIXME: Isn't using a leading underscore a bit suspect here?
|
|
*/
|
|
#define SWIG_PTR "_cPtr"
|
|
|
|
/* This is the name of the hash where the variables existing only in PHP
|
|
* classes are stored.
|
|
*/
|
|
#define SWIG_DATA "_pData"
|
|
|
|
static int constructors = 0;
|
|
static String *NOTCLASS = NewString("Not a class");
|
|
static Node *classnode = 0;
|
|
static String *module = 0;
|
|
static String *cap_module = 0;
|
|
static String *prefix = 0;
|
|
|
|
static String *shadow_classname = 0;
|
|
|
|
static File *f_begin = 0;
|
|
static File *f_runtime = 0;
|
|
static File *f_runtime_h = 0;
|
|
static File *f_h = 0;
|
|
static File *f_phpcode = 0;
|
|
static File *f_directors = 0;
|
|
static File *f_directors_h = 0;
|
|
static String *phpfilename = 0;
|
|
|
|
static String *s_header;
|
|
static String *s_wrappers;
|
|
static String *s_init;
|
|
static String *r_init; // RINIT user code
|
|
static String *s_shutdown; // MSHUTDOWN user code
|
|
static String *r_shutdown; // RSHUTDOWN user code
|
|
static String *s_vinit; // varinit initialization code.
|
|
static String *s_vdecl;
|
|
static String *s_cinit; // consttab initialization code.
|
|
static String *s_oinit;
|
|
static String *s_entry;
|
|
static String *cs_entry;
|
|
static String *all_cs_entry;
|
|
static String *pragma_incl;
|
|
static String *pragma_code;
|
|
static String *pragma_phpinfo;
|
|
static String *s_oowrappers;
|
|
static String *s_fakeoowrappers;
|
|
static String *s_phpclasses;
|
|
|
|
/* Variables for using PHP classes */
|
|
static Node *current_class = 0;
|
|
|
|
static Hash *shadow_get_vars;
|
|
static Hash *shadow_set_vars;
|
|
static Hash *zend_types = 0;
|
|
|
|
static int shadow = 1;
|
|
|
|
static bool class_has_ctor = false;
|
|
static String *wrapping_member_constant = NULL;
|
|
|
|
// These static variables are used to pass some state from Handlers into functionWrapper
|
|
static enum {
|
|
standard = 0,
|
|
memberfn,
|
|
staticmemberfn,
|
|
membervar,
|
|
staticmembervar,
|
|
constructor,
|
|
directorconstructor
|
|
} wrapperType = standard;
|
|
|
|
extern "C" {
|
|
static void (*r_prevtracefunc) (SwigType *t, String *mangled, String *clientdata) = 0;
|
|
}
|
|
|
|
static void SwigPHP_emit_resource_registrations() {
|
|
Iterator ki;
|
|
|
|
if (!zend_types)
|
|
return;
|
|
|
|
ki = First(zend_types);
|
|
if (ki.key)
|
|
Printf(s_oinit, "\n/* Register resource destructors for pointer types */\n");
|
|
while (ki.key) {
|
|
DOH *key = ki.key;
|
|
Node *class_node = ki.item;
|
|
String *human_name = key;
|
|
|
|
// Write out destructor function header
|
|
Printf(s_wrappers, "static ZEND_RSRC_DTOR_FUNC(_wrap_destroy%s) {\n", key);
|
|
|
|
// write out body
|
|
if (class_node != NOTCLASS) {
|
|
String *destructor = Getattr(class_node, "destructor");
|
|
human_name = Getattr(class_node, "sym:name");
|
|
if (!human_name)
|
|
human_name = Getattr(class_node, "name");
|
|
// Do we have a known destructor for this type?
|
|
if (destructor) {
|
|
Printf(s_wrappers, " %s(rsrc, SWIGTYPE%s->name TSRMLS_CC);\n", destructor, key);
|
|
} else {
|
|
Printf(s_wrappers, " /* No destructor for class %s */\n", human_name);
|
|
Printf(s_wrappers, " efree(rsrc->ptr);\n");
|
|
}
|
|
} else {
|
|
Printf(s_wrappers, " /* No destructor for simple type %s */\n", key);
|
|
Printf(s_wrappers, " efree(rsrc->ptr);\n");
|
|
}
|
|
|
|
// close function
|
|
Printf(s_wrappers, "}\n");
|
|
|
|
// declare le_swig_<mangled> to store php registration
|
|
Printf(s_vdecl, "static int le_swig_%s=0; /* handle for %s */\n", key, human_name);
|
|
|
|
// register with php
|
|
Printf(s_oinit, "le_swig_%s=zend_register_list_destructors_ex"
|
|
"(_wrap_destroy%s,NULL,(char *)(SWIGTYPE%s->name),module_number);\n", key, key, key);
|
|
|
|
// store php type in class struct
|
|
Printf(s_oinit, "SWIG_TypeClientData(SWIGTYPE%s,&le_swig_%s);\n", key, key);
|
|
|
|
ki = Next(ki);
|
|
}
|
|
}
|
|
|
|
class PHP : public Language {
|
|
public:
|
|
PHP() {
|
|
director_language = 1;
|
|
}
|
|
|
|
/* ------------------------------------------------------------
|
|
* main()
|
|
* ------------------------------------------------------------ */
|
|
|
|
virtual void main(int argc, char *argv[]) {
|
|
SWIG_library_directory("php");
|
|
SWIG_config_cppext("cpp");
|
|
|
|
for (int i = 1; i < argc; i++) {
|
|
if (strcmp(argv[i], "-prefix") == 0) {
|
|
if (argv[i + 1]) {
|
|
prefix = NewString(argv[i + 1]);
|
|
Swig_mark_arg(i);
|
|
Swig_mark_arg(i + 1);
|
|
i++;
|
|
} else {
|
|
Swig_arg_error();
|
|
}
|
|
} else if (strcmp(argv[i], "-cppext") == 0) {
|
|
if (argv[i + 1]) {
|
|
SWIG_config_cppext(argv[i + 1]);
|
|
Swig_mark_arg(i);
|
|
Swig_mark_arg(i + 1);
|
|
i++;
|
|
} else {
|
|
Swig_arg_error();
|
|
}
|
|
} else if ((strcmp(argv[i], "-noshadow") == 0) || (strcmp(argv[i], "-noproxy") == 0)) {
|
|
shadow = 0;
|
|
Swig_mark_arg(i);
|
|
} else if (strcmp(argv[i], "-help") == 0) {
|
|
fputs(usage, stdout);
|
|
} else if (strcmp(argv[i], "-make") == 0 ||
|
|
strcmp(argv[i], "-withc") == 0 ||
|
|
strcmp(argv[i], "-withcxx") == 0) {
|
|
Printf(stderr, "*** %s is no longer supported.\n", argv[i]);
|
|
SWIG_exit(EXIT_FAILURE);
|
|
} else if (strcmp(argv[i], "-phpfull") == 0 ||
|
|
strcmp(argv[i], "-withlibs") == 0 ||
|
|
strcmp(argv[i], "-withincs") == 0) {
|
|
Printf(stderr, "*** %s is no longer supported.\n*** We recommend building as a dynamically loadable module.\n", argv[i]);
|
|
SWIG_exit(EXIT_FAILURE);
|
|
} else if (strcmp(argv[i], "-dlname") == 0) {
|
|
Printf(stderr, "*** -dlname is no longer supported.\n*** If you want to change the module name, use -module instead.\n");
|
|
SWIG_exit(EXIT_FAILURE);
|
|
}
|
|
}
|
|
|
|
Preprocessor_define("SWIGPHP 1", 0);
|
|
// SWIGPHP5 is deprecated, and no longer documented.
|
|
Preprocessor_define("SWIGPHP5 1", 0);
|
|
SWIG_typemap_lang("php");
|
|
SWIG_config_file("php.swg");
|
|
allow_overloading();
|
|
}
|
|
|
|
/* ------------------------------------------------------------
|
|
* top()
|
|
* ------------------------------------------------------------ */
|
|
|
|
virtual int top(Node *n) {
|
|
|
|
String *filen;
|
|
String *s_type;
|
|
|
|
/* Check if directors are enabled for this module. */
|
|
Node *mod = Getattr(n, "module");
|
|
if (mod) {
|
|
Node *options = Getattr(mod, "options");
|
|
if (options && Getattr(options, "directors")) {
|
|
allow_directors();
|
|
}
|
|
}
|
|
|
|
/* Set comparison with null for ConstructorToFunction */
|
|
setSubclassInstanceCheck(NewString("$arg->type != IS_NULL"));
|
|
|
|
/* Initialize all of the output files */
|
|
String *outfile = Getattr(n, "outfile");
|
|
String *outfile_h = Getattr(n, "outfile_h");
|
|
|
|
/* main output file */
|
|
f_begin = NewFile(outfile, "w", SWIG_output_files());
|
|
if (!f_begin) {
|
|
FileErrorDisplay(outfile);
|
|
SWIG_exit(EXIT_FAILURE);
|
|
}
|
|
f_runtime = NewStringEmpty();
|
|
|
|
/* sections of the output file */
|
|
s_init = NewString("/* init section */\n");
|
|
r_init = NewString("/* rinit section */\n");
|
|
s_shutdown = NewString("/* shutdown section */\n");
|
|
r_shutdown = NewString("/* rshutdown section */\n");
|
|
s_header = NewString("/* header section */\n");
|
|
s_wrappers = NewString("/* wrapper section */\n");
|
|
s_type = NewStringEmpty();
|
|
/* subsections of the init section */
|
|
s_vinit = NewString("/* vinit subsection */\n");
|
|
s_vdecl = NewString("/* vdecl subsection */\n");
|
|
s_cinit = NewString("/* cinit subsection */\n");
|
|
s_oinit = NewString("/* oinit subsection */\n");
|
|
pragma_phpinfo = NewStringEmpty();
|
|
s_phpclasses = NewString("/* PHP Proxy Classes */\n");
|
|
f_directors_h = NewStringEmpty();
|
|
f_directors = NewStringEmpty();
|
|
|
|
if (directorsEnabled()) {
|
|
f_runtime_h = NewFile(outfile_h, "w", SWIG_output_files());
|
|
if (!f_runtime_h) {
|
|
FileErrorDisplay(outfile_h);
|
|
SWIG_exit(EXIT_FAILURE);
|
|
}
|
|
}
|
|
|
|
/* Register file targets with the SWIG file handler */
|
|
Swig_register_filebyname("begin", f_begin);
|
|
Swig_register_filebyname("runtime", f_runtime);
|
|
Swig_register_filebyname("init", s_init);
|
|
Swig_register_filebyname("rinit", r_init);
|
|
Swig_register_filebyname("shutdown", s_shutdown);
|
|
Swig_register_filebyname("rshutdown", r_shutdown);
|
|
Swig_register_filebyname("header", s_header);
|
|
Swig_register_filebyname("wrapper", s_wrappers);
|
|
Swig_register_filebyname("director", f_directors);
|
|
Swig_register_filebyname("director_h", f_directors_h);
|
|
|
|
Swig_banner(f_begin);
|
|
|
|
Printf(f_runtime, "\n");
|
|
Printf(f_runtime, "#define SWIGPHP\n");
|
|
Printf(f_runtime, "\n");
|
|
|
|
if (directorsEnabled()) {
|
|
Printf(f_runtime, "#define SWIG_DIRECTORS\n");
|
|
}
|
|
|
|
/* Set the module name */
|
|
module = Copy(Getattr(n, "name"));
|
|
cap_module = NewStringf("%(upper)s", module);
|
|
if (!prefix)
|
|
prefix = NewStringEmpty();
|
|
|
|
if (directorsEnabled()) {
|
|
Swig_banner(f_directors_h);
|
|
Printf(f_directors_h, "\n");
|
|
Printf(f_directors_h, "#ifndef SWIG_%s_WRAP_H_\n", cap_module);
|
|
Printf(f_directors_h, "#define SWIG_%s_WRAP_H_\n\n", cap_module);
|
|
|
|
Printf(f_directors, "\n#include \"%s\"\n\n", Swig_file_filename(outfile_h));
|
|
}
|
|
|
|
/* PHP module file */
|
|
filen = NewStringEmpty();
|
|
Printv(filen, SWIG_output_directory(), module, ".php", NIL);
|
|
phpfilename = NewString(filen);
|
|
|
|
f_phpcode = NewFile(filen, "w", SWIG_output_files());
|
|
if (!f_phpcode) {
|
|
FileErrorDisplay(filen);
|
|
SWIG_exit(EXIT_FAILURE);
|
|
}
|
|
|
|
Printf(f_phpcode, "<?php\n\n");
|
|
|
|
Swig_banner(f_phpcode);
|
|
|
|
Printf(f_phpcode, "\n");
|
|
Printf(f_phpcode, "// Try to load our extension if it's not already loaded.\n");
|
|
Printf(f_phpcode, "if (!extension_loaded('%s')) {\n", module);
|
|
Printf(f_phpcode, " if (strtolower(substr(PHP_OS, 0, 3)) === 'win') {\n");
|
|
Printf(f_phpcode, " if (!dl('php_%s.dll')) return;\n", module);
|
|
Printf(f_phpcode, " } else {\n");
|
|
Printf(f_phpcode, " // PHP_SHLIB_SUFFIX gives 'dylib' on MacOS X but modules are 'so'.\n");
|
|
Printf(f_phpcode, " if (PHP_SHLIB_SUFFIX === 'dylib') {\n");
|
|
Printf(f_phpcode, " if (!dl('%s.so')) return;\n", module);
|
|
Printf(f_phpcode, " } else {\n");
|
|
Printf(f_phpcode, " if (!dl('%s.'.PHP_SHLIB_SUFFIX)) return;\n", module);
|
|
Printf(f_phpcode, " }\n");
|
|
Printf(f_phpcode, " }\n");
|
|
Printf(f_phpcode, "}\n\n");
|
|
|
|
/* sub-sections of the php file */
|
|
pragma_code = NewStringEmpty();
|
|
pragma_incl = NewStringEmpty();
|
|
|
|
/* Initialize the rest of the module */
|
|
|
|
Printf(s_oinit, "ZEND_INIT_MODULE_GLOBALS(%s, %s_init_globals, %s_destroy_globals);\n", module, module, module);
|
|
|
|
/* start the header section */
|
|
Printf(s_header, "ZEND_BEGIN_MODULE_GLOBALS(%s)\n", module);
|
|
Printf(s_header, "const char *error_msg;\n");
|
|
Printf(s_header, "int error_code;\n");
|
|
Printf(s_header, "ZEND_END_MODULE_GLOBALS(%s)\n", module);
|
|
Printf(s_header, "ZEND_DECLARE_MODULE_GLOBALS(%s)\n", module);
|
|
Printf(s_header, "#ifdef ZTS\n");
|
|
Printf(s_header, "#define SWIG_ErrorMsg() TSRMG(%s_globals_id, zend_%s_globals *, error_msg )\n", module, module);
|
|
Printf(s_header, "#define SWIG_ErrorCode() TSRMG(%s_globals_id, zend_%s_globals *, error_code )\n", module, module);
|
|
Printf(s_header, "#else\n");
|
|
Printf(s_header, "#define SWIG_ErrorMsg() (%s_globals.error_msg)\n", module);
|
|
Printf(s_header, "#define SWIG_ErrorCode() (%s_globals.error_code)\n", module);
|
|
Printf(s_header, "#endif\n\n");
|
|
|
|
Printf(s_header, "static void %s_init_globals(zend_%s_globals *globals ) {\n", module, module);
|
|
Printf(s_header, " globals->error_msg = default_error_msg;\n");
|
|
Printf(s_header, " globals->error_code = default_error_code;\n");
|
|
Printf(s_header, "}\n");
|
|
|
|
Printf(s_header, "static void %s_destroy_globals(zend_%s_globals * globals) { (void)globals; }\n", module, module);
|
|
|
|
Printf(s_header, "\n");
|
|
Printf(s_header, "static void SWIG_ResetError() {\n");
|
|
Printf(s_header, " TSRMLS_FETCH();\n");
|
|
Printf(s_header, " SWIG_ErrorMsg() = default_error_msg;\n");
|
|
Printf(s_header, " SWIG_ErrorCode() = default_error_code;\n");
|
|
Printf(s_header, "}\n");
|
|
|
|
Append(s_header, "\n");
|
|
Printf(s_header, "ZEND_NAMED_FUNCTION(_wrap_swig_%s_alter_newobject) {\n", module);
|
|
Append(s_header, " zval **args[2];\n");
|
|
Append(s_header, " swig_object_wrapper *value;\n");
|
|
Append(s_header, " int type;\n");
|
|
Append(s_header, " int thisown;\n");
|
|
Append(s_header, "\n");
|
|
Append(s_header, " SWIG_ResetError();\n");
|
|
Append(s_header, " if(ZEND_NUM_ARGS() != 2 || zend_get_parameters_array_ex(2, args) != SUCCESS) {\n");
|
|
Append(s_header, " WRONG_PARAM_COUNT;\n");
|
|
Append(s_header, " }\n");
|
|
Append(s_header, "\n");
|
|
Append(s_header, " value = (swig_object_wrapper *) zend_list_find((*args[0])->value.lval, &type);\n");
|
|
Append(s_header, " value->newobject = zval_is_true(*args[1]);\n");
|
|
Append(s_header, "\n");
|
|
Append(s_header, " return;\n");
|
|
Append(s_header, "}\n");
|
|
Printf(s_header, "ZEND_NAMED_FUNCTION(_wrap_swig_%s_get_newobject) {\n", module);
|
|
Append(s_header, " zval **args[1];\n");
|
|
Append(s_header, " swig_object_wrapper *value;\n");
|
|
Append(s_header, " int type;\n");
|
|
Append(s_header, "\n");
|
|
Append(s_header, " SWIG_ResetError();\n");
|
|
Append(s_header, " if(ZEND_NUM_ARGS() != 1 || zend_get_parameters_array_ex(1, args) != SUCCESS) {\n");
|
|
Append(s_header, " WRONG_PARAM_COUNT;\n");
|
|
Append(s_header, " }\n");
|
|
Append(s_header, "\n");
|
|
Append(s_header, " value = (swig_object_wrapper *) zend_list_find((*args[0])->value.lval, &type);\n");
|
|
Append(s_header, " RETVAL_LONG(value->newobject);\n");
|
|
Append(s_header, "\n");
|
|
Append(s_header, " return;\n");
|
|
Append(s_header, "}\n");
|
|
|
|
Printf(s_header, "#define SWIG_name \"%s\"\n", module);
|
|
/* Printf(s_header,"#ifdef HAVE_CONFIG_H\n");
|
|
Printf(s_header,"#include \"config.h\"\n");
|
|
Printf(s_header,"#endif\n\n");
|
|
*/
|
|
Printf(s_header, "#ifdef __cplusplus\n");
|
|
Printf(s_header, "extern \"C\" {\n");
|
|
Printf(s_header, "#endif\n");
|
|
Printf(s_header, "#include \"php.h\"\n");
|
|
Printf(s_header, "#include \"php_ini.h\"\n");
|
|
Printf(s_header, "#include \"ext/standard/info.h\"\n");
|
|
Printf(s_header, "#include \"php_%s.h\"\n", module);
|
|
Printf(s_header, "#ifdef __cplusplus\n");
|
|
Printf(s_header, "}\n");
|
|
Printf(s_header, "#endif\n\n");
|
|
|
|
if (directorsEnabled()) {
|
|
// Insert director runtime
|
|
Swig_insert_file("director.swg", s_header);
|
|
}
|
|
|
|
/* Create the .h file too */
|
|
filen = NewStringEmpty();
|
|
Printv(filen, SWIG_output_directory(), "php_", module, ".h", NIL);
|
|
f_h = NewFile(filen, "w", SWIG_output_files());
|
|
if (!f_h) {
|
|
FileErrorDisplay(filen);
|
|
SWIG_exit(EXIT_FAILURE);
|
|
}
|
|
|
|
Swig_banner(f_h);
|
|
|
|
Printf(f_h, "\n");
|
|
Printf(f_h, "#ifndef PHP_%s_H\n", cap_module);
|
|
Printf(f_h, "#define PHP_%s_H\n\n", cap_module);
|
|
Printf(f_h, "extern zend_module_entry %s_module_entry;\n", module);
|
|
Printf(f_h, "#define phpext_%s_ptr &%s_module_entry\n\n", module, module);
|
|
Printf(f_h, "#ifdef PHP_WIN32\n");
|
|
Printf(f_h, "# define PHP_%s_API __declspec(dllexport)\n", cap_module);
|
|
Printf(f_h, "#else\n");
|
|
Printf(f_h, "# define PHP_%s_API\n", cap_module);
|
|
Printf(f_h, "#endif\n\n");
|
|
Printf(f_h, "#ifdef ZTS\n");
|
|
Printf(f_h, "#include \"TSRM.h\"\n");
|
|
Printf(f_h, "#endif\n\n");
|
|
Printf(f_h, "PHP_MINIT_FUNCTION(%s);\n", module);
|
|
Printf(f_h, "PHP_MSHUTDOWN_FUNCTION(%s);\n", module);
|
|
Printf(f_h, "PHP_RINIT_FUNCTION(%s);\n", module);
|
|
Printf(f_h, "PHP_RSHUTDOWN_FUNCTION(%s);\n", module);
|
|
Printf(f_h, "PHP_MINFO_FUNCTION(%s);\n\n", module);
|
|
|
|
/* start the function entry section */
|
|
s_entry = NewString("/* entry subsection */\n");
|
|
|
|
/* holds all the per-class function entry sections */
|
|
all_cs_entry = NewString("/* class entry subsection */\n");
|
|
cs_entry = NULL;
|
|
|
|
Printf(s_entry, "/* Every non-class user visible function must have an entry here */\n");
|
|
Printf(s_entry, "static zend_function_entry %s_functions[] = {\n", module);
|
|
|
|
/* start the init section */
|
|
Append(s_init, "#if ZEND_MODULE_API_NO <= 20090626\n");
|
|
Append(s_init, "#undef ZEND_MODULE_BUILD_ID\n");
|
|
Append(s_init, "#define ZEND_MODULE_BUILD_ID (char*)\"API\" ZEND_TOSTR(ZEND_MODULE_API_NO) ZEND_BUILD_TS ZEND_BUILD_DEBUG ZEND_BUILD_SYSTEM ZEND_BUILD_EXTRA\n");
|
|
Append(s_init, "#endif\n");
|
|
Printv(s_init, "zend_module_entry ", module, "_module_entry = {\n" "#if ZEND_MODULE_API_NO > 20010900\n" " STANDARD_MODULE_HEADER,\n" "#endif\n", NIL);
|
|
Printf(s_init, " (char*)\"%s\",\n", module);
|
|
Printf(s_init, " %s_functions,\n", module);
|
|
Printf(s_init, " PHP_MINIT(%s),\n", module);
|
|
Printf(s_init, " PHP_MSHUTDOWN(%s),\n", module);
|
|
Printf(s_init, " PHP_RINIT(%s),\n", module);
|
|
Printf(s_init, " PHP_RSHUTDOWN(%s),\n", module);
|
|
Printf(s_init, " PHP_MINFO(%s),\n", module);
|
|
Printf(s_init, "#if ZEND_MODULE_API_NO > 20010900\n");
|
|
Printf(s_init, " NO_VERSION_YET,\n");
|
|
Printf(s_init, "#endif\n");
|
|
Printf(s_init, " STANDARD_MODULE_PROPERTIES\n");
|
|
Printf(s_init, "};\n");
|
|
Printf(s_init, "zend_module_entry* SWIG_module_entry = &%s_module_entry;\n\n", module);
|
|
|
|
Printf(s_init, "#ifdef __cplusplus\n");
|
|
Printf(s_init, "extern \"C\" {\n");
|
|
Printf(s_init, "#endif\n");
|
|
// We want to write "SWIGEXPORT ZEND_GET_MODULE(%s)" but ZEND_GET_MODULE
|
|
// in PHP5 has "extern "C" { ... }" around it so we can't do that.
|
|
Printf(s_init, "SWIGEXPORT zend_module_entry *get_module(void) { return &%s_module_entry; }\n", module);
|
|
Printf(s_init, "#ifdef __cplusplus\n");
|
|
Printf(s_init, "}\n");
|
|
Printf(s_init, "#endif\n\n");
|
|
|
|
/* We have to register the constants before they are (possibly) used
|
|
* by the pointer typemaps. This all needs re-arranging really as
|
|
* things are being called in the wrong order
|
|
*/
|
|
Printf(s_init, "#define SWIG_php_minit PHP_MINIT_FUNCTION(%s)\n", module);
|
|
|
|
/* Emit all of the code */
|
|
Language::top(n);
|
|
|
|
SwigPHP_emit_resource_registrations();
|
|
// Printv(s_init,s_resourcetypes,NIL);
|
|
/* We need this after all classes written out by ::top */
|
|
Printf(s_oinit, "CG(active_class_entry) = NULL;\n");
|
|
Printf(s_oinit, "/* end oinit subsection */\n");
|
|
Printf(s_init, "%s\n", s_oinit);
|
|
|
|
/* Constants generated during top call */
|
|
Printf(s_cinit, "/* end cinit subsection */\n");
|
|
Printf(s_init, "%s\n", s_cinit);
|
|
Clear(s_cinit);
|
|
Delete(s_cinit);
|
|
|
|
Printf(s_init, " return SUCCESS;\n");
|
|
Printf(s_init, "}\n\n");
|
|
|
|
// Now do REQUEST init which holds any user specified %rinit, and also vinit
|
|
Printf(s_init, "PHP_RINIT_FUNCTION(%s)\n{\n", module);
|
|
Printf(s_init, "%s\n", r_init);
|
|
|
|
/* finish our init section which will have been used by class wrappers */
|
|
Printf(s_vinit, "/* end vinit subsection */\n");
|
|
Printf(s_init, "%s\n", s_vinit);
|
|
Clear(s_vinit);
|
|
Delete(s_vinit);
|
|
|
|
Printf(s_init, " return SUCCESS;\n");
|
|
Printf(s_init, "}\n\n");
|
|
|
|
Printv(s_init, "PHP_MSHUTDOWN_FUNCTION(", module, ")\n"
|
|
"{\n",
|
|
s_shutdown,
|
|
"#ifdef ZTS\n"
|
|
" ts_free_id(", module, "_globals_id);\n"
|
|
"#endif\n"
|
|
" return SUCCESS;\n"
|
|
"}\n\n", NIL);
|
|
|
|
Printf(s_init, "PHP_RSHUTDOWN_FUNCTION(%s)\n{\n", module);
|
|
Printf(s_init, "%s\n", r_shutdown);
|
|
Printf(s_init, " return SUCCESS;\n");
|
|
Printf(s_init, "}\n\n");
|
|
|
|
Printf(s_init, "PHP_MINFO_FUNCTION(%s)\n{\n", module);
|
|
Printf(s_init, "%s", pragma_phpinfo);
|
|
Printf(s_init, "}\n");
|
|
Printf(s_init, "/* end init section */\n");
|
|
|
|
Printf(f_h, "#endif /* PHP_%s_H */\n", cap_module);
|
|
|
|
Close(f_h);
|
|
|
|
String *type_table = NewStringEmpty();
|
|
SwigType_emit_type_table(f_runtime, type_table);
|
|
Printf(s_header, "%s", type_table);
|
|
Delete(type_table);
|
|
|
|
/* Oh dear, more things being called in the wrong order. This whole
|
|
* function really needs totally redoing.
|
|
*/
|
|
|
|
if (directorsEnabled()) {
|
|
Dump(f_directors_h, f_runtime_h);
|
|
Printf(f_runtime_h, "\n");
|
|
Printf(f_runtime_h, "#endif\n");
|
|
Close(f_runtime_h);
|
|
}
|
|
|
|
Printf(s_header, "/* end header section */\n");
|
|
Printf(s_wrappers, "/* end wrapper section */\n");
|
|
Printf(s_vdecl, "/* end vdecl subsection */\n");
|
|
|
|
Dump(f_runtime, f_begin);
|
|
Printv(f_begin, s_header, NIL);
|
|
if (directorsEnabled()) {
|
|
Dump(f_directors, f_begin);
|
|
}
|
|
Printv(f_begin, s_vdecl, s_wrappers, NIL);
|
|
Printv(f_begin, all_cs_entry, "\n\n", s_entry,
|
|
" SWIG_ZEND_NAMED_FE(swig_", module, "_alter_newobject,_wrap_swig_", module, "_alter_newobject,NULL)\n"
|
|
" SWIG_ZEND_NAMED_FE(swig_", module, "_get_newobject,_wrap_swig_", module, "_get_newobject,NULL)\n"
|
|
"{NULL, NULL, NULL}\n};\n\n", NIL);
|
|
Printv(f_begin, s_init, NIL);
|
|
Delete(s_header);
|
|
Delete(s_wrappers);
|
|
Delete(s_init);
|
|
Delete(s_vdecl);
|
|
Delete(all_cs_entry);
|
|
Delete(s_entry);
|
|
Close(f_begin);
|
|
Delete(f_runtime);
|
|
Delete(f_begin);
|
|
|
|
Printf(f_phpcode, "%s\n%s\n", pragma_incl, pragma_code);
|
|
if (s_fakeoowrappers) {
|
|
Printf(f_phpcode, "abstract class %s {", Len(prefix) ? prefix : module);
|
|
Printf(f_phpcode, "%s", s_fakeoowrappers);
|
|
Printf(f_phpcode, "}\n\n");
|
|
Delete(s_fakeoowrappers);
|
|
s_fakeoowrappers = NULL;
|
|
}
|
|
Printf(f_phpcode, "%s\n?>\n", s_phpclasses);
|
|
Close(f_phpcode);
|
|
|
|
return SWIG_OK;
|
|
}
|
|
|
|
/* Just need to append function names to function table to register with PHP. */
|
|
void create_command(String *cname, String *iname) {
|
|
// This is for the single main zend_function_entry record
|
|
Printf(f_h, "ZEND_NAMED_FUNCTION(%s);\n", iname);
|
|
String * s = cs_entry;
|
|
if (!s) s = s_entry;
|
|
Printf(s, " SWIG_ZEND_NAMED_FE(%(lower)s,%s,NULL)\n", cname, iname);
|
|
}
|
|
|
|
/* ------------------------------------------------------------
|
|
* dispatchFunction()
|
|
* ------------------------------------------------------------ */
|
|
void dispatchFunction(Node *n) {
|
|
/* Last node in overloaded chain */
|
|
|
|
int maxargs;
|
|
String *tmp = NewStringEmpty();
|
|
if (Swig_directorclass(n) && wrapperType == directorconstructor) {
|
|
/* We have an extra 'this' parameter. */
|
|
SetFlag(n, "wrap:this");
|
|
}
|
|
String *dispatch = Swig_overload_dispatch(n, "return %s(INTERNAL_FUNCTION_PARAM_PASSTHRU);", &maxargs);
|
|
|
|
/* Generate a dispatch wrapper for all overloaded functions */
|
|
|
|
Wrapper *f = NewWrapper();
|
|
String *symname = Getattr(n, "sym:name");
|
|
String *wname = Swig_name_wrapper(symname);
|
|
|
|
create_command(symname, wname);
|
|
Printv(f->def, "ZEND_NAMED_FUNCTION(", wname, ") {\n", NIL);
|
|
|
|
Wrapper_add_local(f, "argc", "int argc");
|
|
|
|
Printf(tmp, "zval **argv[%d]", maxargs);
|
|
Wrapper_add_local(f, "argv", tmp);
|
|
|
|
Printf(f->code, "argc = ZEND_NUM_ARGS();\n");
|
|
|
|
Printf(f->code, "zend_get_parameters_array_ex(argc,argv);\n");
|
|
|
|
Replaceall(dispatch, "$args", "self,args");
|
|
|
|
Printv(f->code, dispatch, "\n", NIL);
|
|
|
|
Printf(f->code, "SWIG_ErrorCode() = E_ERROR;\n");
|
|
Printf(f->code, "SWIG_ErrorMsg() = \"No matching function for overloaded '%s'\";\n", symname);
|
|
Printv(f->code, "zend_error(SWIG_ErrorCode(),\"%s\",SWIG_ErrorMsg());\n", NIL);
|
|
|
|
Printv(f->code, "}\n", NIL);
|
|
Wrapper_print(f, s_wrappers);
|
|
|
|
DelWrapper(f);
|
|
Delete(dispatch);
|
|
Delete(tmp);
|
|
Delete(wname);
|
|
}
|
|
|
|
/* ------------------------------------------------------------
|
|
* functionWrapper()
|
|
* ------------------------------------------------------------ */
|
|
|
|
/* Helper method for PHP::functionWrapper */
|
|
bool is_class(SwigType *t) {
|
|
Node *n = classLookup(t);
|
|
if (n) {
|
|
String *r = Getattr(n, "php:proxy"); // Set by classDeclaration()
|
|
if (!r)
|
|
r = Getattr(n, "sym:name"); // Not seen by classDeclaration yet, but this is the name
|
|
if (r)
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
virtual int functionWrapper(Node *n) {
|
|
String *name = GetChar(n, "name");
|
|
String *iname = GetChar(n, "sym:name");
|
|
SwigType *d = Getattr(n, "type");
|
|
ParmList *l = Getattr(n, "parms");
|
|
String *nodeType = Getattr(n, "nodeType");
|
|
int newobject = GetFlag(n, "feature:new");
|
|
int constructor = (Cmp(nodeType, "constructor") == 0);
|
|
|
|
Parm *p;
|
|
int i;
|
|
int numopt;
|
|
String *tm;
|
|
Wrapper *f;
|
|
|
|
String *wname;
|
|
int overloaded = 0;
|
|
String *overname = 0;
|
|
|
|
if (Cmp(nodeType, "destructor") == 0) {
|
|
// We just generate the Zend List Destructor and let Zend manage the
|
|
// reference counting. There's no explicit destructor, but the user can
|
|
// just do `$obj = null;' to remove a reference to an object.
|
|
return CreateZendListDestructor(n);
|
|
}
|
|
// Test for overloading;
|
|
if (Getattr(n, "sym:overloaded")) {
|
|
overloaded = 1;
|
|
overname = Getattr(n, "sym:overname");
|
|
} else {
|
|
if (!addSymbol(iname, n))
|
|
return SWIG_ERROR;
|
|
}
|
|
|
|
wname = Swig_name_wrapper(iname);
|
|
if (overname) {
|
|
Printf(wname, "%s", overname);
|
|
}
|
|
|
|
f = NewWrapper();
|
|
numopt = 0;
|
|
|
|
String *outarg = NewStringEmpty();
|
|
String *cleanup = NewStringEmpty();
|
|
|
|
// Not issued for overloaded functions.
|
|
if (!overloaded) {
|
|
create_command(iname, wname);
|
|
}
|
|
Printv(f->def, "ZEND_NAMED_FUNCTION(", wname, ") {\n", NIL);
|
|
|
|
emit_parameter_variables(l, f);
|
|
/* Attach standard typemaps */
|
|
|
|
emit_attach_parmmaps(l, f);
|
|
|
|
// wrap:parms is used by overload resolution.
|
|
Setattr(n, "wrap:parms", l);
|
|
|
|
int num_arguments = emit_num_arguments(l);
|
|
int num_required = emit_num_required(l);
|
|
numopt = num_arguments - num_required;
|
|
|
|
if (wrapperType == directorconstructor)
|
|
num_arguments++;
|
|
|
|
if (num_arguments > 0) {
|
|
String *args = NewStringEmpty();
|
|
if (wrapperType == directorconstructor)
|
|
Wrapper_add_local(f, "arg0", "zval *arg0");
|
|
Printf(args, "zval **args[%d]", num_arguments);
|
|
Wrapper_add_local(f, "args", args);
|
|
Delete(args);
|
|
args = NULL;
|
|
}
|
|
if (is_member_director(n)) {
|
|
Wrapper_add_local(f, "director", "Swig::Director *director = 0");
|
|
Printf(f->code, "director = dynamic_cast<Swig::Director*>(arg1);\n");
|
|
Wrapper_add_local(f, "upcall", "bool upcall = false");
|
|
Printf(f->code, "upcall = !director->is_overriden_method((char *)\"%s\", (char *)\"%s\");\n",
|
|
Swig_class_name(Swig_methodclass(n)), name);
|
|
}
|
|
|
|
// This generated code may be called:
|
|
// 1) as an object method, or
|
|
// 2) as a class-method/function (without a "this_ptr")
|
|
// Option (1) has "this_ptr" for "this", option (2) needs it as
|
|
// first parameter
|
|
|
|
// NOTE: possible we ignore this_ptr as a param for native constructor
|
|
|
|
Printf(f->code, "SWIG_ResetError();\n");
|
|
|
|
if (numopt > 0) { // membervariable wrappers do not have optional args
|
|
Wrapper_add_local(f, "arg_count", "int arg_count");
|
|
Printf(f->code, "arg_count = ZEND_NUM_ARGS();\n");
|
|
Printf(f->code, "if(arg_count<%d || arg_count>%d ||\n", num_required, num_arguments);
|
|
Printf(f->code, " zend_get_parameters_array_ex(arg_count,args)!=SUCCESS)\n");
|
|
Printf(f->code, "\tWRONG_PARAM_COUNT;\n\n");
|
|
} else {
|
|
if (num_arguments == 0) {
|
|
Printf(f->code, "if(ZEND_NUM_ARGS() != 0) {\n");
|
|
} else {
|
|
Printf(f->code, "if(ZEND_NUM_ARGS() != %d || zend_get_parameters_array_ex(%d, args) != SUCCESS) {\n", num_arguments, num_arguments);
|
|
}
|
|
Printf(f->code, "WRONG_PARAM_COUNT;\n}\n\n");
|
|
}
|
|
if (wrapperType == directorconstructor)
|
|
Printf(f->code, "arg0 = *args[0];\n \n");
|
|
|
|
/* Now convert from PHP to C variables */
|
|
// At this point, argcount if used is the number of deliberately passed args
|
|
// not including this_ptr even if it is used.
|
|
// It means error messages may be out by argbase with error
|
|
// reports. We can either take argbase into account when raising
|
|
// errors, or find a better way of dealing with _thisptr.
|
|
// I would like, if objects are wrapped, to assume _thisptr is always
|
|
// _this and not the first argument.
|
|
// This may mean looking at Language::memberfunctionHandler
|
|
|
|
int limit = num_arguments;
|
|
if (wrapperType == directorconstructor)
|
|
limit--;
|
|
for (i = 0, p = l; i < limit; i++) {
|
|
String *source;
|
|
|
|
/* Skip ignored arguments */
|
|
//while (Getattr(p,"tmap:ignore")) { p = Getattr(p,"tmap:ignore:next");}
|
|
while (checkAttribute(p, "tmap:in:numinputs", "0")) {
|
|
p = Getattr(p, "tmap:in:next");
|
|
}
|
|
|
|
SwigType *pt = Getattr(p, "type");
|
|
|
|
if (wrapperType == directorconstructor) {
|
|
source = NewStringf("args[%d]", i+1);
|
|
} else {
|
|
source = NewStringf("args[%d]", i);
|
|
}
|
|
|
|
String *ln = Getattr(p, "lname");
|
|
|
|
/* Check if optional */
|
|
if (i >= num_required) {
|
|
Printf(f->code, "\tif(arg_count > %d) {\n", i);
|
|
}
|
|
|
|
if ((tm = Getattr(p, "tmap:in"))) {
|
|
Replaceall(tm, "$source", source);
|
|
Replaceall(tm, "$target", ln);
|
|
Replaceall(tm, "$input", source);
|
|
Setattr(p, "emit:input", source);
|
|
Printf(f->code, "%s\n", tm);
|
|
if (i == 0 && Getattr(p, "self")) {
|
|
Printf(f->code, "\tif(!arg1) SWIG_PHP_Error(E_ERROR, \"this pointer is NULL\");\n");
|
|
}
|
|
p = Getattr(p, "tmap:in:next");
|
|
if (i >= num_required) {
|
|
Printf(f->code, "}\n");
|
|
}
|
|
continue;
|
|
} else {
|
|
Swig_warning(WARN_TYPEMAP_IN_UNDEF, input_file, line_number, "Unable to use type %s as a function argument.\n", SwigType_str(pt, 0));
|
|
}
|
|
if (i >= num_required) {
|
|
Printf(f->code, "\t}\n");
|
|
}
|
|
Delete(source);
|
|
}
|
|
|
|
Swig_director_emit_dynamic_cast(n, f);
|
|
|
|
/* Insert constraint checking code */
|
|
for (p = l; p;) {
|
|
if ((tm = Getattr(p, "tmap:check"))) {
|
|
Replaceall(tm, "$target", Getattr(p, "lname"));
|
|
Printv(f->code, tm, "\n", NIL);
|
|
p = Getattr(p, "tmap:check:next");
|
|
} else {
|
|
p = nextSibling(p);
|
|
}
|
|
}
|
|
|
|
/* Insert cleanup code */
|
|
for (i = 0, p = l; p; i++) {
|
|
if ((tm = Getattr(p, "tmap:freearg"))) {
|
|
Replaceall(tm, "$source", Getattr(p, "lname"));
|
|
Printv(cleanup, tm, "\n", NIL);
|
|
p = Getattr(p, "tmap:freearg:next");
|
|
} else {
|
|
p = nextSibling(p);
|
|
}
|
|
}
|
|
|
|
/* Insert argument output code */
|
|
for (i = 0, p = l; p; i++) {
|
|
if ((tm = Getattr(p, "tmap:argout"))) {
|
|
Replaceall(tm, "$source", Getattr(p, "lname"));
|
|
// Replaceall(tm,"$input",Getattr(p,"lname"));
|
|
Replaceall(tm, "$target", "return_value");
|
|
Replaceall(tm, "$result", "return_value");
|
|
Replaceall(tm, "$arg", Getattr(p, "emit:input"));
|
|
Replaceall(tm, "$input", Getattr(p, "emit:input"));
|
|
Printv(outarg, tm, "\n", NIL);
|
|
p = Getattr(p, "tmap:argout:next");
|
|
} else {
|
|
p = nextSibling(p);
|
|
}
|
|
}
|
|
|
|
Setattr(n, "wrap:name", wname);
|
|
|
|
/* emit function call */
|
|
String *actioncode = emit_action(n);
|
|
|
|
if ((tm = Swig_typemap_lookup_out("out", n, "result", f, actioncode))) {
|
|
Replaceall(tm, "$input", "result");
|
|
Replaceall(tm, "$source", "result");
|
|
Replaceall(tm, "$target", "return_value");
|
|
Replaceall(tm, "$result", "return_value");
|
|
Replaceall(tm, "$owner", newobject ? "1" : "0");
|
|
Printf(f->code, "%s\n", tm);
|
|
} else {
|
|
Swig_warning(WARN_TYPEMAP_OUT_UNDEF, input_file, line_number, "Unable to use return type %s in function %s.\n", SwigType_str(d, 0), name);
|
|
}
|
|
emit_return_variable(n, d, f);
|
|
|
|
if (outarg) {
|
|
Printv(f->code, outarg, NIL);
|
|
}
|
|
|
|
if (cleanup) {
|
|
Printv(f->code, cleanup, NIL);
|
|
}
|
|
|
|
/* Look to see if there is any newfree cleanup code */
|
|
if (GetFlag(n, "feature:new")) {
|
|
if ((tm = Swig_typemap_lookup("newfree", n, "result", 0))) {
|
|
Printf(f->code, "%s\n", tm);
|
|
Delete(tm);
|
|
}
|
|
}
|
|
|
|
/* See if there is any return cleanup code */
|
|
if ((tm = Swig_typemap_lookup("ret", n, "result", 0))) {
|
|
Printf(f->code, "%s\n", tm);
|
|
Delete(tm);
|
|
}
|
|
|
|
Printf(f->code, "return;\n");
|
|
|
|
/* Error handling code */
|
|
Printf(f->code, "fail:\n");
|
|
Printv(f->code, cleanup, NIL);
|
|
Printv(f->code, "zend_error_noreturn(SWIG_ErrorCode(),\"%s\",SWIG_ErrorMsg());", NIL);
|
|
|
|
Printf(f->code, "}\n");
|
|
|
|
Replaceall(f->code, "$cleanup", cleanup);
|
|
Replaceall(f->code, "$symname", iname);
|
|
|
|
Wrapper_print(f, s_wrappers);
|
|
DelWrapper(f);
|
|
f = NULL;
|
|
|
|
if (overloaded && !Getattr(n, "sym:nextSibling")) {
|
|
dispatchFunction(n);
|
|
}
|
|
|
|
Delete(wname);
|
|
wname = NULL;
|
|
|
|
if (!shadow) {
|
|
return SWIG_OK;
|
|
}
|
|
|
|
// Handle getters and setters.
|
|
if (wrapperType == membervar) {
|
|
const char *p = Char(iname);
|
|
if (strlen(p) > 4) {
|
|
p += strlen(p) - 4;
|
|
String *varname = Getattr(n, "membervariableHandler:sym:name");
|
|
if (strcmp(p, "_get") == 0) {
|
|
Setattr(shadow_get_vars, varname, iname);
|
|
} else if (strcmp(p, "_set") == 0) {
|
|
Setattr(shadow_set_vars, varname, iname);
|
|
}
|
|
}
|
|
return SWIG_OK;
|
|
}
|
|
|
|
// Only look at non-overloaded methods and the last entry in each overload
|
|
// chain (we check the last so that wrap:parms and wrap:name have been set
|
|
// for them all).
|
|
if (overloaded && Getattr(n, "sym:nextSibling") != 0)
|
|
return SWIG_OK;
|
|
|
|
if (!s_oowrappers)
|
|
s_oowrappers = NewStringEmpty();
|
|
|
|
if (newobject || wrapperType == memberfn || wrapperType == staticmemberfn || wrapperType == standard || wrapperType == staticmembervar) {
|
|
bool handle_as_overload = false;
|
|
String **arg_names;
|
|
String **arg_values;
|
|
// Method or static method or plain function.
|
|
const char *methodname = 0;
|
|
String *output = s_oowrappers;
|
|
if (constructor) {
|
|
class_has_ctor = true;
|
|
// Skip the Foo:: prefix.
|
|
char *ptr = strrchr(GetChar(Swig_methodclass(n), "sym:name"), ':');
|
|
if (ptr) {
|
|
ptr++;
|
|
} else {
|
|
ptr = GetChar(Swig_methodclass(n), "sym:name");
|
|
}
|
|
if (strcmp(ptr, GetChar(n, "constructorHandler:sym:name")) == 0) {
|
|
methodname = "__construct";
|
|
} else {
|
|
// The class has multiple constructors and this one is
|
|
// renamed, so this will be a static factory function
|
|
methodname = GetChar(n, "constructorHandler:sym:name");
|
|
}
|
|
} else if (wrapperType == memberfn) {
|
|
methodname = Char(Getattr(n, "memberfunctionHandler:sym:name"));
|
|
} else if (wrapperType == staticmemberfn) {
|
|
methodname = Char(Getattr(n, "staticmemberfunctionHandler:sym:name"));
|
|
} else if (wrapperType == staticmembervar) {
|
|
// Static member variable, wrapped as a function due to PHP limitations.
|
|
methodname = Char(Getattr(n, "staticmembervariableHandler:sym:name"));
|
|
} else { // wrapperType == standard
|
|
methodname = Char(iname);
|
|
if (!s_fakeoowrappers)
|
|
s_fakeoowrappers = NewStringEmpty();
|
|
output = s_fakeoowrappers;
|
|
}
|
|
|
|
bool really_overloaded = overloaded ? true : false;
|
|
int min_num_of_arguments = emit_num_required(l);
|
|
int max_num_of_arguments = emit_num_arguments(l);
|
|
|
|
// For a function with default arguments, we end up with the fullest
|
|
// parmlist in full_parmlist.
|
|
ParmList *full_parmlist = l;
|
|
Hash *ret_types = NewHash();
|
|
Setattr(ret_types, d, d);
|
|
|
|
if (overloaded) {
|
|
// Look at all the overloaded versions of this method in turn to
|
|
// decide if it's really an overloaded method, or just one where some
|
|
// parameters have default values.
|
|
Node *o = Getattr(n, "sym:overloaded");
|
|
while (o) {
|
|
if (o == n) {
|
|
o = Getattr(o, "sym:nextSibling");
|
|
continue;
|
|
}
|
|
|
|
SwigType *d2 = Getattr(o, "type");
|
|
if (!d2) {
|
|
assert(constructor);
|
|
} else if (!Getattr(ret_types, d2)) {
|
|
Setattr(ret_types, d2, d2);
|
|
}
|
|
|
|
ParmList *l2 = Getattr(o, "wrap:parms");
|
|
int num_arguments = emit_num_arguments(l2);
|
|
int num_required = emit_num_required(l2);
|
|
if (num_required < min_num_of_arguments)
|
|
min_num_of_arguments = num_required;
|
|
|
|
if (num_arguments > max_num_of_arguments) {
|
|
max_num_of_arguments = num_arguments;
|
|
full_parmlist = l2;
|
|
}
|
|
o = Getattr(o, "sym:nextSibling");
|
|
}
|
|
|
|
o = Getattr(n, "sym:overloaded");
|
|
while (o) {
|
|
if (o == n) {
|
|
o = Getattr(o, "sym:nextSibling");
|
|
continue;
|
|
}
|
|
|
|
ParmList *l2 = Getattr(o, "wrap:parms");
|
|
Parm *p = l, *p2 = l2;
|
|
if (wrapperType == memberfn) {
|
|
p = nextSibling(p);
|
|
p2 = nextSibling(p2);
|
|
}
|
|
while (p && p2) {
|
|
if (Cmp(Getattr(p, "type"), Getattr(p2, "type")) != 0)
|
|
break;
|
|
if (Cmp(Getattr(p, "name"), Getattr(p2, "name")) != 0)
|
|
break;
|
|
String *value = Getattr(p, "value");
|
|
String *value2 = Getattr(p2, "value");
|
|
if (value && !value2)
|
|
break;
|
|
if (!value && value2)
|
|
break;
|
|
if (value) {
|
|
if (Cmp(value, value2) != 0)
|
|
break;
|
|
}
|
|
p = nextSibling(p);
|
|
p2 = nextSibling(p2);
|
|
}
|
|
if (p && p2)
|
|
break;
|
|
// One parameter list is a prefix of the other, so check that all
|
|
// remaining parameters of the longer list are optional.
|
|
if (p2)
|
|
p = p2;
|
|
while (p && Getattr(p, "value"))
|
|
p = nextSibling(p);
|
|
if (p)
|
|
break;
|
|
o = Getattr(o, "sym:nextSibling");
|
|
}
|
|
if (!o) {
|
|
// This "overloaded method" is really just one with default args.
|
|
really_overloaded = false;
|
|
if (l != full_parmlist) {
|
|
l = full_parmlist;
|
|
if (wrapperType == memberfn)
|
|
l = nextSibling(l);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (wrapperType == memberfn) {
|
|
// Allow for the "this" pointer.
|
|
--min_num_of_arguments;
|
|
--max_num_of_arguments;
|
|
}
|
|
|
|
arg_names = (String **) malloc(max_num_of_arguments * sizeof(String *));
|
|
if (!arg_names) {
|
|
/* FIXME: How should this be handled? The rest of SWIG just seems
|
|
* to not bother checking for malloc failing! */
|
|
fprintf(stderr, "Malloc failed!\n");
|
|
exit(1);
|
|
}
|
|
for (i = 0; i < max_num_of_arguments; ++i) {
|
|
arg_names[i] = NULL;
|
|
}
|
|
|
|
arg_values = (String **) malloc(max_num_of_arguments * sizeof(String *));
|
|
if (!arg_values) {
|
|
/* FIXME: How should this be handled? The rest of SWIG just seems
|
|
* to not bother checking for malloc failing! */
|
|
fprintf(stderr, "Malloc failed!\n");
|
|
exit(1);
|
|
}
|
|
for (i = 0; i < max_num_of_arguments; ++i) {
|
|
arg_values[i] = NULL;
|
|
}
|
|
|
|
Node *o;
|
|
if (overloaded) {
|
|
o = Getattr(n, "sym:overloaded");
|
|
} else {
|
|
o = n;
|
|
}
|
|
while (o) {
|
|
int argno = 0;
|
|
Parm *p = Getattr(o, "wrap:parms");
|
|
if (wrapperType == memberfn)
|
|
p = nextSibling(p);
|
|
while (p) {
|
|
if (GetInt(p, "tmap:in:numinputs") == 0) {
|
|
p = nextSibling(p);
|
|
continue;
|
|
}
|
|
assert(0 <= argno && argno < max_num_of_arguments);
|
|
String *&pname = arg_names[argno];
|
|
const char *pname_cstr = GetChar(p, "name");
|
|
// Just get rid of the C++ namespace part for now.
|
|
const char *ptr = NULL;
|
|
if (pname_cstr && (ptr = strrchr(pname_cstr, ':'))) {
|
|
pname_cstr = ptr + 1;
|
|
}
|
|
if (!pname_cstr) {
|
|
// Unnamed parameter, e.g. int foo(int);
|
|
} else if (pname == NULL) {
|
|
pname = NewString(pname_cstr);
|
|
} else {
|
|
size_t len = strlen(pname_cstr);
|
|
size_t spc = 0;
|
|
size_t len_pname = strlen(Char(pname));
|
|
while (spc + len <= len_pname) {
|
|
if (strncmp(pname_cstr, Char(pname) + spc, len) == 0) {
|
|
char ch = ((char *) Char(pname))[spc + len];
|
|
if (ch == '\0' || ch == ' ') {
|
|
// Already have this pname_cstr.
|
|
pname_cstr = NULL;
|
|
break;
|
|
}
|
|
}
|
|
char *p = strchr(Char(pname) + spc, ' ');
|
|
if (!p)
|
|
break;
|
|
spc = (p + 4) - Char(pname);
|
|
}
|
|
if (pname_cstr) {
|
|
Printf(pname, " or_%s", pname_cstr);
|
|
}
|
|
}
|
|
String *value = NewString(Getattr(p, "value"));
|
|
if (Len(value)) {
|
|
/* Check that value is a valid constant in PHP (and adjust it if
|
|
* necessary, or replace it with "?" if it's just not valid). */
|
|
SwigType *type = Getattr(p, "type");
|
|
switch (SwigType_type(type)) {
|
|
case T_BOOL: {
|
|
if (Strcmp(value, "true") == 0 || Strcmp(value, "false") == 0)
|
|
break;
|
|
char *p;
|
|
errno = 0;
|
|
int n = strtol(Char(value), &p, 0);
|
|
Clear(value);
|
|
if (errno || *p) {
|
|
Append(value, "?");
|
|
} else if (n) {
|
|
Append(value, "true");
|
|
} else {
|
|
Append(value, "false");
|
|
}
|
|
break;
|
|
}
|
|
case T_CHAR:
|
|
case T_SCHAR:
|
|
case T_SHORT:
|
|
case T_INT:
|
|
case T_LONG: {
|
|
char *p;
|
|
errno = 0;
|
|
unsigned int n = strtol(Char(value), &p, 0);
|
|
(void) n;
|
|
if (errno || *p) {
|
|
Clear(value);
|
|
Append(value, "?");
|
|
}
|
|
break;
|
|
}
|
|
case T_UCHAR:
|
|
case T_USHORT:
|
|
case T_UINT:
|
|
case T_ULONG: {
|
|
char *p;
|
|
errno = 0;
|
|
unsigned int n = strtoul(Char(value), &p, 0);
|
|
(void) n;
|
|
if (errno || *p) {
|
|
Clear(value);
|
|
Append(value, "?");
|
|
}
|
|
break;
|
|
}
|
|
case T_FLOAT:
|
|
case T_DOUBLE:{
|
|
char *p;
|
|
errno = 0;
|
|
/* FIXME: strtod is locale dependent... */
|
|
double val = strtod(Char(value), &p);
|
|
if (errno || *p) {
|
|
Clear(value);
|
|
Append(value, "?");
|
|
} else if (strchr(Char(value), '.') == NULL) {
|
|
// Ensure value is a double constant, not an integer one.
|
|
Append(value, ".0");
|
|
double val2 = strtod(Char(value), &p);
|
|
if (errno || *p || val != val2) {
|
|
Clear(value);
|
|
Append(value, "?");
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case T_REFERENCE:
|
|
case T_USER:
|
|
case T_ARRAY:
|
|
Clear(value);
|
|
Append(value, "?");
|
|
break;
|
|
case T_STRING:
|
|
if (Len(value) < 2) {
|
|
// How can a string (including "" be less than 2 characters?)
|
|
Clear(value);
|
|
Append(value, "?");
|
|
} else {
|
|
const char *v = Char(value);
|
|
if (v[0] != '"' || v[Len(value) - 1] != '"') {
|
|
Clear(value);
|
|
Append(value, "?");
|
|
}
|
|
// Strings containing "$" require special handling, but we do
|
|
// that later.
|
|
}
|
|
break;
|
|
case T_VOID:
|
|
assert(false);
|
|
break;
|
|
case T_POINTER: {
|
|
const char *v = Char(value);
|
|
if (v[0] == '(') {
|
|
// Handle "(void*)0", "(TYPE*)0", "(char*)NULL", etc.
|
|
v += strcspn(v + 1, "*()") + 1;
|
|
if (*v == '*') {
|
|
do {
|
|
v++;
|
|
v += strspn(v, " \t");
|
|
} while (*v == '*');
|
|
if (*v++ == ')') {
|
|
v += strspn(v, " \t");
|
|
String * old = value;
|
|
value = NewString(v);
|
|
Delete(old);
|
|
}
|
|
}
|
|
}
|
|
if (Strcmp(value, "NULL") == 0 ||
|
|
Strcmp(value, "0") == 0 ||
|
|
Strcmp(value, "0L") == 0) {
|
|
Clear(value);
|
|
Append(value, "null");
|
|
} else {
|
|
Clear(value);
|
|
Append(value, "?");
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!arg_values[argno]) {
|
|
arg_values[argno] = value;
|
|
value = NULL;
|
|
} else if (Cmp(arg_values[argno], value) != 0) {
|
|
// If a parameter has two different default values in
|
|
// different overloaded forms of the function, we can't
|
|
// set its default in PHP. Flag this by setting its
|
|
// default to `?'.
|
|
Delete(arg_values[argno]);
|
|
arg_values[argno] = NewString("?");
|
|
}
|
|
} else if (arg_values[argno]) {
|
|
// This argument already has a default value in another overloaded
|
|
// form, but doesn't in this form. So don't try to do anything
|
|
// clever, just let the C wrappers resolve the overload and set the
|
|
// default values.
|
|
//
|
|
// This handling is safe, but I'm wondering if it may be overly
|
|
// conservative (FIXME) in some cases. It seems it's only bad when
|
|
// there's an overloaded form with the appropriate number of
|
|
// parameters which doesn't want the default value, but I need to
|
|
// think about this more.
|
|
Delete(arg_values[argno]);
|
|
arg_values[argno] = NewString("?");
|
|
}
|
|
Delete(value);
|
|
p = nextSibling(p);
|
|
++argno;
|
|
}
|
|
if (!really_overloaded)
|
|
break;
|
|
o = Getattr(o, "sym:nextSibling");
|
|
}
|
|
|
|
/* Clean up any parameters which haven't yet got names, or whose
|
|
* names clash. */
|
|
Hash *seen = NewHash();
|
|
/* We need $this to refer to the current class, so can't allow it
|
|
* to be used as a parameter. */
|
|
Setattr(seen, "this", seen);
|
|
/* We use $r to store the return value, so disallow that as a parameter
|
|
* name in case the user uses the "call-time pass-by-reference" feature
|
|
* (it's deprecated and off by default in PHP5, but we want to be
|
|
* maximally portable). Similarly we use $c for the classname or new
|
|
* stdClass object.
|
|
*/
|
|
Setattr(seen, "r", seen);
|
|
Setattr(seen, "c", seen);
|
|
|
|
for (int argno = 0; argno < max_num_of_arguments; ++argno) {
|
|
String *&pname = arg_names[argno];
|
|
if (pname) {
|
|
Replaceall(pname, " ", "_");
|
|
} else {
|
|
/* We get here if the SWIG .i file has "int foo(int);" */
|
|
pname = NewStringEmpty();
|
|
Printf(pname, "arg%d", argno + 1);
|
|
}
|
|
// Check if we've already used this parameter name.
|
|
while (Getattr(seen, pname)) {
|
|
// Append "_" to clashing names until they stop clashing...
|
|
Printf(pname, "_");
|
|
}
|
|
Setattr(seen, Char(pname), seen);
|
|
|
|
if (arg_values[argno] && Cmp(arg_values[argno], "?") == 0) {
|
|
handle_as_overload = true;
|
|
}
|
|
}
|
|
Delete(seen);
|
|
seen = NULL;
|
|
|
|
String *invoke = NewStringEmpty();
|
|
String *prepare = NewStringEmpty();
|
|
String *args = NewStringEmpty();
|
|
|
|
if (!handle_as_overload && !(really_overloaded && max_num_of_arguments > min_num_of_arguments)) {
|
|
Printf(invoke, "%s(", iname);
|
|
if (wrapperType == memberfn) {
|
|
Printf(invoke, "$this->%s", SWIG_PTR);
|
|
}
|
|
for (int i = 0; i < max_num_of_arguments; ++i) {
|
|
if (i)
|
|
Printf(args, ",");
|
|
if (i || wrapperType == memberfn)
|
|
Printf(invoke, ",");
|
|
String *value = arg_values[i];
|
|
if (value) {
|
|
const char *v = Char(value);
|
|
if (v[0] == '"') {
|
|
/* In a PHP double quoted string, $ needs to be escaped as \$. */
|
|
Replaceall(value, "$", "\\$");
|
|
}
|
|
Printf(args, "$%s=%s", arg_names[i], value);
|
|
} else {
|
|
Printf(args, "$%s", arg_names[i]);
|
|
}
|
|
Printf(invoke, "$%s", arg_names[i]);
|
|
}
|
|
Printf(invoke, ")");
|
|
} else {
|
|
int i;
|
|
for (i = 0; i < min_num_of_arguments; ++i) {
|
|
if (i)
|
|
Printf(args, ",");
|
|
Printf(args, "$%s", arg_names[i]);
|
|
}
|
|
String *invoke_args = NewStringEmpty();
|
|
if (wrapperType == memberfn) {
|
|
Printf(invoke_args, "$this->%s", SWIG_PTR);
|
|
if (min_num_of_arguments > 0)
|
|
Printf(invoke_args, ",");
|
|
}
|
|
Printf(invoke_args, "%s", args);
|
|
bool had_a_case = false;
|
|
int last_handled_i = i - 1;
|
|
for (; i < max_num_of_arguments; ++i) {
|
|
if (i)
|
|
Printf(args, ",");
|
|
const char *value = Char(arg_values[i]);
|
|
// FIXME: (really_overloaded && handle_as_overload) is perhaps a
|
|
// little conservative, but it doesn't hit any cases that it
|
|
// shouldn't for Xapian at least (and we need it to handle
|
|
// "Enquire::get_mset()" correctly).
|
|
bool non_php_default = ((really_overloaded && handle_as_overload) ||
|
|
!value || strcmp(value, "?") == 0);
|
|
if (non_php_default)
|
|
value = "null";
|
|
Printf(args, "$%s=%s", arg_names[i], value);
|
|
if (non_php_default) {
|
|
if (!had_a_case) {
|
|
Printf(prepare, "\t\tswitch (func_num_args()) {\n");
|
|
had_a_case = true;
|
|
}
|
|
Printf(prepare, "\t\t");
|
|
while (last_handled_i < i) {
|
|
Printf(prepare, "case %d: ", ++last_handled_i);
|
|
}
|
|
if (Cmp(d, "void") != 0) {
|
|
if ((!directorsEnabled() || !Swig_directorclass(n)) && !newobject) {
|
|
Append(prepare, "$r=");
|
|
} else {
|
|
Printf(prepare, "$this->%s=", SWIG_PTR);
|
|
}
|
|
}
|
|
if (!directorsEnabled() || !Swig_directorclass(n) || !newobject) {
|
|
Printf(prepare, "%s(%s); break;\n", iname, invoke_args);
|
|
} else if (!i) {
|
|
Printf(prepare, "%s($_this%s); break;\n", iname, invoke_args);
|
|
} else {
|
|
Printf(prepare, "%s($_this, %s); break;\n", iname, invoke_args);
|
|
}
|
|
}
|
|
if (i || wrapperType == memberfn)
|
|
Printf(invoke_args, ",");
|
|
Printf(invoke_args, "$%s", arg_names[i]);
|
|
}
|
|
Printf(prepare, "\t\t");
|
|
if (had_a_case)
|
|
Printf(prepare, "default: ");
|
|
if (Cmp(d, "void") != 0) {
|
|
if ((!directorsEnabled() || !Swig_directorclass(n)) && !newobject) {
|
|
Append(prepare, "$r=");
|
|
} else {
|
|
Printf(prepare, "$this->%s=", SWIG_PTR);
|
|
}
|
|
}
|
|
|
|
if (!directorsEnabled() || !Swig_directorclass(n) || !newobject) {
|
|
Printf(prepare, "%s(%s);\n", iname, invoke_args);
|
|
} else {
|
|
Printf(prepare, "%s($_this, %s);\n", iname, invoke_args);
|
|
}
|
|
if (had_a_case)
|
|
Printf(prepare, "\t\t}\n");
|
|
Delete(invoke_args);
|
|
Printf(invoke, "$r");
|
|
}
|
|
|
|
Printf(output, "\n");
|
|
// If it's a member function or a class constructor...
|
|
if (wrapperType == memberfn || (constructor && current_class)) {
|
|
String *acc = NewString(Getattr(n, "access"));
|
|
// If a base has the same method with public access, then PHP
|
|
// requires to have it here as public as well
|
|
Node *bases = Getattr(Swig_methodclass(n), "bases");
|
|
if (bases && Strcmp(acc, "public") != 0) {
|
|
String *warnmsg = 0;
|
|
int haspublicbase = 0;
|
|
Iterator i = First(bases);
|
|
while (i.item) {
|
|
Node *j = firstChild(i.item);
|
|
while (j) {
|
|
if (Strcmp(Getattr(j, "name"), Getattr(n, "name")) != 0) {
|
|
j = nextSibling(j);
|
|
continue;
|
|
}
|
|
if (Strcmp(nodeType(j), "cdecl") == 0) {
|
|
if (!Getattr(j, "access") || checkAttribute(j, "access", "public")) {
|
|
haspublicbase = 1;
|
|
}
|
|
} else if (Strcmp(nodeType(j), "using") == 0 && firstChild(j) && Strcmp(nodeType(firstChild(j)), "cdecl") == 0) {
|
|
if (!Getattr(firstChild(j), "access") || checkAttribute(firstChild(j), "access", "public")) {
|
|
haspublicbase = 1;
|
|
}
|
|
}
|
|
if (haspublicbase) {
|
|
warnmsg = NewStringf("Modifying the access of '%s::%s' to public, as the base '%s' has it as public as well.\n", Getattr(current_class, "classtype"), Getattr(n, "name"), Getattr(i.item, "classtype"));
|
|
break;
|
|
}
|
|
j = nextSibling(j);
|
|
}
|
|
i = Next(i);
|
|
if (haspublicbase) {
|
|
break;
|
|
}
|
|
}
|
|
if (Getattr(n, "access") && haspublicbase) {
|
|
Delete(acc);
|
|
acc = NewString("public");
|
|
Swig_warning(WARN_PHP_PUBLIC_BASE, input_file, line_number, Char(warnmsg));
|
|
Delete(warnmsg);
|
|
}
|
|
}
|
|
if (Cmp(acc, "") != 0) {
|
|
Append(acc, " ");
|
|
}
|
|
if (constructor) {
|
|
const char * arg0;
|
|
if (max_num_of_arguments > 0) {
|
|
arg0 = Char(arg_names[0]);
|
|
} else {
|
|
arg0 = "res";
|
|
Delete(args);
|
|
args = NewString("$res=null");
|
|
}
|
|
SwigType *t = Getattr(current_class, "classtype");
|
|
String *mangled_type = SwigType_manglestr(SwigType_ltype(t));
|
|
Printf(output, "\t%sfunction %s(%s) {\n", acc, methodname, args);
|
|
Printf(output, "\t\tif (is_resource($%s) && get_resource_type($%s) === '_p%s') {\n", arg0, arg0, mangled_type);
|
|
Printf(output, "\t\t\t$this->%s=$%s;\n", SWIG_PTR, arg0);
|
|
Printf(output, "\t\t\treturn;\n");
|
|
Printf(output, "\t\t}\n");
|
|
} else {
|
|
Printf(output, "\t%sfunction %s(%s) {\n", acc, methodname, args);
|
|
}
|
|
Delete(acc);
|
|
} else if (wrapperType == staticmembervar) {
|
|
// We're called twice for a writable static member variable - first
|
|
// with "foo_set" and then with "foo_get" - so generate half the
|
|
// wrapper function each time.
|
|
//
|
|
// For a const static member, we only get called once.
|
|
static bool started = false;
|
|
if (!started) {
|
|
Printf(output, "\tstatic function %s() {\n", methodname);
|
|
if (max_num_of_arguments) {
|
|
// Setter.
|
|
Printf(output, "\t\tif (func_num_args()) {\n");
|
|
Printf(output, "\t\t\t%s(func_get_arg(0));\n", iname);
|
|
Printf(output, "\t\t\treturn;\n");
|
|
Printf(output, "\t\t}\n");
|
|
started = true;
|
|
goto done;
|
|
}
|
|
}
|
|
started = false;
|
|
} else {
|
|
Printf(output, "\tstatic function %s(%s) {\n", methodname, args);
|
|
}
|
|
|
|
if (!newobject)
|
|
Printf(output, "%s", prepare);
|
|
if (constructor) {
|
|
if (!directorsEnabled() || !Swig_directorclass(n)) {
|
|
if (strcmp(methodname, "__construct") == 0) {
|
|
Printf(output, "\t\t$this->%s=%s;\n", SWIG_PTR, invoke);
|
|
} else {
|
|
String *classname = Swig_class_name(current_class);
|
|
Printf(output, "\t\treturn new %s(%s);\n", classname, invoke);
|
|
}
|
|
} else {
|
|
Node *parent = Swig_methodclass(n);
|
|
String *classname = Swig_class_name(parent);
|
|
Printf(output, "\t\tif (get_class($this) === '%s%s') {\n", prefix, classname);
|
|
Printf(output, "\t\t\t$_this = null;\n");
|
|
Printf(output, "\t\t} else {\n");
|
|
Printf(output, "\t\t\t$_this = $this;\n");
|
|
Printf(output, "\t\t}\n");
|
|
if (!Len(prepare)) {
|
|
if (num_arguments > 1) {
|
|
Printf(output, "\t\t$this->%s=%s($_this, %s);\n", SWIG_PTR, iname, args);
|
|
} else {
|
|
Printf(output, "\t\t$this->%s=%s($_this);\n", SWIG_PTR, iname);
|
|
}
|
|
}
|
|
}
|
|
Printf(output, "%s", prepare);
|
|
} else if (Cmp(d, "void") == 0) {
|
|
if (Cmp(invoke, "$r") != 0)
|
|
Printf(output, "\t\t%s;\n", invoke);
|
|
} else if (is_class(d)) {
|
|
if (Cmp(invoke, "$r") != 0)
|
|
Printf(output, "\t\t$r=%s;\n", invoke);
|
|
if (Len(ret_types) == 1) {
|
|
/* If it has an abstract base, then we can't create a new
|
|
* base object. */
|
|
int hasabstractbase = 0;
|
|
Node *bases = Getattr(Swig_methodclass(n), "bases");
|
|
if (bases) {
|
|
Iterator i = First(bases);
|
|
while(i.item) {
|
|
if (Getattr(i.item, "abstract")) {
|
|
hasabstractbase = 1;
|
|
break;
|
|
}
|
|
i = Next(i);
|
|
}
|
|
}
|
|
if (newobject || !hasabstractbase) {
|
|
/*
|
|
* _p_Foo -> Foo, _p_ns__Bar -> Bar
|
|
* TODO: do this in a more elegant way
|
|
*/
|
|
Printf(output, "\t\tif (is_resource($r)) {\n");
|
|
if (Getattr(classLookup(Getattr(n, "type")), "module")) {
|
|
if (Len(prefix) == 0) {
|
|
Printf(output, "\t\t\t$c=substr(get_resource_type($r), (strpos(get_resource_type($r), '__') ? strpos(get_resource_type($r), '__') + 2 : 3));\n");
|
|
} else {
|
|
Printf(output, "\t\t\t$c='%s'.substr(get_resource_type($r), (strpos(get_resource_type($r), '__') ? strpos(get_resource_type($r), '__') + 2 : 3));\n", prefix);
|
|
}
|
|
Printf(output, "\t\t\tif (!class_exists($c)) {\n");
|
|
Printf(output, "\t\t\t\treturn new %s%s($r);\n", prefix, Getattr(classLookup(d), "sym:name"));
|
|
Printf(output, "\t\t\t}\n");
|
|
Printf(output, "\t\t\treturn new $c($r);\n");
|
|
} else {
|
|
Printf(output, "\t\t\t$c = new stdClass();\n");
|
|
Printf(output, "\t\t\t$c->_cPtr = $r;\n");
|
|
Printf(output, "\t\t\treturn $c;\n");
|
|
}
|
|
Printf(output, "\t\t}\n\t\treturn $r;\n");
|
|
} else {
|
|
Printf(output, "\t\t$this->%s = $r;\n", SWIG_PTR);
|
|
Printf(output, "\t\treturn $this;\n");
|
|
}
|
|
} else {
|
|
Printf(output, "\t\tif (!is_resource($r)) return $r;\n");
|
|
Printf(output, "\t\tswitch (get_resource_type($r)) {\n");
|
|
Iterator i = First(ret_types);
|
|
while (i.item) {
|
|
SwigType *ret_type = i.item;
|
|
i = Next(i);
|
|
Printf(output, "\t\t");
|
|
String *mangled = NewString("_p");
|
|
Printf(mangled, "%s", SwigType_manglestr(ret_type));
|
|
Node *class_node = Getattr(zend_types, mangled);
|
|
if (!class_node) {
|
|
/* This is needed when we're returning a pointer to a type
|
|
* rather than returning the type by value or reference. */
|
|
class_node = current_class;
|
|
Delete(mangled);
|
|
mangled = NewString(SwigType_manglestr(ret_type));
|
|
class_node = Getattr(zend_types, mangled);
|
|
}
|
|
if (i.item) {
|
|
Printf(output, "case '%s': ", mangled);
|
|
} else {
|
|
Printf(output, "default: ");
|
|
}
|
|
const char *classname = GetChar(class_node, "sym:name");
|
|
if (!classname)
|
|
classname = GetChar(class_node, "name");
|
|
if (classname)
|
|
Printf(output, "return new %s%s($r);\n", prefix, classname);
|
|
else
|
|
Printf(output, "return $r;\n");
|
|
Delete(mangled);
|
|
}
|
|
Printf(output, "\t\t}\n");
|
|
}
|
|
} else {
|
|
Printf(output, "\t\treturn %s;\n", invoke);
|
|
}
|
|
Printf(output, "\t}\n");
|
|
|
|
done:
|
|
Delete(prepare);
|
|
Delete(invoke);
|
|
free(arg_values);
|
|
|
|
Delete(args);
|
|
args = NULL;
|
|
|
|
for (int i = 0; i < max_num_of_arguments; ++i) {
|
|
Delete(arg_names[i]);
|
|
}
|
|
free(arg_names);
|
|
arg_names = NULL;
|
|
}
|
|
|
|
return SWIG_OK;
|
|
}
|
|
|
|
/* ------------------------------------------------------------
|
|
* globalvariableHandler()
|
|
* ------------------------------------------------------------ */
|
|
|
|
virtual int globalvariableHandler(Node *n) {
|
|
char *name = GetChar(n, "name");
|
|
char *iname = GetChar(n, "sym:name");
|
|
SwigType *t = Getattr(n, "type");
|
|
String *tm;
|
|
|
|
/* First do the wrappers such as name_set(), name_get()
|
|
* as provided by the baseclass's implementation of variableWrapper
|
|
*/
|
|
if (Language::globalvariableHandler(n) == SWIG_NOWRAP) {
|
|
return SWIG_NOWRAP;
|
|
}
|
|
|
|
if (!addSymbol(iname, n))
|
|
return SWIG_ERROR;
|
|
|
|
SwigType_remember(t);
|
|
|
|
/* First link C variables to PHP */
|
|
|
|
tm = Swig_typemap_lookup("varinit", n, name, 0);
|
|
if (tm) {
|
|
Replaceall(tm, "$target", name);
|
|
Printf(s_vinit, "%s\n", tm);
|
|
} else {
|
|
Printf(stderr, "%s: Line %d, Unable to link with type %s\n", input_file, line_number, SwigType_str(t, 0));
|
|
}
|
|
|
|
/* Now generate PHP -> C sync blocks */
|
|
/*
|
|
tm = Swig_typemap_lookup("varin", n, name, 0);
|
|
if(tm) {
|
|
Replaceall(tm, "$symname", iname);
|
|
Printf(f_c->code, "%s\n", tm);
|
|
} else {
|
|
Printf(stderr,"%s: Line %d, Unable to link with type %s\n", input_file, line_number, SwigType_str(t, 0));
|
|
}
|
|
*/
|
|
/* Now generate C -> PHP sync blocks */
|
|
/*
|
|
if(!GetFlag(n,"feature:immutable")) {
|
|
|
|
tm = Swig_typemap_lookup("varout", n, name, 0);
|
|
if(tm) {
|
|
Replaceall(tm, "$symname", iname);
|
|
Printf(f_php->code, "%s\n", tm);
|
|
} else {
|
|
Printf(stderr,"%s: Line %d, Unable to link with type %s\n", input_file, line_number, SwigType_str(t, 0));
|
|
}
|
|
}
|
|
*/
|
|
return SWIG_OK;
|
|
}
|
|
|
|
/* ------------------------------------------------------------
|
|
* constantWrapper()
|
|
* ------------------------------------------------------------ */
|
|
|
|
virtual int constantWrapper(Node *n) {
|
|
String *name = GetChar(n, "name");
|
|
String *iname = GetChar(n, "sym:name");
|
|
SwigType *type = Getattr(n, "type");
|
|
String *rawval = Getattr(n, "rawval");
|
|
String *value = rawval ? rawval : Getattr(n, "value");
|
|
String *tm;
|
|
|
|
if (!addSymbol(iname, n))
|
|
return SWIG_ERROR;
|
|
|
|
SwigType_remember(type);
|
|
|
|
if ((tm = Swig_typemap_lookup("consttab", n, name, 0))) {
|
|
Replaceall(tm, "$source", value);
|
|
Replaceall(tm, "$target", name);
|
|
Replaceall(tm, "$value", value);
|
|
Printf(s_cinit, "%s\n", tm);
|
|
}
|
|
|
|
if (shadow) {
|
|
String *enumvalue = GetChar(n, "enumvalue");
|
|
String *set_to = iname;
|
|
|
|
if (!enumvalue) {
|
|
enumvalue = GetChar(n, "enumvalueex");
|
|
}
|
|
|
|
if (enumvalue) {
|
|
// Check for a simple constant expression which is valid in PHP.
|
|
// If we find one, initialise the const member with it; otherwise
|
|
// we initialise it using the C/C++ wrapped constant.
|
|
const char *p;
|
|
for (p = Char(enumvalue); *p; ++p) {
|
|
if (!isdigit((unsigned char)*p) && !strchr(" +-", *p)) {
|
|
// FIXME: enhance to handle `<previous_enum> + 1' which is what
|
|
// we get for enums that don't have an explicit value set.
|
|
break;
|
|
}
|
|
}
|
|
if (!*p) set_to = enumvalue;
|
|
}
|
|
|
|
if (wrapping_member_constant) {
|
|
if (!s_oowrappers)
|
|
s_oowrappers = NewStringEmpty();
|
|
Printf(s_oowrappers, "\n\tconst %s = %s;\n", wrapping_member_constant, set_to);
|
|
} else {
|
|
if (!s_fakeoowrappers)
|
|
s_fakeoowrappers = NewStringEmpty();
|
|
Printf(s_fakeoowrappers, "\n\tconst %s = %s;\n", iname, set_to);
|
|
}
|
|
}
|
|
|
|
return SWIG_OK;
|
|
}
|
|
|
|
/*
|
|
* PHP::pragma()
|
|
*
|
|
* Pragma directive.
|
|
*
|
|
* %pragma(php) code="String" # Includes a string in the .php file
|
|
* %pragma(php) include="file.php" # Includes a file in the .php file
|
|
*/
|
|
|
|
virtual int pragmaDirective(Node *n) {
|
|
if (!ImportMode) {
|
|
String *lang = Getattr(n, "lang");
|
|
String *type = Getattr(n, "name");
|
|
String *value = Getattr(n, "value");
|
|
|
|
if (Strcmp(lang, "php") == 0 || Strcmp(lang, "php4") == 0) {
|
|
if (Strcmp(type, "code") == 0) {
|
|
if (value) {
|
|
Printf(pragma_code, "%s\n", value);
|
|
}
|
|
} else if (Strcmp(type, "include") == 0) {
|
|
if (value) {
|
|
Printf(pragma_incl, "include '%s';\n", value);
|
|
}
|
|
} else if (Strcmp(type, "phpinfo") == 0) {
|
|
if (value) {
|
|
Printf(pragma_phpinfo, "%s\n", value);
|
|
}
|
|
} else {
|
|
Swig_warning(WARN_PHP_UNKNOWN_PRAGMA, input_file, line_number, "Unrecognized pragma <%s>.\n", type);
|
|
}
|
|
}
|
|
}
|
|
return Language::pragmaDirective(n);
|
|
}
|
|
|
|
/* ------------------------------------------------------------
|
|
* classDeclaration()
|
|
* ------------------------------------------------------------ */
|
|
|
|
virtual int classDeclaration(Node *n) {
|
|
if (!Getattr(n, "feature:onlychildren")) {
|
|
String *symname = Getattr(n, "sym:name");
|
|
Setattr(n, "php:proxy", symname);
|
|
}
|
|
|
|
return Language::classDeclaration(n);
|
|
}
|
|
|
|
/* ------------------------------------------------------------
|
|
* classHandler()
|
|
* ------------------------------------------------------------ */
|
|
|
|
virtual int classHandler(Node *n) {
|
|
constructors = 0;
|
|
current_class = n;
|
|
|
|
if (shadow) {
|
|
char *rename = GetChar(n, "sym:name");
|
|
|
|
if (!addSymbol(rename, n))
|
|
return SWIG_ERROR;
|
|
shadow_classname = NewString(rename);
|
|
|
|
shadow_get_vars = NewHash();
|
|
shadow_set_vars = NewHash();
|
|
|
|
/* Deal with inheritance */
|
|
List *baselist = Getattr(n, "bases");
|
|
if (baselist) {
|
|
Iterator base = First(baselist);
|
|
while (base.item && GetFlag(base.item, "feature:ignore")) {
|
|
base = Next(base);
|
|
}
|
|
base = Next(base);
|
|
if (base.item) {
|
|
/* Warn about multiple inheritance for additional base class(es) */
|
|
while (base.item) {
|
|
if (GetFlag(base.item, "feature:ignore")) {
|
|
base = Next(base);
|
|
continue;
|
|
}
|
|
String *proxyclassname = SwigType_str(Getattr(n, "classtypeobj"), 0);
|
|
String *baseclassname = SwigType_str(Getattr(base.item, "name"), 0);
|
|
Swig_warning(WARN_PHP_MULTIPLE_INHERITANCE, input_file, line_number,
|
|
"Warning for %s proxy: Base %s ignored. Multiple inheritance is not supported in PHP.\n", proxyclassname, baseclassname);
|
|
base = Next(base);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
classnode = n;
|
|
Language::classHandler(n);
|
|
classnode = 0;
|
|
|
|
if (shadow) {
|
|
DOH *key;
|
|
List *baselist = Getattr(n, "bases");
|
|
Iterator ki, base;
|
|
|
|
if (baselist) {
|
|
base = First(baselist);
|
|
while (base.item && GetFlag(base.item, "feature:ignore")) {
|
|
base = Next(base);
|
|
}
|
|
} else {
|
|
base.item = NULL;
|
|
}
|
|
|
|
if (Getattr(n, "abstract") && !GetFlag(n, "feature:notabstract")) {
|
|
Printf(s_phpclasses, "abstract ");
|
|
}
|
|
|
|
Printf(s_phpclasses, "class %s%s ", prefix, shadow_classname);
|
|
String *baseclass = NULL;
|
|
if (base.item && Getattr(base.item, "module")) {
|
|
baseclass = Getattr(base.item, "sym:name");
|
|
if (!baseclass)
|
|
baseclass = Getattr(base.item, "name");
|
|
Printf(s_phpclasses, "extends %s%s ", prefix, baseclass);
|
|
} else if (GetFlag(n, "feature:exceptionclass")) {
|
|
Append(s_phpclasses, "extends Exception ");
|
|
}
|
|
Printf(s_phpclasses, "{\n\tpublic $%s=null;\n", SWIG_PTR);
|
|
if (!baseclass) {
|
|
// Only store this in the base class (NB !baseclass means we *are*
|
|
// a base class...)
|
|
Printf(s_phpclasses, "\tprotected $%s=array();\n", SWIG_DATA);
|
|
}
|
|
|
|
// Write property SET handlers
|
|
ki = First(shadow_set_vars);
|
|
|
|
if (ki.key) {
|
|
// This class has setters.
|
|
Printf(s_phpclasses, "\n\tfunction __set($var,$value) {\n");
|
|
// FIXME: tune this threshold...
|
|
if (Len(shadow_set_vars) <= 2) {
|
|
// Not many setters, so avoid call_user_func.
|
|
while (ki.key) {
|
|
key = ki.key;
|
|
Printf(s_phpclasses, "\t\tif ($var === '%s') return %s($this->%s,$value);\n", key, ki.item, SWIG_PTR);
|
|
ki = Next(ki);
|
|
}
|
|
} else {
|
|
Printf(s_phpclasses, "\t\t$func = '%s_'.$var.'_set';\n", shadow_classname);
|
|
Printf(s_phpclasses, "\t\tif (function_exists($func)) return call_user_func($func,$this->%s,$value);\n", SWIG_PTR);
|
|
}
|
|
Printf(s_phpclasses, "\t\tif ($var === 'thisown') return swig_%s_alter_newobject($this->%s,$value);\n", module, SWIG_PTR);
|
|
if (baseclass) {
|
|
Printf(s_phpclasses, "\t\t%s%s::__set($var,$value);\n", prefix, baseclass);
|
|
} else {
|
|
Printf(s_phpclasses, "\t\t$this->%s[$var] = $value;\n", SWIG_DATA);
|
|
}
|
|
Printf(s_phpclasses, "\t}\n");
|
|
|
|
/* Create __isset for PHP 5.1 and later; PHP 5.0 will just ignore it. */
|
|
Printf(s_phpclasses, "\n\tfunction __isset($var) {\n");
|
|
Printf(s_phpclasses, "\t\tif (function_exists('%s_'.$var.'_set')) return true;\n", shadow_classname);
|
|
Printf(s_phpclasses, "\t\tif ($var === 'thisown') return true;\n");
|
|
if (baseclass) {
|
|
Printf(s_phpclasses, "\t\treturn %s%s::__isset($var);\n", prefix, baseclass);
|
|
} else {
|
|
Printf(s_phpclasses, "\t\treturn array_key_exists($var, $this->%s);\n", SWIG_DATA);
|
|
}
|
|
Printf(s_phpclasses, "\t}\n");
|
|
} else {
|
|
Printf(s_phpclasses, "\n\tfunction __set($var,$value) {\n");
|
|
Printf(s_phpclasses, "\t\tif ($var === 'thisown') return swig_%s_alter_newobject($this->%s,$value);\n", module, SWIG_PTR);
|
|
if (baseclass) {
|
|
Printf(s_phpclasses, "\t\t%s%s::__set($var,$value);\n", prefix, baseclass);
|
|
} else {
|
|
Printf(s_phpclasses, "\t\t$this->%s[$var] = $value;\n", SWIG_DATA);
|
|
}
|
|
Printf(s_phpclasses, "\t}\n");
|
|
Printf(s_phpclasses, "\n\tfunction __isset($var) {\n");
|
|
Printf(s_phpclasses, "\t\tif ($var === 'thisown') return true;\n");
|
|
if (baseclass) {
|
|
Printf(s_phpclasses, "\t\treturn %s%s::__isset($var);\n", prefix, baseclass);
|
|
} else {
|
|
Printf(s_phpclasses, "\t\treturn array_key_exists($var, $this->%s);\n", SWIG_DATA);
|
|
}
|
|
Printf(s_phpclasses, "\t}\n");
|
|
}
|
|
// Write property GET handlers
|
|
ki = First(shadow_get_vars);
|
|
|
|
if (ki.key) {
|
|
// This class has getters.
|
|
Printf(s_phpclasses, "\n\tfunction __get($var) {\n");
|
|
// FIXME: Currently we always use call_user_func for __get, so we can
|
|
// check and wrap the result. This is needless if all the properties
|
|
// are primitive types. Also this doesn't handle all the cases which
|
|
// a method returning an object does.
|
|
Printf(s_phpclasses, "\t\t$func = '%s_'.$var.'_get';\n", shadow_classname);
|
|
Printf(s_phpclasses, "\t\tif (function_exists($func)) {\n");
|
|
Printf(s_phpclasses, "\t\t\t$r = call_user_func($func,$this->%s);\n", SWIG_PTR);
|
|
Printf(s_phpclasses, "\t\t\tif (!is_resource($r)) return $r;\n");
|
|
if (Len(prefix) == 0) {
|
|
Printf(s_phpclasses, "\t\t\t$c=substr(get_resource_type($r), (strpos(get_resource_type($r), '__') ? strpos(get_resource_type($r), '__') + 2 : 3));\n");
|
|
} else {
|
|
Printf(s_phpclasses, "\t\t\t$c='%s'.substr(get_resource_type($r), (strpos(get_resource_type($r), '__') ? strpos(get_resource_type($r), '__') + 2 : 3));\n", prefix);
|
|
}
|
|
Printf(s_phpclasses, "\t\t\treturn new $c($r);\n");
|
|
Printf(s_phpclasses, "\t\t}\n");
|
|
Printf(s_phpclasses, "\t\tif ($var === 'thisown') return swig_%s_get_newobject($this->%s);\n", module, SWIG_PTR);
|
|
if (baseclass) {
|
|
Printf(s_phpclasses, "\t\treturn %s%s::__get($var);\n", prefix, baseclass);
|
|
} else {
|
|
// Reading an unknown property name gives null in PHP.
|
|
Printf(s_phpclasses, "\t\treturn $this->%s[$var];\n", SWIG_DATA);
|
|
}
|
|
Printf(s_phpclasses, "\t}\n");
|
|
} else {
|
|
Printf(s_phpclasses, "\n\tfunction __get($var) {\n");
|
|
Printf(s_phpclasses, "\t\tif ($var === 'thisown') return swig_%s_get_newobject($this->%s);\n", module, SWIG_PTR);
|
|
if (baseclass) {
|
|
Printf(s_phpclasses, "\t\treturn %s%s::__get($var);\n", prefix, baseclass);
|
|
} else {
|
|
Printf(s_phpclasses, "\t\treturn $this->%s[$var];\n", SWIG_DATA);
|
|
}
|
|
Printf(s_phpclasses, "\t}\n");
|
|
}
|
|
|
|
if (!class_has_ctor) {
|
|
Printf(s_phpclasses, "\tfunction __construct($h) {\n");
|
|
Printf(s_phpclasses, "\t\t$this->%s=$h;\n", SWIG_PTR);
|
|
Printf(s_phpclasses, "\t}\n");
|
|
}
|
|
|
|
if (s_oowrappers) {
|
|
Printf(s_phpclasses, "%s", s_oowrappers);
|
|
Delete(s_oowrappers);
|
|
s_oowrappers = NULL;
|
|
}
|
|
class_has_ctor = false;
|
|
|
|
Printf(s_phpclasses, "}\n\n");
|
|
|
|
Delete(shadow_classname);
|
|
shadow_classname = NULL;
|
|
|
|
Delete(shadow_set_vars);
|
|
shadow_set_vars = NULL;
|
|
Delete(shadow_get_vars);
|
|
shadow_get_vars = NULL;
|
|
}
|
|
return SWIG_OK;
|
|
}
|
|
|
|
/* ------------------------------------------------------------
|
|
* memberfunctionHandler()
|
|
* ------------------------------------------------------------ */
|
|
|
|
virtual int memberfunctionHandler(Node *n) {
|
|
wrapperType = memberfn;
|
|
Language::memberfunctionHandler(n);
|
|
wrapperType = standard;
|
|
|
|
return SWIG_OK;
|
|
}
|
|
|
|
/* ------------------------------------------------------------
|
|
* membervariableHandler()
|
|
* ------------------------------------------------------------ */
|
|
|
|
virtual int membervariableHandler(Node *n) {
|
|
wrapperType = membervar;
|
|
Language::membervariableHandler(n);
|
|
wrapperType = standard;
|
|
|
|
return SWIG_OK;
|
|
}
|
|
|
|
/* ------------------------------------------------------------
|
|
* staticmembervariableHandler()
|
|
* ------------------------------------------------------------ */
|
|
|
|
virtual int staticmembervariableHandler(Node *n) {
|
|
wrapperType = staticmembervar;
|
|
Language::staticmembervariableHandler(n);
|
|
wrapperType = standard;
|
|
|
|
return SWIG_OK;
|
|
}
|
|
|
|
/* ------------------------------------------------------------
|
|
* staticmemberfunctionHandler()
|
|
* ------------------------------------------------------------ */
|
|
|
|
virtual int staticmemberfunctionHandler(Node *n) {
|
|
wrapperType = staticmemberfn;
|
|
Language::staticmemberfunctionHandler(n);
|
|
wrapperType = standard;
|
|
|
|
return SWIG_OK;
|
|
}
|
|
|
|
int abstractConstructorHandler(Node *) {
|
|
return SWIG_OK;
|
|
}
|
|
|
|
/* ------------------------------------------------------------
|
|
* constructorHandler()
|
|
* ------------------------------------------------------------ */
|
|
|
|
virtual int constructorHandler(Node *n) {
|
|
constructors++;
|
|
if (Swig_directorclass(n)) {
|
|
String *name = GetChar(Swig_methodclass(n), "name");
|
|
String *ctype = GetChar(Swig_methodclass(n), "classtype");
|
|
String *sname = GetChar(Swig_methodclass(n), "sym:name");
|
|
String *args = NewStringEmpty();
|
|
ParmList *p = Getattr(n, "parms");
|
|
int i;
|
|
|
|
for (i = 0; p; p = nextSibling(p), i++) {
|
|
if (i) {
|
|
Printf(args, ", ");
|
|
}
|
|
if (Strcmp(GetChar(p, "type"), SwigType_str(GetChar(p, "type"), 0))) {
|
|
SwigType *t = Getattr(p, "type");
|
|
Printf(args, "%s", SwigType_rcaststr(t, 0));
|
|
if (SwigType_isreference(t)) {
|
|
Append(args, "*");
|
|
}
|
|
}
|
|
Printf(args, "arg%d", i+1);
|
|
}
|
|
|
|
/* director ctor code is specific for each class */
|
|
Delete(director_ctor_code);
|
|
director_ctor_code = NewStringEmpty();
|
|
director_prot_ctor_code = NewStringEmpty();
|
|
Printf(director_ctor_code, "if ( arg0->type == IS_NULL ) { /* not subclassed */\n");
|
|
Printf(director_prot_ctor_code, "if ( arg0->type == IS_NULL ) { /* not subclassed */\n");
|
|
Printf(director_ctor_code, " result = (%s *)new %s(%s);\n", ctype, ctype, args);
|
|
Printf(director_prot_ctor_code, " SWIG_PHP_Error(E_ERROR, \"accessing abstract class or protected constructor\");\n", name, name, args);
|
|
if (i) {
|
|
Insert(args, 0, ", ");
|
|
}
|
|
Printf(director_ctor_code, "} else {\n result = (%s *)new SwigDirector_%s(arg0%s);\n}\n", ctype, sname, args);
|
|
Printf(director_prot_ctor_code, "} else {\n result = (%s *)new SwigDirector_%s(arg0%s);\n}\n", ctype, sname, args);
|
|
Delete(args);
|
|
|
|
wrapperType = directorconstructor;
|
|
} else {
|
|
wrapperType = constructor;
|
|
}
|
|
Language::constructorHandler(n);
|
|
wrapperType = standard;
|
|
|
|
return SWIG_OK;
|
|
}
|
|
|
|
/* ------------------------------------------------------------
|
|
* CreateZendListDestructor()
|
|
* ------------------------------------------------------------ */
|
|
//virtual int destructorHandler(Node *n) {
|
|
//}
|
|
int CreateZendListDestructor(Node *n) {
|
|
String *name = GetChar(Swig_methodclass(n), "name");
|
|
String *iname = GetChar(n, "sym:name");
|
|
ParmList *l = Getattr(n, "parms");
|
|
|
|
String *destructorname = NewStringEmpty();
|
|
Printf(destructorname, "_%s", Swig_name_wrapper(iname));
|
|
Setattr(classnode, "destructor", destructorname);
|
|
|
|
Wrapper *f = NewWrapper();
|
|
Printf(f->def, "/* This function is designed to be called by the zend list destructors */\n");
|
|
Printf(f->def, "/* to typecast and do the actual destruction */\n");
|
|
Printf(f->def, "static void %s(zend_rsrc_list_entry *rsrc, const char *type_name TSRMLS_DC) {\n", destructorname);
|
|
|
|
Wrapper_add_localv(f, "value", "swig_object_wrapper *value=(swig_object_wrapper *) rsrc->ptr", NIL);
|
|
Wrapper_add_localv(f, "ptr", "void *ptr=value->ptr", NIL);
|
|
Wrapper_add_localv(f, "newobject", "int newobject=value->newobject", NIL);
|
|
|
|
emit_parameter_variables(l, f);
|
|
emit_attach_parmmaps(l, f);
|
|
|
|
// Get type of first arg, thing to be destructed
|
|
// Skip ignored arguments
|
|
Parm *p = l;
|
|
//while (Getattr(p,"tmap:ignore")) {p = Getattr(p,"tmap:ignore:next");}
|
|
while (checkAttribute(p, "tmap:in:numinputs", "0")) {
|
|
p = Getattr(p, "tmap:in:next");
|
|
}
|
|
SwigType *pt = Getattr(p, "type");
|
|
|
|
Printf(f->code, " efree(value);\n");
|
|
Printf(f->code, " if (! newobject) return; /* can't delete it! */\n");
|
|
Printf(f->code, " arg1 = (%s)SWIG_ZTS_ConvertResourceData(ptr,type_name,SWIGTYPE%s TSRMLS_CC);\n", SwigType_lstr(pt, 0), SwigType_manglestr(pt));
|
|
Printf(f->code, " if (! arg1) zend_error(E_ERROR, \"%s resource already free'd\");\n", Char(name));
|
|
|
|
Setattr(n, "wrap:name", destructorname);
|
|
|
|
String *actioncode = emit_action(n);
|
|
Append(f->code, actioncode);
|
|
Delete(actioncode);
|
|
|
|
Append(f->code, "return;\n");
|
|
Append(f->code, "fail:\n");
|
|
Append(f->code, "zend_error_noreturn(SWIG_ErrorCode(),\"%s\",SWIG_ErrorMsg());\n");
|
|
Printf(f->code, "}\n");
|
|
|
|
Wrapper_print(f, s_wrappers);
|
|
|
|
return SWIG_OK;
|
|
}
|
|
|
|
/* ------------------------------------------------------------
|
|
* memberconstantHandler()
|
|
* ------------------------------------------------------------ */
|
|
|
|
virtual int memberconstantHandler(Node *n) {
|
|
wrapping_member_constant = Getattr(n, "sym:name");
|
|
Language::memberconstantHandler(n);
|
|
wrapping_member_constant = NULL;
|
|
return SWIG_OK;
|
|
}
|
|
|
|
int classDirectorInit(Node *n) {
|
|
String *declaration = Swig_director_declaration(n);
|
|
Printf(f_directors_h, "%s\n", declaration);
|
|
Printf(f_directors_h, "public:\n");
|
|
Delete(declaration);
|
|
return Language::classDirectorInit(n);
|
|
}
|
|
|
|
int classDirectorEnd(Node *n) {
|
|
Printf(f_directors_h, "};\n");
|
|
return Language::classDirectorEnd(n);
|
|
}
|
|
|
|
int classDirectorConstructor(Node *n) {
|
|
Node *parent = Getattr(n, "parentNode");
|
|
String *decl = Getattr(n, "decl");
|
|
String *supername = Swig_class_name(parent);
|
|
String *classname = NewStringEmpty();
|
|
Printf(classname, "SwigDirector_%s", supername);
|
|
|
|
/* insert self parameter */
|
|
Parm *p;
|
|
ParmList *superparms = Getattr(n, "parms");
|
|
ParmList *parms = CopyParmList(superparms);
|
|
String *type = NewString("zval");
|
|
SwigType_add_pointer(type);
|
|
p = NewParm(type, NewString("self"), n);
|
|
set_nextSibling(p, parms);
|
|
parms = p;
|
|
|
|
if (!Getattr(n, "defaultargs")) {
|
|
/* constructor */
|
|
{
|
|
Wrapper *w = NewWrapper();
|
|
String *call;
|
|
String *basetype = Getattr(parent, "classtype");
|
|
String *target = Swig_method_decl(0, decl, classname, parms, 0, 0);
|
|
call = Swig_csuperclass_call(0, basetype, superparms);
|
|
Printf(w->def, "%s::%s: %s, Swig::Director(self) {", classname, target, call);
|
|
Append(w->def, "}");
|
|
Delete(target);
|
|
Wrapper_print(w, f_directors);
|
|
Delete(call);
|
|
DelWrapper(w);
|
|
}
|
|
|
|
/* constructor header */
|
|
{
|
|
String *target = Swig_method_decl(0, decl, classname, parms, 0, 1);
|
|
Printf(f_directors_h, " %s;\n", target);
|
|
Delete(target);
|
|
}
|
|
}
|
|
return Language::classDirectorConstructor(n);
|
|
}
|
|
|
|
int classDirectorMethod(Node *n, Node *parent, String *super) {
|
|
int is_void = 0;
|
|
int is_pointer = 0;
|
|
String *decl;
|
|
String *type;
|
|
String *name;
|
|
String *classname;
|
|
String *c_classname = Getattr(parent, "name");
|
|
String *declaration;
|
|
ParmList *l;
|
|
Wrapper *w;
|
|
String *tm;
|
|
String *wrap_args = NewStringEmpty();
|
|
String *return_type;
|
|
String *value = Getattr(n, "value");
|
|
String *storage = Getattr(n, "storage");
|
|
bool pure_virtual = false;
|
|
int status = SWIG_OK;
|
|
int idx;
|
|
bool ignored_method = GetFlag(n, "feature:ignore") ? true : false;
|
|
|
|
if (Cmp(storage, "virtual") == 0) {
|
|
if (Cmp(value, "0") == 0) {
|
|
pure_virtual = true;
|
|
}
|
|
}
|
|
|
|
classname = Getattr(parent, "sym:name");
|
|
type = Getattr(n, "type");
|
|
name = Getattr(n, "name");
|
|
|
|
w = NewWrapper();
|
|
declaration = NewStringEmpty();
|
|
|
|
/* determine if the method returns a pointer */
|
|
decl = Getattr(n, "decl");
|
|
is_pointer = SwigType_ispointer_return(decl);
|
|
is_void = (Cmp(type, "void") == 0 && !is_pointer);
|
|
|
|
/* form complete return type */
|
|
return_type = Copy(type);
|
|
{
|
|
SwigType *t = Copy(decl);
|
|
SwigType *f = SwigType_pop_function(t);
|
|
SwigType_push(return_type, t);
|
|
Delete(f);
|
|
Delete(t);
|
|
}
|
|
|
|
/* virtual method definition */
|
|
l = Getattr(n, "parms");
|
|
String *target;
|
|
String *pclassname = NewStringf("SwigDirector_%s", classname);
|
|
String *qualified_name = NewStringf("%s::%s", pclassname, name);
|
|
SwigType *rtype = Getattr(n, "conversion_operator") ? 0 : type;
|
|
target = Swig_method_decl(rtype, decl, qualified_name, l, 0, 0);
|
|
Printf(w->def, "%s", target);
|
|
Delete(qualified_name);
|
|
Delete(target);
|
|
/* header declaration */
|
|
target = Swig_method_decl(rtype, decl, name, l, 0, 1);
|
|
Printf(declaration, " virtual %s", target);
|
|
Delete(target);
|
|
|
|
// Get any exception classes in the throws typemap
|
|
ParmList *throw_parm_list = 0;
|
|
|
|
if ((throw_parm_list = Getattr(n, "throws")) || Getattr(n, "throw")) {
|
|
Parm *p;
|
|
int gencomma = 0;
|
|
|
|
Append(w->def, " throw(");
|
|
Append(declaration, " throw(");
|
|
|
|
if (throw_parm_list)
|
|
Swig_typemap_attach_parms("throws", throw_parm_list, 0);
|
|
for (p = throw_parm_list; p; p = nextSibling(p)) {
|
|
if ((tm = Getattr(p, "tmap:throws"))) {
|
|
if (gencomma++) {
|
|
Append(w->def, ", ");
|
|
Append(declaration, ", ");
|
|
}
|
|
String *str = SwigType_str(Getattr(p, "type"), 0);
|
|
Append(w->def, str);
|
|
Append(declaration, str);
|
|
Delete(str);
|
|
}
|
|
}
|
|
|
|
Append(w->def, ")");
|
|
Append(declaration, ")");
|
|
}
|
|
|
|
Append(w->def, " {");
|
|
Append(declaration, ";\n");
|
|
|
|
/* declare method return value
|
|
* if the return value is a reference or const reference, a specialized typemap must
|
|
* handle it, including declaration of c_result ($result).
|
|
*/
|
|
if (!is_void) {
|
|
if (!(ignored_method && !pure_virtual)) {
|
|
String *cres = SwigType_lstr(return_type, "c_result");
|
|
Printf(w->code, "%s;\n", cres);
|
|
Delete(cres);
|
|
}
|
|
}
|
|
|
|
if (ignored_method) {
|
|
if (!pure_virtual) {
|
|
if (!is_void)
|
|
Printf(w->code, "return ");
|
|
String *super_call = Swig_method_call(super, l);
|
|
Printf(w->code, "%s;\n", super_call);
|
|
Delete(super_call);
|
|
} else {
|
|
Printf(w->code, "Swig::DirectorPureVirtualException::raise(\"Attempted to invoke pure virtual method %s::%s\");\n", SwigType_namestr(c_classname),
|
|
SwigType_namestr(name));
|
|
}
|
|
} else {
|
|
/* attach typemaps to arguments (C/C++ -> PHP) */
|
|
String *parse_args = NewStringEmpty();
|
|
|
|
/* remove the wrapper 'w' since it was producing spurious temps */
|
|
Swig_typemap_attach_parms("in", l, 0);
|
|
Swig_typemap_attach_parms("directorin", l, 0);
|
|
Swig_typemap_attach_parms("directorargout", l, w);
|
|
|
|
Parm *p;
|
|
char source[256];
|
|
|
|
int outputs = 0;
|
|
if (!is_void)
|
|
outputs++;
|
|
|
|
/* build argument list and type conversion string */
|
|
idx = 0;
|
|
p = l;
|
|
int use_parse = 0;
|
|
while (p != NULL) {
|
|
if (checkAttribute(p, "tmap:in:numinputs", "0")) {
|
|
p = Getattr(p, "tmap:in:next");
|
|
continue;
|
|
}
|
|
|
|
if (Getattr(p, "tmap:directorargout") != 0)
|
|
outputs++;
|
|
|
|
String *pname = Getattr(p, "name");
|
|
String *ptype = Getattr(p, "type");
|
|
|
|
if ((tm = Getattr(p, "tmap:directorin")) != 0) {
|
|
String *parse = Getattr(p, "tmap:directorin:parse");
|
|
if (!parse) {
|
|
sprintf(source, "obj%d", idx++);
|
|
String *input = NewStringf("&%s", source);
|
|
Replaceall(tm, "$input", input);
|
|
Delete(input);
|
|
Replaceall(tm, "$owner", "0");
|
|
Printv(wrap_args, "zval ", source, ";\n", NIL);
|
|
Printf(wrap_args, "args[%d] = &%s;\n", idx - 1, source);
|
|
|
|
Printv(wrap_args, tm, "\n", NIL);
|
|
Putc('O', parse_args);
|
|
} else {
|
|
use_parse = 1;
|
|
Append(parse_args, parse);
|
|
Replaceall(tm, "$input", pname);
|
|
Replaceall(tm, "$owner", "0");
|
|
if (Len(tm) == 0)
|
|
Append(tm, pname);
|
|
}
|
|
p = Getattr(p, "tmap:directorin:next");
|
|
continue;
|
|
} else if (Cmp(ptype, "void")) {
|
|
Swig_warning(WARN_TYPEMAP_DIRECTORIN_UNDEF, input_file, line_number,
|
|
"Unable to use type %s as a function argument in director method %s::%s (skipping method).\n", SwigType_str(ptype, 0),
|
|
SwigType_namestr(c_classname), SwigType_namestr(name));
|
|
status = SWIG_NOWRAP;
|
|
break;
|
|
}
|
|
p = nextSibling(p);
|
|
}
|
|
|
|
/* exception handling */
|
|
tm = Swig_typemap_lookup("director:except", n, "result", 0);
|
|
if (!tm) {
|
|
tm = Getattr(n, "feature:director:except");
|
|
if (tm)
|
|
tm = Copy(tm);
|
|
}
|
|
if ((tm) && Len(tm) && (Strcmp(tm, "1") != 0)) {
|
|
if (Replaceall(tm, "$error", "error")) {
|
|
/* Only declare error if it is used by the typemap. */
|
|
Append(w->code, "int error;\n");
|
|
}
|
|
} else {
|
|
Delete(tm);
|
|
tm = NULL;
|
|
}
|
|
|
|
if (!idx) {
|
|
Printf(w->code, "zval **args = NULL;\n", idx);
|
|
} else {
|
|
Printf(w->code, "zval *args[%d];\n", idx);
|
|
}
|
|
Append(w->code, "zval *result, funcname;\n");
|
|
Append(w->code, "MAKE_STD_ZVAL(result);\n");
|
|
Printf(w->code, "ZVAL_STRING(&funcname, (char *)\"%s\", 0);\n", name);
|
|
Append(w->code, "if (!swig_self) {\n");
|
|
Append(w->code, " SWIG_PHP_Error(E_ERROR, \"this pointer is NULL\");");
|
|
Append(w->code, "}\n\n");
|
|
|
|
/* wrap complex arguments to zvals */
|
|
Printv(w->code, wrap_args, NIL);
|
|
|
|
Append(w->code, "call_user_function(EG(function_table), (zval**)&swig_self, &funcname,\n");
|
|
Printf(w->code, " result, %d, args TSRMLS_CC);\n", idx);
|
|
|
|
if (tm) {
|
|
Printv(w->code, Str(tm), "\n", NIL);
|
|
Delete(tm);
|
|
}
|
|
|
|
/* marshal return value from PHP to C/C++ type */
|
|
|
|
String *cleanup = NewStringEmpty();
|
|
String *outarg = NewStringEmpty();
|
|
|
|
idx = 0;
|
|
|
|
/* marshal return value */
|
|
if (!is_void) {
|
|
/* this seems really silly. the node's type excludes
|
|
* qualifier/pointer/reference markers, which have to be retrieved
|
|
* from the decl field to construct return_type. but the typemap
|
|
* lookup routine uses the node's type, so we have to swap in and
|
|
* out the correct type. it's not just me, similar silliness also
|
|
* occurs in Language::cDeclaration().
|
|
*/
|
|
Setattr(n, "type", return_type);
|
|
tm = Swig_typemap_lookup("directorout", n, "result", w);
|
|
Setattr(n, "type", type);
|
|
if (tm != 0) {
|
|
Replaceall(tm, "$input", "&result");
|
|
char temp[24];
|
|
sprintf(temp, "%d", idx);
|
|
Replaceall(tm, "$argnum", temp);
|
|
|
|
/* TODO check this */
|
|
if (Getattr(n, "wrap:disown")) {
|
|
Replaceall(tm, "$disown", "SWIG_POINTER_DISOWN");
|
|
} else {
|
|
Replaceall(tm, "$disown", "0");
|
|
}
|
|
Replaceall(tm, "$result", "c_result");
|
|
Printv(w->code, tm, "\n", NIL);
|
|
Delete(tm);
|
|
} else {
|
|
Swig_warning(WARN_TYPEMAP_DIRECTOROUT_UNDEF, input_file, line_number,
|
|
"Unable to use return type %s in director method %s::%s (skipping method).\n", SwigType_str(return_type, 0), SwigType_namestr(c_classname),
|
|
SwigType_namestr(name));
|
|
status = SWIG_ERROR;
|
|
}
|
|
}
|
|
|
|
/* marshal outputs */
|
|
for (p = l; p;) {
|
|
if ((tm = Getattr(p, "tmap:directorargout")) != 0) {
|
|
Replaceall(tm, "$input", "result");
|
|
Replaceall(tm, "$result", Getattr(p, "name"));
|
|
Printv(w->code, tm, "\n", NIL);
|
|
p = Getattr(p, "tmap:directorargout:next");
|
|
} else {
|
|
p = nextSibling(p);
|
|
}
|
|
}
|
|
|
|
Append(w->code, "FREE_ZVAL(result);\n");
|
|
|
|
Delete(parse_args);
|
|
Delete(cleanup);
|
|
Delete(outarg);
|
|
}
|
|
|
|
if (!is_void) {
|
|
if (!(ignored_method && !pure_virtual)) {
|
|
String *rettype = SwigType_str(return_type, 0);
|
|
if (!SwigType_isreference(return_type)) {
|
|
Printf(w->code, "return (%s) c_result;\n", rettype);
|
|
} else {
|
|
Printf(w->code, "return (%s) *c_result;\n", rettype);
|
|
}
|
|
Delete(rettype);
|
|
}
|
|
} else {
|
|
Append(w->code, "return;\n");
|
|
}
|
|
|
|
Append(w->code, "fail:\n");
|
|
Append(w->code, "zend_error_noreturn(SWIG_ErrorCode(),\"%s\",SWIG_ErrorMsg());\n");
|
|
Append(w->code, "}\n");
|
|
|
|
// We expose protected methods via an extra public inline method which makes a straight call to the wrapped class' method
|
|
String *inline_extra_method = NewStringEmpty();
|
|
if (dirprot_mode() && !is_public(n) && !pure_virtual) {
|
|
Printv(inline_extra_method, declaration, NIL);
|
|
String *extra_method_name = NewStringf("%sSwigPublic", name);
|
|
Replaceall(inline_extra_method, name, extra_method_name);
|
|
Replaceall(inline_extra_method, ";\n", " {\n ");
|
|
if (!is_void)
|
|
Printf(inline_extra_method, "return ");
|
|
String *methodcall = Swig_method_call(super, l);
|
|
Printv(inline_extra_method, methodcall, ";\n }\n", NIL);
|
|
Delete(methodcall);
|
|
Delete(extra_method_name);
|
|
}
|
|
|
|
/* emit the director method */
|
|
if (status == SWIG_OK) {
|
|
if (!Getattr(n, "defaultargs")) {
|
|
Wrapper_print(w, f_directors);
|
|
Printv(f_directors_h, declaration, NIL);
|
|
Printv(f_directors_h, inline_extra_method, NIL);
|
|
}
|
|
}
|
|
|
|
/* clean up */
|
|
Delete(wrap_args);
|
|
Delete(return_type);
|
|
Delete(pclassname);
|
|
DelWrapper(w);
|
|
return status;
|
|
}
|
|
|
|
int classDirectorDisown(Node *) {
|
|
return SWIG_OK;
|
|
}
|
|
}; /* class PHP */
|
|
|
|
static PHP *maininstance = 0;
|
|
|
|
// We use this function to be able to write out zend_register_list_destructor_ex
|
|
// lines for most things in the type table
|
|
// NOTE: it's a function NOT A PHP::METHOD
|
|
extern "C" void typetrace(SwigType *ty, String *mangled, String *clientdata) {
|
|
Node *class_node;
|
|
if (!zend_types) {
|
|
zend_types = NewHash();
|
|
}
|
|
// we want to know if the type which reduced to this has a constructor
|
|
if ((class_node = maininstance->classLookup(ty))) {
|
|
if (!Getattr(zend_types, mangled)) {
|
|
// OK it may have been set before by a different SwigType but it would
|
|
// have had the same underlying class node I think
|
|
// - it is certainly required not to have different originating class
|
|
// nodes for the same SwigType
|
|
Setattr(zend_types, mangled, class_node);
|
|
}
|
|
} else { // a non-class pointer
|
|
Setattr(zend_types, mangled, NOTCLASS);
|
|
}
|
|
if (r_prevtracefunc)
|
|
(*r_prevtracefunc) (ty, mangled, (String *) clientdata);
|
|
}
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* new_swig_php() - Instantiate module
|
|
* ----------------------------------------------------------------------------- */
|
|
|
|
static Language *new_swig_php() {
|
|
maininstance = new PHP;
|
|
if (!r_prevtracefunc) {
|
|
r_prevtracefunc = SwigType_remember_trace(typetrace);
|
|
} else {
|
|
Printf(stderr, "php Typetrace vector already saved!\n");
|
|
assert(0);
|
|
}
|
|
return maininstance;
|
|
}
|
|
|
|
extern "C" Language *swig_php4(void) {
|
|
Printf(stderr, "*** -php4 is no longer supported.\n"
|
|
"*** Either upgrade to PHP5 or use SWIG 1.3.36 or earlier.\n");
|
|
SWIG_exit(EXIT_FAILURE);
|
|
return NULL; // To avoid compiler warnings.
|
|
}
|
|
|
|
extern "C" Language *swig_php(void) {
|
|
return new_swig_php();
|
|
}
|