+++ /dev/null
-/*******************************************************************************
- * Simplified Wrapper and Interface Generator (SWIG)
- *
- * Author : David Beazley
- *
- * Department of Computer Science
- * University of Chicago
- * 1100 E 58th Street
- * Chicago, IL 60637
- * beazley@cs.uchicago.edu
- *
- * Please read the file LICENSE for the copyright and terms by which SWIG
- * can be used and distributed.
- *******************************************************************************/
-
-/***********************************************************************
- * $Header$
- *
- * perl5.c
- *
- * Definitions for adding functions to Perl 5
- *
- * How to extend perl5 (note : this is totally different in Perl 4) :
- *
- * 1. Variable linkage
- *
- * Must declare two functions :
- *
- * _var_set(SV *sv, MAGIC *mg);
- * _var_get(SV *sv, MAGIC *mg);
- *
- * These functions must set/get the values of a variable using
- * Perl5 internals.
- *
- * To add these to Perl5 (which isn't entirely clear), need to
- * do the following :
- *
- * SV *sv;
- * MAGIC *m;
- * sv = perl_get_sv("varname",TRUE);
- * sv_magic(sv,sv, 'U', "varname", strlen("varname));
- * m = mg_find(sv, 'U');
- * m->mg_virtual = (MGVTBL *) malloc(sizeof(MGVTBL));
- * m->mg_virtual.svt_get = _var_set;
- * m->mg_virtual.svt_set = _var_get;
- * m->mg_virtual.svt_len = 0;
- * m->mg_virtual.svt_free = 0;
- * m->mg_virtual.svt_clear = 0;
- *
- *
- * 2. Function extension
- *
- * Functions are declared as :
- * XS(_wrap_func) {
- * dXSARGS;
- * if (items != parmcount) {
- * croak("Usage :");
- * }
- * ... get arguments ...
- *
- * ... call function ...
- * ... set return value in ST(0)
- * XSRETURN(1);
- * }
- * To extract function arguments, use the following :
- * _arg = (int) SvIV(ST(0))
- * _arg = (double) SvNV(ST(0))
- * _arg = (char *) SvPV(ST(0),na);
- *
- * For return values, use :
- * ST(0) = sv_newmortal();
- * sv_setiv(ST(0), (IV) RETVAL); // Integers
- * sv_setnv(ST(0), (double) RETVAL); // Doubles
- * sv_setpv((SV*) ST(0), RETVAL); // Strings
- *
- * New functions are added using
- * newXS("name", _wrap_func, file)
- *
- *
- * 3. Compilation.
- *
- * Code should be compiled into an object file for dynamic
- * loading into Perl.
- ***********************************************************************/
-
-#include "swig.h"
-#include "perl5.h"
-
-static String pragma_include;
-
-static char *usage = "\
-Perl5 Options (available with -perl5)\n\
- -module name - Set module name\n\
- -package name - Set package prefix\n\
- -static - Omit code related to dynamic loading.\n\
- -shadow - Create shadow classes.\n\
- -compat - Compatibility mode.\n\
- -alt-header file- Use an alternate header.\n\n";
-
-static char *import_file = 0;
-static char *smodule = 0;
-static int compat = 0;
-
-// ---------------------------------------------------------------------
-// PERL5::parse_args(int argc, char *argv[])
-//
-// Parse command line options.
-// ---------------------------------------------------------------------
-
-void
-PERL5::parse_args(int argc, char *argv[]) {
-
- int i = 1;
-
- export_all = 0;
- sprintf(LibDir,"%s", perl_path);
-
- // Look for certain command line options
-
- // Get options
- for (i = 1; i < argc; i++) {
- if (argv[i]) {
- if(strcmp(argv[i],"-package") == 0) {
- if (argv[i+1]) {
- package = new char[strlen(argv[i+1])+1];
- strcpy(package, argv[i+1]);
- mark_arg(i);
- mark_arg(i+1);
- i++;
- } else {
- arg_error();
- }
- } else if (strcmp(argv[i],"-module") == 0) {
- if (argv[i+1]) {
- module = new char[strlen(argv[i+1])+1];
- strcpy(module, argv[i+1]);
- cmodule = module;
- cmodule.replace(":","_");
- mark_arg(i);
- mark_arg(i+1);
- i++;
- } else {
- arg_error();
- }
- } else if (strcmp(argv[i],"-exportall") == 0) {
- export_all = 1;
- mark_arg(i);
- } else if (strcmp(argv[i],"-static") == 0) {
- is_static = 1;
- mark_arg(i);
- } else if (strcmp(argv[i],"-shadow") == 0) {
- blessed = 1;
- mark_arg(i);
- } else if (strcmp(argv[i],"-alt-header") == 0) {
- if (argv[i+1]) {
- alt_header = copy_string(argv[i+1]);
- mark_arg(i);
- mark_arg(i+1);
- i++;
- } else {
- arg_error();
- }
- } else if (strcmp(argv[i],"-compat") == 0) {
- compat = 1;
- mark_arg(i);
- } else if (strcmp(argv[i],"-help") == 0) {
- fputs(usage,stderr);
- }
- }
- }
- // Add a symbol for this module
-
- add_symbol("SWIGPERL",0,0);
- add_symbol("SWIGPERL5",0,0);
-
- // Set name of typemaps
-
- typemap_lang = "perl5";
-
-}
-
-// ------------------------------------------------------------------
-// PERL5::parse()
-//
-// Parse an interface file
-// ------------------------------------------------------------------
-
-void
-PERL5::parse() {
-
-
- printf("Generating wrappers for Perl 5\n");
-
- // Print out PERL5 specific headers
-
- headers();
-
- // Run the parser
-
- yyparse();
- fputs(vinit.get(),f_wrappers);
-}
-
-
-// ---------------------------------------------------------------------
-// PERL5::set_module(char *mod_name, char **mod_list)
-//
-// Sets the module name.
-// Does nothing if it's already set (so it can be overridden as a command
-// line option).
-//
-//----------------------------------------------------------------------
-static String modinit, modextern;
-
-void PERL5::set_module(char *mod_name, char **mod_list) {
- int i;
- if (import_file) {
- if (!(strcmp(import_file,input_file+strlen(input_file)-strlen(import_file)))) {
- if (blessed) {
- fprintf(f_pm,"require %s;\n", mod_name);
- }
- delete [] import_file;
- import_file = 0;
- }
- }
-
- if (module) return;
-
- module = new char[strlen(mod_name)+1];
- strcpy(module,mod_name);
-
- // if there was a mod_list specified, make this big hack
- if (mod_list) {
- modinit << "#define SWIGMODINIT ";
- modextern << "#ifdef __cplusplus\n"
- << "extern \"C\" {\n"
- << "#endif\n";
- i = 0;
- while(mod_list[i]) {
- modinit << "newXS(\"" << mod_list[i] << "::boot_" << mod_list[i] << "\", boot_" << mod_list[i] << ", file);\\\n";
- modextern << "extern void boot_" << mod_list[i] << "(CV *);\n";
- i++;
- }
- modextern << "#ifdef __cplusplus\n"
- << "}\n"
- << "#endif\n";
- modinit << "/* End of extern module initialization */\n";
- }
-
- // Create a C module name and put it in 'cmodule'
-
- cmodule = module;
- cmodule.replace(":","_");
-}
-
-// ---------------------------------------------------------------------
-// PERL5::set_init(char *iname)
-//
-// Sets the initialization function name.
-// Does nothing if it's already set
-//
-//----------------------------------------------------------------------
-
-void PERL5::set_init(char *iname) {
- set_module(iname,0);
-}
-
-// ---------------------------------------------------------------------
-// PERL5::headers(void)
-//
-// Generate the appropriate header files for PERL5 interface.
-// ----------------------------------------------------------------------
-
-void PERL5::headers(void)
-{
-
- emit_banner(f_header);
-
- if (!alt_header) {
- if (insert_file("headers.swg", f_header) == -1) {
- fprintf(stderr,"Perl5 : Fatal error. Unable to locate headers.swg. Possible installation problem.\n");
- SWIG_exit(1);
- }
- } else {
- if (insert_file(alt_header, f_header) == -1) {
- fprintf(stderr,"SWIG : Fatal error. Unable to locate %s.\n",alt_header);
- SWIG_exit(1);
- }
- }
-
- if (NoInclude) {
- fprintf(f_header,"#define SWIG_NOINCLUDE\n");
- }
-
- // Get special SWIG related declarations
- if (insert_file("perl5.swg", f_header) == -1) {
- fprintf(stderr,"SWIG : Fatal error. Unable to locate 'perl5.swg' in SWIG library.\n");
- SWIG_exit(1);
- }
-
- // Get special SWIG related declarations
- if (insert_file("perl5mg.swg", f_header) == -1) {
- fprintf(stderr,"SWIG : Fatal error. Unable to locate 'perl5mg.swg' in SWIG library.\n");
- SWIG_exit(1);
- }
-
-}
-
-// --------------------------------------------------------------------
-// PERL5::initialize()
-//
-// Output initialization code that registers functions with the
-// interface.
-// ---------------------------------------------------------------------
-
-void PERL5::initialize()
-{
-
- char filen[256];
-
- if (!module){
- module = "swig";
- fprintf(stderr,"SWIG : *** Warning. No module name specified.\n");
- }
-
- if (!package) {
- package = new char[strlen(module)+1];
- strcpy(package,module);
- }
-
- // If we're in blessed mode, change the package name to "packagec"
-
- if (blessed) {
- char *newpackage = new char[strlen(package)+2];
- sprintf(newpackage,"%sc",package);
- realpackage = package;
- package = newpackage;
- } else {
- realpackage = package;
- }
-
- // Create a .pm file
- // Need to strip off any prefixes that might be found in
- // the module name
-
- {
- char *m = module + strlen(module);
- while (m != module) {
- if (*m == ':') {
- m++;
- break;
- }
- m--;
- }
- sprintf(filen,"%s%s.pm", output_dir,m);
- if ((f_pm = fopen(filen,"w")) == 0) {
- fprintf(stderr,"Unable to open %s\n", filen);
- SWIG_exit(0);
- }
- }
- if (!blessed) {
- smodule = module;
- } else if (is_static) {
- smodule = new char[strlen(module)+2];
- strcpy(smodule,module);
- strcat(smodule,"c");
- cmodule << "c";
- } else {
- smodule = module;
- }
-
- fprintf(f_header,"#define SWIG_init boot_%s\n\n", cmodule.get());
- fprintf(f_header,"#define SWIG_name \"%s::boot_%s\"\n", package, cmodule.get());
- fprintf(f_header,"#define SWIG_varinit \"%s::var_%s_init();\"\n", package, cmodule.get());
- fprintf(f_header,"#ifdef __cplusplus\n");
- fprintf(f_header,"extern \"C\"\n");
- fprintf(f_header,"#endif\n");
- fprintf(f_header,"#ifndef PERL_OBJECT\n");
- fprintf(f_header,"SWIGEXPORT(void) boot_%s(CV* cv);\n", cmodule.get());
- fprintf(f_header,"#else\n");
- fprintf(f_header,"SWIGEXPORT(void) boot_%s(CV *cv, CPerlObj *);\n",cmodule.get());
- fprintf(f_header,"#endif\n");
- fprintf(f_init,"#ifdef __cplusplus\n");
- fprintf(f_init,"extern \"C\"\n");
- fprintf(f_init,"#endif\n");
- fprintf(f_init,"XS(boot_%s) {\n", cmodule.get());
- fprintf(f_init,"\t dXSARGS;\n");
- fprintf(f_init,"\t char *file = __FILE__;\n");
- fprintf(f_init,"\t cv = cv; items = items;\n");
- fprintf(f_init,"\t newXS(\"%s::var_%s_init\", _wrap_perl5_%s_var_init, file);\n",package,cmodule.get(), cmodule.get());
- vinit << "XS(_wrap_perl5_" << cmodule << "_var_init) {\n"
- << tab4 << "dXSARGS;\n"
- << tab4 << "SV *sv;\n"
- << tab4 << "cv = cv; items = items;\n";
-
- fprintf(f_pm,"# This file was automatically generated by SWIG\n");
- fprintf(f_pm,"package %s;\n",module);
- fprintf(f_pm,"require Exporter;\n");
- if (!is_static) {
- fprintf(f_pm,"require DynaLoader;\n");
- fprintf(f_pm,"@ISA = qw(Exporter DynaLoader);\n");
- } else {
- fprintf(f_pm,"@ISA = qw(Exporter);\n");
- }
-
- // Start creating magic code
-
-
- magic << "#ifdef PERL_OBJECT\n"
- << "#define MAGIC_CLASS _wrap_" << module << "_var::\n"
- << "class _wrap_" << module << "_var : public CPerlObj {\n"
- << "public:\n"
- << "#else\n"
- << "#define MAGIC_CLASS\n"
- << "#endif\n"
- << "SWIGCLASS_STATIC int swig_magic_readonly(SV *sv, MAGIC *mg) {\n"
- << tab4 << "MAGIC_PPERL\n"
- << tab4 << "sv = sv; mg = mg;\n"
- << tab4 << "croak(\"Value is read-only.\");\n"
- << tab4 << "return 0;\n"
- << "}\n"; // Dump out external module declarations
-
- /* Process additional initialization files here */
-
- if (strlen(modinit.get()) > 0) {
- fprintf(f_header,"%s\n",modinit.get());
- }
- if (strlen(modextern.get()) > 0) {
- fprintf(f_header,"%s\n",modextern.get());
- }
-}
-
-// ---------------------------------------------------------------------
-// PERL5::import(char *filename)
-//
-// Import directive
-// ---------------------------------------------------------------------
-
-void PERL5::import(char *filename) {
- if (import_file) delete [] import_file;
- import_file = copy_string(filename);
-}
-
-
-// ---------------------------------------------------------------------
-// PERL5::close(void)
-//
-// Wrap things up. Close initialization function.
-// ---------------------------------------------------------------------
-
-void PERL5::close(void)
-{
- String base;
-
- // Dump out variable wrappers
-
- magic << "\n\n#ifdef PERL_OBJECT\n"
- << "};\n"
- << "#endif\n";
-
- fprintf(f_header,"%s\n", magic.get());
-
- emit_ptr_equivalence(f_init);
-
- fprintf(f_init,"\t ST(0) = &PL_sv_yes;\n");
- fprintf(f_init,"\t XSRETURN(1);\n");
- fprintf(f_init,"}\n");
-
- vinit << tab4 << "XSRETURN(1);\n"
- << "}\n";
-
- fprintf(f_pm,"package %s;\n", package);
-
- if (!is_static) {
- fprintf(f_pm,"bootstrap %s;\n", smodule);
- } else {
- fprintf(f_pm,"boot_%s();\n", smodule);
- }
- fprintf(f_pm,"var_%s_init();\n", cmodule.get());
- fprintf(f_pm,"%s",pragma_include.get());
- fprintf(f_pm,"package %s;\n", realpackage);
- fprintf(f_pm,"@EXPORT = qw(%s );\n",exported.get());
-
- if (blessed) {
-
- base << "\n# ---------- BASE METHODS -------------\n\n"
- << "package " << realpackage << ";\n\n";
-
- // Write out the TIE method
-
- base << "sub TIEHASH {\n"
- << tab4 << "my ($classname,$obj) = @_;\n"
- << tab4 << "return bless $obj, $classname;\n"
- << "}\n\n";
-
- // Output a CLEAR method. This is just a place-holder, but by providing it we
- // can make declarations such as
- // %$u = ( x => 2, y=>3, z =>4 );
- //
- // Where x,y,z are the members of some C/C++ object.
-
- base << "sub CLEAR { }\n\n";
-
- // Output default firstkey/nextkey methods
-
- base << "sub FIRSTKEY { }\n\n";
- base << "sub NEXTKEY { }\n\n";
-
- // Output a 'this' method
-
- base << "sub this {\n"
- << tab4 << "my $ptr = shift;\n"
- << tab4 << "return tied(%$ptr);\n"
- << "}\n\n";
-
- fprintf(f_pm,"%s",base.get());
-
- // Emit function stubs for stand-alone functions
-
- fprintf(f_pm,"\n# ------- FUNCTION WRAPPERS --------\n\n");
- fprintf(f_pm,"package %s;\n\n",realpackage);
- fprintf(f_pm,"%s",func_stubs.get());
-
-
- // Emit package code for different classes
-
- fprintf(f_pm,"%s",pm.get());
-
- // Emit variable stubs
-
- fprintf(f_pm,"\n# ------- VARIABLE STUBS --------\n\n");
- fprintf(f_pm,"package %s;\n\n",realpackage);
- fprintf(f_pm,"%s",var_stubs.get());
-
- }
-
- fprintf(f_pm,"1;\n");
- fclose(f_pm);
-
- // Patch up documentation title
-
- if ((doc_entry) && (module)) {
- doc_entry->cinfo << "Module : " << module << ", "
- << "Package : " << realpackage;
- }
-
-}
-
-// ----------------------------------------------------------------------
-// char *PERL5::type_mangle(DataType *t)
-//
-// Mangles a datatype into a Perl5 name compatible with xsubpp type
-// T_PTROBJ.
-// ----------------------------------------------------------------------
-
-char *
-PERL5::type_mangle(DataType *t) {
- static char result[128];
- int i;
- char *r, *c;
-
- if (blessed) {
-
- // Check to see if we've blessed this datatype
-
- if ((classes.lookup(t->name)) && (t->is_pointer <= 1)) {
-
- // This is a blessed class. Return just the type-name
- strcpy(result,(char *) classes.lookup(t->name));
- return result;
- }
- }
-
- r = result;
- c = t->name;
-
- for ( c = t->name; *c; c++,r++) {
- *r = *c;
- }
- for (i = 0; i < (t->is_pointer-t->implicit_ptr); i++, r++) {
- strcpy(r,"Ptr");
- r+=2;
- }
- *r = 0;
- return result;
-}
-
-// ----------------------------------------------------------------------
-// PERL5::get_pointer(char *iname, char *srcname, char *src, char *target,
-// DataType *t, String &f, char *ret)
-//
-// Emits code to get a pointer from a parameter and do type checking.
-// ----------------------------------------------------------------------
-
-void PERL5::get_pointer(char *iname, char *srcname, char *src, char *dest,
- DataType *t, String &f, char *ret) {
-
- // Now get the pointer value from the string and save in dest
-
- f << tab4 << "if (SWIG_GetPtr(" << src << ",(void **) &" << dest << ",";
-
- // If we're passing a void pointer, we give the pointer conversion a NULL
- // pointer, otherwise pass in the expected type.
-
- if (t->type == T_VOID) f << "(char *) 0 )) {\n";
- else
- f << "\"" << t->print_mangle() << "\")) {\n";
-
- // This part handles the type checking according to three different
- // levels. 0 = no checking, 1 = warning message, 2 = strict.
-
- switch(TypeStrict) {
- case 0: // No type checking
- f << tab4 << "}\n";
- break;
-
- case 1: // Warning message only
-
- // Change this part to how you want to handle a type-mismatch warning.
- // By default, it will just print to stderr.
-
- f << tab8 << "fprintf(stderr,\"Warning : type mismatch in " << srcname
- << " of " << iname << ". Expected " << t->print_mangle()
- << ", received %s\\n\"," << src << ");\n"
- << tab4 << "}\n";
-
- break;
- case 2: // Super strict mode.
-
- // Change this part to return an error.
-
- f << tab8 << "croak(\"Type error in " << srcname
- << " of " << iname << ". Expected " << t->print_mangle() << ".\");\n"
- << tab8 << ret << ";\n"
- << tab4 << "}\n";
-
- break;
-
- default :
- fprintf(stderr,"SWIG Error. Unknown strictness level\n");
- break;
- }
-}
-
-// ----------------------------------------------------------------------
-// PERL5::create_command(char *cname, char *iname)
-//
-// Create a command and register it with the interpreter
-// ----------------------------------------------------------------------
-
-void PERL5::create_command(char *cname, char *iname) {
- fprintf(f_init,"\t newXS(\"%s::%s\", %s, file);\n", package, iname, name_wrapper(cname,""));
- if (export_all) {
- exported << iname << " ";
- }
-}
-
-// ----------------------------------------------------------------------
-// PERL5::create_function(char *name, char *iname, DataType *d,
-// ParmList *l)
-//
-// Create a function declaration and register it with the interpreter.
-// ----------------------------------------------------------------------
-
-void PERL5::create_function(char *name, char *iname, DataType *d, ParmList *l)
-{
- Parm *p;
- int pcount,i,j;
- char *wname;
- char *usage = 0;
- WrapperFunction f;
- char source[256],target[256],temp[256], argnum[32];
- char *tm;
- String cleanup,outarg,build;
- int numopt = 0;
- int need_save, num_saved = 0; // Number of saved arguments.
- int have_build = 0;
-
- // Make a wrapper name for this
-
- wname = name_wrapper(iname,"");
-
- // Now write the wrapper function itself....this is pretty ugly
-
- f.def << "XS(" << wname << ") {\n";
- f.code << tab4 << "cv = cv;\n";
-
- pcount = emit_args(d, l, f);
- numopt = l->numopt();
-
- f.add_local("int","argvi = 0");
-
- // Check the number of arguments
-
- usage = usage_func(iname,d,l);
- f.code << tab4 << "if ((items < " << (pcount-numopt) << ") || (items > " << l->numarg() << ")) \n"
- << tab8 << "croak(\"Usage: " << usage << "\");\n";
-
- // Write code to extract parameters.
- // This section should be able to extract virtually any kind
- // parameter, represented as a string
-
- i = 0;
- j = 0;
- p = l->get_first();
- while (p != 0) {
- // Produce string representation of source and target arguments
- sprintf(source,"ST(%d)",j);
- sprintf(target,"_arg%d",i);
- sprintf(argnum,"%d",j+1);
-
- // Check to see if this argument is being ignored
-
- if (!p->ignore) {
-
- // If there are optional arguments, check for this
-
- if (j>= (pcount-numopt))
- f.code << tab4 << "if (items > " << j << ") {\n";
-
- // See if there is a type-map
- if ((tm = typemap_lookup("in","perl5",p->t,p->name,source,target,&f))) {
- f.code << tm << "\n";
- f.code.replace("$argnum",argnum);
- f.code.replace("$arg",source);
- } else {
-
- if (!p->t->is_pointer) {
-
- // Extract a parameter by "value"
-
- switch(p->t->type) {
-
- // Integers
-
- case T_BOOL:
- case T_INT :
- case T_SHORT :
- case T_LONG :
- case T_SINT :
- case T_SSHORT:
- case T_SLONG:
- case T_SCHAR:
- case T_UINT:
- case T_USHORT:
- case T_ULONG:
- case T_UCHAR:
- f.code << tab4 << "_arg" << i << " = " << p->t->print_cast()
- << "SvIV(ST(" << j << "));\n";
- break;
- case T_CHAR :
-
-
-
- f.code << tab4 << "_arg" << i << " = (char) *SvPV(ST(" << j << "),PL_na);\n";
- break;
-
- // Doubles
-
- case T_DOUBLE :
- case T_FLOAT :
- f.code << tab4 << "_arg" << i << " = " << p->t->print_cast()
- << " SvNV(ST(" << j << "));\n";
- break;
-
- // Void.. Do nothing.
-
- case T_VOID :
- break;
-
- // User defined. This is invalid here. Note, user-defined types by
- // value are handled in the parser.
-
- case T_USER:
-
- // Unsupported data type
-
- default :
- fprintf(stderr,"%s : Line %d. Unable to use type %s as a function argument.\n",input_file, line_number, p->t->print_type());
- break;
- }
- } else {
-
- // Argument is a pointer type. Special case is for char *
- // since that is usually a string.
-
- if ((p->t->type == T_CHAR) && (p->t->is_pointer == 1)) {
- f.code << tab4 << "if (! SvOK((SV*) ST(" << j << "))) { "
- << "_arg" << i << " = 0; }\n";
- f.code << tab4 << "else { _arg"
- << i << " = (char *) SvPV(ST(" << j << "),PL_na); }\n";
- } else {
-
- // Have a generic pointer type here. Read it in as a swig
- // typed pointer.
-
- sprintf(temp,"argument %d", i+1);
- get_pointer(iname,temp,source,target, p->t, f.code, "XSRETURN(1)");
- }
- }
- }
- // The source is going to be an array of saved values.
-
- sprintf(temp,"_saved[%d]",num_saved);
- if (j>= (pcount-numopt))
- f.code << tab4 << "} \n";
- j++;
- } else {
- temp[0] = 0;
- }
- // Check to see if there is any sort of "build" typemap (highly complicated)
-
- if ((tm = typemap_lookup("build","perl5",p->t,p->name,source,target))) {
- build << tm << "\n";
- have_build = 1;
- }
-
- // Check if there is any constraint code
- if ((tm = typemap_lookup("check","perl5",p->t,p->name,source,target))) {
- f.code << tm << "\n";
- f.code.replace("$argnum",argnum);
- }
- need_save = 0;
-
- if ((tm = typemap_lookup("freearg","perl5",p->t,p->name,target,temp))) {
- cleanup << tm << "\n";
- cleanup.replace("$argnum",argnum);
- cleanup.replace("$arg",temp);
- need_save = 1;
- }
- if ((tm = typemap_lookup("argout","perl5",p->t,p->name,target,"ST(argvi)"))) {
- String tempstr;
- tempstr = tm;
- tempstr.replace("$argnum",argnum);
- tempstr.replace("$arg",temp);
- outarg << tempstr << "\n";
- need_save = 1;
- }
- // If we needed a saved variable, we need to emit to emit some code for that
- // This only applies if the argument actually existed (not ignore)
- if ((need_save) && (!p->ignore)) {
- f.code << tab4 << temp << " = " << source << ";\n";
- num_saved++;
- }
- p = l->get_next();
- i++;
- }
-
- // If there were any saved arguments, emit a local variable for them
-
- if (num_saved) {
- sprintf(temp,"_saved[%d]",num_saved);
- f.add_local("SV *",temp);
- }
-
- // If there was a "build" typemap, we need to go in and perform a serious hack
-
- if (have_build) {
- char temp1[32];
- char temp2[256];
- l->sub_parmnames(build); // Replace all parameter names
- j = 1;
- for (i = 0; i < l->nparms; i++) {
- p = l->get(i);
- if (strlen(p->name) > 0) {
- sprintf(temp1,"_in_%s", p->name);
- } else {
- sprintf(temp1,"_in_arg%d", i);
- }
- sprintf(temp2,"argv[%d]",j);
- build.replaceid(temp1,temp2);
- if (!p->ignore)
- j++;
- }
- f.code << build;
- }
-
- // Now write code to make the function call
-
- emit_func_call(name,d,l,f);
-
- // See if there was a typemap
-
- if ((tm = typemap_lookup("out","perl5",d,iname,"_result","ST(argvi)"))) {
- // Yep. Use it instead of the default
- f.code << tm << "\n";
- } else if ((d->type != T_VOID) || (d->is_pointer)) {
- if (!d->is_pointer) {
-
- // Function returns a "value"
- f.code << tab4 << "ST(argvi) = sv_newmortal();\n";
- switch(d->type) {
- case T_INT: case T_BOOL: case T_SINT: case T_UINT:
- case T_SHORT: case T_SSHORT: case T_USHORT:
- case T_LONG : case T_SLONG : case T_ULONG:
- case T_SCHAR: case T_UCHAR :
- f.code << tab4 << "sv_setiv(ST(argvi++),(IV) _result);\n";
- break;
- case T_DOUBLE :
- case T_FLOAT :
- f.code << tab4 << "sv_setnv(ST(argvi++), (double) _result);\n";
- break;
- case T_CHAR :
- f.add_local("char", "_ctemp[2]");
- f.code << tab4 << "_ctemp[0] = _result;\n"
- << tab4 << "_ctemp[1] = 0;\n"
- << tab4 << "sv_setpv((SV*)ST(argvi++),_ctemp);\n";
- break;
-
- // Return a complex type by value
-
- case T_USER:
- d->is_pointer++;
- f.code << tab4 << "sv_setref_pv(ST(argvi++),\"" << d->print_mangle()
- << "\", (void *) _result);\n";
- d->is_pointer--;
- break;
-
- default :
- fprintf(stderr,"%s: Line %d. Unable to use return type %s in function %s.\n", input_file, line_number, d->print_type(), name);
- break;
- }
- } else {
-
- // Is a pointer return type
- f.code << tab4 << "ST(argvi) = sv_newmortal();\n";
- if ((d->type == T_CHAR) && (d->is_pointer == 1)) {
-
- // Return a character string
- f.code << tab4 << "sv_setpv((SV*)ST(argvi++),(char *) _result);\n";
-
- } else {
- // Is an ordinary pointer type.
- f.code << tab4 << "sv_setref_pv(ST(argvi++),\"" << d->print_mangle()
- << "\", (void *) _result);\n";
- }
- }
- }
-
- // If there were any output args, take care of them.
-
- f.code << outarg;
-
- // If there was any cleanup, do that.
-
- f.code << cleanup;
-
- if (NewObject) {
- if ((tm = typemap_lookup("newfree","perl5",d,iname,"_result",""))) {
- f.code << tm << "\n";
- }
- }
-
- if ((tm = typemap_lookup("ret","perl5",d,iname,"_result",""))) {
- // Yep. Use it instead of the default
- f.code << tm << "\n";
- }
-
- // Wrap things up (in a manner of speaking)
-
- f.code << tab4 << "XSRETURN(argvi);\n}\n";
-
- // Add the dXSARGS last
-
- f.add_local("dXSARGS","");
-
- // Substitute the cleanup code
- f.code.replace("$cleanup",cleanup);
- f.code.replace("$name",iname);
-
- // Dump this function out
-
- f.print(f_wrappers);
-
- // Create a first crack at a documentation entry
-
- if (doc_entry) {
- static DocEntry *last_doc_entry = 0;
- doc_entry->usage << usage;
- if (last_doc_entry != doc_entry) {
- doc_entry->cinfo << "returns " << d->print_type();
- last_doc_entry = doc_entry;
- }
- }
-
- // Now register the function
-
- fprintf(f_init,"\t newXS(\"%s::%s\", %s, file);\n", package, iname, wname);
-
- if (export_all) {
- exported << iname << " ";
- }
-
-
- // --------------------------------------------------------------------
- // Create a stub for this function, provided it's not a member function
- //
- // Really we only need to create a stub if this function involves
- // complex datatypes. If it does, we'll make a small wrapper to
- // process the arguments. If it doesn't, we'll just make a symbol
- // table entry.
- // --------------------------------------------------------------------
-
- if ((blessed) && (!member_func)) {
- int need_stub = 0;
- String func;
-
- // We'll make a stub since we may need it anyways
-
- func << "sub " << iname << " {\n"
- << tab4 << "my @args = @_;\n";
-
-
- // Now we have to go through and patch up the argument list. If any
- // arguments to our function correspond to other Perl objects, we
- // need to extract them from a tied-hash table object.
-
- Parm *p = l->get_first();
- int i = 0;
- while(p) {
-
- if (!p->ignore) {
- // Look up the datatype name here
-
- if ((classes.lookup(p->t->name)) && (p->t->is_pointer <= 1)) {
- if (i >= (pcount - numopt))
- func << tab4 << "if (scalar(@args) >= " << i << ") {\n" << tab4;
-
- func << tab4 << "$args[" << i << "] = tied(%{$args[" << i << "]});\n";
-
- if (i >= (pcount - numopt))
- func << tab4 << "}\n";
-
- need_stub = 1;
- }
- i++;
- }
- p = l->get_next();
- }
-
- func << tab4 << "my $result = " << package << "::" << iname << "(@args);\n";
-
- // Now check to see what kind of return result was found.
- // If this function is returning a result by 'value', SWIG did an
- // implicit malloc/new. We'll mark the object like it was created
- // in Perl so we can garbage collect it.
-
- if ((classes.lookup(d->name)) && (d->is_pointer <=1)) {
-
- func << tab4 << "return undef if (!defined($result));\n";
-
- // If we're returning an object by value, put it's reference
- // into our local hash table
-
- if ((d->is_pointer == 0) || ((d->is_pointer == 1) && NewObject)) {
- func << tab4 << "$" << (char *) classes.lookup(d->name) << "::OWNER{$result} = 1;\n";
- }
-
- // We're returning a Perl "object" of some kind. Turn it into
- // a tied hash
-
- func << tab4 << "my %resulthash;\n"
- /* << tab4 << "tie %resulthash, \"" << (char *) classes.lookup(d->name) << "\", $result;\n"
- << tab4 << "return bless \\%resulthash, \"" << (char *) classes.lookup(d->name) << "\";\n"
- */
- << tab4 << "tie %resulthash, ref($result), $result;\n"
- << tab4 << "return bless \\%resulthash, ref($result);\n"
- << "}\n";
-
- need_stub = 1;
- } else {
-
- // Hmmm. This doesn't appear to be anything I know about so just
- // return it unmolested.
-
- func << tab4 <<"return $result;\n"
- << "}\n";
-
- }
-
- // Now check if we needed the stub. If so, emit it, otherwise
- // Emit code to hack Perl's symbol table instead
-
- if (need_stub) {
- func_stubs << func;
- } else {
- func_stubs << "*" << iname << " = *" << package << "::" << iname << ";\n";
- }
- }
-}
-
-// -----------------------------------------------------------------------
-// PERL5::link_variable(char *name, char *iname, DataType *d)
-//
-// Create a link to a C variable.
-// -----------------------------------------------------------------------
-
-void PERL5::link_variable(char *name, char *iname, DataType *t)
-{
- char set_name[256];
- char val_name[256];
- WrapperFunction getf, setf;
- char *tm;
- sprintf(set_name,"_wrap_set_%s",iname);
- sprintf(val_name,"_wrap_val_%s",iname);
-
- // Create a new scalar that we will attach magic to
-
- vinit << tab4 << "sv = perl_get_sv(\"" << package << "::" << iname << "\",TRUE | 0x2);\n";
-
- // Create a Perl function for setting the variable value
-
- if (!(Status & STAT_READONLY)) {
- setf.def << "SWIGCLASS_STATIC int " << set_name << "(SV* sv, MAGIC *mg) {\n";
-
- setf.code << tab4 << "MAGIC_PPERL\n";
- setf.code << tab4 << "mg = mg;\n";
-
- /* Check for a few typemaps */
- if ((tm = typemap_lookup("varin","perl5",t,"","sv",name))) {
- setf.code << tm << "\n";
- } else if ((tm = typemap_lookup("in","perl5",t,"","sv",name))) {
- setf.code << tm << "\n";
- } else {
- if (!t->is_pointer) {
-
- // Set the value to something
-
- switch(t->type) {
- case T_INT : case T_BOOL: case T_SINT : case T_UINT:
- case T_SHORT : case T_SSHORT : case T_USHORT:
- case T_LONG : case T_SLONG : case T_ULONG:
- case T_UCHAR: case T_SCHAR:
- setf.code << tab4 << name << " = " << t->print_cast() << " SvIV(sv);\n";
- break;
- case T_DOUBLE :
- case T_FLOAT :
- setf.code << tab4 << name << " = " << t->print_cast() << " SvNV(sv);\n";
- break;
- case T_CHAR :
- setf.code << tab4 << name << " = (char) *SvPV(sv,PL_na);\n";
- break;
-
- case T_USER:
-
- // Add support for User defined type here
- // Get as a pointer value
-
- t->is_pointer++;
- setf.add_local("void","*_temp");
- get_pointer(iname,"value","sv","_temp", t, setf.code, "return(1)");
- setf.code << tab4 << name << " = *(" << t->print_cast() << " _temp);\n";
- t->is_pointer--;
- break;
-
- default :
- fprintf(stderr,"%s : Line %d. Unable to link with datatype %s (ignored).\n", input_file, line_number, t->print_type());
- return;
- }
- } else {
- // Have some sort of pointer type here, Process it differently
- if ((t->type == T_CHAR) && (t->is_pointer == 1)) {
- setf.add_local("char","*_a");
- setf.code << tab4 << "_a = (char *) SvPV(sv,PL_na);\n";
-
- if (CPlusPlus)
- setf.code << tab4 << "if (" << name << ") delete [] " << name << ";\n"
- << tab4 << name << " = new char[strlen(_a)+1];\n";
- else
- setf.code << tab4 << "if (" << name << ") free(" << name << ");\n"
- << tab4 << name << " = (char *) malloc(strlen(_a)+1);\n";
- setf.code << "strcpy(" << name << ",_a);\n";
- } else {
- // Set the value of a pointer
-
- setf.add_local("void","*_temp");
- get_pointer(iname,"value","sv","_temp", t, setf.code, "return(1)");
- setf.code << tab4 << name << " = " << t->print_cast() << " _temp;\n";
- }
- }
- }
- setf.code << tab4 << "return 1;\n"
- << "}\n";
-
- setf.code.replace("$name",iname);
- setf.print(magic);
-
- }
-
- // Now write a function to evaluate the variable
-
- getf.def << "SWIGCLASS_STATIC int " << val_name << "(SV *sv, MAGIC *mg) {\n";
- getf.code << tab4 << "MAGIC_PPERL\n";
- getf.code << tab4 << "mg = mg;\n";
-
- // Check for a typemap
-
- if ((tm = typemap_lookup("varout","perl5",t,"",name, "sv"))) {
- getf.code << tm << "\n";
- } else if ((tm = typemap_lookup("out","perl5",t,"",name,"sv"))) {
- setf.code << tm << "\n";
- } else {
- if (!t->is_pointer) {
- switch(t->type) {
- case T_INT : case T_BOOL: case T_SINT: case T_UINT:
- case T_SHORT : case T_SSHORT: case T_USHORT:
- case T_LONG : case T_SLONG : case T_ULONG:
- case T_UCHAR: case T_SCHAR:
- getf.code << tab4 << "sv_setiv(sv, (IV) " << name << ");\n";
- vinit << tab4 << "sv_setiv(sv,(IV)" << name << ");\n";
- break;
- case T_DOUBLE :
- case T_FLOAT :
- getf.code << tab4 << "sv_setnv(sv, (double) " << name << ");\n";
- vinit << tab4 << "sv_setnv(sv,(double)" << name << ");\n";
- break;
- case T_CHAR :
- getf.add_local("char","_ptemp[2]");
- getf.code << tab4 << "_ptemp[0] = " << name << ";\n"
- << tab4 << "_ptemp[1] = 0;\n"
- << tab4 << "sv_setpv((SV*) sv, _ptemp);\n";
- break;
- case T_USER:
- t->is_pointer++;
- getf.code << tab4 << "rsv = SvRV(sv);\n"
- << tab4 << "sv_setiv(rsv,(IV) &" << name << ");\n";
-
- // getf.code << tab4 << "sv_setref_pv((SV*) sv,\"" << t->print_mangle()
- // << "\", (void *) &" << name << ");\n";
-
- getf.add_local("SV","*rsv");
- vinit << tab4 << "sv_setref_pv(sv,\"" << t->print_mangle() << "\",(void *) &" << name << ");\n";
- t->is_pointer--;
-
- break;
- default :
- break;
- }
- } else {
-
- // Have some sort of arbitrary pointer type. Return it as a string
-
- if ((t->type == T_CHAR) && (t->is_pointer == 1))
- getf.code << tab4 << "sv_setpv((SV*) sv, " << name << ");\n";
- else {
- getf.code << tab4 << "rsv = SvRV(sv);\n"
- << tab4 << "sv_setiv(rsv,(IV) " << name << ");\n";
- getf.add_local("SV","*rsv");
- vinit << tab4 << "sv_setref_pv(sv,\"" << t->print_mangle() << "\",(void *) 1);\n";
-
- //getf.code << tab4 << "sv_setref_pv((SV*) sv,\"" << t->print_mangle()
- // << "\", (void *) " << name << ");\n";
- }
- }
- }
- getf.code << tab4 << "return 1;\n"
- << "}\n";
-
- getf.code.replace("$name",iname);
- getf.print(magic);
-
- // Now add symbol to the PERL interpreter
- if (Status & STAT_READONLY) {
- vinit << tab4 << "swig_create_magic(sv,\"" << package << "::" << iname << "\",MAGIC_CAST MAGIC_CLASS swig_magic_readonly, MAGIC_CAST MAGIC_CLASS " << val_name << ");\n";
- } else {
- vinit << tab4 << "swig_create_magic(sv,\"" << package << "::" << iname << "\", MAGIC_CAST MAGIC_CLASS " << set_name << ", MAGIC_CAST MAGIC_CLASS " << val_name << ");\n";
- }
- // Add a documentation entry
-
- if (doc_entry) {
- doc_entry->usage << usage_var(iname,t);
- doc_entry->cinfo << "Global : " << t->print_type() << " " << name;
- }
-
- // If we're blessed, try to figure out what to do with the variable
- // 1. If it's a Perl object of some sort, create a tied-hash
- // around it.
- // 2. Otherwise, just hack Perl's symbol table
-
- if (blessed) {
- if ((classes.lookup(t->name)) && (t->is_pointer <= 1)) {
- var_stubs << "\nmy %__" << iname << "_hash;\n"
- << "tie %__" << iname << "_hash,\"" << (char *) classes.lookup(t->name) << "\", $"
- << package << "::" << iname << ";\n"
- << "$" << iname << "= \\%__" << iname << "_hash;\n"
- << "bless $" << iname << ", " << (char *) classes.lookup(t->name) << ";\n";
- } else {
- var_stubs << "*" << iname << " = *" << package << "::" << iname << ";\n";
- }
- if (export_all)
- exported << "$" << name << " ";
- }
-}
-
-// -----------------------------------------------------------------------
-// PERL5::declare_const(char *name, char *iname, DataType *type, char *value)
-//
-// Makes a constant. Really just creates a variable and creates a read-only
-// link to it.
-// ------------------------------------------------------------------------
-
-// Functions used to create constants
-
-static const char *setiv = "#ifndef PERL_OBJECT\
-\n#define swig_setiv(a,b) _swig_setiv(a,b)\
-\nstatic void _swig_setiv(char *name, long value) { \
-\n#else\
-\n#define swig_setiv(a,b) _swig_setiv(pPerl,a,b)\
-\nstatic void _swig_setiv(CPerlObj *pPerl, char *name, long value) { \
-\n#endif\
-\n SV *sv; \
-\n sv = perl_get_sv(name,TRUE | 0x2);\
-\n sv_setiv(sv, (IV) value);\
-\n SvREADONLY_on(sv);\
-\n}\n";
-
-static const char *setnv = "#ifndef PERL_OBJECT\
-\n#define swig_setnv(a,b) _swig_setnv(a,b)\
-\nstatic void _swig_setnv(char *name, double value) { \
-\n#else\
-\n#define swig_setnv(a,b) _swig_setnv(pPerl,a,b)\
-\nstatic void _swig_setnv(CPerlObj *pPerl, char *name, double value) { \
-\n#endif\
-\n SV *sv; \
-\n sv = perl_get_sv(name,TRUE | 0x2);\
-\n sv_setnv(sv, value);\
-\n SvREADONLY_on(sv);\
-\n}\n";
-
-static const char *setpv = "#ifndef PERL_OBJECT\
-\n#define swig_setpv(a,b) _swig_setpv(a,b)\
-\nstatic void _swig_setpv(char *name, char *value) { \
-\n#else\
-\n#define swig_setpv(a,b) _swig_setpv(pPerl,a,b)\
-\nstatic void _swig_setpv(CPerlObj *pPerl, char *name, char *value) { \
-\n#endif\
-\n SV *sv; \
-\n sv = perl_get_sv(name,TRUE | 0x2);\
-\n sv_setpv(sv, value);\
-\n SvREADONLY_on(sv);\
-\n}\n";
-
-static const char *setrv = "#ifndef PERL_OBJECT\
-\n#define swig_setrv(a,b,c) _swig_setrv(a,b,c)\
-\nstatic void _swig_setrv(char *name, void *value, char *type) { \
-\n#else\
-\n#define swig_setrv(a,b,c) _swig_setrv(pPerl,a,b,c)\
-\nstatic void _swig_setrv(CPerlObj *pPerl, char *name, void *value, char *type) { \
-\n#endif\
-\n SV *sv; \
-\n sv = perl_get_sv(name,TRUE | 0x2);\
-\n sv_setref_pv(sv, type, value);\
-\n SvREADONLY_on(sv);\
-\n}\n";
-
-void
-PERL5::declare_const(char *name, char *, DataType *type, char *value)
- {
-
- char *tm;
- static int have_int_func = 0;
- static int have_double_func = 0;
- static int have_char_func = 0;
- static int have_ref_func = 0;
-
- if ((tm = typemap_lookup("const","perl5",type,name,value,name))) {
- fprintf(f_init,"%s\n",tm);
- } else {
- if ((type->type == T_USER) && (!type->is_pointer)) {
- fprintf(stderr,"%s : Line %d. Unsupported constant value.\n", input_file, line_number);
- return;
- }
- // Generate a constant
- // vinit << tab4 << "sv = perl_get_sv(\"" << package << "::" << name << "\",TRUE);\n";
- if (type->is_pointer == 0) {
- switch(type->type) {
- case T_INT:case T_SINT: case T_UINT: case T_BOOL:
- case T_SHORT: case T_SSHORT: case T_USHORT:
- case T_LONG: case T_SLONG: case T_ULONG:
- case T_SCHAR: case T_UCHAR:
- if (!have_int_func) {
- fprintf(f_header,"%s\n",setiv);
- have_int_func = 1;
- }
- vinit << tab4 << "swig_setiv(\"" << package << "::" << name << "\", (long) " << value << ");\n";
- break;
- case T_DOUBLE:
- case T_FLOAT:
- if (!have_double_func) {
- fprintf(f_header,"%s\n",setnv);
- have_double_func = 1;
- }
- vinit << tab4 << "swig_setnv(\"" << package << "::" << name << "\", (double) (" << value << "));\n";
- break;
- case T_CHAR :
- if (!have_char_func) {
- fprintf(f_header,"%s\n",setpv);
- have_char_func = 1;
- }
- vinit << tab4 << "swig_setpv(\"" << package << "::" << name << "\", \"" << value << "\");\n";
- break;
- default:
- fprintf(stderr,"%s : Line %d. Unsupported constant value.\n", input_file, line_number);
- break;
- }
- } else {
- if ((type->type == T_CHAR) && (type->is_pointer == 1)) {
- if (!have_char_func) {
- fprintf(f_header,"%s\n",setpv);
- have_char_func = 1;
- }
- vinit << tab4 << "swig_setpv(\"" << package << "::" << name << "\", \"" << value << "\");\n";
- } else {
- // A user-defined type. We're going to munge it into a string pointer value
- if (!have_ref_func) {
- fprintf(f_header,"%s\n",setrv);
- have_ref_func = 1;
- }
- vinit << tab4 << "swig_setrv(\"" << package << "::" << name << "\", (void *) " << value << ", \""
- << type->print_mangle() << "\");\n";
- }
- }
- }
-
- // Patch up the documentation entry
-
- if (doc_entry) {
- doc_entry->usage = "";
- doc_entry->usage << usage_const(name,type,value);
- doc_entry->cinfo = "";
- doc_entry->cinfo << "Constant: " << type->print_type();
- }
-
- if (blessed) {
- if ((classes.lookup(type->name)) && (type->is_pointer <= 1)) {
- var_stubs << "\nmy %__" << name << "_hash;\n"
- << "tie %__" << name << "_hash,\"" << (char *) classes.lookup(type->name) << "\", $"
- << package << "::" << name << ";\n"
- << "$" << name << "= \\%__" << name << "_hash;\n"
- << "bless $" << name << ", " << (char *) classes.lookup(type->name) << ";\n";
- } else {
- var_stubs << "*" << name << " = *" << package << "::" << name << ";\n";
- }
- }
- if (export_all)
- exported << "$" << name << " ";
-}
-
-// ----------------------------------------------------------------------
-// PERL5::usage_var(char *iname, DataType *t)
-//
-// Produces a usage string for a Perl 5 variable.
-// ----------------------------------------------------------------------
-
-char *PERL5::usage_var(char *iname, DataType *) {
-
- static char temp[1024];
- char *c;
-
- sprintf(temp,"$%s", iname);
- c = temp + strlen(temp);
- return temp;
-}
-
-// ---------------------------------------------------------------------------
-// char *PERL5::usage_func(pkg, char *iname, DataType *t, ParmList *l)
-//
-// Produces a usage string for a function in Perl
-// ---------------------------------------------------------------------------
-
-char *PERL5::usage_func(char *iname, DataType *, ParmList *l) {
-
- static String temp;
- Parm *p;
- int i;
-
- temp = "";
- temp << iname << "(";
-
- /* Now go through and print parameters */
-
- p = l->get_first();
- i = 0;
- while (p != 0) {
- if (!p->ignore) {
- /* If parameter has been named, use that. Otherwise, just print a type */
-
- if ((p->t->type != T_VOID) || (p->t->is_pointer)) {
- if (strlen(p->name) > 0) {
- temp << p->name;
- } else {
- temp << p->t->print_type();
- }
- }
- i++;
- p = l->get_next();
- if (p)
- if (!p->ignore)
- temp << ",";
- } else {
- p = l->get_next();
- if (p)
- if ((i>0) && (!p->ignore))
- temp << ",";
- }
- }
- temp << ");";
- return temp.get();
-}
-
-// ----------------------------------------------------------------------
-// PERL5::usage_const(char *iname, DataType *type, char *value)
-//
-// Produces a usage string for a Perl 5 constant
-// ----------------------------------------------------------------------
-
-char *PERL5::usage_const(char *iname, DataType *, char *value) {
-
- static char temp[1024];
- if (value) {
- sprintf(temp,"$%s = %s", iname, value);
- } else {
- sprintf(temp,"$%s", iname);
- }
- return temp;
-}
-
-// -----------------------------------------------------------------------
-// PERL5::add_native(char *name, char *funcname)
-//
-// Add a native module name to Perl5.
-// -----------------------------------------------------------------------
-
-void PERL5::add_native(char *name, char *funcname) {
- fprintf(f_init,"\t newXS(\"%s::%s\", %s, file);\n", package,name, funcname);
- if (export_all)
- exported << name << " ";
- if (blessed) {
- func_stubs << "*" << name << " = *" << package << "::" << name << ";\n";
- }
-}
-
-/****************************************************************************
- *** OBJECT-ORIENTED FEATURES
- ****************************************************************************
- *** These extensions provide a more object-oriented interface to C++
- *** classes and structures. The code here is based on extensions
- *** provided by David Fletcher and Gary Holt.
- ***
- *** I have generalized these extensions to make them more general purpose
- *** and to resolve object-ownership problems.
- ***
- *** The approach here is very similar to the Python module :
- *** 1. All of the original methods are placed into a single
- *** package like before except that a 'c' is appended to the
- *** package name.
- ***
- *** 2. All methods and function calls are wrapped with a new
- *** perl function. While possibly inefficient this allows
- *** us to catch complex function arguments (which are hard to
- *** track otherwise).
- ***
- *** 3. Classes are represented as tied-hashes in a manner similar
- *** to Gary Holt's extension. This allows us to access
- *** member data.
- ***
- *** 4. Stand-alone (global) C functions are modified to take
- *** tied hashes as arguments for complex datatypes (if
- *** appropriate).
- ***
- *** 5. Global variables involving a class/struct is encapsulated
- *** in a tied hash.
- ***
- *** 6. Object ownership is maintained by having a hash table
- *** within in each package called "this". It is unlikely
- *** that C++ program will use this so it's a somewhat
- *** safe variable name.
- ***
- ****************************************************************************/
-
-static int class_renamed = 0;
-static String fullclassname;
-
-// --------------------------------------------------------------------------
-// PERL5::cpp_open_class(char *classname, char *rname, int strip)
-//
-// Opens a new C++ class or structure. Basically, this just records
-// the class name and clears a few variables.
-// --------------------------------------------------------------------------
-
-void PERL5::cpp_open_class(char *classname, char *rname, char *ctype, int strip) {
-
- char temp[256];
- extern void typeeq_addtypedef(char *, char *);
-
- // Register this with the default class handler
-
- this->Language::cpp_open_class(classname, rname, ctype, strip);
-
- if (blessed) {
- have_constructor = 0;
- have_destructor = 0;
- have_data_members = 0;
-
- // If the class is being renamed to something else, use the renaming
-
- if (rname) {
- class_name = copy_string(rname);
- class_renamed = 1;
- // Now things get even more hideous. Need to register an equivalence
- // between the renamed name and the new name. Yuck!
- // printf("%s %s\n", classname, rname);
- typeeq_addtypedef(classname,rname);
- typeeq_addtypedef(rname,classname);
- /*
- fprintf(f_init,"\t SWIG_RegisterMapping(\"%s\",\"%s\",0);\n",classname,rname);
- fprintf(f_init,"\t SWIG_RegisterMapping(\"%s\",\"%s\",0);\n",rname,classname);
- */
- } else {
- class_name = copy_string(classname);
- class_renamed = 0;
- }
-
- // A highly experimental feature. This is the fully qualified
- // name of the Perl class
-
- if (!compat) {
- fullclassname = realpackage;
- fullclassname << "::" << class_name;
- } else {
- fullclassname = class_name;
- }
-
- fullclassname = class_name;
-
- real_classname = copy_string(classname);
- if (base_class) delete base_class;
- base_class = 0;
- class_type = copy_string(ctype);
- pcode = new String();
- blessedmembers = new String();
- member_keys = new String();
-
- // Add some symbols to the hash tables
-
- // classes.add(real_classname,copy_string(class_name)); /* Map original classname to class */
- classes.add(real_classname,copy_string(fullclassname)); /* Map original classname to class */
-
- // Add full name of datatype to the hash table just in case the user uses it
-
- sprintf(temp,"%s %s", class_type, fullclassname.get());
- // classes.add(temp,copy_string(class_name)); /* Map full classname to classs */
- }
-}
-
-// -------------------------------------------------------------------------------
-// PERL5::cpp_close_class()
-//
-// These functions close a class definition.
-//
-// This also sets up the hash table of classes we've seen go by.
-// -------------------------------------------------------------------------------
-
-void PERL5::cpp_close_class() {
-
- // We need to check to make sure we got constructors, and other
- // stuff here.
-
- if (blessed) {
- pm << "\n############# Class : " << fullclassname << " ##############\n";
- pm << "\npackage " << fullclassname << ";\n";
-
- // If we are inheriting from a base class, set that up
-
- if (strcmp(class_name,realpackage))
- pm << "@ISA = qw( " << realpackage;
- else
- pm << "@ISA = qw( ";
-
- if (base_class) {
- pm << " " << *base_class;
- }
- pm << " );\n";
-
- // Dump out a hash table containing the pointers that we own
-
- pm << "%OWNER = ();\n";
- if (have_data_members) {
- pm << "%BLESSEDMEMBERS = (\n"
- << blessedmembers->get()
- << ");\n\n";
- }
- if (have_data_members || have_destructor)
- pm << "%ITERATORS = ();\n";
-
-
- // Dump out the package methods
-
- pm << *pcode;
- delete pcode;
-
- // Output methods for managing ownership
-
- pm << "sub DISOWN {\n"
- << tab4 << "my $self = shift;\n"
- << tab4 << "my $ptr = tied(%$self);\n"
- << tab4 << "delete $OWNER{$ptr};\n"
- << tab4 << "};\n\n"
- << "sub ACQUIRE {\n"
- << tab4 << "my $self = shift;\n"
- << tab4 << "my $ptr = tied(%$self);\n"
- << tab4 << "$OWNER{$ptr} = 1;\n"
- << tab4 << "};\n\n";
-
- // Only output the following methods if a class has member data
-
- if (have_data_members) {
-
- // Output a FETCH method. This is actually common to all classes
- pm << "sub FETCH {\n"
- << tab4 << "my ($self,$field) = @_;\n"
- << tab4 << "my $member_func = \"" << package << "::" << name_get(name_member("${field}",class_name,AS_IS),AS_IS) << "\";\n"
- << tab4 << "my $val = &$member_func($self);\n"
- << tab4 << "if (exists $BLESSEDMEMBERS{$field}) {\n"
- << tab8 << "return undef if (!defined($val));\n"
- << tab8 << "my %retval;\n"
- << tab8 << "tie %retval,$BLESSEDMEMBERS{$field},$val;\n"
- << tab8 << "return bless \\%retval, $BLESSEDMEMBERS{$field};\n"
- << tab4 << "}\n"
- << tab4 << "return $val;\n"
- << "}\n\n";
-
- // Output a STORE method. This is also common to all classes (might move to base class)
-
- pm << "sub STORE {\n"
- << tab4 << "my ($self,$field,$newval) = @_;\n"
- << tab4 << "my $member_func = \"" << package << "::" << name_set(name_member("${field}",class_name,AS_IS),AS_IS) << "\";\n"
- << tab4 << "if (exists $BLESSEDMEMBERS{$field}) {\n"
- << tab8 << "&$member_func($self,tied(%{$newval}));\n"
- << tab4 << "} else {\n"
- << tab8 << "&$member_func($self,$newval);\n"
- << tab4 << "}\n"
- << "}\n\n";
-
- // Output a FIRSTKEY method. This is to allow iteration over a structure's keys.
-
- pm << "sub FIRSTKEY {\n"
- << tab4 << "my $self = shift;\n"
- << tab4 << "$ITERATORS{$self} = [" << member_keys->get() << "];\n"
- << tab4 << "my $first = shift @{$ITERATORS{$self}};\n"
- << tab4 << "return $first;\n"
- << "}\n\n";
-
- // Output a NEXTKEY method. This is the iterator so that each and keys works
-
- pm << "sub NEXTKEY {\n"
- << tab4 << "my $self = shift;\n"
- << tab4 << "$nelem = scalar @{$ITERATORS{$self}};\n"
- << tab4 << "if ($nelem > 0) {\n"
- << tab8 << "my $member = shift @{$ITERATORS{$self}};\n"
- << tab8 << "return $member;\n"
- << tab4 << "} else {\n"
- << tab8 << "$ITERATORS{$self} = [" << member_keys->get() << "];\n"
- << tab8 << "return ();\n"
- << tab4 << "}\n"
- << "}\n\n";
- }
- }
-}
-
-// --------------------------------------------------------------------------
-// PERL5::cpp_member_func(char *name, char *iname, DataType *t, ParmList *l)
-//
-// Handles a C++ member function. This basically does the same thing as
-// the non-C++ version, but we set up a few status variables that affect
-// the function generation function.
-//
-// --------------------------------------------------------------------------
-
-void PERL5::cpp_member_func(char *name, char *iname, DataType *t, ParmList *l) {
-
- String func;
- char *realname;
- Parm *p;
- int i;
- String cname = "perl5:";
- int pcount, numopt;
-
- // First emit normal member function
-
- member_func = 1;
- this->Language::cpp_member_func(name,iname,t,l);
- member_func = 0;
-
- if (!blessed) return;
-
- // Now emit a Perl wrapper function around our member function, we might need
- // to patch up some arguments along the way
-
- if (!iname)
- realname = name;
- else
- realname = iname;
-
- cname << class_name << "::" << realname;
- if (add_symbol(cname.get(),0,0)) {
- return; // Forget it, we saw this function already
- }
-
- func << "sub " << realname << " {\n"
- << tab4 << "my @args = @_;\n"
- << tab4 << "$args[0] = tied(%{$args[0]});\n";
-
- // Now we have to go through and patch up the argument list. If any
- // arguments to our function correspond to other Perl objects, we
- // need to extract them from a tied-hash table object.
-
- p = l->get_first();
- pcount = l->nparms;
- numopt = l->numopt();
- i = 1;
- while(p) {
- if (!p->ignore) {
-
- // Look up the datatype name here
- if ((classes.lookup(p->t->name)) && (p->t->is_pointer <= 1)) {
- // Yep. This smells alot like an object, patch up the arguments
-
- if (i >= (pcount - numopt))
- func << tab4 << "if (scalar(@args) >= " << i << ") {\n";
-
- func << tab4 << "$args[" << i << "] = tied(%{$args[" << i << "]});\n";
-
- if (i >= (pcount - numopt))
- func << tab4 << "}\n";
- }
- i++;
- }
- p = l->get_next();
- }
-
- // Okay. We've made argument adjustments, now call into the package
-
- func << tab4 << "my $result = " << package << "::" << name_member(realname,class_name)
- << "(@args);\n";
-
- // Now check to see what kind of return result was found.
- // If this function is returning a result by 'value', SWIG did an
- // implicit malloc/new. We'll mark the object like it was created
- // in Perl so we can garbage collect it.
-
- if ((classes.lookup(t->name)) && (t->is_pointer <=1)) {
-
- func << tab4 << "return undef if (!defined($result));\n";
-
- // If we're returning an object by value, put it's reference
- // into our local hash table
-
- if ((t->is_pointer == 0) || ((t->is_pointer == 1) && NewObject)) {
- func << tab4 << "$" << (char *) classes.lookup(t->name) << "::OWNER{$result} = 1;\n";
- }
-
- // We're returning a Perl "object" of some kind. Turn it into
- // a tied hash
-
- func << tab4 << "my %resulthash;\n"
- /* << tab4 << "tie %resulthash, \"" << (char *) classes.lookup(t->name) << "\", $result;\n"
- << tab4 << "return bless \\%resulthash, \"" << (char *) classes.lookup(t->name) << "\";\n" */
- << tab4 << "tie %resulthash, ref($result), $result;\n"
- << tab4 << "return bless \\%resulthash, ref($result);\n"
-
- << "}\n";
-
- } else {
-
- // Hmmm. This doesn't appear to be anything I know about so just
- // return it unmolested.
-
- func << tab4 <<"return $result;\n"
- << "}\n";
-
- }
-
- // Append our function to the pcode segment
-
- *pcode << func;
-
- // Create a new kind of documentation entry for the shadow class
-
- if (doc_entry) {
- doc_entry->usage = ""; // Blow away whatever was there before
- doc_entry->usage << usage_func(realname,t,l);
- }
-}
-
-// --------------------------------------------------------------------------------
-// PERL5::cpp_variable(char *name, char *iname, DataType *t)
-//
-// Adds an instance member. This is a little hairy because data members are
-// really added with a tied-hash table that is attached to the object.
-//
-// On the low level, we will emit a pair of get/set functions to retrieve
-// values just like before. These will then be encapsulated in a FETCH/STORE
-// method associated with the tied-hash.
-//
-// In the event that a member is an object that we have already wrapped, then
-// we need to retrieve the data a tied-hash as opposed to what SWIG normally
-// returns. To determine this, we build an internal hash called 'BLESSEDMEMBERS'
-// that contains the names and types of tied data members. If a member name
-// is in the list, we tie it, otherwise, we just return the normal SWIG value.
-// --------------------------------------------------------------------------------
-
-void PERL5::cpp_variable(char *name, char *iname, DataType *t) {
-
- char *realname;
- String cname = "perl5:";
-
- // Emit a pair of get/set functions for the variable
-
- member_func = 1;
- this->Language::cpp_variable(name, iname, t);
- member_func = 0;
-
- if (iname) realname = iname;
- else realname = name;
-
- if (blessed) {
- cname << class_name << "::" << realname;
- if (add_symbol(cname.get(),0,0)) {
- return; // Forget it, we saw this already
- }
-
- // Store name of key for future reference
-
- *member_keys << "'" << realname << "', ";
-
- // Now we need to generate a little Perl code for this
-
- if ((classes.lookup(t->name)) && (t->is_pointer <= 1)) {
-
- // This is a Perl object that we have already seen. Add an
- // entry to the members list
-
- *blessedmembers << tab4 << realname << " => '" << (char *) classes.lookup(t->name) << "',\n";
-
- }
-
- // Patch up the documentation entry
-
- if (doc_entry) {
- doc_entry->usage = "";
- doc_entry->usage << "$this->{" << realname << "}";
- }
- }
- have_data_members++;
-}
-
-
-// -----------------------------------------------------------------------------
-// void PERL5::cpp_constructor(char *name, char *iname, ParmList *l)
-//
-// Emits a blessed constructor for our class. In addition to our construct
-// we manage a Perl hash table containing all of the pointers created by
-// the constructor. This prevents us from accidentally trying to free
-// something that wasn't necessarily allocated by malloc or new
-// -----------------------------------------------------------------------------
-
-void PERL5::cpp_constructor(char *name, char *iname, ParmList *l) {
- Parm *p;
- int i;
- char *realname;
- String cname="perl5:constructor:";
-
- // Emit an old-style constructor for this class
-
- member_func = 1;
- this->Language::cpp_constructor(name, iname, l);
-
- if (blessed) {
-
- if (iname)
- realname = iname;
- else {
- if (class_renamed) realname = class_name;
- else realname = class_name;
- }
-
- cname << class_name << "::" << realname;
- if (add_symbol(cname.get(),0,0)) {
- return; // Forget it, we saw this already
- }
- if ((strcmp(realname,class_name) == 0) || ((!iname) && (ObjCClass)) ){
-
- // Emit a blessed constructor
-
- *pcode << "sub new {\n";
-
- } else {
-
- // Constructor doesn't match classname so we'll just use the normal name
-
- *pcode << "sub " << name_construct(realname) << " () {\n";
-
- }
-
- *pcode << tab4 << "my $self = shift;\n"
- << tab4 << "my @args = @_;\n";
-
- // We are going to need to patch up arguments here if necessary
- // Now we have to go through and patch up the argument list. If any
- // arguments to our function correspond to other Perl objects, we
- // need to extract them from a tied-hash table object.
-
- p = l->get_first();
- i = 0;
- while(p) {
-
- // Look up the datatype name here
-
- if ((classes.lookup(p->t->name)) && (p->t->is_pointer <= 1)) {
-
- // Yep. This smells alot like an object, patch up the arguments
- *pcode << tab4 << "$args[" << i << "] = tied(%{$args[" << i << "]});\n";
- }
- p = l->get_next();
- i++;
- }
-
- *pcode << tab4 << "$self = " << package << "::" << name_construct(realname) << "(@args);\n"
- << tab4 << "return undef if (!defined($self));\n"
- << tab4 << "bless $self, \"" << fullclassname << "\";\n"
- << tab4 << "$OWNER{$self} = 1;\n"
- << tab4 << "my %retval;\n"
- << tab4 << "tie %retval, \"" << fullclassname << "\", $self;\n"
- << tab4 << "return bless \\%retval,\"" << fullclassname << "\";\n"
- << "}\n\n";
- have_constructor = 1;
-
- // Patch up the documentation entry
-
- if (doc_entry) {
- doc_entry->usage = "";
- doc_entry->usage << usage_func("new",0,l);
- }
- }
- member_func = 0;
-}
-
-
-// ------------------------------------------------------------------------------
-// void PERL5::cpp_destructor(char *name, char *newname)
-//
-// Creates a destructor for a blessed object
-// ------------------------------------------------------------------------------
-
-void PERL5::cpp_destructor(char *name, char *newname) {
-
- char *realname;
- member_func = 1;
- this->Language::cpp_destructor(name, newname);
-
- if (blessed) {
- if (newname) realname = newname;
- else {
- if (class_renamed) realname = class_name;
- else realname = name;
- }
-
- // Emit a destructor for this object
-
- *pcode << "sub DESTROY {\n"
- << tab4 << "my $self = tied(%{$_[0]});\n"
- << tab4 << "delete $ITERATORS{$self};\n"
- << tab4 << "if (exists $OWNER{$self}) {\n"
- << tab8 << package << "::" << name_destroy(realname) << "($self);\n"
- << tab8 << "delete $OWNER{$self};\n"
- << tab4 << "}\n}\n\n";
-
- have_destructor = 1;
-
- if (doc_entry) {
- doc_entry->usage = "DESTROY";
- doc_entry->cinfo = "Destructor";
- }
- }
- member_func = 0;
-}
-// -----------------------------------------------------------------------------
-// void PERL5::cpp_static_func(char *name, char *iname, DataType *t, ParmList *l)
-//
-// Emits a wrapper for a static class function. Basically, we just call the
-// appropriate method in the module package.
-// ------------------------------------------------------------------------------
-void PERL5::cpp_static_func(char *name, char *iname, DataType *t, ParmList *l) {
- this->Language::cpp_static_func(name,iname,t,l);
- char *realname;
- if (iname) realname = name;
- else realname = iname;
-
- if (blessed) {
- *pcode << "*" << realname << " = *" << realpackage << "::" << name_member(realname,class_name) << ";\n";
- }
-}
-
-// ------------------------------------------------------------------------------
-// void PERL5::cpp_inherit(char **baseclass, int mode)
-//
-// This sets the Perl5 baseclass (if possible).
-// ------------------------------------------------------------------------------
-
-void PERL5::cpp_inherit(char **baseclass, int) {
-
- char *bc;
- int i = 0, have_first = 0;
- if (!blessed) {
- this->Language::cpp_inherit(baseclass);
- return;
- }
-
- // Inherit variables and constants from base classes, but not
- // functions (since Perl can handle that okay).
-
- this->Language::cpp_inherit(baseclass, INHERIT_CONST | INHERIT_VAR);
-
- // Now tell the Perl5 module that we're inheriting from base classes
-
- base_class = new String;
- while (baseclass[i]) {
- // See if this is a class we know about
- bc = (char *) classes.lookup(baseclass[i]);
- if (bc) {
- if (have_first) *base_class << " ";
- *base_class << bc;
- have_first = 1;
- }
- i++;
- }
- if (!have_first) {
- delete base_class;
- base_class = 0;
- }
-}
-
-// --------------------------------------------------------------------------------
-// PERL5::cpp_declare_const(char *name, char *iname, DataType *type, char *value)
-//
-// Add access to a C++ constant. We can really just do this by hacking
-// the symbol table
-// --------------------------------------------------------------------------------
-
-void PERL5::cpp_declare_const(char *name, char *iname, DataType *type, char *value) {
- char *realname;
- int oldblessed = blessed;
- String cname;
-
- // Create a normal constant
- blessed = 0;
- this->Language::cpp_declare_const(name, iname, type, value);
- blessed = oldblessed;
-
- if (blessed) {
- if (!iname)
- realname = name;
- else
- realname = iname;
-
- cname << class_name << "::" << realname;
- if (add_symbol(cname.get(),0,0)) {
- return; // Forget it, we saw this already
- }
-
- // Create a symbol table entry for it
- *pcode << "*" << realname << " = *" << package << "::" << name_member(realname,class_name) << ";\n";
-
- // Fix up the documentation entry
-
- if (doc_entry) {
- doc_entry->usage = "";
- doc_entry->usage << realname;
- if (value) {
- doc_entry->usage << " = " << value;
- }
- }
- }
-}
-
-// -----------------------------------------------------------------------
-// PERL5::cpp_class_decl(char *name, char *rename, char *type)
-//
-// Treatment of an empty class definition. Used to handle
-// shadow classes across modules.
-// -----------------------------------------------------------------------
-
-void PERL5::cpp_class_decl(char *name, char *rename, char *type) {
- char temp[256];
- if (blessed) {
- classes.add(name,copy_string(rename));
- // Add full name of datatype to the hash table
- if (strlen(type) > 0) {
- sprintf(temp,"%s %s", type, name);
- classes.add(temp,copy_string(rename));
- }
- }
-}
-
-// --------------------------------------------------------------------------------
-// PERL5::add_typedef(DataType *t, char *name)
-//
-// This is called whenever a typedef is encountered. When shadow classes are
-// used, this function lets us discovered hidden uses of a class. For example :
-//
-// struct FooBar {
-// ...
-// }
-//
-// typedef FooBar *FooBarPtr;
-//
-// --------------------------------------------------------------------------------
-
-void PERL5::add_typedef(DataType *t, char *name) {
-
- if (!blessed) return;
-
- // First check to see if there aren't too many pointers
-
- if (t->is_pointer > 1) return;
-
- if (classes.lookup(name)) return; // Already added
-
- // Now look up the datatype in our shadow class hash table
-
- if (classes.lookup(t->name)) {
-
- // Yep. This datatype is in the hash
-
- // Put this types 'new' name into the hash
-
- classes.add(name,copy_string((char *) classes.lookup(t->name)));
- }
-}
-
-
-// --------------------------------------------------------------------------------
-// PERL5::pragma(char *, char *, char *)
-//
-// Pragma directive.
-//
-// %pragma(perl5) code="String" # Includes a string in the .pm file
-// %pragma(perl5) include="file.pl" # Includes a file in the .pm file
-//
-// --------------------------------------------------------------------------------
-
-void PERL5::pragma(char *lang, char *code, char *value) {
- if (strcmp(lang,"perl5") == 0) {
- if (strcmp(code,"code") == 0) {
- // Dump the value string into the .pm file
- if (value) {
- pragma_include << value << "\n";
- }
- } else if (strcmp(code,"include") == 0) {
- // Include a file into the .pm file
- if (value) {
- if (get_file(value,pragma_include) == -1) {
- fprintf(stderr,"%s : Line %d. Unable to locate file %s\n", input_file, line_number,value);
- }
- }
- } else {
- fprintf(stderr,"%s : Line %d. Unrecognized pragma.\n", input_file,line_number);
- }
- }
-}