swig/SWIG/Source/Modules1.1/perl5.cxx
2000-12-24 04:04:01 +00:00

1956 lines
56 KiB
C++

/* -----------------------------------------------------------------------------
* perl5.cxx
*
* Generate Perl5 wrappers
*
* Author(s) : David Beazley (beazley@cs.uchicago.edu)
* Loic Dachary (loic@ceic.com)
* David Fletcher
* Gary Holt
*
* Copyright (C) 1999-2000. The University of Chicago
* See the file LICENSE for information on usage and redistribution.
* ----------------------------------------------------------------------------- */
/* DB: I had to take some features related to package naming out of this to
get the new type system to work. These need to be put back in at some point. */
static char cvsroot[] = "$Header$";
#include "swig11.h"
#include "perl5.h"
static char *usage = (char*)"\
Perl5 Options (available with -perl5)\n\
-module name - Set module name\n\
-interface name - Set interface 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\n";
static String *smodule = 0;
static int compat = 0;
static int export_all = 0;
static String *package = 0;
static String *module = 0;
static String *interface = 0;
static String *cmodule = 0;
static String *vinit = 0;
static FILE *f_pm = 0;
static String *pm; /* Package initialization code */
static String *magic; /* Magic variable wrappers */
static int is_static = 0;
/* The following variables are used to manage Perl5 classes */
static int blessed = 0; /* Enable object oriented features */
static Hash *classes = 0; /* A hash table for storing the classes we've seen so far */
static Hash *symbols = 0;
static int have_constructor = 0;
static int have_destructor= 0;
static int have_data_members = 0;
static String *class_name = 0; /* Name of the class (what Perl thinks it is) */
static String *class_type = 0; /* Type of class "struct", "class", "union" */
static String *real_classname = 0; /* Real name of C/C++ class */
static String *base_class = 0; /* Base class (if using inheritance) */
static int class_renamed = 0;
static String *fullclassname = 0;
static String *pcode = 0; /* Perl code associated with each class */
static String *blessedmembers = 0; /* Member data associated with each class */
static int member_func = 0; /* Set to 1 when wrapping a member function */
static String *realpackage = 0; /* Name of real module */
static String *func_stubs = 0; /* Function stubs */
static String *var_stubs = 0; /* Variable stubs */
static String *member_keys = 0; /* Keys for all member data */
static String *exported = 0; /* Exported symbols */
static String *pragma_include = 0;
/* Test to see if a type corresponds to something wrapped with a shadow class */
static DOH *is_shadow(SwigType *t) {
DOH *r;
SwigType *lt = Swig_clocal_type(t);
r = Getattr(classes,lt);
Delete(lt);
return r;
}
/* -----------------------------------------------------------------------------
* PERL5::parse_args()
* ----------------------------------------------------------------------------- */
void
PERL5::parse_args(int argc, char *argv[]) {
int i = 1;
cmodule = NewString("");
Swig_swiglib_set("perl5");
for (i = 1; i < argc; i++) {
if (argv[i]) {
if(strcmp(argv[i],"-package") == 0) {
if (argv[i+1]) {
package = NewString(argv[i+1]);
Swig_mark_arg(i);
Swig_mark_arg(i+1);
i++;
} else {
Swig_arg_error();
}
} else if(strcmp(argv[i],"-interface") == 0) {
if (argv[i+1]) {
interface = NewString(argv[i+1]);
Swig_mark_arg(i);
Swig_mark_arg(i+1);
i++;
} else {
Swig_arg_error();
}
} else if (strcmp(argv[i],"-exportall") == 0) {
export_all = 1;
Swig_mark_arg(i);
} else if (strcmp(argv[i],"-static") == 0) {
is_static = 1;
Swig_mark_arg(i);
} else if (strcmp(argv[i],"-shadow") == 0) {
blessed = 1;
Swig_mark_arg(i);
} else if (strcmp(argv[i],"-compat") == 0) {
compat = 1;
Swig_mark_arg(i);
} else if (strcmp(argv[i],"-help") == 0) {
fputs(usage,stderr);
}
}
}
Preprocessor_define((void *) "SWIGPERL 1", 0);
Preprocessor_define((void *) "SWIGPERL5 1", 0);
}
/* -----------------------------------------------------------------------------
* PERL5::initialize()
* ----------------------------------------------------------------------------- */
void
PERL5::initialize(String *modname)
{
char filen[256];
classes = NewHash();
symbols = NewHash();
vinit = NewString("");
pm = NewString("");
func_stubs = NewString("");
var_stubs = NewString("");
exported = NewString("");
magic = NewString("");
pragma_include = NewString("");
Swig_banner(f_runtime);
if (NoInclude) {
Printf(f_header,"#define SWIG_NOINCLUDE\n");
}
if (Swig_insert_file("common.swg", f_runtime) == -1) {
Printf(stderr,"SWIG : Fatal error. Unable to locate 'common.swg' in SWIG library.\n");
Swig_exit (EXIT_FAILURE);
}
if (Swig_insert_file("perl5.swg", f_runtime) == -1) {
Printf(stderr,"SWIG : Fatal error. Unable to locate 'perl5.swg' in SWIG library.\n");
Swig_exit (EXIT_FAILURE);
}
if (!module) module = NewString(modname);
/* Create a C module name and put it in 'cmodule' */
Clear(cmodule);
Append(cmodule,module);
Replace(cmodule,":","_",DOH_REPLACE_ANY);
if (!package) {
package = NewString(module);
}
/* If we're in blessed mode, change the package name to "packagec" */
if (blessed) {
realpackage = package;
package = interface ? interface : NewStringf("%sc",package);
} else {
realpackage = NewString(package);
}
/* Create a .pm file
* Need to strip off any prefixes that might be found in
* the module name */
{
char *m = Char(module) + Len(module);
while (m != Char(module)) {
if (*m == ':') {
m++;
break;
}
m--;
}
sprintf(filen,"%s%s.pm", output_dir,m);
if ((f_pm = fopen(filen,"w")) == 0) {
Printf(stderr,"Unable to open %s\n", filen);
Swig_exit (EXIT_FAILURE);
}
}
if (!blessed) {
smodule = NewString(module);
} else if (is_static) {
smodule = NewStringf("%sc",module);
Append(cmodule,"c");
Append(cmodule,"c");
} else {
smodule = NewString(module);
}
{
String *tmp = NewString(realpackage);
Replace(tmp,":","_", DOH_REPLACE_ANY);
Printf(f_header,"#define SWIG_init boot_%s\n\n", tmp);
Printf(f_header,"#define SWIG_name \"%s::boot_%s\"\n", package, tmp);
Delete(tmp);
}
Printf(f_header,"#define SWIG_varinit \"%s::var_%s_init();\"\n", package, cmodule);
Printf(f_header,"#ifdef __cplusplus\n");
Printf(f_header,"extern \"C\"\n");
Printf(f_header,"#endif\n");
Printf(f_header,"#ifndef PERL_OBJECT\n");
Printf(f_header,"SWIGEXPORT(void) SWIG_init (CV* cv);\n");
Printf(f_header,"#else\n");
Printf(f_header,"SWIGEXPORT(void) SWIG_init (CV *cv, CPerlObj *);\n");
Printf(f_header,"#endif\n");
Printf(f_init,"#ifdef __cplusplus\n");
Printf(f_init,"extern \"C\"\n");
Printf(f_init,"#endif\n");
Printf(f_init,"XS(SWIG_init) {\n");
Printf(f_init,"\t dXSARGS;\n");
Printf(f_init,"\t int i;\n");
Printf(f_init,"\t char *file = __FILE__;\n");
Printv(f_init,
"for (i = 0; swig_types_initial[i]; i++) {\n",
"swig_types[i] = SWIG_TypeRegister(swig_types_initial[i]);\n",
"}\n", 0);
Printf(f_init,"\t newXS(\"%s::var_%s_init\", _wrap_perl5_%s_var_init, file);\n",package,cmodule, cmodule);
Printv(vinit,
"XS(_wrap_perl5_", cmodule, "_var_init) {\n",
tab4, "dXSARGS;\n",
tab4, "SV *sv;\n",
0);
Printf(f_pm,"# This file was automatically generated by SWIG\n");
Printf(f_pm,"package %s;\n",realpackage);
Printf(f_pm,"require Exporter;\n");
if (!is_static) {
Printf(f_pm,"require DynaLoader;\n");
Printf(f_pm,"@ISA = qw(Exporter DynaLoader);\n");
} else {
Printf(f_pm,"@ISA = qw(Exporter);\n");
}
/* Start creating magic code */
Printv(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",
0);
}
/* -----------------------------------------------------------------------------
* PERL5::import()
* ----------------------------------------------------------------------------- */
void
PERL5::import(String *modname) {
if (blessed) {
Printf(f_pm,"require %s;\n", modname);
}
}
/* -----------------------------------------------------------------------------
* PERL5::close()
* ----------------------------------------------------------------------------- */
void
PERL5::close(void) {
String *base = NewString("");
/* Dump out variable wrappers */
Printv(magic,
"\n\n#ifdef PERL_OBJECT\n",
"};\n",
"#endif\n",
0);
Printf(f_header,"%s\n", magic);
String *type_table = NewString("");
SwigType_emit_type_table(f_runtime,type_table);
/* Patch the type table to reflect the names used by shadow classes */
if (blessed) {
SwigType *type;
for (type = Firstkey(classes); type; type = Nextkey(classes)) {
String *mangle = NewStringf("\"%s\"", SwigType_manglestr(type));
String *rep = NewStringf("\"%s\"", Getattr(classes,type));
Replace(type_table,mangle,rep,DOH_REPLACE_ANY);
Delete(mangle);
Delete(rep);
}
}
Printf(f_wrappers,"%s",type_table);
Delete(type_table);
/* Printf(stdout,"::: Perl shadow :::\n\n%s",classes); */
Printf(f_init,"\t ST(0) = &PL_sv_yes;\n");
Printf(f_init,"\t XSRETURN(1);\n");
Printf(f_init,"}\n");
Printv(vinit,tab4, "XSRETURN(1);\n", "}\n", 0);
Printf(f_wrappers,"%s", vinit);
Printf(f_pm,"package %s;\n", package);
if (!is_static) {
Printf(f_pm,"bootstrap %s;\n", realpackage);
} else {
String *tmp = NewString(realpackage);
Replace(tmp,":","_",DOH_REPLACE_ANY);
Printf(f_pm,"boot_%s();\n", tmp);
Delete(tmp);
}
Printf(f_pm,"var_%s_init();\n", cmodule);
Printf(f_pm,"%s",pragma_include);
Printf(f_pm,"package %s;\n", realpackage);
Printf(f_pm,"@EXPORT = qw(%s );\n",exported);
if (blessed) {
Printv(base,
"\n# ---------- BASE METHODS -------------\n\n",
"package ", realpackage, ";\n\n",
0);
/* Write out the TIE method */
Printv(base,
"sub TIEHASH {\n",
tab4, "my ($classname,$obj) = @_;\n",
tab4, "return bless $obj, $classname;\n",
"}\n\n",
0);
/* 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. */
Printf(base,"sub CLEAR { }\n\n");
/* Output default firstkey/nextkey methods */
Printf(base, "sub FIRSTKEY { }\n\n");
Printf(base, "sub NEXTKEY { }\n\n");
/* Output a 'this' method */
Printv(base,
"sub this {\n",
tab4, "my $ptr = shift;\n",
tab4, "return tied(%$ptr);\n",
"}\n\n",
0);
Printf(f_pm,"%s",base);
/* Emit function stubs for stand-alone functions */
Printf(f_pm,"\n# ------- FUNCTION WRAPPERS --------\n\n");
Printf(f_pm,"package %s;\n\n",realpackage);
Printf(f_pm,"%s",func_stubs);
/* Emit package code for different classes */
Printf(f_pm,"%s",pm);
/* Emit variable stubs */
Printf(f_pm,"\n# ------- VARIABLE STUBS --------\n\n");
Printf(f_pm,"package %s;\n\n",realpackage);
Printf(f_pm,"%s",var_stubs);
}
Printf(f_pm,"1;\n");
fclose(f_pm);
Delete(base);
}
/* -----------------------------------------------------------------------------
* get_pointer()
* ----------------------------------------------------------------------------- */
static void
get_pointer(char *iname, char *srcname, char *src, char *dest,
SwigType *t, String *f, char *ret) {
SwigType_remember(t);
SwigType *lt = Swig_clocal_type(t);
Printv(f, "if (SWIG_ConvertPtr(", src, ",(void **) &", dest, ",", 0);
/* If we're passing a void pointer, we give the pointer conversion a NULL
pointer, otherwise pass in the expected type. */
if (Cmp(lt,"p.void") == 0) {
Printf(f, " 0 ) < 0) {\n");
} else {
Printv(f, "SWIGTYPE", SwigType_manglestr(t), ") < 0) {\n",0);
}
Printv(f,
"croak(\"Type error in ", srcname, " of ", iname,". Expected %s\", SWIGTYPE",
SwigType_manglestr(t), "->name);\n",
ret, ";\n",
"}\n",
0);
Delete(lt);
}
/* -----------------------------------------------------------------------------
* PERL5::create_command()
* ----------------------------------------------------------------------------- */
void
PERL5::create_command(String *cname, String *iname) {
Printf(f_init,"\t newXS(\"%s::%s\", %s, file);\n", package, iname, Swig_name_wrapper(cname));
if (export_all) {
Printf(exported,"%s ",iname);
}
}
/* -----------------------------------------------------------------------------
* PERL5::create_function()
* ----------------------------------------------------------------------------- */
void
PERL5::function(DOH *node)
{
char *name, *iname;
SwigType *d;
ParmList *l;
Parm *p;
int pcount,i,j;
Wrapper *f;
char source[256],target[256],temp[256], argnum[32];
char *tm;
String *cleanup, *outarg;
int numopt = 0;
int need_save, num_saved = 0;
name = GetChar(node,"name");
iname = GetChar(node,"scriptname");
d = Getattr(node,"type");
l = Getattr(node,"parms");
f = NewWrapper();
cleanup = NewString("");
outarg = NewString("");
Printv(f, "XS(", Swig_name_wrapper(iname), ") {\n", 0);
pcount = emit_args(node, f);
numopt = check_numopt(l);
Wrapper_add_local(f,"argvi","int argvi = 0");
/* Check the number of arguments */
Printf(f," if ((items < %d) || (items > %d)) \n", pcount-numopt, ParmList_numarg(l));
Printf(f," croak(\"Usage: %s\");\n", usage_func(iname,d,l));
/* Write code to extract parameters. */
i = 0;
j = 0;
for (p = l; p; p = Getnext(p)) {
SwigType *pt = Gettype(p);
String *pn = Getname(p);
/* Produce string representation of source and target arguments */
sprintf(source,"ST(%d)",j);
sprintf(target,"%s", Char(Getlname(p)));
sprintf(argnum,"%d",j+1);
/* Check to see if this argument is being ignored */
if (!Getignore(p)) {
/* Check for optional argument */
if (j>= (pcount-numopt))
Printf(f," if (items > %d) {\n", j);
if ((tm = Swig_typemap_lookup((char*)"in",pt,pn,source,target,f))) {
Printf(f,"%s\n",tm);
Replace(f,"$argnum",argnum,DOH_REPLACE_ANY);
Replace(f,"$arg",source,DOH_REPLACE_ANY);
} else {
switch(SwigType_type(pt)) {
case T_BOOL:
case T_INT :
case T_SHORT :
case T_LONG :
case T_SCHAR:
case T_UINT:
case T_USHORT:
case T_ULONG:
case T_UCHAR:
Printf(f," %s = (%s)SvIV(ST(%d));\n", target, SwigType_lstr(pt,0),j);
break;
case T_CHAR :
Printf(f," %s = (char) *SvPV(ST(%d),PL_na);\n", target, j);
break;
case T_DOUBLE :
case T_FLOAT :
Printf(f," %s = (%s)SvNV(ST(%d));\n", target, SwigType_lstr(pt,0), j);
break;
case T_VOID :
break;
case T_USER:
SwigType_add_pointer(pt);
sprintf(temp,"argument %d", i+1);
get_pointer(iname, temp, source, target, pt, f, (char *)"XSRETURN(1)");
SwigType_del_pointer(pt);
break;
case T_STRING:
Printf(f," if (! SvOK((SV*) ST(%d))) { %s = 0; }\n", j, target);
Printf(f," else { %s = (char *) SvPV(ST(%d),PL_na); }\n", target,j);
break;
case T_POINTER: case T_ARRAY: case T_REFERENCE:
sprintf(temp,"argument %d", i+1);
get_pointer(iname,temp,source,target, pt, f, (char*)"XSRETURN(1)");
break;
default :
Printf(stderr,"%s:%d. Unable to use type %s as a function argument.\n",Getfile(node), Getline(node), SwigType_str(pt,0));
break;
}
}
/* The source is going to be an array of saved values. */
sprintf(temp,"_saved[%d]",num_saved);
if (j>= (pcount-numopt))
Printf(f," } \n");
j++;
} else {
temp[0] = 0;
}
/* Check if there is any constraint code */
if ((tm = Swig_typemap_lookup((char*)"check",pt,pn,source,target,0))) {
Printf(f,"%s\n", tm);
Replace(f,"$argnum",argnum, DOH_REPLACE_ANY);
}
need_save = 0;
if ((tm = Swig_typemap_lookup((char*)"freearg",pt,pn,target,temp,0))) {
Printf(cleanup,"%s\n", tm);
Replace(cleanup,"$argnum",argnum,DOH_REPLACE_ANY);
Replace(cleanup,"$arg",temp,DOH_REPLACE_ANY);
need_save = 1;
}
if ((tm = Swig_typemap_lookup((char*)"argout",pt,pn,target,(char*)"ST(argvi)",0))) {
String *tempstr = NewString(tm);
Replace(tempstr,"$argnum",argnum, DOH_REPLACE_ANY);
Replace(tempstr,"$arg",temp, DOH_REPLACE_ANY);
Printf(outarg,"%s\n", tempstr);
Delete(tempstr);
need_save = 1;
}
/* If we need 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) && (!Getignore(p))) {
Printv(f, tab4, temp, " = ", source, ";\n", 0);
num_saved++;
}
i++;
}
/* If there were any saved arguments, emit a local variable for them */
if (num_saved) {
sprintf(temp,"_saved[%d]",num_saved);
Wrapper_add_localv(f,"_saved","SV *",temp,0);
}
/* Now write code to make the function call */
emit_func_call(node,f);
if ((tm = Swig_typemap_lookup((char*)"out",d,iname,(char*)"result",(char*)"ST(argvi)",0))) {
Printf(f, "%s\n", tm);
} else {
if (SwigType_type(d) != T_VOID) {
Printf(f," ST(argvi) = sv_newmortal();\n");
switch (SwigType_type(d)) {
case T_INT: case T_BOOL: case T_UINT:
case T_SHORT: case T_USHORT:
case T_LONG : case T_ULONG:
case T_SCHAR: case T_UCHAR :
Printf(f," sv_setiv(ST(argvi++),(IV) result);\n");
break;
case T_DOUBLE :
case T_FLOAT :
Printf(f," sv_setnv(ST(argvi++), (double) result);\n");
break;
case T_CHAR :
Wrapper_add_local(f,"_ctemp", "char ctemp[2]");
Printv(f,
tab4, "ctemp[0] = result;\n",
tab4, "ctemp[1] = 0;\n",
tab4, "sv_setpv((SV*)ST(argvi++),ctemp);\n",
0);
break;
case T_USER:
SwigType_add_pointer(d);
SwigType_remember(d);
Printv(f,
tab4, "SWIG_MakePtr(ST(argvi++), (void *) result, SWIGTYPE", SwigType_manglestr(d),");\n", 0);
SwigType_del_pointer(d);
break;
case T_STRING:
Printf(f," sv_setpv((SV*)ST(argvi++),(char *) result);\n");
break;
case T_POINTER: case T_ARRAY: case T_REFERENCE:
SwigType_remember(d);
Printv(f, tab4, "SWIG_MakePtr(ST(argvi++), (void *) result, SWIGTYPE", SwigType_manglestr(d), ");\n", 0);
break;
default :
Printf(stderr,"%s:%d. Unable to use return type %s in function %s.\n", Getfile(node), Getline(node), SwigType_str(d,0), name);
break;
}
}
}
/* If there were any output args, take care of them. */
Printv(f,outarg,0);
/* If there was any cleanup, do that. */
Printv(f,cleanup,0);
if (NewObject) {
if ((tm = Swig_typemap_lookup((char*)"newfree",d,iname,(char*)"result",(char*)"",0))) {
Printf(f,"%s\n",tm);
}
}
if ((tm = Swig_typemap_lookup((char*)"ret",d,iname,(char*)"result",(char*)"",0))) {
Printf(f,"%s\n", tm);
}
Printf(f," XSRETURN(argvi);\n}\n");
/* Add the dXSARGS last */
Wrapper_add_local(f,"dXSARGS","dXSARGS");
/* Substitute the cleanup code */
Replace(f,"$cleanup",cleanup,DOH_REPLACE_ANY);
Replace(f,"$name",iname,DOH_REPLACE_ANY);
/* Dump the wrapper function */
Printf(f_wrappers,"%s", f);
/* Now register the function */
Printf(f_init,"\t newXS(\"%s::%s\", %s, file);\n", package, iname, Swig_name_wrapper(iname));
if (export_all) {
Printf(exported,"%s ", 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 = NewString("");
/* We'll make a stub since we may need it anyways */
Printv(func, "sub ", iname, " {\n",
tab4, "my @args = @_;\n",
0);
/* 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;
int i = 0;
while(p) {
SwigType *pt = Gettype(p);
if (!Getignore(p)) {
/* Look up the datatype name here */
char sourceNtarget[256];
sprintf(sourceNtarget,"$args[%d]",i);
if ((tm = Swig_typemap_lookup((char*)"perl5in",pt,(char*)"",sourceNtarget,sourceNtarget,0))) {
Printf(func,"%s\n", tm);
} else if (is_shadow(pt)) {
/*
if (i >= (pcount - numopt))
Printf(func," if (scalar(@args) >= %d) {\n ", i);
Printf(func," $args[%d] = tied(%%{$args[%d]});\n", i, i);
if (i >= (pcount - numopt))
Printf(func," }\n");
need_stub = 1;
*/
}
i++;
}
p = Getnext(p);
}
Printv(func, tab4, "my $result = ", package, "::", iname, "(@args);\n", 0);
/* 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 ((tm = Swig_typemap_lookup((char*)"perl5out",d,(char*)"",name,(char*)"sv",0))) {
Printv(func,
tm, "\n",
tab4, "return $result;\n",
"}\n",
0);
need_stub = 1;
} else if (is_shadow(d)) {
Printv(func, tab4, "return undef if (!defined($result));\n", 0);
/* If we're returning an object by value, put it's reference
into our local hash table */
if ((!SwigType_ispointer(d)) || NewObject) {
Printv(func, tab4, "$", is_shadow(d), "::OWNER{$result} = 1;\n", 0);
}
/* We're returning a Perl "object" of some kind. Turn it into a tied hash */
Printv(func,
tab4, "my %resulthash;\n",
tab4, "tie %resulthash, ref($result), $result;\n",
tab4, "return bless \\%resulthash, ref($result);\n",
"}\n",
0);
need_stub = 1;
} else {
/* Hmmm. This doesn't appear to be anything I know about */
Printv(func, tab4, "return $result;\n", "}\n", 0);
}
/* Now check if we needed the stub. If so, emit it, otherwise
* Emit code to hack Perl's symbol table instead */
if (need_stub) {
Printf(func_stubs,"%s",func);
} else {
Printv(func_stubs,"*", iname, " = *", package, "::", iname, ";\n", 0);
}
Delete(func);
}
Delete(cleanup);
Delete(outarg);
Delete(f);
}
/* -----------------------------------------------------------------------------
* PERL5::link_variable()
* ----------------------------------------------------------------------------- */
void PERL5::variable(DOH *node) {
char *name, *iname;
SwigType *t;
char set_name[256];
char val_name[256];
Wrapper *getf, *setf;
char *tm;
int setable = 1;
name = GetChar(node,"name");
iname = GetChar(node,"scriptname");
t = Getattr(node,"type");
sprintf(set_name,"_wrap_set_%s",iname);
sprintf(val_name,"_wrap_val_%s",iname);
getf = NewWrapper();
setf = NewWrapper();
/* Create a new scalar that we will attach magic to */
Printv(vinit, tab4, "sv = perl_get_sv(\"", package, "::", iname, "\",TRUE | 0x2);\n", 0);
/* Create a Perl function for setting the variable value */
if (!ReadOnly) {
Printf(setf,"SWIGCLASS_STATIC int %s(SV* sv, MAGIC *mg) {\n", set_name);
Printv(setf,
tab4, "MAGIC_PPERL\n",
tab4, "mg = mg;\n",
0);
/* Check for a few typemaps */
if ((tm = Swig_typemap_lookup((char*)"varin",t,(char*)"",(char*)"sv",name,0))) {
Printf(setf,"%s\n", tm);
} else if ((tm = Swig_typemap_lookup((char*)"in",t,(char*)"",(char*)"sv",name,0))) {
Printf(setf,"%s\n", tm);
} else {
switch(SwigType_type(t)) {
case T_INT : case T_BOOL: case T_UINT:
case T_SHORT : case T_USHORT:
case T_LONG : case T_ULONG:
case T_UCHAR: case T_SCHAR:
Printv(setf,tab4, name, " = (", SwigType_str(t,0), ") SvIV(sv);\n", 0);
break;
case T_DOUBLE :
case T_FLOAT :
Printv(setf, tab4, name, " = (", SwigType_str(t,0), ") SvNV(sv);\n", 0);
break;
case T_CHAR :
Printv(setf, tab4, name, " = (char) *SvPV(sv,PL_na);\n", 0);
break;
case T_USER:
SwigType_add_pointer(t);
Wrapper_add_local(setf,"_temp", "void *_temp");
get_pointer(iname,(char*)"value",(char*)"sv",(char*)"_temp", t, setf, (char*)"return(1)");
Printv(setf, tab4, name, " = *((", SwigType_str(t,0), ") _temp);\n", 0);
SwigType_del_pointer(t);
break;
case T_STRING:
Wrapper_add_local(setf,"_a","char *_a");
Printf(setf," _a = (char *) SvPV(sv,PL_na);\n");
if (CPlusPlus)
Printv(setf,
tab4, "if (", name, ") delete [] ", name, ";\n",
tab4, name, " = new char[strlen(_a)+1];\n",
0);
else
Printv(setf,
tab4, "if (", name, ") free((char*)", name, ");\n",
tab4, name, " = (char *) malloc(strlen(_a)+1);\n",
0);
Printv(setf,"strcpy((char*)", name, ",_a);\n", 0);
break;
case T_ARRAY:
{
SwigType *aop;
SwigType *ta = Copy(t);
aop = SwigType_pop(ta);
if (SwigType_type(ta) == T_CHAR) {
String *dim = SwigType_array_getdim(aop,0);
if (dim && Len(dim)) {
Printf(setf, "strncpy(%s,(char*) SvPV(sv,PL_na), %s);\n", name,dim);
setable = 1;
} else {
setable = 0;
}
} else {
setable = 0;
}
Delete(ta);
Delete(aop);
}
break;
case T_POINTER: case T_REFERENCE:
Wrapper_add_local(setf,"_temp","void *_temp");
get_pointer(iname,(char*)"value",(char*)"sv",(char*)"_temp", t, setf, (char*)"return(1)");
Printv(setf,tab4, name, " = (", SwigType_str(t,0), ") _temp;\n", 0);
break;
default :
Printf(stderr,"%s:%d. Unable to link with datatype %s (ignored).\n", Getfile(node), Getline(node), SwigType_str(t,0));
return;
}
}
Printf(setf," return 1;\n}\n");
Replace(setf,"$name",iname, DOH_REPLACE_ANY);
Printf(magic,"%s", setf);
}
/* Now write a function to evaluate the variable */
Printf(getf,"SWIGCLASS_STATIC int %s(SV *sv, MAGIC *mg) {\n", val_name);
Printv(getf,
tab4, "MAGIC_PPERL\n",
tab4, "mg = mg;\n",
0);
if ((tm = Swig_typemap_lookup((char*)"varout",t,(char*)"",name, (char*)"sv",0))) {
Printf(getf,"%s\n", tm);
} else if ((tm = Swig_typemap_lookup((char*)"out",t,(char*)"",name,(char*)"sv",0))) {
Printf(getf,"%s\n", tm);
} else {
switch(SwigType_type(t)) {
case T_INT : case T_BOOL: case T_UINT:
case T_SHORT : case T_USHORT:
case T_LONG : case T_ULONG:
case T_UCHAR: case T_SCHAR:
Printv(getf,tab4, "sv_setiv(sv, (IV) ", name, ");\n", 0);
Printv(vinit, tab4, "sv_setiv(sv,(IV)", name, ");\n",0);
break;
case T_DOUBLE :
case T_FLOAT :
Printv(getf, tab4,"sv_setnv(sv, (double) ", name, ");\n", 0);
Printv(vinit, tab4, "sv_setnv(sv,(double)", name, ");\n",0);
break;
case T_CHAR :
Wrapper_add_local(getf,"_ptemp","char _ptemp[2]");
Printv(getf,
tab4, "_ptemp[0] = ", name, ";\n",
tab4, "_ptemp[1] = 0;\n",
tab4, "sv_setpv((SV*) sv, _ptemp);\n",
0);
break;
case T_USER:
SwigType_add_pointer(t);
Printv(getf,
tab4, "rsv = SvRV(sv);\n",
tab4, "sv_setiv(rsv,(IV) &", name, ");\n",
0);
Wrapper_add_local(getf,"rsv","SV *rsv");
Printv(vinit, tab4, "SWIG_MakePtr(sv, (void *) &", name, ",SWIGTYPE", SwigType_manglestr(t), ");\n",0);
SwigType_del_pointer(t);
break;
case T_STRING:
Printv(getf, tab4, "sv_setpv((SV*) sv, ", name, ");\n", 0);
break;
case T_ARRAY:
{
SwigType *aop;
SwigType *ta = Copy(t);
aop = SwigType_pop(ta);
if (SwigType_type(ta) == T_CHAR) {
Printv(getf, "sv_setpv((SV*)sv, ", name, ");\n", 0);
Delete(ta);
Delete(aop);
break;
}
Delete(ta);
Delete(aop);
}
/* No break here is intentional */
case T_POINTER: case T_REFERENCE:
Printv(getf,
tab4, "rsv = SvRV(sv);\n",
tab4, "sv_setiv(rsv,(IV) ", name, ");\n",
0);
Wrapper_add_local(getf,"rsv","SV *rsv");
Printv(vinit, tab4, "SWIG_MakePtr(sv,(void *) 1, SWIGTYPE", SwigType_manglestr(t), ");\n",0);
break;
default :
break;
}
}
Printf(getf," return 1;\n}\n");
Replace(getf,"$name",iname, DOH_REPLACE_ANY);
Printf(magic,"%s", getf);
/* Now add symbol to the PERL interpreter */
if ((ReadOnly) || (!setable)) {
Printv(vinit, tab4, "swig_create_magic(sv,\"", package, "::", iname, "\",MAGIC_CAST MAGIC_CLASS swig_magic_readonly, MAGIC_CAST MAGIC_CLASS ", val_name, ");\n",0);
} else {
Printv(vinit, tab4, "swig_create_magic(sv,\"", package, "::", iname, "\", MAGIC_CAST MAGIC_CLASS ", set_name, ", MAGIC_CAST MAGIC_CLASS ", val_name, ");\n",0);
}
/* 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 (is_shadow(t)) {
Printv(var_stubs,
"\nmy %__", iname, "_hash;\n",
"tie %__", iname, "_hash,\"", is_shadow(t), "\", $",
package, "::", iname, ";\n",
"$", iname, "= \\%__", iname, "_hash;\n",
"bless $", iname, ", ", is_shadow(t), ";\n",
0);
} else {
Printv(var_stubs, "*", iname, " = *", package, "::", iname, ";\n", 0);
}
if (export_all)
Printf(exported,"$%s ", name);
}
Delete(setf);
Delete(getf);
}
/* -----------------------------------------------------------------------------
* PERL5::constant()
* ----------------------------------------------------------------------------- */
/* 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::constant(DOH *node)
{
char *name;
SwigType *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;
name = GetChar(node,"name");
type = Getattr(node,"type");
value = GetChar(node,"value");
if ((tm = Swig_typemap_lookup((char*)"const",type,name,value,name,0))) {
Printf(f_init,"%s\n",tm);
} else {
switch(SwigType_type(type)) {
case T_INT: case T_UINT: case T_BOOL:
case T_SHORT: case T_USHORT:
case T_LONG: case T_ULONG:
case T_SCHAR: case T_UCHAR:
if (!have_int_func) {
Printf(f_header,"%s\n",setiv);
have_int_func = 1;
}
Printv(vinit, tab4, "swig_setiv(\"", package, "::", name, "\", (long) ", value, ");\n",0);
break;
case T_DOUBLE:
case T_FLOAT:
if (!have_double_func) {
Printf(f_header,"%s\n",setnv);
have_double_func = 1;
}
Printv(vinit, tab4, "swig_setnv(\"", package, "::", name, "\", (double) (", value, "));\n",0);
break;
case T_CHAR :
if (!have_char_func) {
Printf(f_header,"%s\n",setpv);
have_char_func = 1;
}
Printf(vinit," swig_setpv(\"%s::%s\",\"%s\");\n", package, name, value);
break;
case T_STRING:
if (!have_char_func) {
Printf(f_header,"%s\n",setpv);
have_char_func = 1;
}
Printf(vinit," swig_setpv(\"%s::%s\",\"%s\");\n", package, name, value);
break;
case T_POINTER: case T_ARRAY: case T_REFERENCE:
if (!have_ref_func) {
Printf(f_header,"%s\n",setrv);
have_ref_func = 1;
}
Printv(vinit, tab4, "swig_setrv(\"", package, "::", name, "\", (void *) ", value, ", \"",
SwigType_manglestr(type), "\");\n", 0);
break;
default:
Printf(stderr,"%s:%d. Unsupported constant value.\n", Getfile(node), Getline(node));
break;
}
}
if (blessed) {
if (is_shadow(type)) {
Printv(var_stubs,
"\nmy %__", name, "_hash;\n",
"tie %__", name, "_hash,\"", is_shadow(type), "\", $",
package, "::", name, ";\n",
"$", name, "= \\%__", name, "_hash;\n",
"bless $", name, ", ", is_shadow(type), ";\n",
0);
} else {
Printv(var_stubs, "*",name," = *", package, "::", name, ";\n", 0);
}
}
if (export_all)
Printf(exported,"$%s ",name);
}
/* -----------------------------------------------------------------------------
* PERL5::usage_func()
* ----------------------------------------------------------------------------- */
char *
PERL5::usage_func(char *iname, SwigType *, ParmList *l) {
static String *temp = 0;
Parm *p;
int i;
if (!temp) temp = NewString("");
Clear(temp);
Printf(temp,"%s(",iname);
/* Now go through and print parameters */
p = l;
i = 0;
while (p != 0) {
SwigType *pt = Gettype(p);
String *pn = Getname(p);
if (!Getignore(p)) {
/* If parameter has been named, use that. Otherwise, just print a type */
if (SwigType_type(pt) != T_VOID) {
if (Len(pn) > 0) {
Printf(temp,"%s",pn);
} else {
Printf(temp,"%s",SwigType_str(pt,0));
}
}
i++;
p = Getnext(p);
if (p)
if (!Getignore(p))
Putc(',',temp);
} else {
p = Getnext(p);
if (p)
if ((i>0) && (!Getignore(p)))
Putc(',',temp);
}
}
Printf(temp,");");
return Char(temp);
}
/* -----------------------------------------------------------------------------
* PERL5::nativefunction()
* ----------------------------------------------------------------------------- */
void
PERL5::nativefunction(DOH *node) {
char *name, *funcname;
name = GetChar(node,"scriptname");
funcname = GetChar(node,"name");
Printf(f_init,"\t newXS(\"%s::%s\", %s, file);\n", package,name, funcname);
if (export_all)
Printf(exported,"%s ",name);
if (blessed) {
Printv(func_stubs,"*", name, " = *", package, "::", name, ";\n", 0);
}
}
/****************************************************************************
*** 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.
***
****************************************************************************/
/* -----------------------------------------------------------------------------
* PERL5::cpp_open_class()
* ----------------------------------------------------------------------------- */
void
PERL5::cpp_open_class(DOH *node) {
this->Language::cpp_open_class(node);
char *classname = GetChar(node,"name");
char *rname = GetChar(node,"scriptname");
char *ctype = GetChar(node,"classtype");
if (blessed) {
have_constructor = 0;
have_destructor = 0;
have_data_members = 0;
Delete(class_name); class_name = 0;
Delete(class_type); class_type =0;
Delete(real_classname); real_classname = 0;
Delete(base_class); base_class = 0;
Delete(fullclassname); fullclassname = 0;
/* If the class is being renamed to something else, use the renaming */
if (rname) {
class_name = NewString(rname);
class_renamed = 1;
} else {
class_name = NewString(classname);
class_renamed = 0;
}
/* Use the fully qualified name of the Perl class */
if (!compat) {
fullclassname = NewStringf("%s::%s",realpackage,class_name);
} else {
fullclassname = NewString(class_name);
}
real_classname = NewString(classname);
if (base_class) Delete(base_class);
base_class = 0;
class_type = NewString(ctype);
pcode = NewString("");
blessedmembers = NewString("");
member_keys = NewString("");
/* Add some symbols to the hash tables */
Hash *nnode = NewHash();
Setattr(nnode,"name", classname);
Setattr(nnode,"scriptname", fullclassname);
Setattr(nnode,"classtype", ctype);
cpp_class_decl(nnode);
}
}
/* -----------------------------------------------------------------------------
* PERL5::cpp_close_class()
* ----------------------------------------------------------------------------- */
void
PERL5::cpp_close_class() {
if (blessed) {
Printv(pm,
"\n############# Class : ", fullclassname, " ##############\n",
"\npackage ", fullclassname, ";\n",
0);
/* If we are inheriting from a base class, set that up */
if (Cmp(class_name,realpackage))
Printv(pm, "@ISA = qw( ",realpackage, 0);
else
Printv(pm, "@ISA = qw( ", 0);
if (base_class) {
Printv(pm, " ", base_class, 0);
}
Printf(pm, " );\n");
/* Dump out a hash table containing the pointers that we own */
Printf(pm, "%%OWNER = ();\n");
if (have_data_members) {
Printv(pm,
"%BLESSEDMEMBERS = (\n", blessedmembers, ");\n\n",
0);
}
if (have_data_members || have_destructor)
Printf(pm, "%%ITERATORS = ();\n");
/* Dump out the package methods */
Printv(pm,pcode,0);
Delete(pcode);
/* Output methods for managing ownership */
Printv(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",
0);
/* 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 */
Printv(pm,
"sub FETCH {\n",
tab4, "my ($self,$field) = @_;\n",
tab4, "my $member_func = \"", package, "::", Swig_name_get(Swig_name_member(class_name,(char*)"${field}")), "\";\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",
0);
/* Output a STORE method. This is also common to all classes (might move to base class) */
Printv(pm,
"sub STORE {\n",
tab4, "my ($self,$field,$newval) = @_;\n",
tab4, "my $member_func = \"", package, "::", Swig_name_set(Swig_name_member(class_name,(char*)"${field}")), "\";\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",
0);
/* Output a FIRSTKEY method. This is to allow iteration over a structure's keys. */
Printv(pm,
"sub FIRSTKEY {\n",
tab4, "my $self = shift;\n",
tab4, "$ITERATORS{$self} = [", member_keys, "];\n",
tab4, "my $first = shift @{$ITERATORS{$self}};\n",
tab4, "return $first;\n",
"}\n\n",
0);
/* Output a NEXTKEY method. This is the iterator so that each and keys works */
Printv(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, "];\n",
tab8, "return ();\n",
tab4, "}\n",
"}\n\n",
0);
}
}
}
/* -----------------------------------------------------------------------------
* PERL5::cpp_member_func()
* ----------------------------------------------------------------------------- */
void
PERL5::cpp_memberfunction(DOH *node) {
char *name, *iname;
SwigType *t;
ParmList *l;
String *func;
char *realname;
Parm *p;
int i;
String *cname;
int pcount, numopt;
char *tm;
int need_wrapper = 0;
member_func = 1;
this->Language::cpp_memberfunction(node);
member_func = 0;
if (!blessed) return;
name = GetChar(node,"name");
iname = GetChar(node,"scriptname");
t = Getattr(node,"type");
l = Getattr(node,"parms");
func = NewString("");
cname = NewString("perl5:");
/* 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;
Printf(cname,"%s::%s",class_name,realname);
if (Getattr(symbols,cname)) {
return; /* Forget it, we saw this already */
}
Setattr(symbols,cname,cname);
Printv(func,
"sub ", realname, " {\n",
tab4, "my @args = @_;\n",
0);
/* 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;
pcount = ParmList_len(l);
numopt = check_numopt(l);
i = 1;
while(p) {
SwigType *pt = Gettype(p);
if (!Getignore(p)) {
char sourceNtarget[512];
sprintf(sourceNtarget, "$args[%d]", i);
if ((tm = Swig_typemap_lookup((char*)"perl5in",pt,(char*)"",sourceNtarget,sourceNtarget,0))) {
Printf(func,"%s\n",tm);
need_wrapper = 1;
}
i++;
}
p = Getnext(p);
}
/* Okay. We've made argument adjustments, now call into the package */
Printv(func,
tab4, "my $result = ", package, "::", Swig_name_member(class_name,realname),
"(@args);\n",
0);
/* 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 ((tm = Swig_typemap_lookup((char*)"perl5out",t,(char*)"",name,(char*)"sv",0))) {
Printv(func,
tm, "\n",
tab4,"return $result;\n",
"}\n",
0);
need_wrapper = 1;
} else if (is_shadow(t)) {
Printv(func,tab4, "return undef if (!defined($result));\n", 0);
/* If we're returning an object by value, put it's reference
into our local hash table */
if (!SwigType_ispointer(t) || NewObject) {
Printv(func, tab4, "$", is_shadow(t), "::OWNER{$result} = 1; \n", 0);
}
/* We're returning a Perl "object" of some kind. Turn it into
a tied hash */
Printv(func,
tab4, "my %resulthash;\n",
tab4, "tie %resulthash, ref($result), $result;\n",
tab4, "return bless \\%resulthash, ref($result);\n",
"}\n",
0);
need_wrapper = 1;
} else {
/* Hmmm. This doesn't appear to be anything I know about so just
return it unmodified */
Printv(func, tab4,"return $result;\n", "}\n", 0);
}
if (need_wrapper) {
Printv(pcode,func,0);
} else {
Printv(pcode,"*",realname," = *", package, "::", Swig_name_member(class_name,realname), ";\n", 0);
}
Delete(func);
Delete(cname);
}
/* -----------------------------------------------------------------------------
* PERL5::cpp_variable()
*
* 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(DOH *node) {
char *name, *iname;
SwigType *t;
char *realname;
String *cname;
cname = NewString("perl5:");
/* Emit a pair of get/set functions for the variable */
member_func = 1;
this->Language::cpp_variable(node);
member_func = 0;
if (blessed) {
name = GetChar(node,"name");
iname = GetChar(node,"scriptname");
t = Getattr(node,"type");
if (iname) realname = iname;
else realname = name;
Printf(cname,"%s::%s", class_name, realname);
if (Getattr(symbols,cname)) {
Delete(cname);
return;
}
Setattr(symbols,cname,cname);
/* Store name of key for future reference */
Printf(member_keys,"'%s', ", realname);
/* Now we need to generate a little Perl code for this */
if (is_shadow(t)) {
/* This is a Perl object that we have already seen. Add an
entry to the members list*/
Printv(blessedmembers,
tab4, realname, " => '", is_shadow(t), "',\n",
0);
}
}
have_data_members++;
Delete(cname);
}
/* -----------------------------------------------------------------------------
* PERL5::cpp_constructor()
*
* 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(DOH *node) {
char *name, *iname;
ParmList *l;
Parm *p;
int i;
String *realname;
String *cname;
cname = NewString("perl5:constructor:");
/* Emit an old-style constructor for this class */
member_func = 1;
this->Language::cpp_constructor(node);
if (blessed) {
name = GetChar(node,"name");
iname = GetChar(node,"scriptname");
l = Getattr(node,"parms");
if (iname)
realname = iname;
else {
if (class_renamed) realname = class_name;
else realname = class_name;
}
Printf(cname,"%s::%s", class_name, realname);
if (Getattr(symbols,cname)) {
Delete(cname);
return;
}
Setattr(symbols,cname, cname);
if ((Cmp(realname,class_name) == 0)) {
/* Emit a blessed constructor */
Printf(pcode, "sub new {\n");
} else {
/* Constructor doesn't match classname so we'll just use the normal name */
Printv(pcode, "sub ", Swig_name_construct(realname), " () {\n", 0);
}
Printv(pcode, tab4, "my $self = shift;\n",
tab4, "my @args = @_;\n", 0);
/* 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;
i = 0;
while(p) {
SwigType *pt = Gettype(p);
if (is_shadow(pt)) {
/* Yep. This smells alot like an object, patch up the arguments */
Printf(pcode, " $args[%d] = tied(%%{$args[%d]});\n", i, i);
}
p = Getnext(p);
i++;
}
Printv(pcode,
tab4, "$self = ", package, "::", Swig_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",
0);
have_constructor = 1;
}
Delete(cname);
member_func = 0;
}
/* -----------------------------------------------------------------------------
* PERL5::cpp_destructor()
* ----------------------------------------------------------------------------- */
void
PERL5::cpp_destructor(DOH *node) {
String *realname;
char *name, *newname;
member_func = 1;
this->Language::cpp_destructor(node);
if (blessed) {
name = GetChar(node,"name");
newname = GetChar(node,"scriptname");
if (newname) realname = newname;
else {
if (class_renamed) realname = class_name;
else realname = name;
}
/* Emit a destructor for this object*/
Printv(pcode,
"sub DESTROY {\n",
tab4, "return unless $_[0]->isa('HASH');\n",
tab4, "my $self = tied(%{$_[0]});\n",
tab4, "delete $ITERATORS{$self};\n",
tab4, "if (exists $OWNER{$self}) {\n",
tab8, package, "::", Swig_name_destroy(realname), "($self);\n",
tab8, "delete $OWNER{$self};\n",
tab4, "}\n}\n\n",
0);
have_destructor = 1;
}
member_func = 0;
}
/* -----------------------------------------------------------------------------
* PERL5::cpp_staticfunction()
* ----------------------------------------------------------------------------- */
void
PERL5::cpp_staticfunction(DOH *node) {
char *name, *iname;
this->Language::cpp_staticfunction(node);
char *realname;
if (blessed) {
name = GetChar(node,"name");
iname = GetChar(node,"scriptname");
if (iname) realname = name;
else realname = iname;
Printv(pcode, "*", realname, " = *", realpackage, "::", Swig_name_member(class_name,realname), ";\n", 0);
}
}
/* -----------------------------------------------------------------------------
* PERL5::cpp_inherit()
* ------------------------------------------------------------------------------ */
void
PERL5::cpp_inherit(List *bases) {
String *base;
char *bc;
int have_first = 0;
if (!blessed) {
this->Language::cpp_inherit(bases);
return;
}
/* Inherit variables and constants from base classes, but not
functions (since Perl can handle that okay). */
this->Language::cpp_inherit(bases);
/* Now tell the Perl5 module that we're inheriting from base classes */
base_class = NewString("");
for (base = Firstitem(bases); base; base = Nextitem(bases)) {
/* See if this is a class we know about */
String *b = NewString(base);
bc = Char(is_shadow(b));
Delete(b);
if (bc) {
if (have_first) Putc(' ', base_class);
Printf(base_class,bc);
have_first = 1;
}
}
if (!have_first) {
Delete(base_class);
base_class = 0;
}
}
/* -----------------------------------------------------------------------------
* PERL5::cpp_constant()
* ----------------------------------------------------------------------------- */
void
PERL5::cpp_constant(DOH *node) {
char *name, *iname;
String *realname;
int oldblessed = blessed;
char cname[256];
/* Create a normal constant */
blessed = 0;
this->Language::cpp_constant(node);
blessed = oldblessed;
if (blessed) {
name = GetChar(node,"name");
iname = GetChar(node,"scriptname");
if (!iname)
realname = name;
else
realname = iname;
sprintf(cname,"%s::%s",Char(class_name),Char(realname));
if (Getattr(symbols, cname)) {
return;
}
Setattr(symbols, cname,cname);
/* Create a symbol table entry for it */
Printv(pcode, "*", realname, " = *", package, "::", Swig_name_member(class_name,realname), ";\n", 0);
}
}
/* -----------------------------------------------------------------------------
* PERL5::cpp_class_decl()
* ----------------------------------------------------------------------------- */
void
PERL5::cpp_class_decl(DOH *node) {
String *name = Getname(node);
String *rename = Getattr(node,"scriptname");
String *ctype = Getattr(node,"classtype");
String *stype;
if (blessed) {
stype = NewString(name);
SwigType_add_pointer(stype);
Setattr(classes,stype,rename);
Delete(stype);
if (Len(ctype) > 0) {
stype = NewStringf("%s %s",ctype,name);
SwigType_add_pointer(stype);
Setattr(classes,stype,rename);
Delete(stype);
}
}
}
/* -----------------------------------------------------------------------------
* PERL5::add_typedef()
* ----------------------------------------------------------------------------- */
void
PERL5::add_typedef(SwigType *t, String *name) {
if (!blessed) return;
if (is_shadow(t)) {
DOH *node = NewHash();
Setattr(node,"name",name);
Setattr(node,"scriptname", is_shadow(t));
Setattr(node,"classtype","");
cpp_class_decl(node);
}
}
/* -----------------------------------------------------------------------------
* PERL5::pragma()
*
* 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(DOH *node) {
String *name = Getattr(node,"name");
String *value = Getattr(node,"value");
if (Cmp(name,"code") == 0) {
/* Dump the value string into the .pm file */
if (value) {
Printf(pragma_include, "%s\n", value);
}
} else if (Cmp(name,"include") == 0) {
/* Include a file into the .pm file */
if (value) {
FILE *f = Swig_open(value);
if (!f) {
Printf(stderr,"%s:%d. Unable to locate file %s\n", Getfile(node), Getline(node),value);
} else {
char buffer[4096];
while (fgets(buffer,4095,f)) {
Printf(pragma_include,"%s",buffer);
}
}
}
}
}