git-svn-id: https://swig.svn.sourceforge.net/svnroot/swig/trunk/SWIG@957 626c5289-ae23-0410-ae9c-e8d60b6d4f22
1508 lines
42 KiB
C++
1508 lines
42 KiB
C++
/********************************************************************
|
|
* Ruby module for SWIG
|
|
*
|
|
* $Header$
|
|
*
|
|
* Copyright (C) 2000 Network Applied Communication Laboratory, Inc.
|
|
* Copyright (C) 2000 Information-technology Promotion Agency, Japan
|
|
*
|
|
* Masaki Fukushima
|
|
*
|
|
********************************************************************/
|
|
|
|
static char cvsroot[] = "$Header$";
|
|
|
|
#include "swig11.h"
|
|
#include "ruby.h"
|
|
|
|
#include <ctype.h>
|
|
#include <string.h>
|
|
|
|
/* for debug */
|
|
#define P(obj) printf("\"%s\"\n", Char(Str(obj)))
|
|
|
|
class RClass {
|
|
private:
|
|
String *temp;
|
|
public:
|
|
String *name; /* class name (renamed) */
|
|
String *cname; /* original C class/struct name */
|
|
String *vname; /* variable name */
|
|
String *type;
|
|
String *prefix;
|
|
String *header;
|
|
String *init;
|
|
|
|
String *aliases;
|
|
String *includes;
|
|
Hash *freemethods;
|
|
Hash *predmethods;
|
|
int destructor_defined;
|
|
|
|
RClass(void) {
|
|
freemethods = NewHash();
|
|
predmethods = NewHash();
|
|
destructor_defined = 0;
|
|
name = NewString("");
|
|
cname = NewString("");
|
|
vname = NewString("");
|
|
type = NewString("");
|
|
prefix = NewString("");
|
|
header = NewString("");
|
|
init = NewString("");
|
|
aliases = NewString("");
|
|
includes = NewString("");
|
|
temp = NewString("");
|
|
}
|
|
~RClass() {
|
|
Delete(name);
|
|
Delete(cname);
|
|
Delete(vname);
|
|
Delete(type);
|
|
Delete(prefix);
|
|
Delete(header);
|
|
Delete(init);
|
|
Delete(aliases);
|
|
Delete(includes);
|
|
Delete(freemethods);
|
|
Delete(predmethods);
|
|
Delete(temp);
|
|
}
|
|
|
|
void set_name(char *cn, char *rn, char *valn) {
|
|
Clear(cname);
|
|
Append(cname,cn);
|
|
Clear(name);
|
|
Append(name,valn);
|
|
Clear(vname);
|
|
Printf(vname,"c%s",name);
|
|
Printv(prefix,(rn ? rn : cn), "_", 0);
|
|
}
|
|
|
|
char *strip(char *s) {
|
|
if (strncmp(s, Char(prefix), Len(prefix)) != 0)
|
|
return s;
|
|
Clear(temp);
|
|
Append(temp,s);
|
|
Replace(temp,prefix,"",DOH_REPLACE_ANY);
|
|
return Char(temp);
|
|
}
|
|
};
|
|
|
|
|
|
static char *usage = (char*)"\
|
|
Ruby Options (available with -ruby)\n\
|
|
-module name - Set module name\n\
|
|
-feature name - Set feature name (used by `require')\n";
|
|
|
|
static char *module = 0;
|
|
static char *modvar = 0;
|
|
static char *feature = 0;
|
|
static String *other_extern = 0;
|
|
static String *other_init = 0;
|
|
static char *import_file;
|
|
|
|
static int current;
|
|
|
|
enum {
|
|
NO_CPP,
|
|
MEMBER_FUNC,
|
|
CONSTRUCTOR,
|
|
DESTRUCTOR,
|
|
MEMBER_VAR,
|
|
CLASS_CONST,
|
|
STATIC_FUNC,
|
|
STATIC_VAR
|
|
};
|
|
|
|
static Hash *classes; /* key=cname val=RClass */
|
|
static RClass *klass; /* Currently processing class */
|
|
static Hash *special_methods; /* Python style special method name table */
|
|
|
|
|
|
#define RCLASS(hash, name) (RClass*)(Getattr(hash, name) ? Data(Getattr(hash, name)) : 0)
|
|
#define SET_RCLASS(hash, name, klass) Setattr(hash, name, NewVoid(klass, 0))
|
|
|
|
/* ---------------------------------------------------------------------
|
|
* RUBY::parse_args(int argc, char *argv[])
|
|
*
|
|
* Parse command line options and initializes variables.
|
|
* --------------------------------------------------------------------- */
|
|
|
|
void RUBY::parse_args(int argc, char *argv[]) {
|
|
/* Look for certain command line options */
|
|
for (int i = 1; i < argc; i++) {
|
|
if (argv[i]) {
|
|
if (strcmp(argv[i],"-feature") == 0) {
|
|
if (argv[i+1]) {
|
|
char *name = argv[i+1];
|
|
feature = new char [strlen(name)+1];
|
|
strcpy(feature, name);
|
|
Swig_mark_arg(i);
|
|
Swig_mark_arg(i+1);
|
|
i++;
|
|
} else {
|
|
Swig_arg_error();
|
|
}
|
|
} else if (strcmp(argv[i],"-help") == 0) {
|
|
Printf(stderr,"%s\n", usage);
|
|
}
|
|
}
|
|
}
|
|
/* Set location of SWIG library */
|
|
strcpy(LibDir,"ruby");
|
|
|
|
/* Add a symbol to the parser for conditional compilation */
|
|
Preprocessor_define((void *) "SWIGRUBY", 0);
|
|
SWIG_config_file("ruby.i");
|
|
}
|
|
|
|
|
|
static void insert_file(char *filename, File *file) {
|
|
if (Swig_insert_file(filename, file) == -1) {
|
|
Printf(stderr,
|
|
"SWIG : Fatal error. "
|
|
"Unable to locate %s. (Possible installation problem).\n",
|
|
filename);
|
|
SWIG_exit (EXIT_FAILURE);
|
|
}
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------
|
|
* RUBY::initialize()
|
|
*
|
|
* Produces an initialization function. Assumes that the module
|
|
* name has already been specified.
|
|
* --------------------------------------------------------------------- */
|
|
|
|
void RUBY::initialize(String *modname) {
|
|
import_file = 0;
|
|
current = NO_CPP;
|
|
klass = 0;
|
|
classes = NewHash();
|
|
special_methods = NewHash();
|
|
other_extern = NewString("");
|
|
other_init = NewString("");
|
|
|
|
/* Python style special method name. */
|
|
/* Basic */
|
|
Setattr(special_methods, "__repr__", "inspect");
|
|
Setattr(special_methods, "__str__", "to_s");
|
|
Setattr(special_methods, "__cmp__", "<=>");
|
|
Setattr(special_methods, "__hash__", "hash");
|
|
Setattr(special_methods, "__nonzero__", "nonzero?");
|
|
/* Callable */
|
|
Setattr(special_methods, "__call__", "call");
|
|
/* Collection */
|
|
Setattr(special_methods, "__len__", "length");
|
|
Setattr(special_methods, "__getitem__", "[]");
|
|
Setattr(special_methods, "__setitem__", "[]=");
|
|
/* Numeric */
|
|
Setattr(special_methods, "__add__", "+");
|
|
Setattr(special_methods, "__sub__", "-");
|
|
Setattr(special_methods, "__mul__", "*");
|
|
Setattr(special_methods, "__div__", "/");
|
|
Setattr(special_methods, "__mod__", "%");
|
|
Setattr(special_methods, "__divmod__", "divmod");
|
|
Setattr(special_methods, "__pow__", "**");
|
|
Setattr(special_methods, "__lshift__", "<<");
|
|
Setattr(special_methods, "__rshift__", ">>");
|
|
Setattr(special_methods, "__and__", "&");
|
|
Setattr(special_methods, "__xor__", "^");
|
|
Setattr(special_methods, "__or__", "|");
|
|
Setattr(special_methods, "__neg__", "-@");
|
|
Setattr(special_methods, "__pos__", "+@");
|
|
Setattr(special_methods, "__abs__", "abs");
|
|
Setattr(special_methods, "__invert__", "~");
|
|
Setattr(special_methods, "__int__", "to_i");
|
|
Setattr(special_methods, "__float__", "to_f");
|
|
Setattr(special_methods, "__coerce__", "coerce");
|
|
|
|
Swig_banner(f_header);
|
|
|
|
Printf(f_header,"/* Implementation : RUBY */\n\n");
|
|
Printf(f_header,"#define SWIGRUBY\n");
|
|
|
|
insert_file((char*)"common.swg", f_header);
|
|
insert_file((char*)"ruby.swg", f_header);
|
|
if (NoInclude) {
|
|
insert_file((char*)"rubydec.swg", f_header);
|
|
} else {
|
|
insert_file((char*)"rubydef.swg", f_header);
|
|
}
|
|
|
|
/* typedef void *VALUE */
|
|
SwigType *value = NewSwigType(T_VOID);
|
|
SwigType_setbase(value,(char*)"void");
|
|
SwigType_add_pointer(value);
|
|
SwigType_typedef(value,(char*)"VALUE");
|
|
Delete(value);
|
|
|
|
/* Old set_module code */
|
|
|
|
if (!module) {
|
|
module = new char[Len(modname)+1];
|
|
strcpy(module, Char(modname));
|
|
}
|
|
if (!feature) {
|
|
feature = new char[strlen(module)+1];
|
|
strcpy(feature, module);
|
|
}
|
|
/* module name must be a constant. */
|
|
module[0] = toupper(module[0]);
|
|
|
|
modvar = new char[1+strlen(module)+1];
|
|
modvar[0] = 'm';
|
|
strcpy(modvar+1, module);
|
|
|
|
/* Old init code */
|
|
|
|
Printf(f_header,"#define SWIG_init Init_%s\n", feature);
|
|
Printf(f_header,"#define SWIG_name \"%s\"\n\n", module);
|
|
Printf(f_header,"static VALUE %s;\n", modvar);
|
|
Printf(f_header,"\n%s\n", other_extern);
|
|
|
|
/* Start generating the initialization function */
|
|
Printv(f_init,
|
|
"\n",
|
|
"#ifdef __cplusplus\n",
|
|
"extern \"C\"\n",
|
|
"#endif\n",
|
|
"void Init_", feature, "(void) {\n",
|
|
"int i;\n",
|
|
other_init,
|
|
"\n",
|
|
0);
|
|
|
|
Printv(f_init, tab4, modvar, " = rb_define_module(\"", module, "\");\n",
|
|
"_mSWIG = rb_define_module_under(", modvar, ", \"SWIG\");\n",
|
|
0);
|
|
Printv(f_init,
|
|
"\n",
|
|
"for (i = 0; swig_types_initial[i]; i++) {\n",
|
|
"swig_types[i] = SWIG_TypeRegister(swig_types_initial[i]);\n",
|
|
"SWIG_define_class(swig_types[i]);\n",
|
|
"}\n",
|
|
0);
|
|
Printf(f_init,"\n");
|
|
klass = new RClass();
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------
|
|
* RUBY::close(void)
|
|
*
|
|
* Finish the initialization function. Close any additional files and
|
|
* resources in use.
|
|
* --------------------------------------------------------------------- */
|
|
|
|
void RUBY::close(void) {
|
|
/* Finish off our init function */
|
|
Printf(f_init,"}\n");
|
|
SwigType_emit_type_table(f_header,f_wrappers);
|
|
}
|
|
|
|
/* --------------------------------------------------------------------------
|
|
* RUBY::nativefunction()
|
|
* -------------------------------------------------------------------------- */
|
|
void
|
|
RUBY::nativefunction(DOH *node) {
|
|
Printf(stderr,"%s:%d. Adding native function %s not supported (ignored).\n", Getfile(node), Getline(node), Getattr(node,"scriptname"));
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------
|
|
* RUBY::make_wrapper_name(char *cname)
|
|
*
|
|
* Creates a name for a wrapper function
|
|
* iname = Name of the function in scripting language
|
|
* --------------------------------------------------------------------- */
|
|
|
|
String *RUBY::make_wrapper_name(char *iname) {
|
|
String *wname = Swig_name_wrapper(iname);
|
|
Replace(wname, "?", "_p", DOH_REPLACE_ANY);
|
|
Replace(wname, "!", "_bang", DOH_REPLACE_ANY);
|
|
return wname;
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------
|
|
* RUBY::create_command(char *cname, char *iname)
|
|
*
|
|
* Creates a new command from a C function.
|
|
* cname = Name of the C function
|
|
* iname = Name of function in scripting language
|
|
* argc = Number of arguments
|
|
* --------------------------------------------------------------------- */
|
|
|
|
static int create_argc = 0;
|
|
|
|
void RUBY::create_command(String *scname, String *siname) {
|
|
char *cname, *iname;
|
|
int argc = create_argc;
|
|
cname = Char(scname);
|
|
iname = Char(siname);
|
|
String *wname = make_wrapper_name(iname);
|
|
if (CPlusPlus) {
|
|
Insert(wname,0,"VALUEFUNC(");
|
|
Append(wname,")");
|
|
}
|
|
if (current != NO_CPP)
|
|
iname = klass->strip(iname);
|
|
if (Getattr(special_methods, iname)) {
|
|
iname = GetChar(special_methods, iname);
|
|
}
|
|
|
|
String *s = NewString("");
|
|
String *temp = NewString("");
|
|
char argcs[32];
|
|
sprintf(argcs,"%d",argc);
|
|
|
|
switch (current) {
|
|
case MEMBER_FUNC:
|
|
Printv(klass->init, tab4, "rb_define_method(", klass->vname, ", \"",
|
|
iname, "\", ", wname, ", ", argcs, ");\n", 0);
|
|
|
|
break;
|
|
case CONSTRUCTOR:
|
|
Printv(s, tab4, "rb_define_singleton_method(", klass->vname,
|
|
", \"new\", ", wname, ", ", argcs, ");\n", 0);
|
|
Replace(klass->init,"$constructor", s, DOH_REPLACE_ANY);
|
|
break;
|
|
case MEMBER_VAR:
|
|
Append(temp,iname);
|
|
Replace(temp,"_set", "=", DOH_REPLACE_ANY);
|
|
Replace(temp,"_get", "", DOH_REPLACE_ANY);
|
|
Printv(klass->init, tab4, "rb_define_method(", klass->vname, ", \"",
|
|
temp, "\", ", wname, ", ", argcs, ");\n", 0);
|
|
break;
|
|
case STATIC_FUNC:
|
|
Printv(klass->init, tab4, "rb_define_singleton_method(", klass->vname,
|
|
", \"", iname, "\", ", wname, ", ", argcs, ");\n", 0);
|
|
break;
|
|
default:
|
|
Printv(s, tab4, "rb_define_module_function(", modvar, ", \"",
|
|
iname, "\", ", wname, ", ", argcs, ");\n",0);
|
|
Printv(f_init,s,0);
|
|
break;
|
|
}
|
|
Delete(s);
|
|
Delete(temp);
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------
|
|
* RUBY::function()
|
|
*
|
|
* Create a function declaration and register it with the interpreter.
|
|
* --------------------------------------------------------------------- */
|
|
|
|
void RUBY::function(DOH *node) {
|
|
char *name, *iname;
|
|
SwigType *t;
|
|
ParmList *l;
|
|
|
|
char source[256], target[256];
|
|
char *tm;
|
|
String *cleanup, *outarg;
|
|
Wrapper *f;
|
|
int i;
|
|
|
|
name = GetChar(node,"name");
|
|
iname = GetChar(node,"scriptname");
|
|
t = Getattr(node,"type");
|
|
l = Getattr(node,"parms");
|
|
|
|
/* Ruby needs no destructor wrapper */
|
|
if (current == DESTRUCTOR) {
|
|
Wrapper *dummy = NewWrapper();
|
|
emit_func_call(node,dummy);
|
|
Delete(dummy);
|
|
return;
|
|
}
|
|
|
|
char mname[256], inamebuf[256];
|
|
int predicate = 0, need_result = 0;
|
|
|
|
cleanup = NewString("");
|
|
outarg = NewString("");
|
|
f = NewWrapper();
|
|
|
|
switch (current) {
|
|
case MEMBER_FUNC:
|
|
case MEMBER_VAR:
|
|
case STATIC_FUNC:
|
|
strcpy(mname, klass->strip(iname));
|
|
if (Getattr(klass->predmethods, mname)) {
|
|
predicate = 1;
|
|
sprintf(inamebuf,"%s?",iname);
|
|
iname = inamebuf;
|
|
}
|
|
break;
|
|
}
|
|
String *wname = make_wrapper_name(iname);
|
|
|
|
/* Get number of arguments */
|
|
int numarg = ParmList_numarg(l);
|
|
int numopt = check_numopt(l);
|
|
|
|
int start = 0;
|
|
int use_self = 0;
|
|
switch (current) {
|
|
case MEMBER_FUNC:
|
|
case MEMBER_VAR:
|
|
numarg--;
|
|
start++;
|
|
use_self = 1;
|
|
break;
|
|
}
|
|
|
|
int numreq = 0;
|
|
int numoptreal = 0;
|
|
Parm *p = l;
|
|
for (i = 0; i < start; i++) p = Getnext(p);
|
|
for (i = start; p; i++, p = Getnext(p)) {
|
|
if (!Getignore(p)) {
|
|
if (i >= ParmList_len(l) - numopt) numoptreal++;
|
|
else numreq++;
|
|
}
|
|
}
|
|
int vararg = (numoptreal != 0);
|
|
|
|
/* Now write the wrapper function itself */
|
|
Printv(f, "static VALUE\n", wname, "(", 0);
|
|
if (vararg) {
|
|
Printv(f, "int argc, VALUE *argv, VALUE self",0);
|
|
} else {
|
|
Printv(f, "VALUE self", 0);
|
|
p = l;
|
|
for (i = 0; i < start; i++) p = Getnext(p);
|
|
for (i = start; p; i++, p = Getnext(p)) {
|
|
if (!Getignore(p)) {
|
|
Printf(f,", VALUE varg%d", i);
|
|
}
|
|
}
|
|
}
|
|
Printf(f,") {\n");
|
|
|
|
/* Emit all of the local variables for holding arguments. */
|
|
if (vararg) {
|
|
p = l;
|
|
for (i = 0; i < start; i++) p = Getnext(p);
|
|
for (i = start; p; i++, p = Getnext(p)) {
|
|
if (!Getignore(p)) {
|
|
char s[256];
|
|
sprintf(s,"varg%d",i);
|
|
Wrapper_add_localv(f,s,"VALUE",s,0);
|
|
}
|
|
}
|
|
}
|
|
int pcount = emit_args(node,f);
|
|
|
|
/* Emit count to check the number of arguments */
|
|
if (vararg) {
|
|
int numscan = 0;
|
|
for (p = l, i = 0; i < start; i++) p = Getnext(p);
|
|
for (i = start; p; i++, p = Getnext(p)) {
|
|
if (!Getignore(p)) numscan++;
|
|
}
|
|
Printf(f,"rb_scan_args(argc, argv, \"%d%d\"", (numarg-numoptreal), numscan - (numarg-numoptreal));
|
|
for (p = l, i = 0; i < start; i++) p = Getnext(p);
|
|
for (i = start; p; i++, p = Getnext(p)) {
|
|
if (!Getignore(p)) {
|
|
Printf(f,", &varg%d", i);
|
|
}
|
|
}
|
|
Printf(f,");\n");
|
|
}
|
|
|
|
/* Now walk the function parameter list and generate code */
|
|
/* to get arguments */
|
|
int j = 0; /* Total number of non-optional arguments */
|
|
|
|
p = l;
|
|
for (i = 0; i < pcount ; i++, p = Getnext(p)) {
|
|
SwigType *pt = Gettype(p);
|
|
String *pn = Getname(p);
|
|
|
|
/* Produce string representation of source and target arguments */
|
|
int selfp = (use_self && i == 0);
|
|
if (selfp)
|
|
strcpy(source,"self");
|
|
else
|
|
sprintf(source,"varg%d",i);
|
|
|
|
sprintf(target,"%s", Char(Getlname(p)));
|
|
|
|
if (!Getignore(p)) {
|
|
char *tab = (char*)tab4;
|
|
if (j >= (pcount-numopt)) { /* Check if parsing an optional argument */
|
|
Printf(f," if (argc > %d) {\n", j - start);
|
|
tab = (char*)tab8;
|
|
}
|
|
|
|
/* Get typemap for this argument */
|
|
tm = ruby_typemap_lookup((char*)"in",pt,pn,source,target,f);
|
|
if (tm) {
|
|
String *s = NewString(tm);
|
|
Printv(f, s, 0);
|
|
Replace(f, "$arg", source, DOH_REPLACE_ANY);
|
|
Delete(s);
|
|
} else {
|
|
Printf(stderr,"%s:%d. No typemapping for datatype %s\n",
|
|
Getfile(node), Getline(node), SwigType_str(pt,0));
|
|
}
|
|
if (j >= (pcount-numopt))
|
|
Printv(f, tab4, "} \n", 0);
|
|
j++;
|
|
}
|
|
|
|
/* Check to see if there was any sort of a constaint typemap */
|
|
tm = ruby_typemap_lookup((char*)"check",pt,pn,source,target);
|
|
if (tm) {
|
|
String *s = NewString(tm);
|
|
Printv(f, s, 0);
|
|
Replace(f, "$arg", source, DOH_REPLACE_ANY);
|
|
Delete(s);
|
|
}
|
|
|
|
/* Check if there was any cleanup code (save it for later) */
|
|
tm = ruby_typemap_lookup((char*)"freearg",pt,pn,target,source);
|
|
if (tm) {
|
|
String *s = NewString(tm);
|
|
Printv(cleanup,s,0);
|
|
Replace(cleanup,"$arg",source, DOH_REPLACE_ANY);
|
|
Delete(s);
|
|
}
|
|
|
|
tm = ruby_typemap_lookup((char*)"argout",pt,pn,target,(char*)"vresult");
|
|
if (tm) {
|
|
String *s = NewString(tm);
|
|
need_result = 1;
|
|
Printv(outarg, s, 0);
|
|
Replace(outarg, "$arg", source, DOH_REPLACE_ANY);
|
|
Delete(s);
|
|
}
|
|
}
|
|
|
|
/* Now write code to make the function call */
|
|
emit_func_call(node,f);
|
|
|
|
|
|
/* Return value if necessary */
|
|
if (SwigType_type(t) != T_VOID) {
|
|
need_result = 1;
|
|
if (predicate) {
|
|
Printv(f, tab4, "vresult = (result ? Qtrue : Qfalse);\n", 0);
|
|
} else {
|
|
tm = ruby_typemap_lookup((char*)"out",t,name,(char*)"result",(char*)"vresult");
|
|
if (tm) {
|
|
String *s = NewString(tm);
|
|
Printv(f, s, 0);
|
|
Delete(s);
|
|
} else {
|
|
Printf(stderr,"%s:%d. No return typemap for datatype %s\n",
|
|
Getfile(node), Getline(node),SwigType_str(t,0));
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Dump argument output code; */
|
|
Printv(f,outarg,0);
|
|
|
|
/* Dump the argument cleanup code */
|
|
Printv(f,cleanup,0);
|
|
|
|
/* Look for any remaining cleanup. This processes the %new directive */
|
|
if (NewObject) {
|
|
tm = ruby_typemap_lookup((char*)"newfree",t,name,(char*)"result",(char*)"");
|
|
if (tm) {
|
|
String *s = NewString(tm);
|
|
Printv(f,s, 0);
|
|
Delete(s);
|
|
}
|
|
}
|
|
|
|
/* free pragma */
|
|
if (current == MEMBER_FUNC && Getattr(klass->freemethods, mname)) {
|
|
Printv(f, tab4, "DATA_PTR(self) = 0;\n", 0);
|
|
}
|
|
|
|
/* Special processing on return value. */
|
|
tm = ruby_typemap_lookup((char*)"ret",t,name,(char*)"result",(char*)"");
|
|
if (tm) {
|
|
String *s = NewString(tm);
|
|
Printv(f,s, 0);
|
|
}
|
|
|
|
/* Wrap things up (in a manner of speaking) */
|
|
if (need_result) {
|
|
Wrapper_add_local(f,"vresult","VALUE vresult = Qnil");
|
|
Printv(f, tab4, "return vresult;\n}\n", 0);
|
|
} else {
|
|
Printv(f, tab4, "return Qnil;\n}\n", 0);
|
|
}
|
|
|
|
/* Substitute the cleanup code */
|
|
Replace(f,"$cleanup",cleanup, DOH_REPLACE_ANY);
|
|
|
|
/* Emit the function */
|
|
Printf(f_wrappers,"%s", f);
|
|
|
|
/* Now register the function with the language */
|
|
create_argc = vararg ? -1 : numarg;
|
|
create_command(name, iname);
|
|
Delete(cleanup);
|
|
Delete(outarg);
|
|
Delete(f);
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------
|
|
* RUBY::variable()
|
|
*
|
|
* Create a link to a C variable.
|
|
* --------------------------------------------------------------------- */
|
|
|
|
void RUBY::variable(DOH *node) {
|
|
char *name, *iname;
|
|
SwigType *t;
|
|
|
|
char *tm, *source;
|
|
|
|
String *getfname, *setfname;
|
|
Wrapper *getf, *setf;
|
|
|
|
name = GetChar(node,"name");
|
|
iname = GetChar(node,"scriptname");
|
|
t = Getattr(node,"type");
|
|
|
|
getf = NewWrapper();
|
|
setf = NewWrapper();
|
|
|
|
/* create getter */
|
|
getfname = NewString(Swig_name_get(name));
|
|
Replace(getfname,"::", "_", DOH_REPLACE_ANY); /* FIXME: Swig_name_get bug? */
|
|
Printv(getf, "static VALUE\n", getfname, "(", 0);
|
|
Printf(getf, "VALUE self");
|
|
Printf(getf, ") {\n");
|
|
Wrapper_add_local(getf,"_val","VALUE _val");
|
|
|
|
if (SwigType_type(t) == T_USER) {
|
|
/* Hack this into a pointer */
|
|
String *pname = NewString("");
|
|
Printv(pname, "&", name, 0);
|
|
source = Char(pname);
|
|
} else {
|
|
source = name;
|
|
}
|
|
|
|
tm = ruby_typemap_lookup((char*)"varout",t,name,source,(char*)"_val");
|
|
if (!tm)
|
|
tm = ruby_typemap_lookup((char*)"out",t,name,source,(char*)"_val");
|
|
if (tm) {
|
|
String *s = NewString(tm);
|
|
Printv(getf,s, 0);
|
|
Delete(s);
|
|
} else {
|
|
Printf(stderr,"%s:%d. Unable to link with variable type %s\n",
|
|
Getfile(node), Getline(node),SwigType_str(t,0));
|
|
}
|
|
Printv(getf, tab4, "return _val;\n}\n", 0);
|
|
Printf(f_wrappers,"%s", getf);
|
|
|
|
if (ReadOnly) {
|
|
setfname = NewString("NULL");
|
|
} else {
|
|
/* create setter */
|
|
char *target;
|
|
|
|
setfname = NewString(Swig_name_set(name));
|
|
Replace(setfname,"::", "_", DOH_REPLACE_ANY); /* FIXME: Swig_name_get bug? */
|
|
Printv(setf, "static VALUE\n", setfname, "(VALUE self, ", 0);
|
|
Printf(setf, "VALUE _val) {\n");
|
|
|
|
if (SwigType_type(t) == T_USER) {
|
|
SwigType_add_pointer(t);
|
|
Wrapper_add_localv(setf,"temp",SwigType_lstr(t,0), "temp",0);
|
|
SwigType_del_pointer(t);
|
|
target = "temp";
|
|
} else {
|
|
target = name;
|
|
}
|
|
|
|
tm = ruby_typemap_lookup((char*)"varin",t,name,(char*)"_val",target);
|
|
if (!tm)
|
|
tm = ruby_typemap_lookup((char*)"in",t,name,(char*)"_val",target);
|
|
if (tm) {
|
|
String *s = NewString(tm);
|
|
Printv(setf,s,0);
|
|
Delete(s);
|
|
} else {
|
|
Printf(stderr,"%s:%d. Unable to link with variable type %s\n",
|
|
Getfile(node), Getline(node),SwigType_str(t,0));
|
|
}
|
|
if (SwigType_type(t) == T_USER) {
|
|
Printv(setf, name, " = *temp;\n",0);
|
|
}
|
|
Printv(setf, tab4, "return _val;\n",0);
|
|
Printf(setf,"}\n");
|
|
Printf(f_wrappers,"%s", setf);
|
|
}
|
|
|
|
/* define accessor method */
|
|
if (CPlusPlus) {
|
|
Insert(getfname,0,"VALUEFUNC(");
|
|
Append(getfname,")");
|
|
Insert(setfname,0,"VALUEFUNC(");
|
|
Append(setfname,")");
|
|
}
|
|
|
|
String *s = NewString("");
|
|
switch (current) {
|
|
case STATIC_VAR:
|
|
/* C++ class variable */
|
|
Printv(s,
|
|
tab4, "rb_define_singleton_method(", klass->vname, ", \"",
|
|
klass->strip(iname), "\", ", getfname, ", 0);\n",
|
|
0);
|
|
if (!ReadOnly) {
|
|
Printv(s,
|
|
tab4, "rb_define_singleton_method(", klass->vname, ", \"",
|
|
klass->strip(iname), "=\", ", setfname, ", 1);\n",
|
|
0);
|
|
}
|
|
Printv(klass->init,s,0);
|
|
break;
|
|
default:
|
|
/* C global variable */
|
|
/* wrapped in Ruby module attribute */
|
|
Printv(s,
|
|
tab4, "rb_define_singleton_method(", modvar, ", \"",
|
|
iname, "\", ", getfname, ", 0);\n",
|
|
0);
|
|
if (!ReadOnly) {
|
|
Printv(s,
|
|
tab4, "rb_define_singleton_method(", modvar, ", \"",
|
|
iname, "=\", ", setfname, ", 1);\n",
|
|
0);
|
|
}
|
|
Printv(f_init,s,0);
|
|
Delete(s);
|
|
break;
|
|
}
|
|
Delete(getfname);
|
|
Delete(setfname);
|
|
Delete(setf);
|
|
Delete(getf);
|
|
}
|
|
|
|
|
|
/* ---------------------------------------------------------------------
|
|
* RUBY::validate_const_name(char *name)
|
|
*
|
|
* Validate constant name.
|
|
* --------------------------------------------------------------------- */
|
|
|
|
char *RUBY::validate_const_name(char *name) {
|
|
if (!name || name[0] == '\0')
|
|
return name;
|
|
|
|
if (isupper(name[0]))
|
|
return name;
|
|
|
|
if (islower(name[0])) {
|
|
name[0] = toupper(name[0]);
|
|
/* Printf(stderr,"%s:%d. Wrong constant/class/module name "
|
|
"(corrected to `%s')\n", Getfile(node), Getline(node), name); */
|
|
|
|
Printf(stderr,"?:?. Wrong constant/class/module name (corrected to '%s')\n", name);
|
|
return name;
|
|
}
|
|
|
|
Printf(stderr,"?:?. Wrong constant/class/module name\n");
|
|
return name;
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------
|
|
* RUBY::constant()
|
|
*
|
|
* Makes a constant.
|
|
* --------------------------------------------------------------------- */
|
|
|
|
void RUBY::constant(DOH *node) {
|
|
char *tm;
|
|
char *name, *iname;
|
|
SwigType *type;
|
|
char *value;
|
|
|
|
name = GetChar(node,"name");
|
|
iname = GetChar(node,"scriptname");
|
|
type = Getattr(node,"type");
|
|
value = GetChar(node,"value");
|
|
|
|
if (current == CLASS_CONST)
|
|
iname = klass->strip(iname);
|
|
|
|
tm = ruby_typemap_lookup((char*)"const",type,name,value,iname);
|
|
if (tm) {
|
|
String *str = NewString(tm);
|
|
Replace(str,"$value",value, DOH_REPLACE_ANY);
|
|
if (current == CLASS_CONST) {
|
|
Replace(str,"$module", klass->vname, DOH_REPLACE_ANY);
|
|
Printv(klass->init, str, 0);
|
|
} else {
|
|
Replace(str,"$module", modvar, DOH_REPLACE_ANY);
|
|
Printf(f_init,"%s", str);
|
|
}
|
|
Delete(str);
|
|
} else {
|
|
Printf(stderr,"%s:%d. Unable to create constant %s = %s\n",
|
|
Getfile(node), Getline(node), SwigType_str(type,0), value);
|
|
}
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------
|
|
* RUBY::ruby_typemap_lookup(char *op, SwigType *type, char *pname, char *source, char *target, WrapperFunction *f = 0)
|
|
*
|
|
* Ruby specific typemap_lookup.
|
|
* op = string code for type of mapping
|
|
* type = the datatype
|
|
* pname = an optional parameter name
|
|
* source = a string with the source variable
|
|
* target = a string containing the target value
|
|
* f = a wrapper function object (optional)
|
|
* --------------------------------------------------------------------- */
|
|
|
|
char *RUBY::ruby_typemap_lookup(char *op, SwigType *type, String_or_char *pname, char *source, char *target, Wrapper *f) {
|
|
static String *s = 0;
|
|
char *tm;
|
|
String *target_replace = NewString(target);
|
|
target = Char(target_replace);
|
|
int type_code, add_pointer = 0;
|
|
|
|
if (SwigType_type(type) == T_USER)
|
|
add_pointer = 1;
|
|
if (add_pointer)
|
|
SwigType_add_pointer(type);
|
|
type_code = SwigType_type(type);
|
|
|
|
RClass *cls = RCLASS(classes, SwigType_base(type));
|
|
|
|
if (!s) s = NewString("");
|
|
Clear(s);
|
|
|
|
if ((strcmp("out", op) == 0 || strcmp("in", op) == 0)
|
|
&& Cmp(SwigType_base(type), "VALUE") == 0) {
|
|
Printf(s,"$target = $source;\n");
|
|
} else if (strcmp("out", op) == 0
|
|
&& (type_code == T_POINTER || type_code == T_REFERENCE)
|
|
&& cls) {
|
|
const char *vname = (current == CONSTRUCTOR ? "self" : Char(cls->vname));
|
|
Printv(s, "$target = Wrap_", cls->cname, "(", vname, ", $source);\n",0);
|
|
} else if (strcmp("in", op)==0
|
|
&& (type_code == T_POINTER || type_code == T_REFERENCE)
|
|
&& cls) {
|
|
Printv(s, "Get_", cls->cname, "($source, $target);\n", 0);
|
|
} else {
|
|
if (add_pointer) {
|
|
SwigType_del_pointer(type);
|
|
add_pointer = 0;
|
|
}
|
|
|
|
tm = Swig_typemap_lookup(op, type, pname, source, target, f);
|
|
if (tm) {
|
|
Delete(target_replace);
|
|
Printv(s, tm, "\n", 0);
|
|
} else {
|
|
Clear(s);
|
|
if (strcmp("in", op) == 0) {
|
|
String *v = NewString("");
|
|
if (from_VALUE(type, (char*)"$source", (char*)"$target", v))
|
|
Printv(s, v, "\n", 0);
|
|
Delete(v);
|
|
} else if (strcmp("out", op) == 0) {
|
|
String *v = NewString("");
|
|
if (to_VALUE(type, (char*)"$source", v))
|
|
Printv(s, "$target = ", v, ";\n", 0);
|
|
Delete(v);
|
|
} else if (strcmp("const", op) == 0) {
|
|
String *v = NewString("");
|
|
if (to_VALUE(type, (char*)"$value", v, 1)) {
|
|
Printv(s, "rb_define_const($module, \"$target\", ", v, ");\n", 0);
|
|
validate_const_name(target);
|
|
}
|
|
Delete(v);
|
|
}
|
|
}
|
|
}
|
|
if (source && strlen(source) > 0)
|
|
Replace(s,"$source",source, DOH_REPLACE_ANY);
|
|
if (target && strlen(target) > 0)
|
|
Replace(s,"$target",target, DOH_REPLACE_ANY);
|
|
Replace(s,"$type", SwigType_str(type,0), DOH_REPLACE_ANY);
|
|
|
|
if (add_pointer) {
|
|
SwigType_del_pointer(type);
|
|
add_pointer = 0;
|
|
}
|
|
|
|
if (Len(s) == 0)
|
|
return NULL;
|
|
return Char(s);
|
|
}
|
|
|
|
|
|
static void
|
|
convert_pointer(char *src, SwigType *t, String *f) {
|
|
SwigType_remember(t);
|
|
Printv(f, "SWIG_NewPointerObj((void *)", src, ", SWIGTYPE", SwigType_manglestr(t), ")", 0);
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------
|
|
* RUBY::to_VALUE(SwigType *type, char *value, literal)
|
|
*
|
|
* Makes a VALUE (as a string)
|
|
* type = Datatype of the C value
|
|
* value = C value (as a string)
|
|
* str = resulting code (as a string)
|
|
* raw = value is raw string (not quoted) ?
|
|
* --------------------------------------------------------------------- */
|
|
|
|
int RUBY::to_VALUE(SwigType *type, char *value, String *str, int raw) {
|
|
Clear(str);
|
|
switch(SwigType_type(type)) {
|
|
case T_INT:
|
|
case T_SHORT:
|
|
case T_LONG:
|
|
case T_SCHAR:
|
|
Printv(str, "INT2NUM(", value, ")", 0);
|
|
break;
|
|
case T_UINT:
|
|
case T_USHORT:
|
|
case T_ULONG:
|
|
case T_UCHAR:
|
|
Printv(str,"UINT2NUM(", value, ")", 0);
|
|
break;
|
|
case T_DOUBLE:
|
|
case T_FLOAT:
|
|
Printv(str, "rb_float_new(", value, ")", 0);
|
|
break;
|
|
case T_CHAR:
|
|
Printv(str, "rb_str_new(&", value, ", 1)", 0);
|
|
break;
|
|
case T_BOOL:
|
|
Printv(str, "(", value, " ? Qtrue : Qfalse)", 0);
|
|
break;
|
|
case T_STRING:
|
|
if (raw)
|
|
Printv(str, "rb_str_new2(\"", value, "\")", 0);
|
|
else
|
|
Printv(str, "rb_str_new2(", value, ")", 0);
|
|
break;
|
|
case T_ARRAY:
|
|
{
|
|
SwigType *aop;
|
|
SwigType *ta = Copy(type);
|
|
aop = SwigType_pop(ta);
|
|
if (SwigType_type(ta) == T_CHAR) {
|
|
Printf(str, "rb_str_new2(%s)", value);
|
|
break;
|
|
}
|
|
convert_pointer(value, type, str);
|
|
break;
|
|
}
|
|
case T_POINTER: case T_REFERENCE:
|
|
convert_pointer(value, type, str);
|
|
break;
|
|
case T_USER:
|
|
SwigType_add_pointer(type);
|
|
convert_pointer(value, type, str);
|
|
SwigType_del_pointer(type);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
if (Len(str) == 0)
|
|
return 0;
|
|
return 1;
|
|
}
|
|
|
|
|
|
static void
|
|
get_pointer(char *src, char *dest, SwigType *t, String *f) {
|
|
SwigType *lt;
|
|
|
|
SwigType_remember(t);
|
|
Printv(f, dest, " = (", SwigType_lstr(t,0), ")SWIG_ConvertPtr(", src, ", ", 0);
|
|
|
|
lt = Swig_clocal_type(t);
|
|
if (Cmp(lt,"p.void") == 0) {
|
|
Printv(f, "0);", 0);
|
|
} else {
|
|
Printv(f, "SWIGTYPE", SwigType_manglestr(t), ");", 0);
|
|
}
|
|
Delete(lt);
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------
|
|
* RUBY::from_VALUE(SwigType *type, char *value)
|
|
*
|
|
* extract VALUE
|
|
* type = Datatype of the C value
|
|
* value = Ruby VALUE (as a string)
|
|
* target= target C variable (as a string)
|
|
* str = resulting code (as a string)
|
|
* --------------------------------------------------------------------- */
|
|
|
|
int RUBY::from_VALUE(SwigType *type, char *value, char *target, String *str) {
|
|
Clear(str);
|
|
switch(SwigType_type(type)) {
|
|
case T_INT:
|
|
Printv(str, target, " = NUM2INT(", value, ");", 0);
|
|
break;
|
|
case T_LONG:
|
|
Printv(str, target, " = NUM2LONG(", value, ");", 0);
|
|
break;
|
|
case T_SHORT:
|
|
Printv(str, target, " = NUM2SHRT(", value, ");", 0);
|
|
break;
|
|
case T_UINT:
|
|
Printv(str, target, " = NUM2UINT(", value, ");", 0);
|
|
break;
|
|
case T_ULONG:
|
|
Printv(str, target, " = NUM2ULONG(", value, ");", 0);
|
|
break;
|
|
case T_USHORT:
|
|
Printv(str, target, " = NUM2USHRT(", value, ");", 0);
|
|
break;
|
|
case T_DOUBLE:
|
|
case T_FLOAT:
|
|
Printv(str, target, " = NUM2DBL(", value, ");", 0);
|
|
break;
|
|
case T_CHAR: case T_SCHAR: case T_UCHAR:
|
|
Printv(str, target, " = NUM2CHR(", value, ");", 0);
|
|
break;
|
|
case T_BOOL:
|
|
Printv(str, target, " = RTEST(", value, ");", 0);
|
|
break;
|
|
case T_STRING:
|
|
Printv(str, target, " = STR2CSTR(", value, ");", 0);
|
|
break;
|
|
case T_ARRAY:
|
|
{
|
|
SwigType *aop;
|
|
SwigType *ta = Copy(type);
|
|
aop = SwigType_pop(ta);
|
|
if (SwigType_type(ta) == T_CHAR) {
|
|
String *dim = SwigType_array_getdim(aop,0);
|
|
if (dim && Len(dim)) {
|
|
Printf(str, "strncpy(%s, STR2CSTR(%s), %s);", target, value, dim);
|
|
}
|
|
break;
|
|
}
|
|
get_pointer(value, target, type, str);
|
|
break;
|
|
}
|
|
case T_POINTER: case T_REFERENCE:
|
|
get_pointer(value, target, type, str);
|
|
break;
|
|
case T_USER:
|
|
SwigType_add_pointer(type);
|
|
get_pointer(value, target, type, str);
|
|
SwigType_del_pointer(type);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
if (Len(str) == 0) return 0;
|
|
return 1;
|
|
}
|
|
|
|
/* ----------------------------------------------------------------------
|
|
* void RUBY::cpp_open_class(char *classname, char *classrename, char *ctype, int strip)
|
|
*
|
|
* Open a new C++ class.
|
|
*
|
|
* INPUTS:
|
|
* name = Real name of the C++ class
|
|
* rename = New name of the class (if %name was used)
|
|
* ctype = Class type (struct, class, union, etc...)
|
|
* strip = Flag indicating whether we should strip the
|
|
* class type off
|
|
*
|
|
* This function is in charge of creating a new class. The SWIG parser has
|
|
* already processed the entire class definition prior to calling this
|
|
* function (which should simplify things considerably).
|
|
*
|
|
* ---------------------------------------------------------------------- */
|
|
|
|
void RUBY::cpp_open_class(DOH *node) {
|
|
this->Language::cpp_open_class(node);
|
|
|
|
char *cname = GetChar(node,"name");
|
|
char *rename = GetChar(node,"scriptname");
|
|
char *ctype = GetChar(node,"classtype");
|
|
int strip = GetInt(node,"strip");
|
|
|
|
klass = RCLASS(classes, cname);
|
|
|
|
if (strip) {
|
|
Clear(klass->type);
|
|
Append(klass->type, klass->cname);
|
|
} else {
|
|
Clear(klass->type);
|
|
Printv(klass->type, ctype, " ", klass->cname,0);
|
|
}
|
|
|
|
Printv(klass->header, "\nstatic VALUE ", klass->vname, ";\n", 0);
|
|
Printv(klass->init, "\n", tab4, 0);
|
|
Printv(klass->init, klass->vname, " = rb_define_class_under(", modvar,
|
|
", \"", klass->name, "\", $super);\n", 0);
|
|
Replace(klass->includes,"$class", klass->vname, DOH_REPLACE_ANY);
|
|
Printv(klass->init, klass->includes,0);
|
|
Printv(klass->init, "$constructor",0);
|
|
|
|
Printv(klass->header,
|
|
"$markproto",
|
|
"$freeproto",
|
|
"#define Wrap_", klass->cname, "(klass, ptr) (\\\n",
|
|
tab4, "(ptr) ? Data_Wrap_Struct(klass",
|
|
", $markfunc, $freefunc, ptr) : Qnil )\n",
|
|
"#define Get_", klass->cname, "(val, ptr) {\\\n",
|
|
tab4, "if (NIL_P(val)) ptr = NULL;\\\n",
|
|
tab4, "else {\\\n",
|
|
tab8, "if (!rb_obj_is_kind_of(val, ", klass->vname, "))\\\n",
|
|
tab8, tab4, "rb_raise(rb_eTypeError, \"wrong argument type",
|
|
" (expected ", klass->name, ")\");\\\n",
|
|
tab8, "Data_Get_Struct(val, ", klass->type, ", ptr);\\\n",
|
|
tab8, "if (!ptr) rb_raise(rb_eRuntimeError, \"",
|
|
"This ", klass->name, " already released\");\\\n",
|
|
tab4, "}\\\n",
|
|
"}\n",
|
|
0);
|
|
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------
|
|
* void RUBY::cpp_close_class()
|
|
*
|
|
* Close the current class
|
|
* --------------------------------------------------------------------- */
|
|
|
|
void RUBY::cpp_close_class() {
|
|
this->Language::cpp_close_class();
|
|
|
|
Replace(klass->header,"$markfunc", "0", DOH_REPLACE_ANY);
|
|
Replace(klass->header,"$markproto", "", DOH_REPLACE_ANY);
|
|
if (!klass->destructor_defined) {
|
|
Replace(klass->header,"$freefunc", "0", DOH_REPLACE_ANY);
|
|
Replace(klass->header,"$freeproto", "", DOH_REPLACE_ANY);
|
|
}
|
|
Printv(f_header, klass->header,0);
|
|
|
|
Replace(klass->aliases,"$class", klass->vname, DOH_REPLACE_ANY);
|
|
Printv(klass->init, klass->aliases,0);
|
|
|
|
String *s = NewString("");
|
|
Printv(s, tab4, "rb_undef_method(CLASS_OF(", klass->vname,
|
|
"), \"new\");\n", 0);
|
|
Replace(klass->init,"$constructor", s, DOH_REPLACE_ANY);
|
|
Replace(klass->init,"$super", "rb_cObject", DOH_REPLACE_ANY);
|
|
|
|
Printv(f_init,klass->init,0);
|
|
klass = 0;
|
|
}
|
|
|
|
/* ----------------------------------------------------------------------
|
|
* void RUBY::cpp_inherit(char **baseclass, int mode)
|
|
*
|
|
* Inherit attributes from given baseclass.
|
|
*
|
|
* INPUT:
|
|
* baseclass = NULL terminate list of baseclasses
|
|
*
|
|
* --------------------------------------------------------------------- */
|
|
|
|
|
|
void RUBY::cpp_inherit(List *bases, int mode) {
|
|
if (!bases) return;
|
|
String *base;
|
|
for (base = Firstitem(bases); base; base = Nextitem(bases)) {
|
|
RClass *super = RCLASS(classes, Char(base));
|
|
if (super) {
|
|
Replace(klass->init,"$super", super->vname, DOH_REPLACE_ANY);
|
|
break; /* ignore multiple inheritance */
|
|
}
|
|
}
|
|
}
|
|
|
|
/* ----------------------------------------------------------------------
|
|
* void RUBY::cpp_member_func(char *name, char *iname, SwigType *t, ParmList *l)
|
|
*
|
|
* Method for adding C++ member function
|
|
*
|
|
* INPUTS:
|
|
* name - name of the member function
|
|
* iname - renaming (if given)
|
|
* t - Return datatype
|
|
* l - Parameter list
|
|
*
|
|
* By default, we're going to create a function of the form :
|
|
*
|
|
* Foo_bar(this,args)
|
|
*
|
|
* Where Foo is the classname, bar is the member name and the this pointer
|
|
* is explicitly attached to the beginning.
|
|
*
|
|
* The renaming only applies to the member function part, not the full
|
|
* classname.
|
|
*
|
|
* --------------------------------------------------------------------- */
|
|
|
|
void RUBY::cpp_memberfunction(DOH *node) {
|
|
current = MEMBER_FUNC;
|
|
this->Language::cpp_memberfunction(node);
|
|
current = NO_CPP;
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------
|
|
* void RUBY::cpp_constructor(char *name, char *iname, ParmList *l)
|
|
*
|
|
* Method for adding C++ member constructor
|
|
*
|
|
* INPUTS:
|
|
* name - Name of the constructor (usually same as classname)
|
|
* iname - Renamed version
|
|
* l - parameters
|
|
* -------------------------------------------------------------------- */
|
|
|
|
void RUBY::cpp_constructor(DOH *node) {
|
|
current = CONSTRUCTOR;
|
|
this->Language::cpp_constructor(node);
|
|
current = NO_CPP;
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------
|
|
* void RUBY::cpp_destructor(char *name, char *iname)
|
|
*
|
|
* Method for adding C++ member destructor
|
|
*
|
|
* INPUT:
|
|
* name - Name of the destructor (classname)
|
|
* iname - Renamed destructor
|
|
*
|
|
* -------------------------------------------------------------------- */
|
|
|
|
void RUBY::cpp_destructor(DOH *node) {
|
|
char *name, *newname;
|
|
|
|
name = GetChar(node,"name");
|
|
newname = GetChar(node,"scriptname");
|
|
current = DESTRUCTOR;
|
|
this->Language::cpp_destructor(node);
|
|
|
|
String *freefunc = NewString("");
|
|
String *freeproto = NewString("");
|
|
String *freebody = NewString("");
|
|
|
|
Printv(freefunc, "free_", klass->cname, 0);
|
|
Printv(freeproto, "static void ", freefunc, "(", klass->type, " *);\n", 0);
|
|
Printv(freebody, "static void\n",
|
|
freefunc, "(", klass->type, " *", Swig_cparm_name(0,0), ") {\n",
|
|
tab4, 0);
|
|
if (AddMethods) {
|
|
Printv(freebody, Swig_name_destroy(name), "(", Swig_cparm_name(0,0), ")", 0);
|
|
} else {
|
|
/* When no addmethods mode, swig emits no destroy function. */
|
|
if (CPlusPlus)
|
|
Printv(freebody, Swig_cppdestructor_call(), 0);
|
|
else
|
|
Printv(freebody, Swig_cdestructor_call(), 0);
|
|
}
|
|
Printv(freebody, ";\n}\n", 0);
|
|
if (CPlusPlus) {
|
|
Insert(freefunc,0,"VOIDFUNC(");
|
|
Append(freefunc,")");
|
|
}
|
|
|
|
Replace(klass->header,"$freefunc", freefunc, DOH_REPLACE_ANY);
|
|
Replace(klass->header,"$freeproto", freeproto, DOH_REPLACE_ANY);
|
|
Printv(f_wrappers, freebody, 0);
|
|
|
|
klass->destructor_defined = 1;
|
|
current = NO_CPP;
|
|
Delete(freefunc);
|
|
Delete(freeproto);
|
|
Delete(freebody);
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------
|
|
* void RUBY::cpp_variable(char *name, char *iname, SwigType *t)
|
|
*
|
|
* Wrap a C++ data member
|
|
*
|
|
* INPUTS :
|
|
* name = Name of the C++ member
|
|
* iname = Name as used in the interpreter
|
|
* t = Datatype
|
|
*
|
|
* This creates a pair of functions to set/get the variable of a member.
|
|
* -------------------------------------------------------------------- */
|
|
|
|
void RUBY::cpp_variable(DOH *node) {
|
|
current = MEMBER_VAR;
|
|
this->Language::cpp_variable(node);
|
|
current = NO_CPP;
|
|
}
|
|
|
|
/* -----------------------------------------------------------------------
|
|
* void RUBY::cpp_static_func(char *name, char *iname, SwigType *t, ParmList *l)
|
|
*
|
|
* Wrap a static C++ function
|
|
*
|
|
* INPUTS:
|
|
* name = Real name of the function
|
|
* iname = New name in interpreter
|
|
* t = Return datatype
|
|
* l = Parameters
|
|
* ---------------------------------------------------------------------- */
|
|
|
|
void RUBY::cpp_staticfunction(DOH *node) {
|
|
current = STATIC_FUNC;
|
|
this->Language::cpp_staticfunction(node);
|
|
current = NO_CPP;
|
|
}
|
|
|
|
/* ----------------------------------------------------------------------
|
|
* void RUBY::cpp_declare_const(char *name, char *iname, SwigType *t, char *value)
|
|
*
|
|
* Create a C++ constant
|
|
*
|
|
* INPUTS :
|
|
* name = Real name of the constant
|
|
* iname = new name
|
|
* t = Datatype
|
|
* value = value as a string
|
|
*
|
|
* --------------------------------------------------------------------- */
|
|
|
|
|
|
void RUBY::cpp_constant(DOH *node) {
|
|
current = CLASS_CONST;
|
|
this->Language::cpp_constant(node);
|
|
current = NO_CPP;
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------
|
|
* void RUBY::cpp_static_var(char *name, char *iname, SwigType *t)
|
|
*
|
|
* Wrap a static C++ variable
|
|
*
|
|
* INPUT :
|
|
* name = name of the variable
|
|
* iname = interpreter name
|
|
* t = Datatype
|
|
*
|
|
* --------------------------------------------------------------------- */
|
|
|
|
void RUBY::cpp_staticvariable(DOH *node) {
|
|
current = STATIC_VAR;
|
|
this->Language::cpp_staticvariable(node);
|
|
current = NO_CPP;
|
|
}
|
|
|
|
/* -----------------------------------------------------------------------
|
|
* RUBY::cpp_class_decl(char *name, char *rename, char *type)
|
|
*
|
|
* A forward class declaration
|
|
* ----------------------------------------------------------------------- */
|
|
|
|
void RUBY::cpp_class_decl(DOH *node) {
|
|
String *cname = Getattr(node,"name");
|
|
String *rename = Getattr(node,"scriptname");
|
|
String *ctype = Getattr(node,"classtype");
|
|
String *valid_name = NewString((rename ? rename : cname));
|
|
validate_const_name(Char(valid_name));
|
|
klass->set_name(Char(cname), Char(rename), Char(valid_name));
|
|
SET_RCLASS(classes, Char(cname), klass);
|
|
if (ctype && Len(ctype) > 0) {
|
|
char temp[256];
|
|
sprintf(temp,"%s %s", Char(ctype), Char(cname));
|
|
SET_RCLASS(classes, temp, klass);
|
|
}
|
|
/*
|
|
char s[256];
|
|
sprintf(s,"extern VALUE %s;\n", Char(klass->vname));
|
|
Printf(f_header, s);
|
|
*/
|
|
klass = new RClass();
|
|
Delete(valid_name);
|
|
}
|
|
|
|
/* --------------------------------------------------------------------
|
|
* void RUBY::pragma(char *target, char *var, char *value)
|
|
*
|
|
* A pragma declaration
|
|
* -------------------------------------------------------------------- */
|
|
|
|
void RUBY::pragma(DOH *node) {
|
|
String *cmd = Getattr(node,"name");
|
|
String *value = Getattr(node,"value");
|
|
if (Cmp(cmd, "free") == 0) {
|
|
char name[64];
|
|
if (sscanf(Char(value), " %s ", name) != 1) {
|
|
Printf(stderr, "%s:%d. Invalid free pragma.\n",
|
|
Getfile(node), Getline(node));
|
|
return;
|
|
}
|
|
Setattr(klass->freemethods, name, name);
|
|
} else if (Cmp(cmd, "include") == 0) {
|
|
char name[64];
|
|
if (sscanf(Char(value), " %s ", name) != 1) {
|
|
Printf(stderr, "%s:%d. Invalid include pragma.\n",
|
|
Getfile(node), Getline(node));
|
|
return;
|
|
}
|
|
Printv(klass->includes,tab4, "rb_include_module($class, ",
|
|
"rb_eval_string(\"", name, "\"));\n", 0);
|
|
} else if (Cmp(cmd, "alias") == 0) {
|
|
char alias[64], name[64];
|
|
if (sscanf(Char(value), " %s %s ", alias, name) != 2) {
|
|
Printf(stderr, "%s:%d. Invalid alias pragma.\n",
|
|
Getfile(node), Getline(node));
|
|
return;
|
|
}
|
|
Printv(klass->aliases, tab4, "rb_define_alias($class, ",
|
|
"\"", alias, "\", \"", name, "\");\n", 0);
|
|
} else if (Cmp(cmd, "pred") == 0) {
|
|
char *tok;
|
|
tok = strtok(Char(value), " \t");
|
|
while (tok) {
|
|
Setattr(klass->predmethods, tok, tok);
|
|
tok = strtok(0, " \t");
|
|
}
|
|
} else if (Cmp(cmd, "debug") == 0) {
|
|
Printf(f_header, "/* %s */\n", value);
|
|
Printf(f_wrappers, "/* %s */\n", value);
|
|
Printf(f_init, "/* %s */\n", value);
|
|
Printf(stderr, "%s\n", value);
|
|
}
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------
|
|
* RUBY::import(char *filename)
|
|
*
|
|
* Imports a SWIG module as a separate file.
|
|
*---------------------------------------------------------------------- */
|
|
|
|
|
|
void RUBY::import(String *modname) {
|
|
Printf(f_init, "rb_f_require(Qnil, rb_str_new2(\"%s\"));\n", modname);
|
|
}
|
|
|
|
/*
|
|
* Local Variables:
|
|
* c-basic-offset: 2
|
|
* End:
|
|
*/
|
|
|
|
|
|
|
|
|
|
|