1/* -----------------------------------------------------------------------------
2 * See the LICENSE file for information on copyright, usage and redistribution
3 * of SWIG, and the README file for authors - http://www.swig.org/release.html.
4 *
5 * php.cxx
6 *
7 * PHP language module for SWIG.
8 * -----------------------------------------------------------------------------
9 */
10
11/* FIXME: PHP5 OO wrapping TODO list:
12 *
13 * Medium term:
14 *
15 * Handle default parameters on overloaded methods in PHP where possible.
16 *   (Mostly done - just need to handle cases of overloaded methods with
17 *   default parameters...)
18 *   This is an optimisation - we could handle this case using a PHP
19 *   default value, but currently we treat it as we would for a default
20 *   value which is a compound C++ expression (i.e. as if we had a
21 *   method with two overloaded forms instead of a single method with
22 *   a default parameter value).
23 *
24 * Long term:
25 *
26 * Sort out locale-dependent behaviour of strtod() - it's harmless unless
27 *   SWIG ever sets the locale and DOH/base.c calls atof, so we're probably
28 *   OK currently at least.
29 */
30
31/*
32 * TODO: Replace remaining stderr messages with Swig_error or Swig_warning
33 * (may need to add more WARN_PHP_xxx codes...)
34 */
35
36char cvsroot_php_cxx[] = "$Id: php.cxx 11637 2009-08-18 16:23:23Z vmiklos $";
37
38#include "swigmod.h"
39
40#include <ctype.h>
41#include <errno.h>
42
43static const char *usage = (char *) "\
44PHP Options (available with -php)\n\
45     -cppext          - cpp file extension (default to .cpp)\n\
46     -noproxy         - Don't generate proxy classes.\n\
47     -prefix <prefix> - Prepend <prefix> to all class names in PHP wrappers\n\
48\n";
49
50/* The original class wrappers for PHP stored the pointer to the C++ class in
51 * the object property _cPtr.  If we use the same name for the member variable
52 * which we put the pointer to the C++ class in, then the flat function
53 * wrappers will automatically pull it out without any changes being required.
54 * FIXME: Isn't using a leading underscore a bit suspect here?
55 */
56#define SWIG_PTR "_cPtr"
57
58/* This is the name of the hash where the variables existing only in PHP
59 * classes are stored.
60 */
61#define SWIG_DATA "_pData"
62
63static int constructors = 0;
64static String *NOTCLASS = NewString("Not a class");
65static Node *classnode = 0;
66static String *module = 0;
67static String *cap_module = 0;
68static String *prefix = 0;
69
70static String *shadow_classname = 0;
71
72static File *f_begin = 0;
73static File *f_runtime = 0;
74static File *f_runtime_h = 0;
75static File *f_h = 0;
76static File *f_phpcode = 0;
77static File *f_directors = 0;
78static File *f_directors_h = 0;
79static String *phpfilename = 0;
80
81static String *s_header;
82static String *s_wrappers;
83static String *s_init;
84static String *r_init;		// RINIT user code
85static String *s_shutdown;	// MSHUTDOWN user code
86static String *r_shutdown;	// RSHUTDOWN user code
87static String *s_vinit;		// varinit initialization code.
88static String *s_vdecl;
89static String *s_cinit;		// consttab initialization code.
90static String *s_oinit;
91static String *s_entry;
92static String *cs_entry;
93static String *all_cs_entry;
94static String *pragma_incl;
95static String *pragma_code;
96static String *pragma_phpinfo;
97static String *s_oowrappers;
98static String *s_fakeoowrappers;
99static String *s_phpclasses;
100
101/* Variables for using PHP classes */
102static Node *current_class = 0;
103
104static Hash *shadow_get_vars;
105static Hash *shadow_set_vars;
106static Hash *zend_types = 0;
107
108static int shadow = 1;
109
110static bool class_has_ctor = false;
111static String *wrapping_member_constant = NULL;
112
113// These static variables are used to pass some state from Handlers into functionWrapper
114static enum {
115  standard = 0,
116  memberfn,
117  staticmemberfn,
118  membervar,
119  staticmembervar,
120  constructor,
121  directorconstructor
122} wrapperType = standard;
123
124extern "C" {
125  static void (*r_prevtracefunc) (SwigType *t, String *mangled, String *clientdata) = 0;
126}
127
128static void SwigPHP_emit_resource_registrations() {
129  Iterator ki;
130
131  if (!zend_types)
132    return;
133
134  ki = First(zend_types);
135  if (ki.key)
136    Printf(s_oinit, "\n/* Register resource destructors for pointer types */\n");
137  while (ki.key) {
138    DOH *key = ki.key;
139    Node *class_node = ki.item;
140    String *human_name = key;
141
142    // Write out destructor function header
143    Printf(s_wrappers, "static ZEND_RSRC_DTOR_FUNC(_wrap_destroy%s) {\n", key);
144
145    // write out body
146    if (class_node != NOTCLASS) {
147      String *destructor = Getattr(class_node, "destructor");
148      human_name = Getattr(class_node, "sym:name");
149      if (!human_name)
150        human_name = Getattr(class_node, "name");
151      // Do we have a known destructor for this type?
152      if (destructor) {
153        Printf(s_wrappers, "  %s(rsrc, SWIGTYPE%s->name TSRMLS_CC);\n", destructor, key);
154      } else {
155        Printf(s_wrappers, "  /* No destructor for class %s */\n", human_name);
156        Printf(s_wrappers, "  efree(rsrc->ptr);\n");
157      }
158    } else {
159      Printf(s_wrappers, "  /* No destructor for simple type %s */\n", key);
160      Printf(s_wrappers, "  efree(rsrc->ptr);\n");
161    }
162
163    // close function
164    Printf(s_wrappers, "}\n");
165
166    // declare le_swig_<mangled> to store php registration
167    Printf(s_vdecl, "static int le_swig_%s=0; /* handle for %s */\n", key, human_name);
168
169    // register with php
170    Printf(s_oinit, "le_swig_%s=zend_register_list_destructors_ex"
171		    "(_wrap_destroy%s,NULL,(char *)(SWIGTYPE%s->name),module_number);\n", key, key, key);
172
173    // store php type in class struct
174    Printf(s_oinit, "SWIG_TypeClientData(SWIGTYPE%s,&le_swig_%s);\n", key, key);
175
176    ki = Next(ki);
177  }
178}
179
180class PHP : public Language {
181public:
182  PHP() {
183    director_language = 1;
184  }
185
186  /* ------------------------------------------------------------
187   * main()
188   * ------------------------------------------------------------ */
189
190  virtual void main(int argc, char *argv[]) {
191    SWIG_library_directory("php");
192    SWIG_config_cppext("cpp");
193
194    for (int i = 1; i < argc; i++) {
195      if (strcmp(argv[i], "-prefix") == 0) {
196	if (argv[i + 1]) {
197	  prefix = NewString(argv[i + 1]);
198	  Swig_mark_arg(i);
199	  Swig_mark_arg(i + 1);
200	  i++;
201	} else {
202	  Swig_arg_error();
203	}
204      } else if (strcmp(argv[i], "-cppext") == 0) {
205	if (argv[i + 1]) {
206	  SWIG_config_cppext(argv[i + 1]);
207	  Swig_mark_arg(i);
208	  Swig_mark_arg(i + 1);
209	  i++;
210	} else {
211	  Swig_arg_error();
212	}
213      } else if ((strcmp(argv[i], "-noshadow") == 0) || (strcmp(argv[i], "-noproxy") == 0)) {
214	shadow = 0;
215	Swig_mark_arg(i);
216      } else if (strcmp(argv[i], "-help") == 0) {
217	fputs(usage, stdout);
218      } else if (strcmp(argv[i], "-make") == 0 ||
219		 strcmp(argv[i], "-withc") == 0 ||
220		 strcmp(argv[i], "-withcxx") == 0) {
221	Printf(stderr, "*** %s is no longer supported.\n", argv[i]);
222	SWIG_exit(EXIT_FAILURE);
223      } else if (strcmp(argv[i], "-phpfull") == 0 ||
224		 strcmp(argv[i], "-withlibs") == 0 ||
225		 strcmp(argv[i], "-withincs") == 0) {
226	Printf(stderr, "*** %s is no longer supported.\n*** We recommend building as a dynamically loadable module.\n", argv[i]);
227	SWIG_exit(EXIT_FAILURE);
228      } else if (strcmp(argv[i], "-dlname") == 0) {
229	Printf(stderr, "*** -dlname is no longer supported.\n*** If you want to change the module name, use -module instead.\n");
230	SWIG_exit(EXIT_FAILURE);
231      }
232    }
233
234    Preprocessor_define("SWIGPHP 1", 0);
235    // SWIGPHP5 is deprecated, and no longer documented.
236    Preprocessor_define("SWIGPHP5 1", 0);
237    SWIG_typemap_lang("php");
238    SWIG_config_file("php.swg");
239    allow_overloading();
240  }
241
242  /* ------------------------------------------------------------
243   * top()
244   * ------------------------------------------------------------ */
245
246  virtual int top(Node *n) {
247
248    String *filen;
249    String *s_type;
250
251    /* Check if directors are enabled for this module. */
252    Node *mod = Getattr(n, "module");
253    if (mod) {
254      Node *options = Getattr(mod, "options");
255      if (options && Getattr(options, "directors")) {
256	allow_directors();
257      }
258    }
259
260    /* Set comparison with null for ConstructorToFunction */
261    setSubclassInstanceCheck(NewString("$arg->type != IS_NULL"));
262
263    /* Initialize all of the output files */
264    String *outfile = Getattr(n, "outfile");
265    String *outfile_h = Getattr(n, "outfile_h");
266
267    /* main output file */
268    f_begin = NewFile(outfile, "w", SWIG_output_files());
269    if (!f_begin) {
270      FileErrorDisplay(outfile);
271      SWIG_exit(EXIT_FAILURE);
272    }
273    f_runtime = NewStringEmpty();
274
275    /* sections of the output file */
276    s_init = NewString("/* init section */\n");
277    r_init = NewString("/* rinit section */\n");
278    s_shutdown = NewString("/* shutdown section */\n");
279    r_shutdown = NewString("/* rshutdown section */\n");
280    s_header = NewString("/* header section */\n");
281    s_wrappers = NewString("/* wrapper section */\n");
282    s_type = NewStringEmpty();
283    /* subsections of the init section */
284    s_vinit = NewString("/* vinit subsection */\n");
285    s_vdecl = NewString("/* vdecl subsection */\n");
286    s_cinit = NewString("/* cinit subsection */\n");
287    s_oinit = NewString("/* oinit subsection */\n");
288    pragma_phpinfo = NewStringEmpty();
289    s_phpclasses = NewString("/* PHP Proxy Classes */\n");
290    f_directors_h = NewStringEmpty();
291    f_directors = NewStringEmpty();
292
293    if (directorsEnabled()) {
294      f_runtime_h = NewFile(outfile_h, "w", SWIG_output_files());
295      if (!f_runtime_h) {
296	FileErrorDisplay(outfile_h);
297	SWIG_exit(EXIT_FAILURE);
298      }
299    }
300
301    /* Register file targets with the SWIG file handler */
302    Swig_register_filebyname("begin", f_begin);
303    Swig_register_filebyname("runtime", f_runtime);
304    Swig_register_filebyname("init", s_init);
305    Swig_register_filebyname("rinit", r_init);
306    Swig_register_filebyname("shutdown", s_shutdown);
307    Swig_register_filebyname("rshutdown", r_shutdown);
308    Swig_register_filebyname("header", s_header);
309    Swig_register_filebyname("wrapper", s_wrappers);
310    Swig_register_filebyname("director", f_directors);
311    Swig_register_filebyname("director_h", f_directors_h);
312
313    Swig_banner(f_begin);
314
315    Printf(f_runtime, "\n");
316    Printf(f_runtime, "#define SWIGPHP\n");
317    Printf(f_runtime, "\n");
318
319    if (directorsEnabled()) {
320      Printf(f_runtime, "#define SWIG_DIRECTORS\n");
321    }
322
323    /* Set the module name */
324    module = Copy(Getattr(n, "name"));
325    cap_module = NewStringf("%(upper)s", module);
326    if (!prefix)
327      prefix = NewStringEmpty();
328
329    if (directorsEnabled()) {
330      Swig_banner(f_directors_h);
331      Printf(f_directors_h, "\n");
332      Printf(f_directors_h, "#ifndef SWIG_%s_WRAP_H_\n", cap_module);
333      Printf(f_directors_h, "#define SWIG_%s_WRAP_H_\n\n", cap_module);
334
335      Printf(f_directors, "\n#include \"%s\"\n\n", Swig_file_filename(outfile_h));
336    }
337
338    /* PHP module file */
339    filen = NewStringEmpty();
340    Printv(filen, SWIG_output_directory(), module, ".php", NIL);
341    phpfilename = NewString(filen);
342
343    f_phpcode = NewFile(filen, "w", SWIG_output_files());
344    if (!f_phpcode) {
345      FileErrorDisplay(filen);
346      SWIG_exit(EXIT_FAILURE);
347    }
348
349    Printf(f_phpcode, "<?php\n\n");
350
351    Swig_banner(f_phpcode);
352
353    Printf(f_phpcode, "\n");
354    Printf(f_phpcode, "// Try to load our extension if it's not already loaded.\n");
355    Printf(f_phpcode, "if (!extension_loaded('%s')) {\n", module);
356    Printf(f_phpcode, "  if (strtolower(substr(PHP_OS, 0, 3)) === 'win') {\n");
357    Printf(f_phpcode, "    if (!dl('php_%s.dll')) return;\n", module);
358    Printf(f_phpcode, "  } else {\n");
359    Printf(f_phpcode, "    // PHP_SHLIB_SUFFIX gives 'dylib' on MacOS X but modules are 'so'.\n");
360    Printf(f_phpcode, "    if (PHP_SHLIB_SUFFIX === 'dylib') {\n");
361    Printf(f_phpcode, "      if (!dl('%s.so')) return;\n", module);
362    Printf(f_phpcode, "    } else {\n");
363    Printf(f_phpcode, "      if (!dl('%s.'.PHP_SHLIB_SUFFIX)) return;\n", module);
364    Printf(f_phpcode, "    }\n");
365    Printf(f_phpcode, "  }\n");
366    Printf(f_phpcode, "}\n\n");
367
368    /* sub-sections of the php file */
369    pragma_code = NewStringEmpty();
370    pragma_incl = NewStringEmpty();
371
372    /* Initialize the rest of the module */
373
374    Printf(s_oinit, "ZEND_INIT_MODULE_GLOBALS(%s, %s_init_globals, %s_destroy_globals);\n", module, module, module);
375
376    /* start the header section */
377    Printf(s_header, "ZEND_BEGIN_MODULE_GLOBALS(%s)\n", module);
378    Printf(s_header, "const char *error_msg;\n");
379    Printf(s_header, "int error_code;\n");
380    Printf(s_header, "ZEND_END_MODULE_GLOBALS(%s)\n", module);
381    Printf(s_header, "ZEND_DECLARE_MODULE_GLOBALS(%s)\n", module);
382    Printf(s_header, "#ifdef ZTS\n");
383    Printf(s_header, "#define SWIG_ErrorMsg() TSRMG(%s_globals_id, zend_%s_globals *, error_msg )\n", module, module);
384    Printf(s_header, "#define SWIG_ErrorCode() TSRMG(%s_globals_id, zend_%s_globals *, error_code )\n", module, module);
385    Printf(s_header, "#else\n");
386    Printf(s_header, "#define SWIG_ErrorMsg() (%s_globals.error_msg)\n", module);
387    Printf(s_header, "#define SWIG_ErrorCode() (%s_globals.error_code)\n", module);
388    Printf(s_header, "#endif\n\n");
389
390    Printf(s_header, "static void %s_init_globals(zend_%s_globals *globals ) {\n", module, module);
391    Printf(s_header, "  globals->error_msg = default_error_msg;\n");
392    Printf(s_header, "  globals->error_code = default_error_code;\n");
393    Printf(s_header, "}\n");
394
395    Printf(s_header, "static void %s_destroy_globals(zend_%s_globals * globals) { (void)globals; }\n", module, module);
396
397    Printf(s_header, "\n");
398    Printf(s_header, "static void SWIG_ResetError() {\n");
399    Printf(s_header, "  TSRMLS_FETCH();\n");
400    Printf(s_header, "  SWIG_ErrorMsg() = default_error_msg;\n");
401    Printf(s_header, "  SWIG_ErrorCode() = default_error_code;\n");
402    Printf(s_header, "}\n");
403
404    Append(s_header, "\n");
405    Printf(s_header, "ZEND_NAMED_FUNCTION(_wrap_swig_%s_alter_newobject) {\n", module);
406    Append(s_header, "  zval **args[2];\n");
407    Append(s_header, "  swig_object_wrapper *value;\n");
408    Append(s_header, "  int type;\n");
409    Append(s_header, "  int thisown;\n");
410    Append(s_header, "\n");
411    Append(s_header, "  SWIG_ResetError();\n");
412    Append(s_header, "  if(ZEND_NUM_ARGS() != 2 || zend_get_parameters_array_ex(2, args) != SUCCESS) {\n");
413    Append(s_header, "    WRONG_PARAM_COUNT;\n");
414    Append(s_header, "  }\n");
415    Append(s_header, "\n");
416    Append(s_header, "  value = (swig_object_wrapper *) zend_list_find((*args[0])->value.lval, &type);\n");
417    Append(s_header, "  value->newobject = zval_is_true(*args[1]);\n");
418    Append(s_header, "\n");
419    Append(s_header, "  return;\n");
420    Append(s_header, "}\n");
421    Printf(s_header, "ZEND_NAMED_FUNCTION(_wrap_swig_%s_get_newobject) {\n", module);
422    Append(s_header, "  zval **args[1];\n");
423    Append(s_header, "  swig_object_wrapper *value;\n");
424    Append(s_header, "  int type;\n");
425    Append(s_header, "\n");
426    Append(s_header, "  SWIG_ResetError();\n");
427    Append(s_header, "  if(ZEND_NUM_ARGS() != 1 || zend_get_parameters_array_ex(1, args) != SUCCESS) {\n");
428    Append(s_header, "    WRONG_PARAM_COUNT;\n");
429    Append(s_header, "  }\n");
430    Append(s_header, "\n");
431    Append(s_header, "  value = (swig_object_wrapper *) zend_list_find((*args[0])->value.lval, &type);\n");
432    Append(s_header, "  RETVAL_LONG(value->newobject);\n");
433    Append(s_header, "\n");
434    Append(s_header, "  return;\n");
435    Append(s_header, "}\n");
436
437    Printf(s_header, "#define SWIG_name  \"%s\"\n", module);
438    /*     Printf(s_header,"#ifdef HAVE_CONFIG_H\n");
439       Printf(s_header,"#include \"config.h\"\n");
440       Printf(s_header,"#endif\n\n");
441     */
442    Printf(s_header, "#ifdef __cplusplus\n");
443    Printf(s_header, "extern \"C\" {\n");
444    Printf(s_header, "#endif\n");
445    Printf(s_header, "#include \"php.h\"\n");
446    Printf(s_header, "#include \"php_ini.h\"\n");
447    Printf(s_header, "#include \"ext/standard/info.h\"\n");
448    Printf(s_header, "#include \"php_%s.h\"\n", module);
449    Printf(s_header, "#ifdef __cplusplus\n");
450    Printf(s_header, "}\n");
451    Printf(s_header, "#endif\n\n");
452
453    if (directorsEnabled()) {
454      // Insert director runtime
455      Swig_insert_file("director.swg", s_header);
456    }
457
458    /* Create the .h file too */
459    filen = NewStringEmpty();
460    Printv(filen, SWIG_output_directory(), "php_", module, ".h", NIL);
461    f_h = NewFile(filen, "w", SWIG_output_files());
462    if (!f_h) {
463      FileErrorDisplay(filen);
464      SWIG_exit(EXIT_FAILURE);
465    }
466
467    Swig_banner(f_h);
468
469    Printf(f_h, "\n");
470    Printf(f_h, "#ifndef PHP_%s_H\n", cap_module);
471    Printf(f_h, "#define PHP_%s_H\n\n", cap_module);
472    Printf(f_h, "extern zend_module_entry %s_module_entry;\n", module);
473    Printf(f_h, "#define phpext_%s_ptr &%s_module_entry\n\n", module, module);
474    Printf(f_h, "#ifdef PHP_WIN32\n");
475    Printf(f_h, "# define PHP_%s_API __declspec(dllexport)\n", cap_module);
476    Printf(f_h, "#else\n");
477    Printf(f_h, "# define PHP_%s_API\n", cap_module);
478    Printf(f_h, "#endif\n\n");
479    Printf(f_h, "#ifdef ZTS\n");
480    Printf(f_h, "#include \"TSRM.h\"\n");
481    Printf(f_h, "#endif\n\n");
482    Printf(f_h, "PHP_MINIT_FUNCTION(%s);\n", module);
483    Printf(f_h, "PHP_MSHUTDOWN_FUNCTION(%s);\n", module);
484    Printf(f_h, "PHP_RINIT_FUNCTION(%s);\n", module);
485    Printf(f_h, "PHP_RSHUTDOWN_FUNCTION(%s);\n", module);
486    Printf(f_h, "PHP_MINFO_FUNCTION(%s);\n\n", module);
487
488    /* start the function entry section */
489    s_entry = NewString("/* entry subsection */\n");
490
491    /* holds all the per-class function entry sections */
492    all_cs_entry = NewString("/* class entry subsection */\n");
493    cs_entry = NULL;
494
495    Printf(s_entry, "/* Every non-class user visible function must have an entry here */\n");
496    Printf(s_entry, "static zend_function_entry %s_functions[] = {\n", module);
497
498    /* start the init section */
499    Append(s_init, "#if ZEND_MODULE_API_NO <= 20090626\n");
500    Append(s_init, "#undef ZEND_MODULE_BUILD_ID\n");
501    Append(s_init, "#define ZEND_MODULE_BUILD_ID (char*)\"API\" ZEND_TOSTR(ZEND_MODULE_API_NO) ZEND_BUILD_TS ZEND_BUILD_DEBUG ZEND_BUILD_SYSTEM ZEND_BUILD_EXTRA\n");
502    Append(s_init, "#endif\n");
503    Printv(s_init, "zend_module_entry ", module, "_module_entry = {\n" "#if ZEND_MODULE_API_NO > 20010900\n" "    STANDARD_MODULE_HEADER,\n" "#endif\n", NIL);
504    Printf(s_init, "    (char*)\"%s\",\n", module);
505    Printf(s_init, "    %s_functions,\n", module);
506    Printf(s_init, "    PHP_MINIT(%s),\n", module);
507    Printf(s_init, "    PHP_MSHUTDOWN(%s),\n", module);
508    Printf(s_init, "    PHP_RINIT(%s),\n", module);
509    Printf(s_init, "    PHP_RSHUTDOWN(%s),\n", module);
510    Printf(s_init, "    PHP_MINFO(%s),\n", module);
511    Printf(s_init, "#if ZEND_MODULE_API_NO > 20010900\n");
512    Printf(s_init, "    NO_VERSION_YET,\n");
513    Printf(s_init, "#endif\n");
514    Printf(s_init, "    STANDARD_MODULE_PROPERTIES\n");
515    Printf(s_init, "};\n");
516    Printf(s_init, "zend_module_entry* SWIG_module_entry = &%s_module_entry;\n\n", module);
517
518    Printf(s_init, "#ifdef __cplusplus\n");
519    Printf(s_init, "extern \"C\" {\n");
520    Printf(s_init, "#endif\n");
521    // We want to write "SWIGEXPORT ZEND_GET_MODULE(%s)" but ZEND_GET_MODULE
522    // in PHP5 has "extern "C" { ... }" around it so we can't do that.
523    Printf(s_init, "SWIGEXPORT zend_module_entry *get_module(void) { return &%s_module_entry; }\n", module);
524    Printf(s_init, "#ifdef __cplusplus\n");
525    Printf(s_init, "}\n");
526    Printf(s_init, "#endif\n\n");
527
528    /* We have to register the constants before they are (possibly) used
529     * by the pointer typemaps. This all needs re-arranging really as
530     * things are being called in the wrong order
531     */
532    Printf(s_init, "#define SWIG_php_minit PHP_MINIT_FUNCTION(%s)\n", module);
533
534    /* Emit all of the code */
535    Language::top(n);
536
537    SwigPHP_emit_resource_registrations();
538    //    Printv(s_init,s_resourcetypes,NIL);
539    /* We need this after all classes written out by ::top */
540    Printf(s_oinit, "CG(active_class_entry) = NULL;\n");
541    Printf(s_oinit, "/* end oinit subsection */\n");
542    Printf(s_init, "%s\n", s_oinit);
543
544    /* Constants generated during top call */
545    Printf(s_cinit, "/* end cinit subsection */\n");
546    Printf(s_init, "%s\n", s_cinit);
547    Clear(s_cinit);
548    Delete(s_cinit);
549
550    Printf(s_init, "    return SUCCESS;\n");
551    Printf(s_init, "}\n\n");
552
553    // Now do REQUEST init which holds any user specified %rinit, and also vinit
554    Printf(s_init, "PHP_RINIT_FUNCTION(%s)\n{\n", module);
555    Printf(s_init, "%s\n", r_init);
556
557    /* finish our init section which will have been used by class wrappers */
558    Printf(s_vinit, "/* end vinit subsection */\n");
559    Printf(s_init, "%s\n", s_vinit);
560    Clear(s_vinit);
561    Delete(s_vinit);
562
563    Printf(s_init, "    return SUCCESS;\n");
564    Printf(s_init, "}\n\n");
565
566    Printv(s_init, "PHP_MSHUTDOWN_FUNCTION(", module, ")\n"
567		   "{\n",
568		   s_shutdown,
569		   "#ifdef ZTS\n"
570		   "    ts_free_id(", module, "_globals_id);\n"
571		   "#endif\n"
572		   "    return SUCCESS;\n"
573		   "}\n\n", NIL);
574
575    Printf(s_init, "PHP_RSHUTDOWN_FUNCTION(%s)\n{\n", module);
576    Printf(s_init, "%s\n", r_shutdown);
577    Printf(s_init, "    return SUCCESS;\n");
578    Printf(s_init, "}\n\n");
579
580    Printf(s_init, "PHP_MINFO_FUNCTION(%s)\n{\n", module);
581    Printf(s_init, "%s", pragma_phpinfo);
582    Printf(s_init, "}\n");
583    Printf(s_init, "/* end init section */\n");
584
585    Printf(f_h, "#endif /* PHP_%s_H */\n", cap_module);
586
587    Close(f_h);
588
589    String *type_table = NewStringEmpty();
590    SwigType_emit_type_table(f_runtime, type_table);
591    Printf(s_header, "%s", type_table);
592    Delete(type_table);
593
594    /* Oh dear, more things being called in the wrong order. This whole
595     * function really needs totally redoing.
596     */
597
598    if (directorsEnabled()) {
599      Dump(f_directors_h, f_runtime_h);
600      Printf(f_runtime_h, "\n");
601      Printf(f_runtime_h, "#endif\n");
602      Close(f_runtime_h);
603    }
604
605    Printf(s_header, "/* end header section */\n");
606    Printf(s_wrappers, "/* end wrapper section */\n");
607    Printf(s_vdecl, "/* end vdecl subsection */\n");
608
609    Dump(f_runtime, f_begin);
610    Printv(f_begin, s_header, NIL);
611    if (directorsEnabled()) {
612      Dump(f_directors, f_begin);
613    }
614    Printv(f_begin, s_vdecl, s_wrappers, NIL);
615    Printv(f_begin, all_cs_entry, "\n\n", s_entry,
616	" SWIG_ZEND_NAMED_FE(swig_", module, "_alter_newobject,_wrap_swig_", module, "_alter_newobject,NULL)\n"
617	" SWIG_ZEND_NAMED_FE(swig_", module, "_get_newobject,_wrap_swig_", module, "_get_newobject,NULL)\n"
618	"{NULL, NULL, NULL}\n};\n\n", NIL);
619    Printv(f_begin, s_init, NIL);
620    Delete(s_header);
621    Delete(s_wrappers);
622    Delete(s_init);
623    Delete(s_vdecl);
624    Delete(all_cs_entry);
625    Delete(s_entry);
626    Close(f_begin);
627    Delete(f_runtime);
628    Delete(f_begin);
629
630    Printf(f_phpcode, "%s\n%s\n", pragma_incl, pragma_code);
631    if (s_fakeoowrappers) {
632      Printf(f_phpcode, "abstract class %s {", Len(prefix) ? prefix : module);
633      Printf(f_phpcode, "%s", s_fakeoowrappers);
634      Printf(f_phpcode, "}\n\n");
635      Delete(s_fakeoowrappers);
636      s_fakeoowrappers = NULL;
637    }
638    Printf(f_phpcode, "%s\n?>\n", s_phpclasses);
639    Close(f_phpcode);
640
641    return SWIG_OK;
642  }
643
644  /* Just need to append function names to function table to register with PHP. */
645  void create_command(String *cname, String *iname) {
646    // This is for the single main zend_function_entry record
647    Printf(f_h, "ZEND_NAMED_FUNCTION(%s);\n", iname);
648    String * s = cs_entry;
649    if (!s) s = s_entry;
650    Printf(s, " SWIG_ZEND_NAMED_FE(%(lower)s,%s,NULL)\n", cname, iname);
651  }
652
653  /* ------------------------------------------------------------
654   * dispatchFunction()
655   * ------------------------------------------------------------ */
656  void dispatchFunction(Node *n) {
657    /* Last node in overloaded chain */
658
659    int maxargs;
660    String *tmp = NewStringEmpty();
661    if (Swig_directorclass(n) && wrapperType == directorconstructor) {
662      /* We have an extra 'this' parameter. */
663      SetFlag(n, "wrap:this");
664    }
665    String *dispatch = Swig_overload_dispatch(n, "return %s(INTERNAL_FUNCTION_PARAM_PASSTHRU);", &maxargs);
666
667    /* Generate a dispatch wrapper for all overloaded functions */
668
669    Wrapper *f = NewWrapper();
670    String *symname = Getattr(n, "sym:name");
671    String *wname = Swig_name_wrapper(symname);
672
673    create_command(symname, wname);
674    Printv(f->def, "ZEND_NAMED_FUNCTION(", wname, ") {\n", NIL);
675
676    Wrapper_add_local(f, "argc", "int argc");
677
678    Printf(tmp, "zval **argv[%d]", maxargs);
679    Wrapper_add_local(f, "argv", tmp);
680
681    Printf(f->code, "argc = ZEND_NUM_ARGS();\n");
682
683    Printf(f->code, "zend_get_parameters_array_ex(argc,argv);\n");
684
685    Replaceall(dispatch, "$args", "self,args");
686
687    Printv(f->code, dispatch, "\n", NIL);
688
689    Printf(f->code, "SWIG_ErrorCode() = E_ERROR;\n");
690    Printf(f->code, "SWIG_ErrorMsg() = \"No matching function for overloaded '%s'\";\n", symname);
691    Printv(f->code, "zend_error(SWIG_ErrorCode(),\"%s\",SWIG_ErrorMsg());\n", NIL);
692
693    Printv(f->code, "}\n", NIL);
694    Wrapper_print(f, s_wrappers);
695
696    DelWrapper(f);
697    Delete(dispatch);
698    Delete(tmp);
699    Delete(wname);
700  }
701
702  /* ------------------------------------------------------------
703   * functionWrapper()
704   * ------------------------------------------------------------ */
705
706  /* Helper method for PHP::functionWrapper */
707  bool is_class(SwigType *t) {
708    Node *n = classLookup(t);
709    if (n) {
710      String *r = Getattr(n, "php:proxy");	// Set by classDeclaration()
711      if (!r)
712	r = Getattr(n, "sym:name");	// Not seen by classDeclaration yet, but this is the name
713      if (r)
714	return true;
715    }
716    return false;
717  }
718
719  virtual int functionWrapper(Node *n) {
720    String *name = GetChar(n, "name");
721    String *iname = GetChar(n, "sym:name");
722    SwigType *d = Getattr(n, "type");
723    ParmList *l = Getattr(n, "parms");
724    String *nodeType = Getattr(n, "nodeType");
725    int newobject = GetFlag(n, "feature:new");
726    int constructor = (Cmp(nodeType, "constructor") == 0);
727
728    Parm *p;
729    int i;
730    int numopt;
731    String *tm;
732    Wrapper *f;
733
734    String *wname;
735    int overloaded = 0;
736    String *overname = 0;
737
738    if (Cmp(nodeType, "destructor") == 0) {
739      // We just generate the Zend List Destructor and let Zend manage the
740      // reference counting.  There's no explicit destructor, but the user can
741      // just do `$obj = null;' to remove a reference to an object.
742      return CreateZendListDestructor(n);
743    }
744    // Test for overloading;
745    if (Getattr(n, "sym:overloaded")) {
746      overloaded = 1;
747      overname = Getattr(n, "sym:overname");
748    } else {
749      if (!addSymbol(iname, n))
750	return SWIG_ERROR;
751    }
752
753    wname = Swig_name_wrapper(iname);
754    if (overname) {
755      Printf(wname, "%s", overname);
756    }
757
758    f = NewWrapper();
759    numopt = 0;
760
761    String *outarg = NewStringEmpty();
762    String *cleanup = NewStringEmpty();
763
764    // Not issued for overloaded functions.
765    if (!overloaded) {
766      create_command(iname, wname);
767    }
768    Printv(f->def, "ZEND_NAMED_FUNCTION(", wname, ") {\n", NIL);
769
770    emit_parameter_variables(l, f);
771    /* Attach standard typemaps */
772
773    emit_attach_parmmaps(l, f);
774
775    // wrap:parms is used by overload resolution.
776    Setattr(n, "wrap:parms", l);
777
778    int num_arguments = emit_num_arguments(l);
779    int num_required = emit_num_required(l);
780    numopt = num_arguments - num_required;
781
782    if (wrapperType == directorconstructor)
783      num_arguments++;
784
785    if (num_arguments > 0) {
786      String *args = NewStringEmpty();
787      if (wrapperType == directorconstructor)
788        Wrapper_add_local(f, "arg0", "zval *arg0");
789      Printf(args, "zval **args[%d]", num_arguments);
790      Wrapper_add_local(f, "args", args);
791      Delete(args);
792      args = NULL;
793    }
794    if (is_member_director(n)) {
795      Wrapper_add_local(f, "director", "Swig::Director *director = 0");
796      Printf(f->code, "director = dynamic_cast<Swig::Director*>(arg1);\n");
797      Wrapper_add_local(f, "upcall", "bool upcall = false");
798      Printf(f->code, "upcall = !director->is_overriden_method((char *)\"%s\", (char *)\"%s\");\n",
799	  Swig_class_name(Swig_methodclass(n)), name);
800    }
801
802    // This generated code may be called:
803    // 1) as an object method, or
804    // 2) as a class-method/function (without a "this_ptr")
805    // Option (1) has "this_ptr" for "this", option (2) needs it as
806    // first parameter
807
808    // NOTE: possible we ignore this_ptr as a param for native constructor
809
810    Printf(f->code, "SWIG_ResetError();\n");
811
812    if (numopt > 0) {		// membervariable wrappers do not have optional args
813      Wrapper_add_local(f, "arg_count", "int arg_count");
814      Printf(f->code, "arg_count = ZEND_NUM_ARGS();\n");
815      Printf(f->code, "if(arg_count<%d || arg_count>%d ||\n", num_required, num_arguments);
816      Printf(f->code, "   zend_get_parameters_array_ex(arg_count,args)!=SUCCESS)\n");
817      Printf(f->code, "\tWRONG_PARAM_COUNT;\n\n");
818    } else {
819      if (num_arguments == 0) {
820	Printf(f->code, "if(ZEND_NUM_ARGS() != 0) {\n");
821      } else {
822	Printf(f->code, "if(ZEND_NUM_ARGS() != %d || zend_get_parameters_array_ex(%d, args) != SUCCESS) {\n", num_arguments, num_arguments);
823      }
824      Printf(f->code, "WRONG_PARAM_COUNT;\n}\n\n");
825    }
826    if (wrapperType == directorconstructor)
827      Printf(f->code, "arg0 = *args[0];\n  \n");
828
829    /* Now convert from PHP to C variables */
830    // At this point, argcount if used is the number of deliberately passed args
831    // not including this_ptr even if it is used.
832    // It means error messages may be out by argbase with error
833    // reports.  We can either take argbase into account when raising
834    // errors, or find a better way of dealing with _thisptr.
835    // I would like, if objects are wrapped, to assume _thisptr is always
836    // _this and not the first argument.
837    // This may mean looking at Language::memberfunctionHandler
838
839    int limit = num_arguments;
840    if (wrapperType == directorconstructor)
841      limit--;
842    for (i = 0, p = l; i < limit; i++) {
843      String *source;
844
845      /* Skip ignored arguments */
846      //while (Getattr(p,"tmap:ignore")) { p = Getattr(p,"tmap:ignore:next");}
847      while (checkAttribute(p, "tmap:in:numinputs", "0")) {
848	p = Getattr(p, "tmap:in:next");
849      }
850
851      SwigType *pt = Getattr(p, "type");
852
853      if (wrapperType == directorconstructor) {
854	source = NewStringf("args[%d]", i+1);
855      } else {
856	source = NewStringf("args[%d]", i);
857      }
858
859      String *ln = Getattr(p, "lname");
860
861      /* Check if optional */
862      if (i >= num_required) {
863	Printf(f->code, "\tif(arg_count > %d) {\n", i);
864      }
865
866      if ((tm = Getattr(p, "tmap:in"))) {
867	Replaceall(tm, "$source", source);
868	Replaceall(tm, "$target", ln);
869	Replaceall(tm, "$input", source);
870	Setattr(p, "emit:input", source);
871	Printf(f->code, "%s\n", tm);
872	if (i == 0 && Getattr(p, "self")) {
873	  Printf(f->code, "\tif(!arg1) SWIG_PHP_Error(E_ERROR, \"this pointer is NULL\");\n");
874	}
875	p = Getattr(p, "tmap:in:next");
876	if (i >= num_required) {
877	  Printf(f->code, "}\n");
878	}
879	continue;
880      } else {
881	Swig_warning(WARN_TYPEMAP_IN_UNDEF, input_file, line_number, "Unable to use type %s as a function argument.\n", SwigType_str(pt, 0));
882      }
883      if (i >= num_required) {
884	Printf(f->code, "\t}\n");
885      }
886      Delete(source);
887    }
888
889    Swig_director_emit_dynamic_cast(n, f);
890
891    /* Insert constraint checking code */
892    for (p = l; p;) {
893      if ((tm = Getattr(p, "tmap:check"))) {
894	Replaceall(tm, "$target", Getattr(p, "lname"));
895	Printv(f->code, tm, "\n", NIL);
896	p = Getattr(p, "tmap:check:next");
897      } else {
898	p = nextSibling(p);
899      }
900    }
901
902    /* Insert cleanup code */
903    for (i = 0, p = l; p; i++) {
904      if ((tm = Getattr(p, "tmap:freearg"))) {
905	Replaceall(tm, "$source", Getattr(p, "lname"));
906	Printv(cleanup, tm, "\n", NIL);
907	p = Getattr(p, "tmap:freearg:next");
908      } else {
909	p = nextSibling(p);
910      }
911    }
912
913    /* Insert argument output code */
914    for (i = 0, p = l; p; i++) {
915      if ((tm = Getattr(p, "tmap:argout"))) {
916	Replaceall(tm, "$source", Getattr(p, "lname"));
917	//      Replaceall(tm,"$input",Getattr(p,"lname"));
918	Replaceall(tm, "$target", "return_value");
919	Replaceall(tm, "$result", "return_value");
920	Replaceall(tm, "$arg", Getattr(p, "emit:input"));
921	Replaceall(tm, "$input", Getattr(p, "emit:input"));
922	Printv(outarg, tm, "\n", NIL);
923	p = Getattr(p, "tmap:argout:next");
924      } else {
925	p = nextSibling(p);
926      }
927    }
928
929    Setattr(n, "wrap:name", wname);
930
931    /* emit function call */
932    String *actioncode = emit_action(n);
933
934    if ((tm = Swig_typemap_lookup_out("out", n, "result", f, actioncode))) {
935      Replaceall(tm, "$input", "result");
936      Replaceall(tm, "$source", "result");
937      Replaceall(tm, "$target", "return_value");
938      Replaceall(tm, "$result", "return_value");
939      Replaceall(tm, "$owner", newobject ? "1" : "0");
940      Printf(f->code, "%s\n", tm);
941    } else {
942      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);
943    }
944    emit_return_variable(n, d, f);
945
946    if (outarg) {
947      Printv(f->code, outarg, NIL);
948    }
949
950    if (cleanup) {
951      Printv(f->code, cleanup, NIL);
952    }
953
954    /* Look to see if there is any newfree cleanup code */
955    if (GetFlag(n, "feature:new")) {
956      if ((tm = Swig_typemap_lookup("newfree", n, "result", 0))) {
957	Printf(f->code, "%s\n", tm);
958	Delete(tm);
959      }
960    }
961
962    /* See if there is any return cleanup code */
963    if ((tm = Swig_typemap_lookup("ret", n, "result", 0))) {
964      Printf(f->code, "%s\n", tm);
965      Delete(tm);
966    }
967
968    Printf(f->code, "return;\n");
969
970    /* Error handling code */
971    Printf(f->code, "fail:\n");
972    Printv(f->code, cleanup, NIL);
973    Printv(f->code, "zend_error_noreturn(SWIG_ErrorCode(),\"%s\",SWIG_ErrorMsg());", NIL);
974
975    Printf(f->code, "}\n");
976
977    Replaceall(f->code, "$cleanup", cleanup);
978    Replaceall(f->code, "$symname", iname);
979
980    Wrapper_print(f, s_wrappers);
981    DelWrapper(f);
982    f = NULL;
983
984    if (overloaded && !Getattr(n, "sym:nextSibling")) {
985      dispatchFunction(n);
986    }
987
988    Delete(wname);
989    wname = NULL;
990
991    if (!shadow) {
992      return SWIG_OK;
993    }
994
995    // Handle getters and setters.
996    if (wrapperType == membervar) {
997      const char *p = Char(iname);
998      if (strlen(p) > 4) {
999	p += strlen(p) - 4;
1000	String *varname = Getattr(n, "membervariableHandler:sym:name");
1001	if (strcmp(p, "_get") == 0) {
1002	  Setattr(shadow_get_vars, varname, iname);
1003	} else if (strcmp(p, "_set") == 0) {
1004	  Setattr(shadow_set_vars, varname, iname);
1005	}
1006      }
1007      return SWIG_OK;
1008    }
1009
1010    // Only look at non-overloaded methods and the last entry in each overload
1011    // chain (we check the last so that wrap:parms and wrap:name have been set
1012    // for them all).
1013    if (overloaded && Getattr(n, "sym:nextSibling") != 0)
1014      return SWIG_OK;
1015
1016    if (!s_oowrappers)
1017      s_oowrappers = NewStringEmpty();
1018
1019    if (newobject || wrapperType == memberfn || wrapperType == staticmemberfn || wrapperType == standard || wrapperType == staticmembervar) {
1020      bool handle_as_overload = false;
1021      String **arg_names;
1022      String **arg_values;
1023      // Method or static method or plain function.
1024      const char *methodname = 0;
1025      String *output = s_oowrappers;
1026      if (constructor) {
1027	class_has_ctor = true;
1028	// Skip the Foo:: prefix.
1029	char *ptr = strrchr(GetChar(Swig_methodclass(n), "sym:name"), ':');
1030	if (ptr) {
1031	  ptr++;
1032	} else {
1033	  ptr = GetChar(Swig_methodclass(n), "sym:name");
1034	}
1035	if (strcmp(ptr, GetChar(n, "constructorHandler:sym:name")) == 0) {
1036	  methodname = "__construct";
1037	} else {
1038	  // The class has multiple constructors and this one is
1039	  // renamed, so this will be a static factory function
1040	  methodname = GetChar(n, "constructorHandler:sym:name");
1041	}
1042      } else if (wrapperType == memberfn) {
1043	methodname = Char(Getattr(n, "memberfunctionHandler:sym:name"));
1044      } else if (wrapperType == staticmemberfn) {
1045	methodname = Char(Getattr(n, "staticmemberfunctionHandler:sym:name"));
1046      } else if (wrapperType == staticmembervar) {
1047	// Static member variable, wrapped as a function due to PHP limitations.
1048	methodname = Char(Getattr(n, "staticmembervariableHandler:sym:name"));
1049      } else {			// wrapperType == standard
1050	methodname = Char(iname);
1051	if (!s_fakeoowrappers)
1052	  s_fakeoowrappers = NewStringEmpty();
1053	output = s_fakeoowrappers;
1054      }
1055
1056      bool really_overloaded = overloaded ? true : false;
1057      int min_num_of_arguments = emit_num_required(l);
1058      int max_num_of_arguments = emit_num_arguments(l);
1059
1060      // For a function with default arguments, we end up with the fullest
1061      // parmlist in full_parmlist.
1062      ParmList *full_parmlist = l;
1063      Hash *ret_types = NewHash();
1064      Setattr(ret_types, d, d);
1065
1066      if (overloaded) {
1067	// Look at all the overloaded versions of this method in turn to
1068	// decide if it's really an overloaded method, or just one where some
1069	// parameters have default values.
1070	Node *o = Getattr(n, "sym:overloaded");
1071	while (o) {
1072	  if (o == n) {
1073	    o = Getattr(o, "sym:nextSibling");
1074	    continue;
1075	  }
1076
1077	  SwigType *d2 = Getattr(o, "type");
1078	  if (!d2) {
1079	    assert(constructor);
1080	  } else if (!Getattr(ret_types, d2)) {
1081	    Setattr(ret_types, d2, d2);
1082	  }
1083
1084	  ParmList *l2 = Getattr(o, "wrap:parms");
1085	  int num_arguments = emit_num_arguments(l2);
1086	  int num_required = emit_num_required(l2);
1087	  if (num_required < min_num_of_arguments)
1088	    min_num_of_arguments = num_required;
1089
1090	  if (num_arguments > max_num_of_arguments) {
1091	    max_num_of_arguments = num_arguments;
1092	    full_parmlist = l2;
1093	  }
1094	  o = Getattr(o, "sym:nextSibling");
1095	}
1096
1097	o = Getattr(n, "sym:overloaded");
1098	while (o) {
1099	  if (o == n) {
1100	    o = Getattr(o, "sym:nextSibling");
1101	    continue;
1102	  }
1103
1104	  ParmList *l2 = Getattr(o, "wrap:parms");
1105	  Parm *p = l, *p2 = l2;
1106	  if (wrapperType == memberfn) {
1107	    p = nextSibling(p);
1108	    p2 = nextSibling(p2);
1109	  }
1110	  while (p && p2) {
1111	    if (Cmp(Getattr(p, "type"), Getattr(p2, "type")) != 0)
1112	      break;
1113	    if (Cmp(Getattr(p, "name"), Getattr(p2, "name")) != 0)
1114	      break;
1115	    String *value = Getattr(p, "value");
1116	    String *value2 = Getattr(p2, "value");
1117	    if (value && !value2)
1118	      break;
1119	    if (!value && value2)
1120	      break;
1121	    if (value) {
1122	      if (Cmp(value, value2) != 0)
1123		break;
1124	    }
1125	    p = nextSibling(p);
1126	    p2 = nextSibling(p2);
1127	  }
1128	  if (p && p2)
1129	    break;
1130	  // One parameter list is a prefix of the other, so check that all
1131	  // remaining parameters of the longer list are optional.
1132	  if (p2)
1133	    p = p2;
1134	  while (p && Getattr(p, "value"))
1135	    p = nextSibling(p);
1136	  if (p)
1137	    break;
1138	  o = Getattr(o, "sym:nextSibling");
1139	}
1140	if (!o) {
1141	  // This "overloaded method" is really just one with default args.
1142	  really_overloaded = false;
1143	  if (l != full_parmlist) {
1144	    l = full_parmlist;
1145	    if (wrapperType == memberfn)
1146	      l = nextSibling(l);
1147	  }
1148	}
1149      }
1150
1151      if (wrapperType == memberfn) {
1152	// Allow for the "this" pointer.
1153	--min_num_of_arguments;
1154	--max_num_of_arguments;
1155      }
1156
1157      arg_names = (String **) malloc(max_num_of_arguments * sizeof(String *));
1158      if (!arg_names) {
1159	/* FIXME: How should this be handled?  The rest of SWIG just seems
1160	 * to not bother checking for malloc failing! */
1161	fprintf(stderr, "Malloc failed!\n");
1162	exit(1);
1163      }
1164      for (i = 0; i < max_num_of_arguments; ++i) {
1165	arg_names[i] = NULL;
1166      }
1167
1168      arg_values = (String **) malloc(max_num_of_arguments * sizeof(String *));
1169      if (!arg_values) {
1170	/* FIXME: How should this be handled?  The rest of SWIG just seems
1171	 * to not bother checking for malloc failing! */
1172	fprintf(stderr, "Malloc failed!\n");
1173	exit(1);
1174      }
1175      for (i = 0; i < max_num_of_arguments; ++i) {
1176	arg_values[i] = NULL;
1177      }
1178
1179      Node *o;
1180      if (overloaded) {
1181	o = Getattr(n, "sym:overloaded");
1182      } else {
1183	o = n;
1184      }
1185      while (o) {
1186	int argno = 0;
1187	Parm *p = Getattr(o, "wrap:parms");
1188	if (wrapperType == memberfn)
1189	  p = nextSibling(p);
1190	while (p) {
1191	  if (GetInt(p, "tmap:in:numinputs") == 0) {
1192	    p = nextSibling(p);
1193	    continue;
1194	  }
1195	  assert(0 <= argno && argno < max_num_of_arguments);
1196	  String *&pname = arg_names[argno];
1197	  const char *pname_cstr = GetChar(p, "name");
1198	  // Just get rid of the C++ namespace part for now.
1199	  const char *ptr = NULL;
1200	  if (pname_cstr && (ptr = strrchr(pname_cstr, ':'))) {
1201	    pname_cstr = ptr + 1;
1202	  }
1203	  if (!pname_cstr) {
1204	    // Unnamed parameter, e.g. int foo(int);
1205	  } else if (pname == NULL) {
1206	    pname = NewString(pname_cstr);
1207	  } else {
1208	    size_t len = strlen(pname_cstr);
1209	    size_t spc = 0;
1210	    size_t len_pname = strlen(Char(pname));
1211	    while (spc + len <= len_pname) {
1212	      if (strncmp(pname_cstr, Char(pname) + spc, len) == 0) {
1213		char ch = ((char *) Char(pname))[spc + len];
1214		if (ch == '\0' || ch == ' ') {
1215		  // Already have this pname_cstr.
1216		  pname_cstr = NULL;
1217		  break;
1218		}
1219	      }
1220	      char *p = strchr(Char(pname) + spc, ' ');
1221	      if (!p)
1222		break;
1223	      spc = (p + 4) - Char(pname);
1224	    }
1225	    if (pname_cstr) {
1226	      Printf(pname, " or_%s", pname_cstr);
1227	    }
1228	  }
1229	  String *value = NewString(Getattr(p, "value"));
1230	  if (Len(value)) {
1231	    /* Check that value is a valid constant in PHP (and adjust it if
1232	     * necessary, or replace it with "?" if it's just not valid). */
1233	    SwigType *type = Getattr(p, "type");
1234	    switch (SwigType_type(type)) {
1235	      case T_BOOL: {
1236		if (Strcmp(value, "true") == 0 || Strcmp(value, "false") == 0)
1237		  break;
1238		char *p;
1239		errno = 0;
1240		int n = strtol(Char(value), &p, 0);
1241	        Clear(value);
1242		if (errno || *p) {
1243		  Append(value, "?");
1244		} else if (n) {
1245		  Append(value, "true");
1246		} else {
1247		  Append(value, "false");
1248		}
1249		break;
1250	      }
1251	      case T_CHAR:
1252	      case T_SCHAR:
1253	      case T_SHORT:
1254	      case T_INT:
1255	      case T_LONG: {
1256		char *p;
1257		errno = 0;
1258		unsigned int n = strtol(Char(value), &p, 0);
1259		(void) n;
1260		if (errno || *p) {
1261		  Clear(value);
1262		  Append(value, "?");
1263		}
1264		break;
1265	      }
1266	      case T_UCHAR:
1267	      case T_USHORT:
1268	      case T_UINT:
1269	      case T_ULONG: {
1270		char *p;
1271		errno = 0;
1272		unsigned int n = strtoul(Char(value), &p, 0);
1273		(void) n;
1274		if (errno || *p) {
1275		  Clear(value);
1276		  Append(value, "?");
1277		}
1278		break;
1279	      }
1280	      case T_FLOAT:
1281	      case T_DOUBLE:{
1282		char *p;
1283		errno = 0;
1284		/* FIXME: strtod is locale dependent... */
1285		double val = strtod(Char(value), &p);
1286		if (errno || *p) {
1287		  Clear(value);
1288		  Append(value, "?");
1289		} else if (strchr(Char(value), '.') == NULL) {
1290		  // Ensure value is a double constant, not an integer one.
1291		  Append(value, ".0");
1292		  double val2 = strtod(Char(value), &p);
1293		  if (errno || *p || val != val2) {
1294		    Clear(value);
1295		    Append(value, "?");
1296		  }
1297		}
1298		break;
1299	      }
1300	      case T_REFERENCE:
1301	      case T_USER:
1302	      case T_ARRAY:
1303		Clear(value);
1304		Append(value, "?");
1305		break;
1306	      case T_STRING:
1307		if (Len(value) < 2) {
1308		  // How can a string (including "" be less than 2 characters?)
1309		  Clear(value);
1310		  Append(value, "?");
1311		} else {
1312		  const char *v = Char(value);
1313		  if (v[0] != '"' || v[Len(value) - 1] != '"') {
1314		    Clear(value);
1315		    Append(value, "?");
1316		  }
1317		  // Strings containing "$" require special handling, but we do
1318		  // that later.
1319		}
1320		break;
1321	      case T_VOID:
1322		assert(false);
1323		break;
1324	      case T_POINTER: {
1325		const char *v = Char(value);
1326		if (v[0] == '(') {
1327		  // Handle "(void*)0", "(TYPE*)0", "(char*)NULL", etc.
1328		  v += strcspn(v + 1, "*()") + 1;
1329		  if (*v == '*') {
1330		    do {
1331		      v++;
1332		      v += strspn(v, " \t");
1333		    } while (*v == '*');
1334		    if (*v++ == ')') {
1335		      v += strspn(v, " \t");
1336		      String * old = value;
1337		      value = NewString(v);
1338		      Delete(old);
1339		    }
1340		  }
1341		}
1342		if (Strcmp(value, "NULL") == 0 ||
1343		    Strcmp(value, "0") == 0 ||
1344		    Strcmp(value, "0L") == 0) {
1345		  Clear(value);
1346		  Append(value, "null");
1347		} else {
1348		  Clear(value);
1349		  Append(value, "?");
1350		}
1351		break;
1352	      }
1353	    }
1354
1355	    if (!arg_values[argno]) {
1356	      arg_values[argno] = value;
1357	      value = NULL;
1358	    } else if (Cmp(arg_values[argno], value) != 0) {
1359	      // If a parameter has two different default values in
1360	      // different overloaded forms of the function, we can't
1361	      // set its default in PHP.  Flag this by setting its
1362	      // default to `?'.
1363	      Delete(arg_values[argno]);
1364	      arg_values[argno] = NewString("?");
1365	    }
1366	  } else if (arg_values[argno]) {
1367	    // This argument already has a default value in another overloaded
1368	    // form, but doesn't in this form.  So don't try to do anything
1369	    // clever, just let the C wrappers resolve the overload and set the
1370	    // default values.
1371	    //
1372	    // This handling is safe, but I'm wondering if it may be overly
1373	    // conservative (FIXME) in some cases.  It seems it's only bad when
1374	    // there's an overloaded form with the appropriate number of
1375	    // parameters which doesn't want the default value, but I need to
1376	    // think about this more.
1377	    Delete(arg_values[argno]);
1378	    arg_values[argno] = NewString("?");
1379	  }
1380	  Delete(value);
1381	  p = nextSibling(p);
1382	  ++argno;
1383	}
1384	if (!really_overloaded)
1385	  break;
1386	o = Getattr(o, "sym:nextSibling");
1387      }
1388
1389      /* Clean up any parameters which haven't yet got names, or whose
1390       * names clash. */
1391      Hash *seen = NewHash();
1392      /* We need $this to refer to the current class, so can't allow it
1393       * to be used as a parameter. */
1394      Setattr(seen, "this", seen);
1395      /* We use $r to store the return value, so disallow that as a parameter
1396       * name in case the user uses the "call-time pass-by-reference" feature
1397       * (it's deprecated and off by default in PHP5, but we want to be
1398       * maximally portable).  Similarly we use $c for the classname or new
1399       * stdClass object.
1400       */
1401      Setattr(seen, "r", seen);
1402      Setattr(seen, "c", seen);
1403
1404      for (int argno = 0; argno < max_num_of_arguments; ++argno) {
1405	String *&pname = arg_names[argno];
1406	if (pname) {
1407	  Replaceall(pname, " ", "_");
1408	} else {
1409	  /* We get here if the SWIG .i file has "int foo(int);" */
1410	  pname = NewStringEmpty();
1411	  Printf(pname, "arg%d", argno + 1);
1412	}
1413	// Check if we've already used this parameter name.
1414	while (Getattr(seen, pname)) {
1415	  // Append "_" to clashing names until they stop clashing...
1416	  Printf(pname, "_");
1417	}
1418	Setattr(seen, Char(pname), seen);
1419
1420	if (arg_values[argno] && Cmp(arg_values[argno], "?") == 0) {
1421	  handle_as_overload = true;
1422	}
1423      }
1424      Delete(seen);
1425      seen = NULL;
1426
1427      String *invoke = NewStringEmpty();
1428      String *prepare = NewStringEmpty();
1429      String *args = NewStringEmpty();
1430
1431      if (!handle_as_overload && !(really_overloaded && max_num_of_arguments > min_num_of_arguments)) {
1432	Printf(invoke, "%s(", iname);
1433	if (wrapperType == memberfn) {
1434	  Printf(invoke, "$this->%s", SWIG_PTR);
1435	}
1436	for (int i = 0; i < max_num_of_arguments; ++i) {
1437	  if (i)
1438	    Printf(args, ",");
1439	  if (i || wrapperType == memberfn)
1440	    Printf(invoke, ",");
1441	  String *value = arg_values[i];
1442	  if (value) {
1443	    const char *v = Char(value);
1444	    if (v[0] == '"') {
1445	      /* In a PHP double quoted string, $ needs to be escaped as \$. */
1446	      Replaceall(value, "$", "\\$");
1447	    }
1448	    Printf(args, "$%s=%s", arg_names[i], value);
1449	  } else {
1450	    Printf(args, "$%s", arg_names[i]);
1451	  }
1452	  Printf(invoke, "$%s", arg_names[i]);
1453	}
1454	Printf(invoke, ")");
1455      } else {
1456	int i;
1457	for (i = 0; i < min_num_of_arguments; ++i) {
1458	  if (i)
1459	    Printf(args, ",");
1460	  Printf(args, "$%s", arg_names[i]);
1461	}
1462	String *invoke_args = NewStringEmpty();
1463	if (wrapperType == memberfn) {
1464	  Printf(invoke_args, "$this->%s", SWIG_PTR);
1465	  if (min_num_of_arguments > 0)
1466	    Printf(invoke_args, ",");
1467	}
1468	Printf(invoke_args, "%s", args);
1469	bool had_a_case = false;
1470	int last_handled_i = i - 1;
1471	for (; i < max_num_of_arguments; ++i) {
1472	  if (i)
1473	    Printf(args, ",");
1474	  const char *value = Char(arg_values[i]);
1475	  // FIXME: (really_overloaded && handle_as_overload) is perhaps a
1476	  // little conservative, but it doesn't hit any cases that it
1477	  // shouldn't for Xapian at least (and we need it to handle
1478	  // "Enquire::get_mset()" correctly).
1479	  bool non_php_default = ((really_overloaded && handle_as_overload) ||
1480				  !value || strcmp(value, "?") == 0);
1481	  if (non_php_default)
1482	    value = "null";
1483	  Printf(args, "$%s=%s", arg_names[i], value);
1484	  if (non_php_default) {
1485	    if (!had_a_case) {
1486	      Printf(prepare, "\t\tswitch (func_num_args()) {\n");
1487	      had_a_case = true;
1488	    }
1489	    Printf(prepare, "\t\t");
1490	    while (last_handled_i < i) {
1491	      Printf(prepare, "case %d: ", ++last_handled_i);
1492	    }
1493	    if (Cmp(d, "void") != 0) {
1494		if ((!directorsEnabled() || !Swig_directorclass(n)) && !newobject) {
1495		Append(prepare, "$r=");
1496	      } else {
1497		Printf(prepare, "$this->%s=", SWIG_PTR);
1498	      }
1499	    }
1500	    if (!directorsEnabled() || !Swig_directorclass(n) || !newobject) {
1501	      Printf(prepare, "%s(%s); break;\n", iname, invoke_args);
1502	    } else if (!i) {
1503	      Printf(prepare, "%s($_this%s); break;\n", iname, invoke_args);
1504	    } else {
1505	      Printf(prepare, "%s($_this, %s); break;\n", iname, invoke_args);
1506	    }
1507	  }
1508	  if (i || wrapperType == memberfn)
1509	    Printf(invoke_args, ",");
1510	  Printf(invoke_args, "$%s", arg_names[i]);
1511	}
1512	Printf(prepare, "\t\t");
1513	if (had_a_case)
1514	  Printf(prepare, "default: ");
1515	if (Cmp(d, "void") != 0) {
1516	  if ((!directorsEnabled() || !Swig_directorclass(n)) && !newobject) {
1517	    Append(prepare, "$r=");
1518	  } else {
1519	    Printf(prepare, "$this->%s=", SWIG_PTR);
1520	  }
1521	}
1522
1523	if (!directorsEnabled() || !Swig_directorclass(n) || !newobject) {
1524	  Printf(prepare, "%s(%s);\n", iname, invoke_args);
1525	} else {
1526	  Printf(prepare, "%s($_this, %s);\n", iname, invoke_args);
1527	}
1528	if (had_a_case)
1529	  Printf(prepare, "\t\t}\n");
1530	Delete(invoke_args);
1531	Printf(invoke, "$r");
1532      }
1533
1534      Printf(output, "\n");
1535      // If it's a member function or a class constructor...
1536      if (wrapperType == memberfn || (constructor && current_class)) {
1537	String *acc = NewString(Getattr(n, "access"));
1538	// If a base has the same method with public access, then PHP
1539	// requires to have it here as public as well
1540	Node *bases = Getattr(Swig_methodclass(n), "bases");
1541	if (bases && Strcmp(acc, "public") != 0) {
1542	  String *warnmsg = 0;
1543	  int haspublicbase = 0;
1544	  Iterator i = First(bases);
1545	  while (i.item) {
1546	    Node *j = firstChild(i.item);
1547	    while (j) {
1548	      if (Strcmp(Getattr(j, "name"), Getattr(n, "name")) != 0) {
1549		j = nextSibling(j);
1550		continue;
1551	      }
1552	      if (Strcmp(nodeType(j), "cdecl") == 0) {
1553		if (!Getattr(j, "access") || checkAttribute(j, "access", "public")) {
1554		  haspublicbase = 1;
1555		}
1556	      } else if (Strcmp(nodeType(j), "using") == 0 && firstChild(j) && Strcmp(nodeType(firstChild(j)), "cdecl") == 0) {
1557		if (!Getattr(firstChild(j), "access") || checkAttribute(firstChild(j), "access", "public")) {
1558		  haspublicbase = 1;
1559		}
1560	      }
1561	      if (haspublicbase) {
1562		  warnmsg = NewStringf("Modifying the access of '%s::%s' to public, as the base '%s' has it as public as well.\n", Getattr(current_class, "classtype"), Getattr(n, "name"), Getattr(i.item, "classtype"));
1563		  break;
1564	      }
1565	      j = nextSibling(j);
1566	    }
1567	    i = Next(i);
1568	    if (haspublicbase) {
1569	      break;
1570	    }
1571	  }
1572	  if (Getattr(n, "access") && haspublicbase) {
1573	    Delete(acc);
1574	    acc = NewString("public");
1575	    Swig_warning(WARN_PHP_PUBLIC_BASE, input_file, line_number, Char(warnmsg));
1576	    Delete(warnmsg);
1577	  }
1578	}
1579	if (Cmp(acc, "") != 0) {
1580	  Append(acc, " ");
1581	}
1582	if (constructor) {
1583	  const char * arg0;
1584	  if (max_num_of_arguments > 0) {
1585	    arg0 = Char(arg_names[0]);
1586	  } else {
1587	    arg0 = "res";
1588	    Delete(args);
1589	    args = NewString("$res=null");
1590	  }
1591	  SwigType *t = Getattr(current_class, "classtype");
1592	  String *mangled_type = SwigType_manglestr(SwigType_ltype(t));
1593	  Printf(output, "\t%sfunction %s(%s) {\n", acc, methodname, args);
1594	  Printf(output, "\t\tif (is_resource($%s) && get_resource_type($%s) === '_p%s') {\n", arg0, arg0, mangled_type);
1595	  Printf(output, "\t\t\t$this->%s=$%s;\n", SWIG_PTR, arg0);
1596	  Printf(output, "\t\t\treturn;\n");
1597	  Printf(output, "\t\t}\n");
1598	} else {
1599	  Printf(output, "\t%sfunction %s(%s) {\n", acc, methodname, args);
1600	}
1601	Delete(acc);
1602      } else if (wrapperType == staticmembervar) {
1603	// We're called twice for a writable static member variable - first
1604	// with "foo_set" and then with "foo_get" - so generate half the
1605	// wrapper function each time.
1606	//
1607	// For a const static member, we only get called once.
1608	static bool started = false;
1609	if (!started) {
1610	  Printf(output, "\tstatic function %s() {\n", methodname);
1611	  if (max_num_of_arguments) {
1612	    // Setter.
1613	    Printf(output, "\t\tif (func_num_args()) {\n");
1614	    Printf(output, "\t\t\t%s(func_get_arg(0));\n", iname);
1615	    Printf(output, "\t\t\treturn;\n");
1616	    Printf(output, "\t\t}\n");
1617	    started = true;
1618	    goto done;
1619	  }
1620	}
1621	started = false;
1622      } else {
1623	Printf(output, "\tstatic function %s(%s) {\n", methodname, args);
1624      }
1625
1626      if (!newobject)
1627	Printf(output, "%s", prepare);
1628      if (constructor) {
1629	if (!directorsEnabled() || !Swig_directorclass(n)) {
1630	  if (strcmp(methodname, "__construct") == 0) {
1631	    Printf(output, "\t\t$this->%s=%s;\n", SWIG_PTR, invoke);
1632	  } else {
1633	    String *classname = Swig_class_name(current_class);
1634	    Printf(output, "\t\treturn new %s(%s);\n", classname, invoke);
1635	  }
1636	} else {
1637	  Node *parent = Swig_methodclass(n);
1638	  String *classname = Swig_class_name(parent);
1639	  Printf(output, "\t\tif (get_class($this) === '%s%s') {\n", prefix, classname);
1640	  Printf(output, "\t\t\t$_this = null;\n");
1641	  Printf(output, "\t\t} else {\n");
1642	  Printf(output, "\t\t\t$_this = $this;\n");
1643	  Printf(output, "\t\t}\n");
1644	  if (!Len(prepare)) {
1645	    if (num_arguments > 1) {
1646	      Printf(output, "\t\t$this->%s=%s($_this, %s);\n", SWIG_PTR, iname, args);
1647	    } else {
1648	      Printf(output, "\t\t$this->%s=%s($_this);\n", SWIG_PTR, iname);
1649	    }
1650	  }
1651	}
1652	Printf(output, "%s", prepare);
1653      } else if (Cmp(d, "void") == 0) {
1654	if (Cmp(invoke, "$r") != 0)
1655	  Printf(output, "\t\t%s;\n", invoke);
1656      } else if (is_class(d)) {
1657	if (Cmp(invoke, "$r") != 0)
1658	  Printf(output, "\t\t$r=%s;\n", invoke);
1659	if (Len(ret_types) == 1) {
1660	  /* If it has an abstract base, then we can't create a new
1661	   * base object. */
1662	  int hasabstractbase = 0;
1663	  Node *bases = Getattr(Swig_methodclass(n), "bases");
1664	  if (bases) {
1665	    Iterator i = First(bases);
1666	    while(i.item) {
1667	      if (Getattr(i.item, "abstract")) {
1668		hasabstractbase = 1;
1669		break;
1670	      }
1671	      i = Next(i);
1672	    }
1673	  }
1674	  if (newobject || !hasabstractbase) {
1675	    /*
1676	     * _p_Foo -> Foo, _p_ns__Bar -> Bar
1677	     * TODO: do this in a more elegant way
1678	     */
1679	    Printf(output, "\t\tif (is_resource($r)) {\n");
1680	    if (Getattr(classLookup(Getattr(n, "type")), "module")) {
1681	      if (Len(prefix) == 0) {
1682		Printf(output, "\t\t\t$c=substr(get_resource_type($r), (strpos(get_resource_type($r), '__') ? strpos(get_resource_type($r), '__') + 2 : 3));\n");
1683	      } else {
1684		Printf(output, "\t\t\t$c='%s'.substr(get_resource_type($r), (strpos(get_resource_type($r), '__') ? strpos(get_resource_type($r), '__') + 2 : 3));\n", prefix);
1685	      }
1686	      Printf(output, "\t\t\tif (!class_exists($c)) {\n");
1687	      Printf(output, "\t\t\t\treturn new %s($r);\n", Getattr(classLookup(d), "sym:name"));
1688	      Printf(output, "\t\t\t}\n");
1689	      Printf(output, "\t\t\treturn new $c($r);\n");
1690	    } else {
1691	      Printf(output, "\t\t\t$c = new stdClass();\n");
1692	      Printf(output, "\t\t\t$c->_cPtr = $r;\n");
1693	      Printf(output, "\t\t\treturn $c;\n");
1694	    }
1695	    Printf(output, "\t\t}\n\t\treturn $r;\n");
1696	  } else {
1697	    Printf(output, "\t\t$this->%s = $r;\n", SWIG_PTR);
1698	    Printf(output, "\t\treturn $this;\n");
1699	  }
1700	} else {
1701	  Printf(output, "\t\tif (!is_resource($r)) return $r;\n");
1702	  Printf(output, "\t\tswitch (get_resource_type($r)) {\n");
1703	  Iterator i = First(ret_types);
1704	  while (i.item) {
1705	    SwigType *ret_type = i.item;
1706	    i = Next(i);
1707	    Printf(output, "\t\t");
1708	    String *mangled = NewString("_p");
1709	    Printf(mangled, "%s", SwigType_manglestr(ret_type));
1710	    Node *class_node = Getattr(zend_types, mangled);
1711	    if (!class_node) {
1712	      /* This is needed when we're returning a pointer to a type
1713	       * rather than returning the type by value or reference. */
1714	      class_node = current_class;
1715	      Delete(mangled);
1716	      mangled = NewString(SwigType_manglestr(ret_type));
1717	      class_node = Getattr(zend_types, mangled);
1718	    }
1719	    if (i.item) {
1720	      Printf(output, "case '%s': ", mangled);
1721	    } else {
1722	      Printf(output, "default: ");
1723	    }
1724	    const char *classname = GetChar(class_node, "sym:name");
1725	    if (!classname)
1726	      classname = GetChar(class_node, "name");
1727	    if (classname)
1728	      Printf(output, "return new %s%s($r);\n", prefix, classname);
1729            else
1730	      Printf(output, "return $r;\n");
1731	    Delete(mangled);
1732	  }
1733	  Printf(output, "\t\t}\n");
1734	}
1735      } else {
1736	Printf(output, "\t\treturn %s;\n", invoke);
1737      }
1738      Printf(output, "\t}\n");
1739
1740done:
1741      Delete(prepare);
1742      Delete(invoke);
1743      free(arg_values);
1744
1745      Delete(args);
1746      args = NULL;
1747
1748      for (int i = 0; i < max_num_of_arguments; ++i) {
1749	Delete(arg_names[i]);
1750      }
1751      free(arg_names);
1752      arg_names = NULL;
1753    }
1754
1755    return SWIG_OK;
1756  }
1757
1758  /* ------------------------------------------------------------
1759   * globalvariableHandler()
1760   * ------------------------------------------------------------ */
1761
1762  virtual int globalvariableHandler(Node *n) {
1763    char *name = GetChar(n, "name");
1764    char *iname = GetChar(n, "sym:name");
1765    SwigType *t = Getattr(n, "type");
1766    String *tm;
1767
1768    /* First do the wrappers such as name_set(), name_get()
1769     * as provided by the baseclass's implementation of variableWrapper
1770     */
1771    if (Language::globalvariableHandler(n) == SWIG_NOWRAP) {
1772      return SWIG_NOWRAP;
1773    }
1774
1775    if (!addSymbol(iname, n))
1776      return SWIG_ERROR;
1777
1778    SwigType_remember(t);
1779
1780    /* First link C variables to PHP */
1781
1782    tm = Swig_typemap_lookup("varinit", n, name, 0);
1783    if (tm) {
1784      Replaceall(tm, "$target", name);
1785      Printf(s_vinit, "%s\n", tm);
1786    } else {
1787      Printf(stderr, "%s: Line %d, Unable to link with type %s\n", input_file, line_number, SwigType_str(t, 0));
1788    }
1789
1790    /* Now generate PHP -> C sync blocks */
1791    /*
1792       tm = Swig_typemap_lookup("varin", n, name, 0);
1793       if(tm) {
1794       Replaceall(tm, "$symname", iname);
1795       Printf(f_c->code, "%s\n", tm);
1796       } else {
1797       Printf(stderr,"%s: Line %d, Unable to link with type %s\n", input_file, line_number, SwigType_str(t, 0));
1798       }
1799     */
1800    /* Now generate C -> PHP sync blocks */
1801    /*
1802       if(!GetFlag(n,"feature:immutable")) {
1803
1804       tm = Swig_typemap_lookup("varout", n, name, 0);
1805       if(tm) {
1806       Replaceall(tm, "$symname", iname);
1807       Printf(f_php->code, "%s\n", tm);
1808       } else {
1809       Printf(stderr,"%s: Line %d, Unable to link with type %s\n", input_file, line_number, SwigType_str(t, 0));
1810       }
1811       }
1812     */
1813    return SWIG_OK;
1814  }
1815
1816  /* ------------------------------------------------------------
1817   * constantWrapper()
1818   * ------------------------------------------------------------ */
1819
1820  virtual int constantWrapper(Node *n) {
1821    String *name = GetChar(n, "name");
1822    String *iname = GetChar(n, "sym:name");
1823    SwigType *type = Getattr(n, "type");
1824    String *rawval = Getattr(n, "rawval");
1825    String *value = rawval ? rawval : Getattr(n, "value");
1826    String *tm;
1827
1828    if (!addSymbol(iname, n))
1829      return SWIG_ERROR;
1830
1831    SwigType_remember(type);
1832
1833    if ((tm = Swig_typemap_lookup("consttab", n, name, 0))) {
1834      Replaceall(tm, "$source", value);
1835      Replaceall(tm, "$target", name);
1836      Replaceall(tm, "$value", value);
1837      Printf(s_cinit, "%s\n", tm);
1838    }
1839
1840    if (shadow) {
1841      String *enumvalue = GetChar(n, "enumvalue");
1842      String *set_to = iname;
1843
1844      if (!enumvalue) {
1845	enumvalue = GetChar(n, "enumvalueex");
1846      }
1847
1848      if (enumvalue) {
1849	// Check for a simple constant expression which is valid in PHP.
1850	// If we find one, initialise the const member with it; otherwise
1851	// we initialise it using the C/C++ wrapped constant.
1852	const char *p;
1853	for (p = Char(enumvalue); *p; ++p) {
1854	  if (!isdigit((unsigned char)*p) && !strchr(" +-", *p)) {
1855	    // FIXME: enhance to handle `<previous_enum> + 1' which is what
1856	    // we get for enums that don't have an explicit value set.
1857	    break;
1858	  }
1859	}
1860	if (!*p) set_to = enumvalue;
1861      }
1862
1863      if (wrapping_member_constant) {
1864	if (!s_oowrappers)
1865	  s_oowrappers = NewStringEmpty();
1866	Printf(s_oowrappers, "\n\tconst %s = %s;\n", wrapping_member_constant, set_to);
1867      } else {
1868	if (!s_fakeoowrappers)
1869	  s_fakeoowrappers = NewStringEmpty();
1870	Printf(s_fakeoowrappers, "\n\tconst %s = %s;\n", iname, set_to);
1871      }
1872    }
1873
1874    return SWIG_OK;
1875  }
1876
1877  /*
1878   * PHP::pragma()
1879   *
1880   * Pragma directive.
1881   *
1882   * %pragma(php) code="String"         # Includes a string in the .php file
1883   * %pragma(php) include="file.php"    # Includes a file in the .php file
1884   */
1885
1886  virtual int pragmaDirective(Node *n) {
1887    if (!ImportMode) {
1888      String *lang = Getattr(n, "lang");
1889      String *type = Getattr(n, "name");
1890      String *value = Getattr(n, "value");
1891
1892      if (Strcmp(lang, "php") == 0 || Strcmp(lang, "php4") == 0) {
1893	if (Strcmp(type, "code") == 0) {
1894	  if (value) {
1895	    Printf(pragma_code, "%s\n", value);
1896	  }
1897	} else if (Strcmp(type, "include") == 0) {
1898	  if (value) {
1899	    Printf(pragma_incl, "include '%s';\n", value);
1900	  }
1901	} else if (Strcmp(type, "phpinfo") == 0) {
1902	  if (value) {
1903	    Printf(pragma_phpinfo, "%s\n", value);
1904	  }
1905	} else {
1906	  Swig_warning(WARN_PHP_UNKNOWN_PRAGMA, input_file, line_number, "Unrecognized pragma <%s>.\n", type);
1907	}
1908      }
1909    }
1910    return Language::pragmaDirective(n);
1911  }
1912
1913  /* ------------------------------------------------------------
1914   * classDeclaration()
1915   * ------------------------------------------------------------ */
1916
1917  virtual int classDeclaration(Node *n) {
1918    if (!Getattr(n, "feature:onlychildren")) {
1919      String *symname = Getattr(n, "sym:name");
1920      Setattr(n, "php:proxy", symname);
1921    }
1922
1923    return Language::classDeclaration(n);
1924  }
1925
1926  /* ------------------------------------------------------------
1927   * classHandler()
1928   * ------------------------------------------------------------ */
1929
1930  virtual int classHandler(Node *n) {
1931    constructors = 0;
1932    //SwigType *t = Getattr(n, "classtype");
1933    current_class = n;
1934    // String *use_class_name=SwigType_manglestr(SwigType_ltype(t));
1935
1936    if (shadow) {
1937      char *rename = GetChar(n, "sym:name");
1938
1939      if (!addSymbol(rename, n))
1940	return SWIG_ERROR;
1941      shadow_classname = NewString(rename);
1942
1943      shadow_get_vars = NewHash();
1944      shadow_set_vars = NewHash();
1945
1946      /* Deal with inheritance */
1947      List *baselist = Getattr(n, "bases");
1948      if (baselist) {
1949	Iterator base = First(baselist);
1950	while (base.item && GetFlag(base.item, "feature:ignore")) {
1951	  base = Next(base);
1952	}
1953	base = Next(base);
1954	if (base.item) {
1955	  /* Warn about multiple inheritance for additional base class(es) */
1956	  while (base.item) {
1957	    if (GetFlag(base.item, "feature:ignore")) {
1958	      base = Next(base);
1959	      continue;
1960	    }
1961	    String *proxyclassname = SwigType_str(Getattr(n, "classtypeobj"), 0);
1962	    String *baseclassname = SwigType_str(Getattr(base.item, "name"), 0);
1963	    Swig_warning(WARN_PHP_MULTIPLE_INHERITANCE, input_file, line_number,
1964			 "Warning for %s proxy: Base %s ignored. Multiple inheritance is not supported in PHP.\n", proxyclassname, baseclassname);
1965	    base = Next(base);
1966	  }
1967	}
1968      }
1969    }
1970
1971    classnode = n;
1972    Language::classHandler(n);
1973    classnode = 0;
1974
1975    if (shadow) {
1976      DOH *key;
1977      List *baselist = Getattr(n, "bases");
1978      Iterator ki, base;
1979
1980      if (baselist) {
1981	base = First(baselist);
1982	while (base.item && GetFlag(base.item, "feature:ignore")) {
1983	  base = Next(base);
1984	}
1985      } else {
1986	base.item = NULL;
1987      }
1988
1989      if (Getattr(n, "abstract") && !GetFlag(n, "feature:notabstract")) {
1990	Printf(s_phpclasses, "abstract ");
1991      }
1992
1993      Printf(s_phpclasses, "class %s%s ", prefix, shadow_classname);
1994      String *baseclass = NULL;
1995      if (base.item && Getattr(base.item, "module")) {
1996	baseclass = Getattr(base.item, "sym:name");
1997	if (!baseclass)
1998	  baseclass = Getattr(base.item, "name");
1999	Printf(s_phpclasses, "extends %s%s ", prefix, baseclass);
2000      } else if (GetFlag(n, "feature:exceptionclass")) {
2001	Append(s_phpclasses, "extends Exception ");
2002      }
2003      Printf(s_phpclasses, "{\n\tpublic $%s=null;\n", SWIG_PTR);
2004      if (!baseclass) {
2005	// Only store this in the base class (NB !baseclass means we *are*
2006	// a base class...)
2007	Printf(s_phpclasses, "\tprotected $%s=array();\n", SWIG_DATA);
2008      }
2009
2010      // Write property SET handlers
2011      ki = First(shadow_set_vars);
2012
2013      if (ki.key) {
2014	// This class has setters.
2015	Printf(s_phpclasses, "\n\tfunction __set($var,$value) {\n");
2016	// FIXME: tune this threshold...
2017	if (Len(shadow_set_vars) <= 2) {
2018	  // Not many setters, so avoid call_user_func.
2019	  while (ki.key) {
2020	    key = ki.key;
2021	    Printf(s_phpclasses, "\t\tif ($var === '%s') return %s($this->%s,$value);\n", key, ki.item, SWIG_PTR);
2022	    ki = Next(ki);
2023	  }
2024	} else {
2025	  Printf(s_phpclasses, "\t\t$func = '%s_'.$var.'_set';\n", shadow_classname);
2026	  Printf(s_phpclasses, "\t\tif (function_exists($func)) return call_user_func($func,$this->%s,$value);\n", SWIG_PTR);
2027	}
2028	Printf(s_phpclasses, "\t\tif ($var === 'thisown') return swig_%s_alter_newobject($this->%s,$value);\n", module, SWIG_PTR);
2029	if (baseclass) {
2030	  Printf(s_phpclasses, "\t\t%s%s::__set($var,$value);\n", prefix, baseclass);
2031	} else {
2032	  Printf(s_phpclasses, "\t\t$this->%s[$var] = $value;\n", SWIG_DATA);
2033	}
2034	Printf(s_phpclasses, "\t}\n");
2035
2036	/* Create __isset for PHP 5.1 and later; PHP 5.0 will just ignore it. */
2037	Printf(s_phpclasses, "\n\tfunction __isset($var) {\n");
2038	Printf(s_phpclasses, "\t\tif (function_exists('%s_'.$var.'_set')) return true;\n", shadow_classname);
2039	Printf(s_phpclasses, "\t\tif ($var === 'thisown') return true;\n");
2040	if (baseclass) {
2041	  Printf(s_phpclasses, "\t\treturn %s%s::__isset($var);\n", prefix, baseclass);
2042	} else {
2043	  Printf(s_phpclasses, "\t\treturn array_key_exists($var, $this->%s);\n", SWIG_DATA);
2044	}
2045	Printf(s_phpclasses, "\t}\n");
2046      } else {
2047	Printf(s_phpclasses, "\n\tfunction __set($var,$value) {\n");
2048	Printf(s_phpclasses, "\t\tif ($var === 'thisown') return swig_%s_alter_newobject($this->%s,$value);\n", module, SWIG_PTR);
2049	if (baseclass) {
2050	  Printf(s_phpclasses, "\t\t%s%s::__set($var,$value);\n", prefix, baseclass);
2051	} else {
2052	  Printf(s_phpclasses, "\t\t$this->%s[$var] = $value;\n", SWIG_DATA);
2053	}
2054	Printf(s_phpclasses, "\t}\n");
2055	Printf(s_phpclasses, "\n\tfunction __isset($var) {\n");
2056	Printf(s_phpclasses, "\t\tif ($var === 'thisown') return true;\n");
2057	if (baseclass) {
2058	  Printf(s_phpclasses, "\t\treturn %s%s::__isset($var);\n", prefix, baseclass);
2059	} else {
2060	  Printf(s_phpclasses, "\t\treturn array_key_exists($var, $this->%s);\n", SWIG_DATA);
2061	}
2062	Printf(s_phpclasses, "\t}\n");
2063      }
2064      // Write property GET handlers
2065      ki = First(shadow_get_vars);
2066
2067      if (ki.key) {
2068	// This class has getters.
2069	Printf(s_phpclasses, "\n\tfunction __get($var) {\n");
2070	// FIXME: Currently we always use call_user_func for __get, so we can
2071	// check and wrap the result.  This is needless if all the properties
2072	// are primitive types.  Also this doesn't handle all the cases which
2073	// a method returning an object does.
2074	Printf(s_phpclasses, "\t\t$func = '%s_'.$var.'_get';\n", shadow_classname);
2075	Printf(s_phpclasses, "\t\tif (function_exists($func)) {\n");
2076	Printf(s_phpclasses, "\t\t\t$r = call_user_func($func,$this->%s);\n", SWIG_PTR);
2077	Printf(s_phpclasses, "\t\t\tif (!is_resource($r)) return $r;\n");
2078	if (Len(prefix) == 0) {
2079	  Printf(s_phpclasses, "\t\t\t$c=substr(get_resource_type($r), (strpos(get_resource_type($r), '__') ? strpos(get_resource_type($r), '__') + 2 : 3));\n");
2080	} else {
2081	  Printf(s_phpclasses, "\t\t\t$c='%s'.substr(get_resource_type($r), (strpos(get_resource_type($r), '__') ? strpos(get_resource_type($r), '__') + 2 : 3));\n", prefix);
2082	}
2083	Printf(s_phpclasses, "\t\t\treturn new $c($r);\n");
2084	Printf(s_phpclasses, "\t\t}\n");
2085	Printf(s_phpclasses, "\t\tif ($var === 'thisown') return swig_%s_get_newobject($this->%s);\n", module, SWIG_PTR);
2086	if (baseclass) {
2087	  Printf(s_phpclasses, "\t\treturn %s%s::__get($var);\n", prefix, baseclass);
2088	} else {
2089	  // Reading an unknown property name gives null in PHP.
2090	  Printf(s_phpclasses, "\t\treturn $this->%s[$var];\n", SWIG_DATA);
2091	}
2092	Printf(s_phpclasses, "\t}\n");
2093      } else {
2094	Printf(s_phpclasses, "\n\tfunction __get($var) {\n");
2095	Printf(s_phpclasses, "\t\tif ($var === 'thisown') return swig_%s_get_newobject($this->%s);\n", module, SWIG_PTR);
2096	if (baseclass) {
2097	  Printf(s_phpclasses, "\t\treturn %s%s::__get($var);\n", prefix, baseclass);
2098	} else {
2099	  Printf(s_phpclasses, "\t\treturn $this->%s[$var];\n", SWIG_DATA);
2100	}
2101	Printf(s_phpclasses, "\t}\n");
2102      }
2103
2104      if (!class_has_ctor) {
2105	Printf(s_phpclasses, "\tfunction __construct($h) {\n");
2106	Printf(s_phpclasses, "\t\t$this->%s=$h;\n", SWIG_PTR);
2107	Printf(s_phpclasses, "\t}\n");
2108      }
2109
2110      if (s_oowrappers) {
2111	Printf(s_phpclasses, "%s", s_oowrappers);
2112	Delete(s_oowrappers);
2113	s_oowrappers = NULL;
2114      }
2115      class_has_ctor = false;
2116
2117      Printf(s_phpclasses, "}\n\n");
2118
2119      Delete(shadow_classname);
2120      shadow_classname = NULL;
2121
2122      Delete(shadow_set_vars);
2123      shadow_set_vars = NULL;
2124      Delete(shadow_get_vars);
2125      shadow_get_vars = NULL;
2126    }
2127    return SWIG_OK;
2128  }
2129
2130  /* ------------------------------------------------------------
2131   * memberfunctionHandler()
2132   * ------------------------------------------------------------ */
2133
2134  virtual int memberfunctionHandler(Node *n) {
2135    wrapperType = memberfn;
2136    Language::memberfunctionHandler(n);
2137    wrapperType = standard;
2138
2139    return SWIG_OK;
2140  }
2141
2142  /* ------------------------------------------------------------
2143   * membervariableHandler()
2144   * ------------------------------------------------------------ */
2145
2146  virtual int membervariableHandler(Node *n) {
2147    wrapperType = membervar;
2148    Language::membervariableHandler(n);
2149    wrapperType = standard;
2150
2151    return SWIG_OK;
2152  }
2153
2154  /* ------------------------------------------------------------
2155   * staticmembervariableHandler()
2156   * ------------------------------------------------------------ */
2157
2158  virtual int staticmembervariableHandler(Node *n) {
2159    wrapperType = staticmembervar;
2160    Language::staticmembervariableHandler(n);
2161    wrapperType = standard;
2162
2163    return SWIG_OK;
2164  }
2165
2166  /* ------------------------------------------------------------
2167   * staticmemberfunctionHandler()
2168   * ------------------------------------------------------------ */
2169
2170  virtual int staticmemberfunctionHandler(Node *n) {
2171    wrapperType = staticmemberfn;
2172    Language::staticmemberfunctionHandler(n);
2173    wrapperType = standard;
2174
2175    return SWIG_OK;
2176  }
2177
2178  int abstractConstructorHandler(Node *) {
2179    return SWIG_OK;
2180  }
2181
2182  /* ------------------------------------------------------------
2183   * constructorHandler()
2184   * ------------------------------------------------------------ */
2185
2186  virtual int constructorHandler(Node *n) {
2187    constructors++;
2188    if (Swig_directorclass(n)) {
2189      String *name = GetChar(Swig_methodclass(n), "name");
2190      String *ctype = GetChar(Swig_methodclass(n), "classtype");
2191      String *sname = GetChar(Swig_methodclass(n), "sym:name");
2192      String *args = NewStringEmpty();
2193      ParmList *p = Getattr(n, "parms");
2194      int i;
2195
2196      for (i = 0; p; p = nextSibling(p), i++) {
2197	if (i) {
2198	  Printf(args, ", ");
2199	}
2200	if (Strcmp(GetChar(p, "type"), SwigType_str(GetChar(p, "type"), 0))) {
2201	  SwigType *t = Getattr(p, "type");
2202	  Printf(args, "%s", SwigType_rcaststr(t, 0));
2203	  if (SwigType_isreference(t)) {
2204	    Append(args, "*");
2205	  }
2206	}
2207	Printf(args, "arg%d", i+1);
2208      }
2209
2210      /* director ctor code is specific for each class */
2211      Delete(director_ctor_code);
2212      director_ctor_code = NewStringEmpty();
2213      director_prot_ctor_code = NewStringEmpty();
2214      Printf(director_ctor_code, "if ( arg0->type == IS_NULL ) { /* not subclassed */\n");
2215      Printf(director_prot_ctor_code, "if ( arg0->type == IS_NULL ) { /* not subclassed */\n");
2216      Printf(director_ctor_code, "  result = (%s *)new %s(%s);\n", ctype, ctype, args);
2217      Printf(director_prot_ctor_code, "  SWIG_PHP_Error(E_ERROR, \"accessing abstract class or protected constructor\");\n", name, name, args);
2218      if (i) {
2219	Insert(args, 0, ", ");
2220      }
2221      Printf(director_ctor_code, "} else {\n  result = (%s *)new SwigDirector_%s(arg0%s);\n}\n", ctype, sname, args);
2222      Printf(director_prot_ctor_code, "} else {\n  result = (%s *)new SwigDirector_%s(arg0%s);\n}\n", ctype, sname, args);
2223      Delete(args);
2224
2225      wrapperType = directorconstructor;
2226    } else {
2227      wrapperType = constructor;
2228    }
2229    Language::constructorHandler(n);
2230    wrapperType = standard;
2231
2232    return SWIG_OK;
2233  }
2234
2235  /* ------------------------------------------------------------
2236   * CreateZendListDestructor()
2237   * ------------------------------------------------------------ */
2238  //virtual int destructorHandler(Node *n) {
2239  //}
2240  int CreateZendListDestructor(Node *n) {
2241    String *name = GetChar(Swig_methodclass(n), "name");
2242    String *iname = GetChar(n, "sym:name");
2243    ParmList *l = Getattr(n, "parms");
2244
2245    String *destructorname = NewStringEmpty();
2246    Printf(destructorname, "_%s", Swig_name_wrapper(iname));
2247    Setattr(classnode, "destructor", destructorname);
2248
2249    Wrapper *f = NewWrapper();
2250    Printf(f->def, "/* This function is designed to be called by the zend list destructors */\n");
2251    Printf(f->def, "/* to typecast and do the actual destruction */\n");
2252    Printf(f->def, "static void %s(zend_rsrc_list_entry *rsrc, const char *type_name TSRMLS_DC) {\n", destructorname);
2253
2254    Wrapper_add_localv(f, "value", "swig_object_wrapper *value=(swig_object_wrapper *) rsrc->ptr", NIL);
2255    Wrapper_add_localv(f, "ptr", "void *ptr=value->ptr", NIL);
2256    Wrapper_add_localv(f, "newobject", "int newobject=value->newobject", NIL);
2257
2258    emit_parameter_variables(l, f);
2259    emit_attach_parmmaps(l, f);
2260
2261    // Get type of first arg, thing to be destructed
2262    // Skip ignored arguments
2263    Parm *p = l;
2264    //while (Getattr(p,"tmap:ignore")) {p = Getattr(p,"tmap:ignore:next");}
2265    while (checkAttribute(p, "tmap:in:numinputs", "0")) {
2266      p = Getattr(p, "tmap:in:next");
2267    }
2268    SwigType *pt = Getattr(p, "type");
2269
2270    Printf(f->code, "  efree(value);\n");
2271    Printf(f->code, "  if (! newobject) return; /* can't delete it! */\n");
2272    Printf(f->code, "  arg1 = (%s)SWIG_ZTS_ConvertResourceData(ptr,type_name,SWIGTYPE%s TSRMLS_CC);\n", SwigType_lstr(pt, 0), SwigType_manglestr(pt));
2273    Printf(f->code, "  if (! arg1) zend_error(E_ERROR, \"%s resource already free'd\");\n", Char(name));
2274
2275    Setattr(n, "wrap:name", destructorname);
2276
2277    String *actioncode = emit_action(n);
2278    Append(f->code, actioncode);
2279    Delete(actioncode);
2280
2281    Append(f->code, "return;\n");
2282    Append(f->code, "fail:\n");
2283    Append(f->code, "zend_error_noreturn(SWIG_ErrorCode(),\"%s\",SWIG_ErrorMsg());\n");
2284    Printf(f->code, "}\n");
2285
2286    Wrapper_print(f, s_wrappers);
2287
2288    return SWIG_OK;
2289  }
2290
2291  /* ------------------------------------------------------------
2292   * memberconstantHandler()
2293   * ------------------------------------------------------------ */
2294
2295  virtual int memberconstantHandler(Node *n) {
2296    wrapping_member_constant = Getattr(n, "sym:name");
2297    Language::memberconstantHandler(n);
2298    wrapping_member_constant = NULL;
2299    return SWIG_OK;
2300  }
2301
2302  int classDirectorInit(Node *n) {
2303    String *declaration = Swig_director_declaration(n);
2304    Printf(f_directors_h, "%s\n", declaration);
2305    Printf(f_directors_h, "public:\n");
2306    Delete(declaration);
2307    return Language::classDirectorInit(n);
2308  }
2309
2310  int classDirectorEnd(Node *n) {
2311    Printf(f_directors_h, "};\n");
2312    return Language::classDirectorEnd(n);
2313  }
2314
2315  int classDirectorConstructor(Node *n) {
2316    Node *parent = Getattr(n, "parentNode");
2317    String *decl = Getattr(n, "decl");
2318    String *supername = Swig_class_name(parent);
2319    String *classname = NewStringEmpty();
2320    Printf(classname, "SwigDirector_%s", supername);
2321
2322    /* insert self parameter */
2323    Parm *p;
2324    ParmList *superparms = Getattr(n, "parms");
2325    ParmList *parms = CopyParmList(superparms);
2326    String *type = NewString("zval");
2327    SwigType_add_pointer(type);
2328    p = NewParm(type, NewString("self"));
2329    set_nextSibling(p, parms);
2330    parms = p;
2331
2332    if (!Getattr(n, "defaultargs")) {
2333      /* constructor */
2334      {
2335	Wrapper *w = NewWrapper();
2336	String *call;
2337	String *basetype = Getattr(parent, "classtype");
2338	String *target = Swig_method_decl(0, decl, classname, parms, 0, 0);
2339	call = Swig_csuperclass_call(0, basetype, superparms);
2340	Printf(w->def, "%s::%s: %s, Swig::Director(self) {", classname, target, call);
2341	Append(w->def, "}");
2342	Delete(target);
2343	Wrapper_print(w, f_directors);
2344	Delete(call);
2345	DelWrapper(w);
2346      }
2347
2348      /* constructor header */
2349      {
2350	String *target = Swig_method_decl(0, decl, classname, parms, 0, 1);
2351	Printf(f_directors_h, "    %s;\n", target);
2352	Delete(target);
2353      }
2354    }
2355    return Language::classDirectorConstructor(n);
2356  }
2357
2358  int classDirectorMethod(Node *n, Node *parent, String *super) {
2359    int is_void = 0;
2360    int is_pointer = 0;
2361    String *decl;
2362    String *type;
2363    String *name;
2364    String *classname;
2365    String *c_classname = Getattr(parent, "name");
2366    String *declaration;
2367    ParmList *l;
2368    Wrapper *w;
2369    String *tm;
2370    String *wrap_args = NewStringEmpty();
2371    String *return_type;
2372    String *value = Getattr(n, "value");
2373    String *storage = Getattr(n, "storage");
2374    bool pure_virtual = false;
2375    int status = SWIG_OK;
2376    int idx;
2377    bool ignored_method = GetFlag(n, "feature:ignore") ? true : false;
2378
2379    if (Cmp(storage, "virtual") == 0) {
2380      if (Cmp(value, "0") == 0) {
2381	pure_virtual = true;
2382      }
2383    }
2384
2385    classname = Getattr(parent, "sym:name");
2386    type = Getattr(n, "type");
2387    name = Getattr(n, "name");
2388
2389    w = NewWrapper();
2390    declaration = NewStringEmpty();
2391
2392    /* determine if the method returns a pointer */
2393    decl = Getattr(n, "decl");
2394    is_pointer = SwigType_ispointer_return(decl);
2395    is_void = (Cmp(type, "void") == 0 && !is_pointer);
2396
2397    /* form complete return type */
2398    return_type = Copy(type);
2399    {
2400      SwigType *t = Copy(decl);
2401      SwigType *f = SwigType_pop_function(t);
2402      SwigType_push(return_type, t);
2403      Delete(f);
2404      Delete(t);
2405    }
2406
2407    /* virtual method definition */
2408    l = Getattr(n, "parms");
2409    String *target;
2410    String *pclassname = NewStringf("SwigDirector_%s", classname);
2411    String *qualified_name = NewStringf("%s::%s", pclassname, name);
2412    SwigType *rtype = Getattr(n, "conversion_operator") ? 0 : type;
2413    target = Swig_method_decl(rtype, decl, qualified_name, l, 0, 0);
2414    Printf(w->def, "%s", target);
2415    Delete(qualified_name);
2416    Delete(target);
2417    /* header declaration */
2418    target = Swig_method_decl(rtype, decl, name, l, 0, 1);
2419    Printf(declaration, "    virtual %s", target);
2420    Delete(target);
2421
2422    // Get any exception classes in the throws typemap
2423    ParmList *throw_parm_list = 0;
2424
2425    if ((throw_parm_list = Getattr(n, "throws")) || Getattr(n, "throw")) {
2426      Parm *p;
2427      int gencomma = 0;
2428
2429      Append(w->def, " throw(");
2430      Append(declaration, " throw(");
2431
2432      if (throw_parm_list)
2433	Swig_typemap_attach_parms("throws", throw_parm_list, 0);
2434      for (p = throw_parm_list; p; p = nextSibling(p)) {
2435	if ((tm = Getattr(p, "tmap:throws"))) {
2436	  if (gencomma++) {
2437	    Append(w->def, ", ");
2438	    Append(declaration, ", ");
2439	  }
2440	  String *str = SwigType_str(Getattr(p, "type"), 0);
2441	  Append(w->def, str);
2442	  Append(declaration, str);
2443	  Delete(str);
2444	}
2445      }
2446
2447      Append(w->def, ")");
2448      Append(declaration, ")");
2449    }
2450
2451    Append(w->def, " {");
2452    Append(declaration, ";\n");
2453
2454    /* declare method return value
2455     * if the return value is a reference or const reference, a specialized typemap must
2456     * handle it, including declaration of c_result ($result).
2457     */
2458    if (!is_void) {
2459      if (!(ignored_method && !pure_virtual)) {
2460	String *cres = SwigType_lstr(return_type, "c_result");
2461	Printf(w->code, "%s;\n", cres);
2462	Delete(cres);
2463      }
2464    }
2465
2466    if (ignored_method) {
2467      if (!pure_virtual) {
2468	if (!is_void)
2469	  Printf(w->code, "return ");
2470	String *super_call = Swig_method_call(super, l);
2471	Printf(w->code, "%s;\n", super_call);
2472	Delete(super_call);
2473      } else {
2474	Printf(w->code, "Swig::DirectorPureVirtualException::raise(\"Attempted to invoke pure virtual method %s::%s\");\n", SwigType_namestr(c_classname),
2475	    SwigType_namestr(name));
2476      }
2477    } else {
2478      /* attach typemaps to arguments (C/C++ -> PHP) */
2479      String *parse_args = NewStringEmpty();
2480
2481      /* remove the wrapper 'w' since it was producing spurious temps */
2482      Swig_typemap_attach_parms("in", l, 0);
2483      Swig_typemap_attach_parms("directorin", l, 0);
2484      Swig_typemap_attach_parms("directorargout", l, w);
2485
2486      Parm *p;
2487      char source[256];
2488
2489      int outputs = 0;
2490      if (!is_void)
2491	outputs++;
2492
2493      /* build argument list and type conversion string */
2494      idx = 0;
2495      p = l;
2496      int use_parse = 0;
2497      while (p != NULL) {
2498	if (checkAttribute(p, "tmap:in:numinputs", "0")) {
2499	  p = Getattr(p, "tmap:in:next");
2500	  continue;
2501	}
2502
2503	if (Getattr(p, "tmap:directorargout") != 0)
2504	  outputs++;
2505
2506	String *pname = Getattr(p, "name");
2507	String *ptype = Getattr(p, "type");
2508
2509	if ((tm = Getattr(p, "tmap:directorin")) != 0) {
2510	  String *parse = Getattr(p, "tmap:directorin:parse");
2511	  if (!parse) {
2512	    sprintf(source, "obj%d", idx++);
2513	    String *input = NewStringf("&%s", source);
2514	    Replaceall(tm, "$input", input);
2515	    Delete(input);
2516	    Replaceall(tm, "$owner", "0");
2517	    Printv(wrap_args, "zval ", source, ";\n", NIL);
2518	    Printf(wrap_args, "args[%d] = &%s;\n", idx - 1, source);
2519
2520	    Printv(wrap_args, tm, "\n", NIL);
2521	    Putc('O', parse_args);
2522	  } else {
2523	    use_parse = 1;
2524	    Append(parse_args, parse);
2525	    Replaceall(tm, "$input", pname);
2526	    Replaceall(tm, "$owner", "0");
2527	    if (Len(tm) == 0)
2528	      Append(tm, pname);
2529	  }
2530	  p = Getattr(p, "tmap:directorin:next");
2531	  continue;
2532	} else if (Cmp(ptype, "void")) {
2533	  Swig_warning(WARN_TYPEMAP_DIRECTORIN_UNDEF, input_file, line_number,
2534	      "Unable to use type %s as a function argument in director method %s::%s (skipping method).\n", SwigType_str(ptype, 0),
2535	      SwigType_namestr(c_classname), SwigType_namestr(name));
2536	  status = SWIG_NOWRAP;
2537	  break;
2538	}
2539	p = nextSibling(p);
2540      }
2541      Append(w->code, "int error;\n");
2542      if (!idx) {
2543	Printf(w->code, "zval **args = NULL;\n", idx);
2544      } else {
2545	Printf(w->code, "zval *args[%d];\n", idx);
2546      }
2547      Append(w->code, "zval *result, funcname;\n");
2548      Append(w->code, "MAKE_STD_ZVAL(result);\n");
2549      Printf(w->code, "ZVAL_STRING(&funcname, (char *)\"%s\", 0);\n", name);
2550      Append(w->code, "if (!swig_self) {\n");
2551      Append(w->code, "  SWIG_PHP_Error(E_ERROR, \"this pointer is NULL\");");
2552      Append(w->code, "}\n\n");
2553
2554      /* wrap complex arguments to zvals */
2555      Printv(w->code, wrap_args, NIL);
2556
2557      Append(w->code, "call_user_function(EG(function_table), (zval**)&swig_self, &funcname,\n");
2558      Printf(w->code, "  result, %d, args TSRMLS_CC);\n", idx);
2559
2560      /* exception handling */
2561      tm = Swig_typemap_lookup("director:except", n, "result", 0);
2562      if (!tm) {
2563	tm = Getattr(n, "feature:director:except");
2564	if (tm)
2565	  tm = Copy(tm);
2566      }
2567      if ((tm) && Len(tm) && (Strcmp(tm, "1") != 0)) {
2568	Replaceall(tm, "$error", "error");
2569	Printv(w->code, Str(tm), "\n", NIL);
2570      }
2571      Delete(tm);
2572
2573      /* marshal return value from PHP to C/C++ type */
2574
2575      String *cleanup = NewStringEmpty();
2576      String *outarg = NewStringEmpty();
2577
2578      idx = 0;
2579
2580      /* marshal return value */
2581      if (!is_void) {
2582	/* this seems really silly.  the node's type excludes
2583	 * qualifier/pointer/reference markers, which have to be retrieved
2584	 * from the decl field to construct return_type.  but the typemap
2585	 * lookup routine uses the node's type, so we have to swap in and
2586	 * out the correct type.  it's not just me, similar silliness also
2587	 * occurs in Language::cDeclaration().
2588	 */
2589	Setattr(n, "type", return_type);
2590	tm = Swig_typemap_lookup("directorout", n, "result", w);
2591	Setattr(n, "type", type);
2592	if (tm != 0) {
2593	  Replaceall(tm, "$input", "&result");
2594	  char temp[24];
2595	  sprintf(temp, "%d", idx);
2596	  Replaceall(tm, "$argnum", temp);
2597
2598	  /* TODO check this */
2599	  if (Getattr(n, "wrap:disown")) {
2600	    Replaceall(tm, "$disown", "SWIG_POINTER_DISOWN");
2601	  } else {
2602	    Replaceall(tm, "$disown", "0");
2603	  }
2604	  Replaceall(tm, "$result", "c_result");
2605	  Printv(w->code, tm, "\n", NIL);
2606	  Delete(tm);
2607	} else {
2608	  Swig_warning(WARN_TYPEMAP_DIRECTOROUT_UNDEF, input_file, line_number,
2609	      "Unable to use return type %s in director method %s::%s (skipping method).\n", SwigType_str(return_type, 0), SwigType_namestr(c_classname),
2610	      SwigType_namestr(name));
2611	  status = SWIG_ERROR;
2612	}
2613      }
2614
2615      /* marshal outputs */
2616      for (p = l; p;) {
2617	if ((tm = Getattr(p, "tmap:directorargout")) != 0) {
2618	  Replaceall(tm, "$input", "result");
2619	  Replaceall(tm, "$result", Getattr(p, "name"));
2620	  Printv(w->code, tm, "\n", NIL);
2621	  p = Getattr(p, "tmap:directorargout:next");
2622	} else {
2623	  p = nextSibling(p);
2624	}
2625      }
2626
2627      Append(w->code, "FREE_ZVAL(result);\n");
2628
2629      Delete(parse_args);
2630      Delete(cleanup);
2631      Delete(outarg);
2632    }
2633
2634    if (!is_void) {
2635      if (!(ignored_method && !pure_virtual)) {
2636	String *rettype = SwigType_str(return_type, 0);
2637	if (!SwigType_isreference(return_type)) {
2638	  Printf(w->code, "return (%s) c_result;\n", rettype);
2639	} else {
2640	  Printf(w->code, "return (%s) *c_result;\n", rettype);
2641	}
2642	Delete(rettype);
2643      }
2644    } else {
2645      Append(w->code, "return;\n");
2646    }
2647
2648    Append(w->code, "fail:\n");
2649    Append(w->code, "zend_error_noreturn(SWIG_ErrorCode(),\"%s\",SWIG_ErrorMsg());\n");
2650    Append(w->code, "}\n");
2651
2652    // We expose protected methods via an extra public inline method which makes a straight call to the wrapped class' method
2653    String *inline_extra_method = NewStringEmpty();
2654    if (dirprot_mode() && !is_public(n) && !pure_virtual) {
2655      Printv(inline_extra_method, declaration, NIL);
2656      String *extra_method_name = NewStringf("%sSwigPublic", name);
2657      Replaceall(inline_extra_method, name, extra_method_name);
2658      Replaceall(inline_extra_method, ";\n", " {\n      ");
2659      if (!is_void)
2660	Printf(inline_extra_method, "return ");
2661      String *methodcall = Swig_method_call(super, l);
2662      Printv(inline_extra_method, methodcall, ";\n    }\n", NIL);
2663      Delete(methodcall);
2664      Delete(extra_method_name);
2665    }
2666
2667    /* emit the director method */
2668    if (status == SWIG_OK) {
2669      if (!Getattr(n, "defaultargs")) {
2670	Wrapper_print(w, f_directors);
2671	Printv(f_directors_h, declaration, NIL);
2672	Printv(f_directors_h, inline_extra_method, NIL);
2673      }
2674    }
2675
2676    /* clean up */
2677    Delete(wrap_args);
2678    Delete(return_type);
2679    Delete(pclassname);
2680    DelWrapper(w);
2681    return status;
2682  }
2683
2684  int classDirectorDisown(Node *) {
2685    return SWIG_OK;
2686  }
2687};				/* class PHP */
2688
2689static PHP *maininstance = 0;
2690
2691// We use this function to be able to write out zend_register_list_destructor_ex
2692// lines for most things in the type table
2693// NOTE: it's a function NOT A PHP::METHOD
2694extern "C" void typetrace(SwigType *ty, String *mangled, String *clientdata) {
2695  Node *class_node;
2696  if (!zend_types) {
2697    zend_types = NewHash();
2698  }
2699  // we want to know if the type which reduced to this has a constructor
2700  if ((class_node = maininstance->classLookup(ty))) {
2701    if (!Getattr(zend_types, mangled)) {
2702      // OK it may have been set before by a different SwigType but it would
2703      // have had the same underlying class node I think
2704      // - it is certainly required not to have different originating class
2705      // nodes for the same SwigType
2706      Setattr(zend_types, mangled, class_node);
2707    }
2708  } else {			// a non-class pointer
2709    Setattr(zend_types, mangled, NOTCLASS);
2710  }
2711  if (r_prevtracefunc)
2712    (*r_prevtracefunc) (ty, mangled, (String *) clientdata);
2713}
2714
2715/* -----------------------------------------------------------------------------
2716 * new_swig_php()    - Instantiate module
2717 * ----------------------------------------------------------------------------- */
2718
2719static Language *new_swig_php() {
2720  maininstance = new PHP;
2721  if (!r_prevtracefunc) {
2722    r_prevtracefunc = SwigType_remember_trace(typetrace);
2723  } else {
2724    Printf(stderr, "php Typetrace vector already saved!\n");
2725    assert(0);
2726  }
2727  return maininstance;
2728}
2729
2730extern "C" Language *swig_php4(void) {
2731  Printf(stderr, "*** -php4 is no longer supported.\n"
2732		 "*** Either upgrade to PHP5 or use SWIG 1.3.36 or earlier.\n");
2733  SWIG_exit(EXIT_FAILURE);
2734  return NULL; // To avoid compiler warnings.
2735}
2736
2737extern "C" Language *swig_php(void) {
2738  return new_swig_php();
2739}
2740