Index: Source/Modules/php4.cxx
===================================================================
RCS file: /cvsroot/swig/SWIG/Source/Modules/php4.cxx,v
retrieving revision 1.34
diff -p -u -r1.34 php4.cxx
--- Source/Modules/php4.cxx	20 Mar 2006 00:24:39 -0000	1.34
+++ Source/Modules/php4.cxx	1 May 2006 14:28:41 -0000
@@ -1,14 +1,27 @@
-/* ----------------------------------------------------------------------------- 
+/* -----------------------------------------------------------------------------
  * 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:
+ *
+ * Handle default parameters on overloaded methods in PHP where possible.
+ *   (Mostly done - just need to handle cases of overloaded methods with
+ *   default parameters...)
+ * Set and Get vars handlers.
+ * Option to generate code to work with PHP4 instead ("public $_cPtr;" ->
+ *   "var $_cPtr;", "abstract" -> "", no static class functions - but making
+ *   these changes gives a segfault with make check...)
+ */
 
 /*
- * TODO: Replace stderr messages with Swig_warning
+ * TODO: Replace remaining stderr messages with Swig_warning (need to add more
+ * WARN_XXX codes to be able to...)
  */
 
 char cvsroot_php4_cxx[] = "$Header: /cvsroot/swig/SWIG/Source/Modules/php4.cxx,v 1.34 2006/03/20 00:24:39 marcelomatus Exp $";
@@ -16,27 +29,37 @@ char cvsroot_php4_cxx[] = "$Header: /cvs
 #include "swigmod.h"
 
 #include <ctype.h>
-
+#include <errno.h>
 
 static const char *usage = (char*)"\
 PHP4 Options (available with -php4)\n\
      -cppext         - cpp file extension (default to .cpp)\n\
      -noproxy        - Don't generate proxy classes.\n\
      -dlname <name>  - Set module prefix to <name>\n\
+     -prefix <name>  - Set a prefix <name> to be prepended to all classnames\n\
      -make           - Create simple makefile\n\
      -phpfull        - Create full make files\n\
-     -withincs <libs>- With -phpfull writes needed incs in config.m4\n\
+     -withincs <incs>- With -phpfull writes needed incs in config.m4\n\
      -withlibs <libs>- With -phpfull writes needed libs in config.m4\n\
-     -withc <libs>   - With -phpfull makes extra c files in Makefile.in\n\
-     -withcxx <libs> - With -phpfull makes extra c++ files in Makefile.in\n\
+     -withc <files>  - With -phpfull makes extra C files in Makefile.in\n\
+     -withcxx <files>- 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 *dlname = 0;
+static String *prefix = 0;
 static String *withlibs = 0;
 static String *withincs = 0;
 static String *withc = 0;
@@ -68,9 +91,12 @@ 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 String     *class_name = 0;
+static Node       *current_class = 0;
 
 static Hash     *shadow_get_vars;
 static Hash     *shadow_set_vars;
@@ -79,7 +105,11 @@ static Hash     *shadow_set_vars;
 static int      native_constructor=0;
 static Hash     *zend_types = 0;
 
-static int        shadow        = 1;
+static int        shadow        = 0;
+static bool       new_shadow    = true;
+
+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 {
@@ -118,7 +148,6 @@ static const char *php_header =
 
 void
 SwigPHP_emit_resource_registrations() {
-  DOH *key;
   Iterator ki;
   String *destructor=0;
   String *classname=0;
@@ -129,9 +158,9 @@ SwigPHP_emit_resource_registrations() {
   ki = First(zend_types);
   if (ki.key) Printf(s_oinit,"\n/* Register resource destructors for pointer types */\n");
   while (ki.key) if (1 /* is pointer type*/) {
-    key = ki.key;
-    Node *class_node;
-    if ((class_node=Getattr(zend_types,key))) {
+    DOH *key = ki.key;
+    Node *class_node = ki.item;
+    if (class_node) { // FIXME: can't be NULL?
       // Write out destructor function header
       Printf(s_wrappers,"/* NEW Destructor style */\nstatic ZEND_RSRC_DTOR_FUNC(_wrap_destroy%s) {\n",key);
 
@@ -211,6 +240,15 @@ public:
           } else {
             Swig_arg_error();
           }
+	} 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]);
@@ -256,9 +294,10 @@ public:
           } else {
             Swig_arg_error();
           }
-        }  else if((strcmp(argv[i], "-noshadow") == 0)
-                   || (strcmp(argv[i],"-noproxy") == 0)) {
+        } else if((strcmp(argv[i], "-noshadow") == 0) ||
+                  (strcmp(argv[i], "-noproxy") == 0)) {
           shadow = 0;
+	  new_shadow = false;
           Swig_mark_arg(i);
         } else if(strcmp(argv[i], "-make") == 0) {
           gen_make = 1;
@@ -327,7 +366,7 @@ public:
     // are we a --with- or --enable-
     int with=(withincs || withlibs)?1:0;
     
-    // Note makefile.in only copes with one source file
+    // 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
     
@@ -354,24 +393,24 @@ public:
       
     }
     Printf(f_extra,"LTLIBRARY_SHARED_NAME   = php_%s.la\n", module);
-    Printf(f_extra,"LTLIBRARY_SHARED_LIBADD = $(%(upper)s_SHARED_LIBADD)\n\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,"  $(CXX_COMPILE) -c $<\n\n");
+    Printf(f_extra,"\t$(CXX_COMPILE) -c $<\n\n");
     
     Printf(f_extra,".cxx.lo:\n");
-    Printf(f_extra,"  $(CXX_PHP_COMPILE)\n\n");
+    Printf(f_extra,"\t$(CXX_PHP_COMPILE)\n\n");
     Printf(f_extra,".cxx.slo:\n");
     
-    Printf(f_extra,"  $(CXX_SHARED_COMPILE)\n\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,"  php -q -d extension_dir=modules %s\n\n",Swig_file_filename(phpfilename));
+    Printf(f_extra,"\tphp -q -d extension_dir=modules %s\n\n",Swig_file_filename(phpfilename));
     
     Close(f_extra);
       
@@ -426,16 +465,16 @@ public:
     }
     
     // Now write out tests to find thing.. they may need to extend tests
-    Printf(f_extra,"if test \"$PHP_%(upper)s\" != \"no\"; then\n\n",module);
+    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(%(upper)s_SHARED_LIBADD)\n\n",module);
+    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_%(upper)s $PHP_%(upper)s/lib /usr/lib /usr/local/lib ; do\n",module,module);
+      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");
@@ -447,7 +486,7 @@ public:
       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, %(upper)s_SHARED_LIBADD)\n",module);
+      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");
     }
@@ -456,7 +495,7 @@ public:
       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_%(upper)s $PHP_%(upper)s/include $PHP_%(upper)s/includes $PHP_%(upper)s/inc $PHP_%(upper)s/incs /usr/local/include /usr/include; do\n",module,module,module,module,module);
+      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");
@@ -492,8 +531,8 @@ public:
       Printf(f_extra,"  fi\n\n");
     }
     
-    Printf(f_extra,"  AC_DEFINE(HAVE_%(upper)s, 1, [ ])\n",module);
-    Printf(f_extra,"dnl  AC_DEFINE_UNQUOTED(PHP_%(upper)s_DIR, \"$%(upper)s_DIR\", [ ])\n",module,module);
+    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!
@@ -546,6 +585,7 @@ public:
     s_cinit = NewString("/* cinit subsection */\n");
     s_oinit = NewString("/* oinit subsection */\n");
     pragma_phpinfo = NewString("");
+    s_phpclasses = NewString("/* PHP Proxy Classes */\n");
     
     /* Register file targets with the SWIG file handler */
     Swig_register_filebyname("runtime",f_runtime);
@@ -559,13 +599,14 @@ public:
     /* Set the module name */
     module = Copy(Getattr(n,"name"));
     cap_module = NewStringf("%(upper)s",module);
-    
+    if (!prefix) prefix = Copy(module);
+
     /* Set the dlname */
     if (!dlname) {
 #if defined(_WIN32) || defined(__WIN32__)
-      dlname = NewStringf("php_%s.dll", module);
+      dlname = NewStringf("%s.dll", module);
 #else
-      dlname = NewStringf("php_%s.so", module);
+      dlname = NewStringf("%s.so", module);
 #endif
     }
     
@@ -584,15 +625,13 @@ public:
     
     Swig_banner(f_phpcode);
     
-    Printf(f_phpcode,"global $%s_LOADED__;\n", cap_module);
-    Printf(f_phpcode,"if ($%s_LOADED__) return;\n", cap_module);
-    Printf(f_phpcode,"$%s_LOADED__ = true;\n\n", cap_module);
-    Printf(f_phpcode,"/* if our extension has not been loaded, do what we can */\n");
-    Printf(f_phpcode,"if (!extension_loaded(\"php_%s\")) {\n", module);
+//    Printf(f_phpcode,"/* Check if this file has already been read in */\n");
+//    Printf(f_phpcode,"if (class_exists(\"%sSOMECLASS\") ) return;\n", prefix);
+    Printf(f_phpcode,"/* Try to load our extension if it isn't already loaded */\n");
+    Printf(f_phpcode,"if (!extension_loaded(\"%s\")) {\n", module);
     Printf(f_phpcode,"  if (!dl(\"%s\")) return;\n", dlname);
     Printf(f_phpcode,"}\n\n");
     
-    
     /* sub-sections of the php file */
     pragma_code = NewString("");
     pragma_incl = NewString("");
@@ -803,7 +842,16 @@ public:
     Delete(s_init);
     Delete(s_vdecl);
     Close(f_runtime);
-    Printf(f_phpcode, "%s\n%s\n?>\n", pragma_incl, pragma_code);
+
+    Printf(f_phpcode, "%s\n%s\n", pragma_incl, pragma_code);
+    if (s_fakeoowrappers) {
+      Printf(f_phpcode, "abstract class %s {", prefix);
+      Printf(f_phpcode, "%s", s_fakeoowrappers);
+      Printf(f_phpcode, "}\n\n", prefix);
+      Delete(s_fakeoowrappers);
+      s_fakeoowrappers = NULL;
+    }
+    Printf(f_phpcode, "%s\n?>\n", s_phpclasses);
     Close(f_phpcode); 
     
     if ( gen_extra ) {
@@ -821,9 +869,9 @@ public:
 */
 
   void create_command(String *cname, String *iname) {
-    
+
     Printf(f_h, "ZEND_NAMED_FUNCTION(%s);\n", iname);
-    
+
     // This is for the single main function_entry record
     if (cs_entry) {
       Printf(cs_entry," ZEND_NAMED_FE(%(lower)s,%s, NULL)\n", cname,iname );
@@ -892,6 +940,17 @@ public:
    * functionWrapper()
    * ------------------------------------------------------------ */
 
+  /* Helper method for PHP4::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");
@@ -963,7 +1022,7 @@ public:
     
     String *outarg = NewString("");
     String *cleanup = NewString("");
-    
+
     if (mvr) { // do prop[gs]et header
       if (mvrset) {
         Printf(f->def, "static int _wrap_%s(zend_property_reference *property_reference, pval *value) {\n",iname);
@@ -1027,7 +1086,7 @@ public:
     if (mvr && ! mvrset) {
       Wrapper_add_local(f, "_return_value", "zval _return_value");
       Wrapper_add_local(f, "return_value", "zval *return_value=&_return_value");
-    };
+    }
 
     if(numopt > 0) { // membervariable wrappers do not have optional args
       Wrapper_add_local(f, "arg_count", "int arg_count");
@@ -1048,13 +1107,13 @@ public:
     }
     
     /* Now convert from php to C variables */
-    // At this point, argcount if used is the number of deliberatly passed args
+    // 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
+    // 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 the and not the first argument
+    // _this and not the first argument.
     // This may mean looking at Lang::memberfunctionhandler
 
     for (i = 0, p = l; i < num_arguments; i++) {
@@ -1102,8 +1161,9 @@ public:
         }
         continue;
       } else {
-        Printf(stderr,"%s : Line %d, Unable to use type %s as a function argument.\n",
-               input_file, line_number, SwigType_str(pt,0));
+	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");
@@ -1196,8 +1256,9 @@ public:
         }
       } // end of if-shadow lark
     } else {
-      Printf(stderr,"%s: Line %d, Unable to use return type %s in function %s.\n",
-             input_file, line_number, SwigType_str(d,0), name);
+      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);
     }
     
     if(outarg) {
@@ -1208,7 +1269,7 @@ public:
       Printv(f->code,cleanup,NIL);
     }
     
-    // Whats this bit for?
+    // What's this bit for?
     if((tm = Swig_typemap_lookup_new("ret",n,"result",0))) {
       Printf(f->code,"%s\n", tm);
     }
@@ -1244,6 +1305,503 @@ public:
       dispatchFunction(n);
     }
 
+    // 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) {
+      if (!s_oowrappers) s_oowrappers = NewString("");
+      if (newobject || wrapperType == memberfn || wrapperType == staticmemberfn || wrapperType == standard) {
+	bool handle_as_overload = false;
+	String ** arg_names;
+	String ** arg_values;
+	bool * arg_case = NULL;
+	// Method or static method or plain function.
+	String * methodname = 0;
+	String * output;
+	if (newobject) {
+	  output = s_oowrappers;
+	  class_has_ctor = true;
+	  methodname = NewString("__construct");
+	} else if (wrapperType != standard) {
+	  output = s_oowrappers;
+	  const char *p = strchr(Char(iname), '_');
+	  if (!p) {
+	    Printf(output, "\n/* Skipping method %s because it doesn't have an underscore in */\n", iname);
+	    goto dont_wrap;
+	  }
+	  methodname = NewString(p + 1);
+	} else {
+	  methodname = NewString(iname);
+	  if (!s_fakeoowrappers) s_fakeoowrappers = NewString("");
+	  output = s_fakeoowrappers;
+	}
+
+	// FIXME: this check is (a) Xapian specific and (b) should be handled
+	// in a more useful way elsewhere (by automatic renaming probably).
+	if (strcmp(Char(methodname), "empty") == 0 ||
+	  strcmp(Char(methodname), "clone") == 0) {
+	  Printf(output, "\n/* Skipping method %s because it's a PHP reserved word */\n", methodname);
+	  goto dont_wrap;
+	}
+
+	bool really_overloaded = overloaded;
+	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 0
+	if (Cmp(iname, "new_Document") == 0) {
+	  Printf(stdout, "%s: n=%p\n", iname, (void*)n);
+	  Node * o = Getattr(n, "sym:overloaded");
+	  while (o) {
+	    Printf(stdout, " %s: %p", Getattr(o, "sym:overname"), (void*)o);
+	    ParmList *l2 = Getattr(o, "wrap:parms");
+	    int num_arguments = emit_num_arguments(l2);
+	    int num_required  = emit_num_required(l2);
+	    Printf(stdout, " %d-%d\n", num_arguments, num_required);
+	    for (Parm *p = l2; p; p = nextSibling(p)) {
+	      /* FIXME: strtod is locale dependent... */
+	      String *pname = Getattr(p, "name");
+	      String *pval = Getattr(p, "value");
+	      if (pval) {
+		Printf(stdout, "  %s=%s\n", pname, pval);
+	      } else {
+		Printf(stdout, "  %s\n", pname);
+	      }
+	    }
+	    o = Getattr(o,"sym:nextSibling");
+	  }
+	}
+#endif
+
+	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;
+		// FIXME: check that value is valid in PHP.
+	      }
+	      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);
+	    }
+	  }
+
+	  arg_case = (bool*)malloc(max_num_of_arguments * sizeof(bool));
+	  if (!arg_case) {
+	    /* 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 (int i = 0; i < max_num_of_arguments; ++i) {
+	    arg_case[i] = false;
+	  }
+
+	  o = Getattr(n, "sym:overloaded");
+	  while (o) {
+	    ParmList *l2 = Getattr(o,"wrap:parms");
+	    int num_arguments = emit_num_arguments(l2);
+	    int num_required  = emit_num_required(l2);
+	    if (wrapperType == memberfn) {
+	      --num_arguments;
+	      --num_required;
+	    }
+	    for (int i = num_required; i <= num_arguments; ++i) {
+	      arg_case[i] = true;
+	    }
+	    o = Getattr(o,"sym:nextSibling");
+	  }
+	}
+
+	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 (int 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 (int 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) {
+	    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);
+	      }
+	    }
+	    const char *value = GetChar(p,"value");
+	    if (value) {
+	      /* Check that value is a valid constant in PHP (and adjust it if
+	       * necessary, or replace it with "?" is 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);
+		  if (errno || *p)
+		    value = "?";
+		  else if (n)
+		    value = "true";
+		  else
+		    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) 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) value = "?";
+		  break;
+		}
+		case T_FLOAT:
+		case T_DOUBLE: {
+		  char *p;
+		  errno = 0;
+		  /* FIXME: strtod is locale dependent... */
+		  (void)strtod(Char(value), &p);
+		  if (errno || *p) value = "?";
+		  break;
+		}
+		case T_REFERENCE:
+		case T_USER:
+		case T_ARRAY:
+		case T_STRING: /* FIXME: Check and adjust valid strings. */
+		  value = "?";
+		  break;
+		case T_VOID:
+		  assert(false);
+		  break;
+		case T_POINTER:
+		  /* FIXME: also handle "(void*)0", "(TYPE*)0", etc. */
+		  if (strcmp(value, "0") == 0 || strcmp(value, "NULL") == 0) {
+		    value = "null";
+		  }
+		  break;
+	      }
+
+	      if (!arg_values[argno]) {
+		arg_values[argno] = NewString(value);
+	      } 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("?");
+	      }
+	    }
+	    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 and even later PHP4
+	 * versions apparently, 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 = NewString("");
+	    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;
+
+#if 0
+	for (int argno = 0; argno < max_num_of_arguments; ++argno) {
+	  Printf(stdout, "%s %d : %s\n", iname, argno, arg_names[argno]);
+	}
+#endif
+
+	String * invoke = NewString("");
+	String * prepare = NewString("");
+	String * args = NewString("");
+
+	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) {
+	      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 = NewString("");
+	  if (wrapperType == memberfn) {
+	    Printf(invoke_args, "$this->%s", SWIG_PTR);
+	    if (min_num_of_arguments > 0) Printf(invoke_args, ",");
+	  }
+	  Printf(invoke_args, "%s", args);
+	  Printf(prepare, "\t\tswitch (func_num_args()) {\n");
+	  for ( ; i < max_num_of_arguments; ++i) {
+	    if (i) Printf(args, ",");
+	    const char *value = Char(arg_values[i]);
+	    if (!value || arg_case[i]) value = "null";
+	    /* FIXME: If we use a default value here, merge switch cases. */
+	    //if (!value || strcmp(value, "?") == 0) value = "null";
+	    Printf(args, "$%s=%s", arg_names[i], value);
+	    if (arg_case[i]) {
+	      Printf(prepare, "\t\tcase %d: ", 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\tdefault: ");
+	  if (Cmp(d, "void") != 0) Printf(prepare, "$r=");
+	  Printf(prepare, "%s(%s);\n", iname, invoke_args);
+	  Printf(prepare, "\t\t}\n");
+	  Delete(invoke_args);
+	  Printf(invoke, "$r");
+	}
+
+	Printf(output, "\n");
+	if (wrapperType == memberfn || newobject) {
+	  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 (i.item) {
+		Printf(output, "case \"%s\": ", mangled);
+	      } else {
+		Printf(output, "default: ", mangled);
+	      }
+	      const char * classname = GetChar(class_node, "sym:name");
+	      if (!classname) classname = GetChar(class_node, "name");
+	      Printf(output, "return new %s%s($r);\n", prefix, classname);
+	      Delete(mangled);
+	    }
+	    Printf(output, "\t\t}\n");
+	  }
+	} else {
+	  Printf(output, "\t\treturn %s;\n", invoke);
+	}
+	Printf(output, "\t}\n");
+	Delete(prepare);
+	Delete(invoke);
+dont_wrap:
+	Delete(methodname);
+	methodname = 0;
+      }
+    }
+
     return SWIG_OK;
   }
   
@@ -1330,6 +1888,17 @@ public:
       Replaceall(tm, "$value", value);
       Printf(s_cinit, "%s\n", tm);
     }
+
+    if (new_shadow) {
+      if (wrapping_member_constant) {
+	if (!s_oowrappers) s_oowrappers = NewString("");
+	Printf(s_oowrappers, "\n\tconst %s = %s;\n", wrapping_member_constant, iname);
+      } else {
+	if (!s_fakeoowrappers) s_fakeoowrappers = NewString("");
+	Printf(s_fakeoowrappers, "\n\tconst %s = %s;\n", name, iname);
+      }
+    }
+
     return SWIG_OK;
   }
 
@@ -1391,7 +1960,7 @@ public:
   virtual int classHandler(Node *n) {
     constructors=0;
     //SwigType *t = Getattr(n, "classtype");
-    class_name = Getattr(n, "sym:name");
+    current_class = n;
     // String *use_class_name=SwigType_manglestr(SwigType_ltype(t));
 
     if(shadow) {
@@ -1438,6 +2007,43 @@ public:
       /* Write out class init code */
       Printf(s_vdecl,"static zend_class_entry ce_swig_%s;\n",shadow_classname);
       Printf(s_vdecl,"static zend_class_entry* ptr_ce_swig_%s=NULL;\n",shadow_classname);
+    } else if (new_shadow) {
+      char *rename = GetChar(n, "sym:name");
+
+      if (!addSymbol(rename,n)) return SWIG_ERROR;
+      shadow_classname = Swig_copy_string(rename);
+
+//      if(Strcmp(shadow_classname, module) == 0) {
+//        Printf(stderr, "class name cannot be equal to module name: %s\n", shadow_classname);
+//        SWIG_exit(1);
+//      }
+//
+//      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_PHP4_MULTIPLE_INHERITANCE, input_file, line_number, 
+		"Warning for %s proxy: Base %s ignored. Multiple inheritance is not supported in Php4.\n", proxyclassname, baseclassname);
+	    base = Next(base);
+	  }
+	}
+      }
     }
 
     classnode=n;
@@ -1535,7 +2141,7 @@ public:
         Printf(s_propset," else");
       }
 
-      // If there is a base class then chain it's handler else set directly
+      // If there is a base class then chain its handler else set directly
       // try each base class handler, else set directly...
       if (base.item) {
         Printf(s_propset,  "  {\n    /* chain to base class */\n");
@@ -1626,7 +2232,7 @@ public:
         Printf(s_propget," else");
       }
 
-      // If there is a base class then chain it's handler else return null
+      // If there is a base class then chain its handler else return null
       if (base.item) {
         Printf(s_propget,  "  {\n    /* chain to base class */\n");
         while(base.item) {
@@ -1669,7 +2275,7 @@ public:
       Printf(s_oinit,"\n");
 
       // Write the enum initialisation code in a static block
-      // These are all the enums defined withing the c++ class.
+      // These are all the enums defined within the C++ class.
       
 
       free(shadow_classname);
@@ -1681,6 +2287,106 @@ public:
       Printf(all_cs_entry,"%s   { NULL, NULL, NULL}\n};\n",cs_entry);
       //??delete cs_entry;
       cs_entry=NULL;
+    } else if (new_shadow) {
+      DOH *key;
+      int gcount, scount;
+      String      *s_propget=NewString("");
+      String      *s_propset=NewString("");
+      List *baselist = Getattr(n, "bases");
+      Iterator ki, base;
+
+
+      // If no constructor was generated (abstract class) we had better
+      // generate a constructor that raises an error about instantiating
+      // abstract classes
+//      if (Getattr(n,"abstract") && constructors==0 ) {
+//        // have to write out fake constructor which raises an error when called
+//        abstractConstructorHandler(n);
+//      }
+
+#if 0
+      // ******** Write property SET handlers
+      Printf(s_header,"static int _wrap_propset_%s(zend_property_reference *property_reference, pval *value);\n",
+             shadow_classname);
+      Printf(s_header,"static int _propset_%s(zend_property_reference *property_reference, pval *value);\n",
+             shadow_classname);
+
+      Printf(s_propset,"static int _wrap_propset_%s(zend_property_reference *property_reference, pval *value) { \n",
+             shadow_classname);
+      Printf(s_propset,"  zval * _value;\n");
+      Printf(s_propset,"  zend_llist_element *element = property_reference->elements_list->head;\n");
+      Printf(s_propset,"  zend_overloaded_element *property=(zend_overloaded_element *)element->data;\n");
+      Printf(s_propset,"  if (_propset_%s(property_reference, value)==SUCCESS) return SUCCESS;\n", shadow_classname);
+      Printf(s_propset,"  /* set it ourselves as it is %s */\n",shadow_classname);
+      Printf(s_propset,"  MAKE_STD_ZVAL(_value);\n");
+      Printf(s_propset,"  *_value=*value;\n");
+      Printf(s_propset,"  INIT_PZVAL(_value);\n");
+      Printf(s_propset,"  zval_copy_ctor(_value);\n");
+      Printf(s_propset,"  return add_property_zval_ex(property_reference->object,Z_STRVAL_P(&(property->element)),1+Z_STRLEN_P(&(property->element)),_value);\n");
+      Printf(s_propset,"}\n");
+      Printf(s_propset,"static int _propset_%s(zend_property_reference *property_reference, pval *value) {\n",
+             shadow_classname);
+#endif
+
+      if (baselist) {
+        base=First(baselist);
+      }
+      else {
+        base.item = NULL;
+      }
+
+      while(base.item && GetFlag(base.item,"feature:ignore")) {
+        base = Next(base);
+      }
+
+      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);
+
+      while (ki.key) {
+        key = ki.key;
+        Printf(s_phpclasses, "\t/* FIXME: property setters for %s (key %s) needs emitting */\n", Getattr(shadow_set_vars,key), key);
+
+        ki=Next(ki);
+      }
+
+      // Write property GET handlers
+      ki = First(shadow_get_vars);
+
+      while (ki.key) {
+        key = ki.key;
+        Printf(s_phpclasses, "\t/* FIXME: property setters for %s (key %s) needs emitting */\n", Getattr(shadow_get_vars,key), key);
+
+        ki=Next(ki);
+      }
+
+      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");
+
+      free(shadow_classname);
+      shadow_classname = NULL;
+
+      Delete(shadow_set_vars); shadow_set_vars = NULL;
+      Delete(shadow_get_vars); shadow_get_vars = NULL;
     }
     return SWIG_OK;
   }
@@ -1762,7 +2468,7 @@ public:
       }
     }
 
-    String *class_iname = Swig_name_member(class_name,iname);
+    String *class_iname = Swig_name_member(Getattr(current_class, "sym:name"),iname);
     create_command( iname, Swig_name_wrapper(class_iname) );
 
     Wrapper *f = NewWrapper();
@@ -1800,7 +2506,9 @@ public:
     char *name = GetChar(n, "name");
     char *iname = GetChar(n, "sym:name");
     
+    wrapperType = staticmemberfn;
     Language::staticmemberfunctionHandler(n);
+    wrapperType = standard;
     
     if(shadow) {
       String *symname = Getattr(n, "sym:name");
@@ -1996,7 +2704,9 @@ public:
    * ------------------------------------------------------------ */
 
   virtual int memberconstantHandler(Node *n) {
+    wrapping_member_constant = Getattr(n, "name");
     Language::memberconstantHandler(n);
+    wrapping_member_constant = NULL;
     return SWIG_OK;
   }
 
@@ -2045,5 +2755,3 @@ static Language * new_swig_php() {
 extern "C" Language * swig_php(void) {
   return new_swig_php();
 }
- 
-
