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