From 7dfd9aae311c04a99453bcabc4204646bb458b87 Mon Sep 17 00:00:00 2001 From: Olly Betts Date: Thu, 3 Jul 2008 00:09:56 +0000 Subject: [PATCH] WARN_* constants are user visible, so keep existing WARN_PHP4_* for backward compatibility, but add preferred forms WARN_PHP_* and use these ourselves. Rename Lib/php4 to Lib/php, Source/Modules/php4.cxx to Source/Modules/php.cxx. Add typemaps for const reference so Examples/test-suite/apply_signed_char.i works. git-svn-id: https://swig.svn.sourceforge.net/svnroot/swig/trunk@10633 626c5289-ae23-0410-ae9c-e8d60b6d4f22 --- Examples/test-suite/abstract_virtual.i | 4 +- Examples/test-suite/contract.i | 2 +- Examples/test-suite/default_constructor.i | 4 +- Examples/test-suite/evil_diamond.i | 2 +- Examples/test-suite/evil_diamond_ns.i | 2 +- Examples/test-suite/evil_diamond_prop.i | 2 +- Examples/test-suite/multiple_inheritance.i | 4 +- Examples/test-suite/pure_virtual.i | 2 +- .../test-suite/template_inherit_abstract.i | 2 +- Examples/test-suite/using_composition.i | 6 +- Examples/test-suite/using_extend.i | 2 +- Examples/test-suite/using_namespace.i | 2 +- Lib/{php4 => php}/const.i | 0 Lib/{php4 => php}/globalvar.i | 0 Lib/{php4 => php}/php4.swg | 0 Lib/{php4 => php}/php4init.swg | 0 Lib/{php4 => php}/php4kw.swg | 0 Lib/{php4 => php}/php4run.swg | 0 Lib/{php4 => php}/phppointers.i | 0 Lib/{php4 => php}/std_common.i | 0 Lib/{php4 => php}/std_deque.i | 0 Lib/{php4 => php}/std_map.i | 0 Lib/{php4 => php}/std_pair.i | 0 Lib/{php4 => php}/std_string.i | 0 Lib/{php4 => php}/std_vector.i | 0 Lib/{php4 => php}/stl.i | 0 Lib/{php4 => php}/typemaps.i | 0 Lib/{php4 => php}/utils.i | 2 +- Source/Include/swigwarn.h | 13 +- Source/Makefile.am | 2 +- Source/Modules/php.cxx | 2359 +++++++++++++++++ Source/Modules/{php4.cxx => php5.cxx} | 0 32 files changed, 2388 insertions(+), 22 deletions(-) rename Lib/{php4 => php}/const.i (100%) rename Lib/{php4 => php}/globalvar.i (100%) rename Lib/{php4 => php}/php4.swg (100%) rename Lib/{php4 => php}/php4init.swg (100%) rename Lib/{php4 => php}/php4kw.swg (100%) rename Lib/{php4 => php}/php4run.swg (100%) rename Lib/{php4 => php}/phppointers.i (100%) rename Lib/{php4 => php}/std_common.i (100%) rename Lib/{php4 => php}/std_deque.i (100%) rename Lib/{php4 => php}/std_map.i (100%) rename Lib/{php4 => php}/std_pair.i (100%) rename Lib/{php4 => php}/std_string.i (100%) rename Lib/{php4 => php}/std_vector.i (100%) rename Lib/{php4 => php}/stl.i (100%) rename Lib/{php4 => php}/typemaps.i (100%) rename Lib/{php4 => php}/utils.i (97%) create mode 100644 Source/Modules/php.cxx rename Source/Modules/{php4.cxx => php5.cxx} (100%) diff --git a/Examples/test-suite/abstract_virtual.i b/Examples/test-suite/abstract_virtual.i index e2d8054bb..2e4d105b1 100644 --- a/Examples/test-suite/abstract_virtual.i +++ b/Examples/test-suite/abstract_virtual.i @@ -2,10 +2,10 @@ %warnfilter(SWIGWARN_JAVA_MULTIPLE_INHERITANCE, SWIGWARN_CSHARP_MULTIPLE_INHERITANCE, - SWIGWARN_PHP4_MULTIPLE_INHERITANCE) D; /* C#, Java, Php4 multiple inheritance */ + SWIGWARN_PHP_MULTIPLE_INHERITANCE) D; /* C#, Java, PHP multiple inheritance */ %warnfilter(SWIGWARN_JAVA_MULTIPLE_INHERITANCE, SWIGWARN_CSHARP_MULTIPLE_INHERITANCE, - SWIGWARN_PHP4_MULTIPLE_INHERITANCE) E; /* C#, Java, Php4 multiple inheritance */ + SWIGWARN_PHP_MULTIPLE_INHERITANCE) E; /* C#, Java, PHP multiple inheritance */ %inline %{ #if defined(_MSC_VER) diff --git a/Examples/test-suite/contract.i b/Examples/test-suite/contract.i index 6ee0a353c..a5732105b 100644 --- a/Examples/test-suite/contract.i +++ b/Examples/test-suite/contract.i @@ -3,7 +3,7 @@ %warnfilter(SWIGWARN_RUBY_MULTIPLE_INHERITANCE, SWIGWARN_JAVA_MULTIPLE_INHERITANCE, SWIGWARN_CSHARP_MULTIPLE_INHERITANCE, - SWIGWARN_PHP4_MULTIPLE_INHERITANCE) C; /* Ruby, C#, Java, Php4 multiple inheritance */ + SWIGWARN_PHP_MULTIPLE_INHERITANCE) C; /* Ruby, C#, Java, PHP multiple inheritance */ #ifdef SWIGCSHARP %ignore B::bar; // otherwise get a warning: `C.bar' no suitable methods found to override diff --git a/Examples/test-suite/default_constructor.i b/Examples/test-suite/default_constructor.i index 71600e55a..ff22c7834 100644 --- a/Examples/test-suite/default_constructor.i +++ b/Examples/test-suite/default_constructor.i @@ -5,11 +5,11 @@ %warnfilter(SWIGWARN_JAVA_MULTIPLE_INHERITANCE, SWIGWARN_CSHARP_MULTIPLE_INHERITANCE, - SWIGWARN_PHP4_MULTIPLE_INHERITANCE) EB; /* C#, Java, Php4 multiple inheritance */ + SWIGWARN_PHP_MULTIPLE_INHERITANCE) EB; /* C#, Java, PHP multiple inheritance */ %warnfilter(SWIGWARN_JAVA_MULTIPLE_INHERITANCE, SWIGWARN_CSHARP_MULTIPLE_INHERITANCE, - SWIGWARN_PHP4_MULTIPLE_INHERITANCE) AD; /* C#, Java, Php4 multiple inheritance */ + SWIGWARN_PHP_MULTIPLE_INHERITANCE) AD; /* C#, Java, PHP multiple inheritance */ %warnfilter(SWIGWARN_LANG_FRIEND_IGNORE) F; /* friend function */ diff --git a/Examples/test-suite/evil_diamond.i b/Examples/test-suite/evil_diamond.i index 33353e32e..7b2e9152f 100644 --- a/Examples/test-suite/evil_diamond.i +++ b/Examples/test-suite/evil_diamond.i @@ -6,7 +6,7 @@ %warnfilter(SWIGWARN_RUBY_WRONG_NAME, SWIGWARN_JAVA_MULTIPLE_INHERITANCE, SWIGWARN_CSHARP_MULTIPLE_INHERITANCE, - SWIGWARN_PHP4_MULTIPLE_INHERITANCE) spam; // Ruby, wrong class name - C# & Java, Php4 multiple inheritance + SWIGWARN_PHP_MULTIPLE_INHERITANCE) spam; // Ruby, wrong class name - C# & Java, PHP multiple inheritance %inline %{ diff --git a/Examples/test-suite/evil_diamond_ns.i b/Examples/test-suite/evil_diamond_ns.i index 78a764ccc..515044007 100644 --- a/Examples/test-suite/evil_diamond_ns.i +++ b/Examples/test-suite/evil_diamond_ns.i @@ -6,7 +6,7 @@ %warnfilter(SWIGWARN_RUBY_WRONG_NAME, SWIGWARN_JAVA_MULTIPLE_INHERITANCE, SWIGWARN_CSHARP_MULTIPLE_INHERITANCE, - SWIGWARN_PHP4_MULTIPLE_INHERITANCE) Blah::spam; // Ruby, wrong class name - C# & Java, Php4 multiple inheritance + SWIGWARN_PHP_MULTIPLE_INHERITANCE) Blah::spam; // Ruby, wrong class name - C# & Java, PHP multiple inheritance %inline %{ namespace Blah { diff --git a/Examples/test-suite/evil_diamond_prop.i b/Examples/test-suite/evil_diamond_prop.i index e9fc24f4d..804ea66b4 100644 --- a/Examples/test-suite/evil_diamond_prop.i +++ b/Examples/test-suite/evil_diamond_prop.i @@ -6,7 +6,7 @@ %warnfilter(SWIGWARN_RUBY_WRONG_NAME, SWIGWARN_JAVA_MULTIPLE_INHERITANCE, SWIGWARN_CSHARP_MULTIPLE_INHERITANCE, - SWIGWARN_PHP4_MULTIPLE_INHERITANCE) spam; // Ruby, wrong class name - C# & Java, Php4 multiple inheritance + SWIGWARN_PHP_MULTIPLE_INHERITANCE) spam; // Ruby, wrong class name - C# & Java, PHP multiple inheritance %inline %{ diff --git a/Examples/test-suite/multiple_inheritance.i b/Examples/test-suite/multiple_inheritance.i index 1c4458114..1fc68eef9 100644 --- a/Examples/test-suite/multiple_inheritance.i +++ b/Examples/test-suite/multiple_inheritance.i @@ -5,11 +5,11 @@ It tests basic multiple inheritance */ %warnfilter(SWIGWARN_JAVA_MULTIPLE_INHERITANCE, SWIGWARN_CSHARP_MULTIPLE_INHERITANCE, - SWIGWARN_PHP4_MULTIPLE_INHERITANCE) FooBar; /* C#, Java, Php4 multiple inheritance */ + SWIGWARN_PHP_MULTIPLE_INHERITANCE) FooBar; /* C#, Java, PHP multiple inheritance */ %warnfilter(SWIGWARN_JAVA_MULTIPLE_INHERITANCE, SWIGWARN_CSHARP_MULTIPLE_INHERITANCE, - SWIGWARN_PHP4_MULTIPLE_INHERITANCE) FooBarSpam; /* C#, Java, Php4 multiple inheritance */ + SWIGWARN_PHP_MULTIPLE_INHERITANCE) FooBarSpam; /* C#, Java, PHP multiple inheritance */ %inline %{ diff --git a/Examples/test-suite/pure_virtual.i b/Examples/test-suite/pure_virtual.i index b41e48a89..aab9741a9 100644 --- a/Examples/test-suite/pure_virtual.i +++ b/Examples/test-suite/pure_virtual.i @@ -9,7 +9,7 @@ %warnfilter(SWIGWARN_JAVA_MULTIPLE_INHERITANCE, SWIGWARN_CSHARP_MULTIPLE_INHERITANCE, - SWIGWARN_PHP4_MULTIPLE_INHERITANCE) E; /* C#, Java, Php4 multiple inheritance */ + SWIGWARN_PHP_MULTIPLE_INHERITANCE) E; /* C#, Java, PHP multiple inheritance */ %nodefaultctor C; %nodefaultdtor C; diff --git a/Examples/test-suite/template_inherit_abstract.i b/Examples/test-suite/template_inherit_abstract.i index f676b3b3e..89d983de0 100644 --- a/Examples/test-suite/template_inherit_abstract.i +++ b/Examples/test-suite/template_inherit_abstract.i @@ -4,7 +4,7 @@ %warnfilter(SWIGWARN_JAVA_MULTIPLE_INHERITANCE, SWIGWARN_CSHARP_MULTIPLE_INHERITANCE, - SWIGWARN_PHP4_MULTIPLE_INHERITANCE) oss::Module; /* C#, Java, Php4 multiple inheritance */ + SWIGWARN_PHP_MULTIPLE_INHERITANCE) oss::Module; /* C#, Java, PHP multiple inheritance */ %inline %{ diff --git a/Examples/test-suite/using_composition.i b/Examples/test-suite/using_composition.i index 7bb6add2a..bd0f712b5 100644 --- a/Examples/test-suite/using_composition.i +++ b/Examples/test-suite/using_composition.i @@ -2,13 +2,13 @@ %warnfilter(SWIGWARN_JAVA_MULTIPLE_INHERITANCE, SWIGWARN_CSHARP_MULTIPLE_INHERITANCE, - SWIGWARN_PHP4_MULTIPLE_INHERITANCE) FooBar; // C#, Java, Php4 multiple inheritance + SWIGWARN_PHP_MULTIPLE_INHERITANCE) FooBar; // C#, Java, PHP multiple inheritance %warnfilter(SWIGWARN_JAVA_MULTIPLE_INHERITANCE, SWIGWARN_CSHARP_MULTIPLE_INHERITANCE, - SWIGWARN_PHP4_MULTIPLE_INHERITANCE) FooBar2; // C#, Java, Php4 multiple inheritance + SWIGWARN_PHP_MULTIPLE_INHERITANCE) FooBar2; // C#, Java, PHP multiple inheritance %warnfilter(SWIGWARN_JAVA_MULTIPLE_INHERITANCE, SWIGWARN_CSHARP_MULTIPLE_INHERITANCE, - SWIGWARN_PHP4_MULTIPLE_INHERITANCE) FooBar3; // C#, Java, Php4 multiple inheritance + SWIGWARN_PHP_MULTIPLE_INHERITANCE) FooBar3; // C#, Java, PHP multiple inheritance #ifdef SWIGLUA // lua only has one numeric type, so some overloads shadow each other creating warnings %warnfilter(SWIGWARN_LANG_OVERLOAD_SHADOW) blah; #endif diff --git a/Examples/test-suite/using_extend.i b/Examples/test-suite/using_extend.i index 414ceedb4..e14cc28e8 100644 --- a/Examples/test-suite/using_extend.i +++ b/Examples/test-suite/using_extend.i @@ -2,7 +2,7 @@ %warnfilter(SWIGWARN_JAVA_MULTIPLE_INHERITANCE, SWIGWARN_CSHARP_MULTIPLE_INHERITANCE, - SWIGWARN_PHP4_MULTIPLE_INHERITANCE) FooBar; // C#, Java, Php4 multiple inheritance + SWIGWARN_PHP_MULTIPLE_INHERITANCE) FooBar; // C#, Java, PHP multiple inheritance #ifdef SWIGLUA // lua only has one numeric type, so some overloads shadow each other creating warnings %warnfilter(SWIGWARN_LANG_OVERLOAD_SHADOW) blah; #endif diff --git a/Examples/test-suite/using_namespace.i b/Examples/test-suite/using_namespace.i index 1989b6a0d..799c7cfb5 100644 --- a/Examples/test-suite/using_namespace.i +++ b/Examples/test-suite/using_namespace.i @@ -5,7 +5,7 @@ %warnfilter(SWIGWARN_JAVA_MULTIPLE_INHERITANCE, SWIGWARN_CSHARP_MULTIPLE_INHERITANCE, - SWIGWARN_PHP4_MULTIPLE_INHERITANCE) Hi; // C#, Java, Php4 multiple inheritance + SWIGWARN_PHP_MULTIPLE_INHERITANCE) Hi; // C#, Java, PHP multiple inheritance %inline %{ namespace hello diff --git a/Lib/php4/const.i b/Lib/php/const.i similarity index 100% rename from Lib/php4/const.i rename to Lib/php/const.i diff --git a/Lib/php4/globalvar.i b/Lib/php/globalvar.i similarity index 100% rename from Lib/php4/globalvar.i rename to Lib/php/globalvar.i diff --git a/Lib/php4/php4.swg b/Lib/php/php4.swg similarity index 100% rename from Lib/php4/php4.swg rename to Lib/php/php4.swg diff --git a/Lib/php4/php4init.swg b/Lib/php/php4init.swg similarity index 100% rename from Lib/php4/php4init.swg rename to Lib/php/php4init.swg diff --git a/Lib/php4/php4kw.swg b/Lib/php/php4kw.swg similarity index 100% rename from Lib/php4/php4kw.swg rename to Lib/php/php4kw.swg diff --git a/Lib/php4/php4run.swg b/Lib/php/php4run.swg similarity index 100% rename from Lib/php4/php4run.swg rename to Lib/php/php4run.swg diff --git a/Lib/php4/phppointers.i b/Lib/php/phppointers.i similarity index 100% rename from Lib/php4/phppointers.i rename to Lib/php/phppointers.i diff --git a/Lib/php4/std_common.i b/Lib/php/std_common.i similarity index 100% rename from Lib/php4/std_common.i rename to Lib/php/std_common.i diff --git a/Lib/php4/std_deque.i b/Lib/php/std_deque.i similarity index 100% rename from Lib/php4/std_deque.i rename to Lib/php/std_deque.i diff --git a/Lib/php4/std_map.i b/Lib/php/std_map.i similarity index 100% rename from Lib/php4/std_map.i rename to Lib/php/std_map.i diff --git a/Lib/php4/std_pair.i b/Lib/php/std_pair.i similarity index 100% rename from Lib/php4/std_pair.i rename to Lib/php/std_pair.i diff --git a/Lib/php4/std_string.i b/Lib/php/std_string.i similarity index 100% rename from Lib/php4/std_string.i rename to Lib/php/std_string.i diff --git a/Lib/php4/std_vector.i b/Lib/php/std_vector.i similarity index 100% rename from Lib/php4/std_vector.i rename to Lib/php/std_vector.i diff --git a/Lib/php4/stl.i b/Lib/php/stl.i similarity index 100% rename from Lib/php4/stl.i rename to Lib/php/stl.i diff --git a/Lib/php4/typemaps.i b/Lib/php/typemaps.i similarity index 100% rename from Lib/php4/typemaps.i rename to Lib/php/typemaps.i diff --git a/Lib/php4/utils.i b/Lib/php/utils.i similarity index 97% rename from Lib/php4/utils.i rename to Lib/php/utils.i index f7241187c..77c9e923e 100644 --- a/Lib/php4/utils.i +++ b/Lib/php/utils.i @@ -29,7 +29,7 @@ %enddef %define %pass_by_val( TYPE, CONVERT_IN ) -%typemap(in) TYPE +%typemap(in) TYPE, const TYPE & %{ CONVERT_IN($1,$1_ltype,$input); %} diff --git a/Source/Include/swigwarn.h b/Source/Include/swigwarn.h index 174e8b001..8c4678847 100644 --- a/Source/Include/swigwarn.h +++ b/Source/Include/swigwarn.h @@ -247,10 +247,17 @@ /* please leave 850-869 free for Modula 3 */ -#define WARN_PHP4_MULTIPLE_INHERITANCE 870 -#define WARN_PHP4_UNKNOWN_PRAGMA 871 +/* These are needed for backward compatibility, but you don't need to add + * PHP4 versions of new warnings since existing user interface files can't + * be using them. + */ +#define WARN_PHP4_MULTIPLE_INHERITANCE 870 +#define WARN_PHP4_UNKNOWN_PRAGMA 871 -/* please leave 870-889 free for Php */ +#define WARN_PHP_MULTIPLE_INHERITANCE 870 +#define WARN_PHP_UNKNOWN_PRAGMA 871 + +/* please leave 870-889 free for PHP */ /* Feel free to claim any number in this space that's not currently being used. Just make sure you diff --git a/Source/Makefile.am b/Source/Makefile.am index a72671305..84c595bc0 100644 --- a/Source/Makefile.am +++ b/Source/Makefile.am @@ -57,7 +57,7 @@ eswig_SOURCES = CParse/cscanner.c \ Modules/octave.cxx \ Modules/overload.cxx \ Modules/perl5.cxx \ - Modules/php4.cxx \ + Modules/php.cxx \ Modules/pike.cxx \ Modules/python.cxx \ Modules/r.cxx \ diff --git a/Source/Modules/php.cxx b/Source/Modules/php.cxx new file mode 100644 index 000000000..77f3e0d73 --- /dev/null +++ b/Source/Modules/php.cxx @@ -0,0 +1,2359 @@ +/* ----------------------------------------------------------------------------- + * See the LICENSE file for information on copyright, usage and redistribution + * of SWIG, and the README file for authors - http://www.swig.org/release.html. + * + * php4.cxx + * + * Php language module for SWIG. + * ----------------------------------------------------------------------------- + */ + +/* FIXME: PHP5 OO wrapping TODO list: + * + * Short term: + * + * Sort out auto-renaming of method and class names which are reserved + * words (e.g. empty, clone, exception, etc.) + * + * Sort out wrapping of static member variables in OO PHP5. + * + * 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_php4_cxx[] = "$Id$"; + +#include "swigmod.h" + +#include +#include + +static const char *usage = (char *) "\ +PHP Options (available with -php5)\n\ + -cppext - cpp file extension (default to .cpp)\n\ + -noproxy - Don't generate proxy classes.\n\ + -prefix - Prepend to all class names in PHP5 wrappers\n\ + -make - Create simple makefile\n\ + -phpfull - Create full make files\n\ + -withincs - With -phpfull writes needed incs in config.m4\n\ + -withlibs - With -phpfull writes needed libs in config.m4\n\ + -withc - With -phpfull makes extra C files in Makefile.in\n\ + -withcxx - With -phpfull makes extra C++ files in Makefile.in\n\ +\n"; + +/* The original class wrappers for PHP4 store 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" + +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 *withlibs = 0; +static String *withincs = 0; +static String *withc = 0; +static String *withcxx = 0; + +static String *shadow_classname = 0; + +static int gen_extra = 0; +static int gen_make = 0; + +static File *f_runtime = 0; +static File *f_h = 0; +static File *f_phpcode = 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, + destructor +} wrapperType = standard; + +extern "C" { + static void (*r_prevtracefunc) (SwigType *t, String *mangled, String *clientdata) = 0; +} + +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, "/* NEW Destructor style */\nstatic 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); + } + } else { + Printf(s_wrappers, " /* No destructor for simple type %s */\n", key); + } + + // close function + Printf(s_wrappers, "}\n"); + + // declare le_swig_ 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 { + int php_version; + +public: + PHP(int php_version_):php_version(php_version_) { + } + + /* Test to see if a type corresponds to something wrapped with a shadow class. */ + + String *is_shadow(SwigType *t) { + String *r = 0; + Node *n = classLookup(t); + if (n) { + 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 + } + } + return r; + } + + /* ------------------------------------------------------------ + * main() + * ------------------------------------------------------------ */ + + virtual void main(int argc, char *argv[]) { + SWIG_library_directory("php"); + SWIG_config_cppext("cpp"); + + for (int i = 1; i < argc; i++) { + if (argv[i]) { + if (strcmp(argv[i], "-phpfull") == 0) { + gen_extra = 1; + Swig_mark_arg(i); + } 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); + } else 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], "-withlibs") == 0) { + if (argv[i + 1]) { + withlibs = NewString(argv[i + 1]); + Swig_mark_arg(i); + Swig_mark_arg(i + 1); + i++; + } else { + Swig_arg_error(); + } + } else if (strcmp(argv[i], "-withincs") == 0) { + if (argv[i + 1]) { + withincs = NewString(argv[i + 1]); + Swig_mark_arg(i); + Swig_mark_arg(i + 1); + i++; + } else { + Swig_arg_error(); + } + } else if (strcmp(argv[i], "-withc") == 0) { + if (argv[i + 1]) { + withc = NewString(argv[i + 1]); + Swig_mark_arg(i); + Swig_mark_arg(i + 1); + i++; + } else { + Swig_arg_error(); + } + } else if (strcmp(argv[i], "-withcxx") == 0) { + if (argv[i + 1]) { + withcxx = 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], "-make") == 0) { + gen_make = 1; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-help") == 0) { + fputs(usage, stdout); + } + } + } + + Preprocessor_define("SWIGPHP 1", 0); + Preprocessor_define("SWIGPHP5 1", 0); + SWIG_typemap_lang("php4"); + SWIG_config_file("php4.swg"); + allow_overloading(); + } + + void create_simple_make(void) { + File *f_make; + + f_make = NewFile((void *) "makefile", "w"); + Printf(f_make, "CC=gcc\n"); + Printf(f_make, "CXX=g++\n"); + Printf(f_make, "CXX_SOURCES=%s\n", withcxx); + Printf(f_make, "C_SOURCES=%s\n", withc); + Printf(f_make, "OBJS=%s_wrap.o $(C_SOURCES:.c=.o) $(CXX_SOURCES:.cxx=.o)\n", module); + Printf(f_make, "MODULE=%s.so\n", module); + Printf(f_make, "CFLAGS=-fpic\n"); + Printf(f_make, "LDFLAGS=-shared\n"); + Printf(f_make, "PHP_INC=`php-config --includes`\n"); + Printf(f_make, "EXTRA_INC=\n"); + Printf(f_make, "EXTRA_LIB=\n\n"); + Printf(f_make, "$(MODULE): $(OBJS)\n"); + if (CPlusPlus || (withcxx != NULL)) { + Printf(f_make, "\t$(CXX) $(LDFLAGS) $(OBJS) -o $@ $(EXTRA_LIB)\n\n"); + } else { + Printf(f_make, "\t$(CC) $(LDFLAGS) $(OBJS) -o $@ $(EXTRA_LIB)\n\n"); + } + Printf(f_make, "%%.o: %%.cpp\n"); + Printf(f_make, "\t$(CXX) $(EXTRA_INC) $(PHP_INC) $(CFLAGS) -c $<\n"); + Printf(f_make, "%%.o: %%.cxx\n"); + Printf(f_make, "\t$(CXX) $(EXTRA_INC) $(PHP_INC) $(CFLAGS) -c $<\n"); + Printf(f_make, "%%.o: %%.c\n"); + Printf(f_make, "\t$(CC) $(EXTRA_INC) $(PHP_INC) $(CFLAGS) -c $<\n"); + + Close(f_make); + } + + void create_extra_files(String *outfile) { + File *f_extra; + + static String *configm4 = 0; + static String *makefilein = 0; + static String *credits = 0; + + configm4 = NewStringEmpty(); + Printv(configm4, SWIG_output_directory(), "config.m4", NIL); + + makefilein = NewStringEmpty(); + Printv(makefilein, SWIG_output_directory(), "Makefile.in", NIL); + + credits = NewStringEmpty(); + Printv(credits, SWIG_output_directory(), "CREDITS", NIL); + + // are we a --with- or --enable- + int with = (withincs || withlibs) ? 1 : 0; + + // Note Makefile.in only copes with one source file + // also withincs and withlibs only take one name each now + // the code they generate should be adapted to take multiple lines + + /* Write out Makefile.in */ + f_extra = NewFile(makefilein, "w"); + if (!f_extra) { + FileErrorDisplay(makefilein); + SWIG_exit(EXIT_FAILURE); + } + + Printf(f_extra, "# $Id$\n\n" "LTLIBRARY_NAME = %s.la\n", module); + + // C++ has more and different entries to C in Makefile.in + if (!CPlusPlus) { + Printf(f_extra, "LTLIBRARY_SOURCES = %s %s\n", Swig_file_filename(outfile), withc); + Printf(f_extra, "LTLIBRARY_SOURCES_CPP = %s\n", withcxx); + } else { + Printf(f_extra, "LTLIBRARY_SOURCES = %s\n", withc); + Printf(f_extra, "LTLIBRARY_SOURCES_CPP = %s %s\n", Swig_file_filename(outfile), withcxx); + Printf(f_extra, "LTLIBRARY_OBJECTS_X = $(LTLIBRARY_SOURCES_CPP:.cpp=.lo) $(LTLIBRARY_SOURCES_CPP:.cxx=.lo)\n"); + } + Printf(f_extra, "LTLIBRARY_SHARED_NAME = %s.la\n", module); + Printf(f_extra, "LTLIBRARY_SHARED_LIBADD = $(%s_SHARED_LIBADD)\n\n", cap_module); + Printf(f_extra, "include $(top_srcdir)/build/dynlib.mk\n"); + + Printf(f_extra, "\n# patch in .cxx support to php build system to work like .cpp\n"); + Printf(f_extra, ".SUFFIXES: .cxx\n\n"); + + Printf(f_extra, ".cxx.o:\n"); + Printf(f_extra, "\t$(CXX_COMPILE) -c $<\n\n"); + + Printf(f_extra, ".cxx.lo:\n"); + Printf(f_extra, "\t$(CXX_PHP_COMPILE)\n\n"); + Printf(f_extra, ".cxx.slo:\n"); + + Printf(f_extra, "\t$(CXX_SHARED_COMPILE)\n\n"); + + Printf(f_extra, "\n# make it easy to test module\n"); + Printf(f_extra, "testmodule:\n"); + Printf(f_extra, "\tphp -q -d extension_dir=modules %s\n\n", Swig_file_filename(phpfilename)); + + Close(f_extra); + + /* Now config.m4 */ + // Note: # comments are OK in config.m4 if you don't mind them + // appearing in the final ./configure file + // (which can help with ./configure debugging) + + // NOTE2: phpize really ought to be able to write out a sample + // config.m4 based on some simple data, I'll take this up with + // the php folk! + f_extra = NewFile(configm4, "w"); + if (!f_extra) { + FileErrorDisplay(configm4); + SWIG_exit(EXIT_FAILURE); + } + + Printf(f_extra, "dnl $Id$\n"); + Printf(f_extra, "dnl ***********************************************************************\n"); + Printf(f_extra, "dnl ** THIS config.m4 is provided for PHPIZE and PHP's consumption NOT\n"); + Printf(f_extra, "dnl ** for any part of the rest of the %s build system\n", module); + Printf(f_extra, "dnl ***********************************************************************\n\n"); + + + if (!with) { // must be enable then + Printf(f_extra, "PHP_ARG_ENABLE(%s, whether to enable %s support,\n", module, module); + Printf(f_extra, "[ --enable-%s Enable %s support])\n\n", module, module); + } else { + Printf(f_extra, "PHP_ARG_WITH(%s, for %s support,\n", module, module); + Printf(f_extra, "[ --with-%s[=DIR] Include %s support.])\n\n", module, module); + // These tests try and file the library we need + Printf(f_extra, "dnl THESE TESTS try and find the library and header files\n"); + Printf(f_extra, "dnl your new php module needs. YOU MAY NEED TO EDIT THEM\n"); + Printf(f_extra, "dnl as written they assume your header files are all in the same place\n\n"); + + Printf(f_extra, "dnl ** are we looking for %s_lib.h or something else?\n", module); + if (withincs) + Printf(f_extra, "HNAMES=\"%s\"\n\n", withincs); + else + Printf(f_extra, "HNAMES=\"\"; # %s_lib.h ?\n\n", module); + + Printf(f_extra, "dnl ** Are we looking for lib%s.a or lib%s.so or something else?\n", module, module); + + if (withlibs) + Printf(f_extra, "LIBNAMES=\"%s\"\n\n", withlibs); + else + Printf(f_extra, "LIBNAMES=\"\"; # lib%s.so ?\n\n", module); + + Printf(f_extra, "dnl IF YOU KNOW one of the symbols in the library and you\n"); + Printf(f_extra, "dnl specify it below then we can have a link test to see if it works\n"); + Printf(f_extra, "LIBSYMBOL=\"\"\n\n"); + } + + // Now write out tests to find thing.. they may need to extend tests + Printf(f_extra, "if test \"$PHP_%s\" != \"no\"; then\n\n", cap_module); + + // Ready for when we add libraries as we find them + Printf(f_extra, " PHP_SUBST(%s_SHARED_LIBADD)\n\n", cap_module); + + if (withlibs) { // find more than one library + Printf(f_extra, " for LIBNAME in $LIBNAMES ; do\n"); + Printf(f_extra, " LIBDIR=\"\"\n"); + // For each path element to try... + Printf(f_extra, " for i in $PHP_%s $PHP_%s/lib /usr/lib /usr/local/lib ; do\n", cap_module, cap_module); + Printf(f_extra, " if test -r $i/lib$LIBNAME.a -o -r $i/lib$LIBNAME.so ; then\n"); + Printf(f_extra, " LIBDIR=\"$i\"\n"); + Printf(f_extra, " break\n"); + Printf(f_extra, " fi\n"); + Printf(f_extra, " done\n\n"); + Printf(f_extra, " dnl ** and $LIBDIR should be the library path\n"); + Printf(f_extra, " if test \"$LIBNAME\" != \"\" -a -z \"$LIBDIR\" ; then\n"); + Printf(f_extra, " AC_MSG_RESULT(Library files $LIBNAME not found)\n"); + Printf(f_extra, " AC_MSG_ERROR(Is the %s distribution installed properly?)\n", module); + Printf(f_extra, " else\n"); + Printf(f_extra, " AC_MSG_RESULT(Library files $LIBNAME found in $LIBDIR)\n"); + Printf(f_extra, " PHP_ADD_LIBRARY_WITH_PATH($LIBNAME, $LIBDIR, %s_SHARED_LIBADD)\n", cap_module); + Printf(f_extra, " fi\n"); + Printf(f_extra, " done\n\n"); + } + + if (withincs) { // Find more than once include + Printf(f_extra, " for HNAME in $HNAMES ; do\n"); + Printf(f_extra, " INCDIR=\"\"\n"); + // For each path element to try... + Printf(f_extra, " for i in $PHP_%s $PHP_%s/include $PHP_%s/includes $PHP_%s/inc $PHP_%s/incs /usr/local/include /usr/include; do\n", cap_module, + cap_module, cap_module, cap_module, cap_module); + // Try and find header files + Printf(f_extra, " if test \"$HNAME\" != \"\" -a -r $i/$HNAME ; then\n"); + Printf(f_extra, " INCDIR=\"$i\"\n"); + Printf(f_extra, " break\n"); + Printf(f_extra, " fi\n"); + Printf(f_extra, " done\n\n"); + + Printf(f_extra, " dnl ** Now $INCDIR should be the include file path\n"); + Printf(f_extra, " if test \"$HNAME\" != \"\" -a -z \"$INCDIR\" ; then\n"); + Printf(f_extra, " AC_MSG_RESULT(Include files $HNAME not found)\n"); + Printf(f_extra, " AC_MSG_ERROR(Is the %s distribution installed properly?)\n", module); + Printf(f_extra, " else\n"); + Printf(f_extra, " AC_MSG_RESULT(Include files $HNAME found in $INCDIR)\n"); + Printf(f_extra, " PHP_ADD_INCLUDE($INCDIR)\n"); + Printf(f_extra, " fi\n\n"); + Printf(f_extra, " done\n\n"); + } + + if (CPlusPlus) { + Printf(f_extra, " # As this is a C++ module..\n"); + } + + Printf(f_extra, " PHP_REQUIRE_CXX\n"); + Printf(f_extra, " AC_CHECK_LIB(stdc++, cin)\n"); + + if (with) { + Printf(f_extra, " if test \"$LIBSYMBOL\" != \"\" ; then\n"); + Printf(f_extra, " old_LIBS=\"$LIBS\"\n"); + Printf(f_extra, " LIBS=\"$LIBS -L$TEST_DIR/lib -lm -ldl\"\n"); + Printf(f_extra, " AC_CHECK_LIB($LIBNAME, $LIBSYMBOL, [AC_DEFINE(HAVE_TESTLIB,1, [ ])],\n"); + Printf(f_extra, " [AC_MSG_ERROR(wrong test lib version or lib not found)])\n"); + Printf(f_extra, " LIBS=\"$old_LIBS\"\n"); + Printf(f_extra, " fi\n\n"); + } + + Printf(f_extra, " AC_DEFINE(HAVE_%s, 1, [ ])\n", cap_module); + Printf(f_extra, "dnl AC_DEFINE_UNQUOTED(PHP_%s_DIR, \"$%s_DIR\", [ ])\n", cap_module, cap_module); + Printf(f_extra, " PHP_EXTENSION(%s, $ext_shared)\n", module); + + // and thats all! + Printf(f_extra, "fi\n"); + + Close(f_extra); + + /* CREDITS */ + f_extra = NewFile(credits, "w"); + if (!f_extra) { + FileErrorDisplay(credits); + SWIG_exit(EXIT_FAILURE); + } + Printf(f_extra, "%s\n", module); + Close(f_extra); + } + + /* ------------------------------------------------------------ + * top() + * ------------------------------------------------------------ */ + + virtual int top(Node *n) { + + String *filen; + String *s_type; + + /* Initialize all of the output files */ + String *outfile = Getattr(n, "outfile"); + + /* main output file */ + f_runtime = NewFile(outfile, "w"); + if (!f_runtime) { + FileErrorDisplay(outfile); + SWIG_exit(EXIT_FAILURE); + } + + Swig_banner(f_runtime); + + /* 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"); + + /* Register file targets with the SWIG file handler */ + 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); + + /* Set the module name */ + module = Copy(Getattr(n, "name")); + cap_module = NewStringf("%(upper)s", module); + if (!prefix) + prefix = NewStringEmpty(); + + /* PHP module file */ + filen = NewStringEmpty(); + Printv(filen, SWIG_output_directory(), module, ".php", NIL); + phpfilename = NewString(filen); + + f_phpcode = NewFile(filen, "w"); + if (!f_phpcode) { + FileErrorDisplay(filen); + SWIG_exit(EXIT_FAILURE); + } + + Printf(f_phpcode, "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"); + + 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"); + + /* Create the .h file too */ + filen = NewStringEmpty(); + Printv(filen, SWIG_output_directory(), "php_", module, ".h", NIL); + f_h = NewFile(filen, "w"); + if (!f_h) { + FileErrorDisplay(filen); + SWIG_exit(EXIT_FAILURE); + } + + Swig_banner(f_h); + + Printf(f_h, "\n\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 */ + 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); + + if (gen_extra) { + Printf(s_init, "#ifdef COMPILE_DL_%s\n", cap_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"); + + if (gen_extra) { + 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. + */ + + Printf(s_header, "/* end header section */\n"); + Printf(s_wrappers, "/* end wrapper section */\n"); + Printf(s_vdecl, "/* end vdecl subsection */\n"); + + Printv(f_runtime, s_header, s_vdecl, s_wrappers, NIL); + Printv(f_runtime, all_cs_entry, "\n\n", s_entry, "{NULL, NULL, NULL}\n};\n\n", NIL); + Printv(f_runtime, s_init, NIL); + Delete(s_header); + Delete(s_wrappers); + Delete(s_init); + Delete(s_vdecl); + Delete(all_cs_entry); + Delete(s_entry); + Close(f_runtime); + + 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); + + if (gen_extra) { + create_extra_files(outfile); + } else if (gen_make) { + create_simple_make(); + } + + 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(); + 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(),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"); + + 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 or static member variables. + if (!overloaded && wrapperType != staticmembervar) { + 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 (num_arguments > 0) { + String *args = NewStringf("zval **args[%d]", num_arguments); + Wrapper_add_local(f, "args", args); + Delete(args); + args = NULL; + } + // 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"); + } + + /* 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 + + for (i = 0, p = l; i < num_arguments; 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"); + + 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); + } + + /* 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(SWIG_ErrorCode(),SWIG_ErrorMsg());", NIL); + + Printf(f->code, "}\n"); + + Replaceall(f->code, "$cleanup", cleanup); + Replaceall(f->code, "$symname", iname); + + Wrapper_print(f, s_wrappers); + + if (overloaded && !Getattr(n, "sym:nextSibling")) { + dispatchFunction(n); + } + + Delete(wname); + wname = NULL; + + if (!(shadow && php_version == 5)) { + DelWrapper(f); + 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); + } + } + } + // 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) { + 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 (newobject) { + class_has_ctor = true; + methodname = "__construct"; + } else if (wrapperType == memberfn) { + methodname = Char(Getattr(n, "memberfunctionHandler:sym:name")); + } else if (wrapperType == staticmemberfn) { + methodname = Char(Getattr(n, "staticmemberfunctionHandler: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"); + 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; + (void) strtol(Char(value), &p, 0); + if (errno || *p) { + Clear(value); + Append(value, "?"); + } + break; + } + case T_UCHAR: + case T_USHORT: + case T_UINT: + case T_ULONG: { + char *p; + errno = 0; + (void) strtoul(Char(value), &p, 0); + 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). + */ + Setattr(seen, "r", 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) + Printf(prepare, "$r="); + Printf(prepare, "%s(%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) + Printf(prepare, "$r="); + Printf(prepare, "%s(%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 || (newobject && current_class)) { + Printf(output, "\tfunction %s(%s) {\n", methodname, args); + // We don't need this code if the wrapped class has a copy ctor + // since the flat function new_CLASSNAME will handle it for us. + if (newobject && !Getattr(current_class, "allocate:copy_constructor")) { + SwigType *t = Getattr(current_class, "classtype"); + String *mangled_type = SwigType_manglestr(SwigType_ltype(t)); + Printf(s_oowrappers, "\t\tif (is_resource($%s) && get_resource_type($%s) == \"_p%s\") {\n", arg_names[0], arg_names[0], mangled_type); + Printf(s_oowrappers, "\t\t\t$this->%s=$%s;\n", SWIG_PTR, arg_names[0]); + Printf(s_oowrappers, "\t\t\treturn;\n"); + Printf(s_oowrappers, "\t\t}\n"); + } + } else { + Printf(output, "\tstatic function %s(%s) {\n", methodname, args); + } + Delete(args); + args = NULL; + + for (int i = 0; i < max_num_of_arguments; ++i) { + Delete(arg_names[i]); + } + free(arg_names); + arg_names = NULL; + + Printf(output, "%s", prepare); + if (newobject) { + Printf(output, "\t\t$this->%s=%s;\n", SWIG_PTR, invoke); + } 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) { + Printf(output, "\t\treturn is_resource($r) ? new %s%s($r) : $r;\n", prefix, Getattr(classLookup(d), "sym:name")); + } 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"); + Delete(prepare); + Delete(invoke); + free(arg_values); + } + + DelWrapper(f); + + 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 && php_version == 5) { + 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 ` + 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(php4) code="String" # Includes a string in the .php file + * %pragma(php4) include="file.pl" # 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, "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; + //SwigType *t = Getattr(n, "classtype"); + current_class = n; + // String *use_class_name=SwigType_manglestr(SwigType_ltype(t)); + + 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); + if (base.item) { + String *baseclass = Getattr(base.item, "sym:name"); + if (!baseclass) + baseclass = Getattr(base.item, "name"); + Printf(s_phpclasses, "extends %s%s ", prefix, baseclass); + } + Printf(s_phpclasses, "{\n\tpublic $%s=null;\n", SWIG_PTR); + + // Write property SET handlers + ki = First(shadow_set_vars); + + if (ki.key) { + // This class has setters. + // FIXME: just ignore setting an unknown property name for now. + 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)) call_user_func($func,$this->%s,$value);\n", SWIG_PTR); + } + 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"); + // FIXME: tune this threshold, but it should probably be different to + // that for __set() and __get() as we don't need to call_user_func() + // here... + if (Len(shadow_set_vars) == 1) { + // Only one setter, so just check the name. + Printf(s_phpclasses, "\t\treturn "); + while (ki.key) { + key = ki.key; + Printf(s_phpclasses, "$var == '%s'", ki.key); + ki = Next(ki); + if (ki.key) Printf(s_phpclasses, " || "); + } + Printf(s_phpclasses, ";\n"); + } else { + Printf(s_phpclasses, "\t\treturn function_exists('%s_'.$var.'_set');\n", shadow_classname); + } + 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: tune this threshold... + if (Len(shadow_get_vars) <= 2) { + // Not many getters, so avoid call_user_func. + while (ki.key) { + key = ki.key; + Printf(s_phpclasses, "\t\tif ($var == '%s') return %s($this->%s);\n", key, ki.item, SWIG_PTR); + ki = Next(ki); + } + } else { + Printf(s_phpclasses, "\t\t$func = '%s_'.$var.'_get';\n", shadow_classname); + Printf(s_phpclasses, "\t\tif (function_exists($func)) return call_user_func($func,$this->%s);\n", SWIG_PTR); + } + // Reading an unknown property name gives null in PHP. + Printf(s_phpclasses, "\t\treturn null;\n"); + 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; + this->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; + + SwigType *type = Getattr(n, "type"); + String *name = Getattr(n, "name"); + String *iname = Getattr(n, "sym:name"); + + /* A temporary(!) hack for static member variables. + * Php currently supports class functions, but not class variables. + * Until it does, we convert a class variable to a class function + * that returns the current value of the variable. E.g. + * + * class Example { + * public: + * static int ncount; + * }; + * + * would be available in php as Example::ncount() + */ + + // If the variable is const, then it's wrapped as a constant with set/get + // functions. + if (SwigType_isconst(type)) + return SWIG_OK; + + // This duplicates the logic from Language::variableWrapper() to test if + // the set wrapper is made. + int assignable = is_assignable(n); + if (assignable) { + String *tm = Swig_typemap_lookup("globalin", n, name, 0); + if (!tm && SwigType_isarray(type)) { + assignable = 0; + } + } + + String *class_iname = Swig_name_member(Getattr(current_class, "sym:name"), iname); + create_command(iname, Swig_name_wrapper(class_iname)); + + Wrapper *f = NewWrapper(); + + Printv(f->def, "ZEND_NAMED_FUNCTION(", Swig_name_wrapper(class_iname), ") {\n", NIL); + String *mget = Swig_name_wrapper(Swig_name_get(class_iname)); + String *mset = Swig_name_wrapper(Swig_name_set(class_iname)); + + if (assignable) { + Printf(f->code, "if (ZEND_NUM_ARGS() > 0 ) {\n"); + Printf(f->code, " %s( INTERNAL_FUNCTION_PARAM_PASSTHRU );\n", mset); + Printf(f->code, " // need some error checking here?\n"); + Printf(f->code, " // Set the argument count to 0 for the get call\n"); + Printf(f->code, " ht = 0;\n"); + Printf(f->code, "}\n"); + } + + Printf(f->code, "%s( INTERNAL_FUNCTION_PARAM_PASSTHRU );\n", mget); + Printf(f->code, "}\n"); + + Wrapper_print(f, s_wrappers); + + Delete(class_iname); + Delete(mget); + Delete(mset); + DelWrapper(f); + + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * staticmemberfunctionHandler() + * ------------------------------------------------------------ */ + + virtual int staticmemberfunctionHandler(Node *n) { + wrapperType = staticmemberfn; + Language::staticmemberfunctionHandler(n); + wrapperType = standard; + + return SWIG_OK; + } + + String * GetShadowReturnType(Node *n) { + SwigType *t = Getattr(n, "type"); + + /* Map type here */ + switch (SwigType_type(t)) { + case T_CHAR: + case T_SCHAR: + case T_UCHAR: + case T_SHORT: + case T_USHORT: + case T_INT: + case T_UINT: + case T_LONG: + case T_ULONG: + case T_FLOAT: + case T_DOUBLE: + case T_BOOL: + case T_STRING: + case T_VOID: + break; + case T_POINTER: + case T_REFERENCE: + case T_USER: + if (is_shadow(t)) { + return NewString(Char(is_shadow(t))); + } + break; + case T_ARRAY: + /* TODO */ + break; + default: + Printf(stderr, "GetShadowReturnType: unhandled data type: %s\n", SwigType_str(t, 0)); + break; + } + + return NewStringEmpty(); + } + + String *PhpTypeFromTypemap(char *op, Node *n, String_or_char *lname) { + String *tms = Swig_typemap_lookup(op, n, lname, 0); + if (!tms) + return 0; + else + return NewStringf("%s", tms); + } + + int abstractConstructorHandler(Node *) { + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * constructorHandler() + * ------------------------------------------------------------ */ + + virtual int constructorHandler(Node *n) { + constructors++; + 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); + + Printf(f->code, "}\n"); + + Wrapper_print(f, s_wrappers); + + return SWIG_OK; + + } + + /* ------------------------------------------------------------ + * memberconstantHandler() + * ------------------------------------------------------------ */ + + virtual int memberconstantHandler(Node *n) { + wrapping_member_constant = Getattr(n, "name"); + Language::memberconstantHandler(n); + wrapping_member_constant = NULL; + return SWIG_OK; + } + +}; /* class PHP */ + +/* ----------------------------------------------------------------------------- + * swig_php() - Instantiate module + * ----------------------------------------------------------------------------- */ + +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); +} + +static Language *new_swig_php(int php_version) { + maininstance = new PHP(php_version); + 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_php5(void) { + return new_swig_php(5); +} diff --git a/Source/Modules/php4.cxx b/Source/Modules/php5.cxx similarity index 100% rename from Source/Modules/php4.cxx rename to Source/Modules/php5.cxx