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	17 Apr 2006 03:48:04 -0000
@@ -23,6 +23,7 @@ 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\
@@ -37,6 +38,7 @@ 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,6 +70,9 @@ 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;
@@ -79,7 +84,10 @@ 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;
 
 // These static variables are used to pass some state from Handlers into functionWrapper
 static enum {
@@ -211,6 +219,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]);
@@ -259,6 +276,7 @@ public:
         }  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;
@@ -546,6 +564,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 +578,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
     }
     
@@ -588,7 +608,7 @@ public:
     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,"if (!extension_loaded(\"%s\")) {\n", module);
     Printf(f_phpcode,"  if (!dl(\"%s\")) return;\n", dlname);
     Printf(f_phpcode,"}\n\n");
     
@@ -803,7 +823,34 @@ public:
     Delete(s_init);
     Delete(s_vdecl);
     Close(f_runtime);
-    Printf(f_phpcode, "%s\n%s\n?>\n", pragma_incl, pragma_code);
+
+    Printf(pragma_code, "function swig_coerce_param(&$value, $index) {\n");
+    Printf(pragma_code, "\tif (is_a($value, \"%sSwigBase\")) $value=$value->swig_ptr;\n", prefix);
+    Printf(pragma_code, "}\n\n");
+
+    Printf(pragma_code, "function swig_wrap_return($res) {\n");
+    Printf(pragma_code, "\tif (is_resource($res)) {\n");
+    Printf(pragma_code, "\t\t$type=explode('_', get_resource_type($res));\n");
+    Printf(pragma_code, "\t\tif (count($type) >= 5 && $type[2] == 'Xapian') {\n");
+    Printf(pragma_code, "\t\t\t$class='Xapian'.$type[4];\n");
+    Printf(pragma_code, "\t\t\treturn new $class($res);\n");
+    Printf(pragma_code, "\t\t}\n");
+    Printf(pragma_code, "\t}\n");
+    Printf(pragma_code, "\treturn $res;\n");
+    Printf(pragma_code, "}\n\n");
+
+    Printf(pragma_code, "abstract class %sSwigBase {\n", prefix);
+    Printf(pragma_code, "}\n\n");
+
+    Printf(f_phpcode, "%s\n%s\n", pragma_incl, pragma_code);
+    if (s_fakeoowrappers) {
+      Printf(f_phpcode, "abstract class %s {\n", 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 +868,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 +939,48 @@ 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;
+  }
+
+  /* Helper method for PHP4::functionWrapper */
+  bool parmlist_needs_coercing(ParmList *p, bool * p_has_args) {
+    if (wrapperType == memberfn) {
+      // For a non-static member function, the argument list includes
+      // the "this" pointer, so skip over it.
+      if (p) p = nextSibling(p);
+    }
+    if (p_has_args) *p_has_args = false;
+    while (p) {
+      if (!HashGetAttr(p,k_ignore)) {
+	if (p_has_args) *p_has_args = true;
+	SwigType *t = HashGetAttr(p,k_type);
+	t = SwigType_typedef_resolve_all(t);
+	while (!SwigType_issimple(t)) {
+	  if (SwigType_isclass(t)) break;
+
+	  if (SwigType_isreference(t)) {
+	    t = SwigType_del_reference(t);
+	  } else if (SwigType_ispointer(t)) {
+	    t = SwigType_del_pointer(t);
+	  } else if (SwigType_isarray(t)) {
+	    t = SwigType_del_array(t);
+	  }
+	}
+	if (is_class(t)) return true;
+      }
+      p = nextSibling(p);
+    }
+    return false;
+  }
+
   virtual int functionWrapper(Node *n) {
     String   *name  = GetChar(n,"name");
     String   *iname = GetChar(n,"sym:name");
@@ -963,7 +1052,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 +1116,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 +1137,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++) {
@@ -1244,6 +1333,118 @@ 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) {
+      String * classname = shadow_classname;
+      if (!s_oowrappers) s_oowrappers = NewString("");
+      if (newobject) class_has_ctor = true;
+      if (newobject || wrapperType == memberfn || wrapperType == staticmemberfn || wrapperType == standard) {
+	  // Method or static method or plain function.
+	  String * methodname = 0;
+	  String * args = 0;
+	  String * output;
+	  if (newobject) {
+	    methodname = NewString("__construct");
+	    args = NewString("$h=null");
+	    output = s_oowrappers;
+	  } else if (wrapperType != standard) {
+	    const char *p = strchr(Char(iname), '_');
+	    if (p) methodname = NewString(p + 1);
+	    output = s_oowrappers;
+	  } else {
+	    methodname = NewString(iname);
+	    if (!s_fakeoowrappers) s_fakeoowrappers = NewString("");
+	    output = s_fakeoowrappers;
+	  }
+
+	  if (!methodname) {
+	    Printf(output, "\n/* Skipping method %s because it doesn't have an underscore in */\n", iname);
+	  } else 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);
+	  } else {
+	    if (!args) args = NewString("");
+
+	    Printf(output, "\n");
+	    if (wrapperType == memberfn || newobject) {
+	      Printf(output, "\tpublic function %s(%s) {\n", methodname, args);
+	      if (newobject) {
+		Printf(s_oowrappers, "\t\tif (is_resource($h) && get_resource_type($h) == \"_p_%s__%s\") {\n", module, classname);
+		Printf(s_oowrappers, "\t\t\t$this->swig_ptr=$h;\n");
+		Printf(s_oowrappers, "\t\t\treturn;\n");
+		Printf(s_oowrappers, "\t\t}\n");
+	      }
+	    } else {
+	      Printf(output, "\tpublic static function %s(%s) {\n", methodname, args);
+	    }
+	    Delete(args);
+	    args = NULL;
+
+	    String * invoke = NewString("");
+
+	    bool need_to_coerce = false;
+
+	    bool has_args = false;
+	    if (overloaded) {
+	      has_args = true;
+	      Node *c = Getattr(n,"sym:overloaded");
+	      while (c) {
+		if (Getattr(c,"error")) {
+		  c = Getattr(c,"sym:nextSibling");
+		  continue;
+		}
+
+		if (Getattr(c,"wrap:name")) {
+		  ParmList *p = Getattr(c,"wrap:parms");
+		  if (parmlist_needs_coercing(p, NULL)) {
+		    need_to_coerce = true;
+		    break;
+		  }
+		}
+		c = Getattr(c,"sym:nextSibling");
+	      }
+	    } else {
+	      need_to_coerce = parmlist_needs_coercing(l, &has_args);
+	    }
+	    if (newobject && !overloaded && num_required == 1 && num_arguments == 1) {
+	      // The constructor only has one form which takes a single argument.
+	      // (FIXME what about overloads which all take a single argument?)
+	      if (need_to_coerce)
+		Printf(output, "\t\tswig_coerce_param($h,0);\n");
+	      Printf(invoke, "%s($h)", iname);
+	    } else if (has_args || overloaded) {
+	      Printf(output, "\t\t$a=func_get_args();\n");
+	      if (need_to_coerce)
+		Printf(output, "\t\tarray_walk_recursive($a,'swig_coerce_param');\n");
+	      if (wrapperType == memberfn)
+		Printf(output, "\t\tarray_unshift($a,$this->swig_ptr);\n");
+	      Printf(invoke, "call_user_func_array('%s',$a)", iname);
+	    } else {
+	      // No argument list and not overloaded, so no parameters to coerce.
+	      if (wrapperType == memberfn)
+		Printf(invoke, "%s($this->swig_ptr)", iname);
+	      else
+		Printf(invoke, "%s()", iname);
+	    }
+	    if (newobject) {
+	      Printf(output, "\t\t$this->swig_ptr=%s;\n", invoke);
+	    } else if (Cmp(d, "void") == 0) {
+	      Printf(output, "\t\t%s;\n", invoke);
+	    } else if (is_class(d)) {
+	      Printf(output, "\t\treturn swig_wrap_return(%s);\n", invoke);
+	    } else {
+	      Printf(output, "\t\treturn %s;\n", invoke);
+	    }
+	    Printf(output, "\t}\n");
+	    Delete(invoke);
+	  }
+	  Delete(methodname);
+	  methodname = 0;
+      }
+    }
+
     return SWIG_OK;
   }
   
@@ -1438,6 +1639,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 +1773,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 +1864,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) {
@@ -1681,6 +1919,111 @@ 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);
+      }
+
+      String *baseclass = 0;
+      if (base.item) {
+	baseclass = Swig_copy_string(GetChar(base.item, "sym:name"));
+      } else {
+	baseclass = NewString("SwigBase");
+      }
+      Printf(s_phpclasses, "class %s%s extends %s%s {\n", prefix, shadow_classname, prefix, baseclass);
+      Printf(s_phpclasses, "\tpublic $swig_ptr=null;\n");
+
+      // 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);
+      }
+
+      // Write the enum initialisation code in a static block
+      // These are all the enums defined within the C++ class.
+      // FIXME: ...
+
+      if (!class_has_ctor) {
+	Printf(s_phpclasses, "\tpublic function __construct($h=null) {\n");
+	Printf(s_phpclasses, "\t\t$this->swig_ptr=$h;\n");
+	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;
   }
@@ -1800,7 +2143,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");
